파이썬 Tornado를 활용한 웹 프로젝트 데모 템플릿

간단해 보이지만 실제로 구현하려면 다양한 문제에 직면하게 됩니다. 이번에는 개발 과정에서 겪은 경로를 정리하여 추후 참고할 수 있도록 기록합니다.

#!/usr/bin/env python
# coding=utf-8

import os
import tornado.httpserver
import tornado.options
import tornado.web
from auto_gen_jd import AutoGenJD
from jd_parser import JdParser
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

tornado.options.define("port", default=8086, help="서버 포트 설정", type=int)

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        input_text = self.get_argument("source", "")
        count = int(self.get_argument("num", 5))
        output_result = self.get_argument("result", [])
        self.render("input_template.html", source=input_text, result=output_result, num=count)

    def post(self):
        input_text = self.get_argument("source", "")
        count = int(self.get_argument("num", 5))
        generator = AutoGenJD()
        generated_jds = generator.generate_with_kmeans(input_text, count)
        self.render("output_template.html", source=input_text, result=generated_jds, num=count)


class JobDescriptionHandler(tornado.web.RequestHandler):
    def get(self):
        input_text = self.get_argument("source", "")
        result = self.get_argument("result", [])
        self.render("input_jobdesc.html", source=input_text, result=result)

    def post(self):
        raw_text = self.get_argument("source", "")
        parser = JdParser()
        parsed_data = parser.extract_multiple_jobs(raw_text)
        self.render("output_jobdesc.html", source=raw_text, result=parsed_data)


if __name__ == "__main__":
    job_generator = AutoGenJD()
    job_parser = JdParser()
    tornado.options.parse_command_line()
    
    app = tornado.web.Application(
        handlers=[
            (r'/', MainHandler),
            (r'/generate', JobDescriptionHandler),
            (r'/parse', JobDescriptionHandler)
        ],
        template_path=os.path.join(os.path.dirname(__file__), "templates"),
        debug=True,
        autoescape=None
    )
    
    print("Tornado 서버 시작 중...")
    server = tornado.httpserver.HTTPServer(app)
    server.listen(tornado.options.options.port)
    tornado.ioloop.IOLoop.current().start()
  
템플릿 파일은 총 4개이며, 구조는 유사합니다. **output_jobdesc.html**

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>직무 설명서 분석기</title>
  <link rel="stylesheet" href="http://cdn.amazeui.org/amazeui/2.4.0/css/amazeui.min.css">
  <link rel="icon" href="favicon.ico">

  <script>
    function showResult() {
      const hintDiv = document.getElementById("resultHint");
      hintDiv.innerHTML = '<div class="am-active">분석 완료: <i class="am-icon-spinner am-icon-spin"></i></div>';
      hintDiv.style.color = "#c60a00";
      return true;
    }
  </script>
</head>
<body>
  <div class="am-topbar">
    <h1 class="am-active">온라인 시연 환경</h1>
  </div>

  <div class="am-g">
    <div class="am-u-sm-7 am-u-sm-centered">
      <div class="am-intro-left am-active" style="height:80px">
        <label><em>사용 안내</em></label>
        <p class="am-serif">채용 공고 내용을 입력 후 제출하면 자동으로 구조화된 정보를 제공합니다.<a href="/generate" title="자동 생성">자동 직무 생성</a></p>
      </div>

      <form class="am-form am-form-horizontal" action="/parse" method="post" onsubmit="return showResult()">
        <textarea name="source" rows="20" cols="110" class="am-form-field am-radius" placeholder="채용 공고 텍스트 입력..." autofocus="true">{{ source }}</textarea>
        <div style="text-align:center">
          <button type="submit" class="am-btn am-btn-primary" value="전송">제출</button>
        </div>
      </form>
    </div>

    <div class="am-u-sm-6 am-u-sm-centered">
      <div id="resultHint">결과 준비 중...</div>
      <div id="jobResults">
        {% for idx, item in enumerate(result, 1) %}
          <br /> 항목 #{{ idx }} ────────────── <br />
          <ul>
            {% for key, value in item.items() %}
              {% if key in ['demand', 'duty', 'benefits', 'other'] %}
                <li title="{{ {'demand': '요구 조건', 'duty': '업무 내용', 'benefits': '복리후생', 'other': '기타'}[key] }}">{{ key }}: {{ value }}</li>
              {% else %}
                <li title="{{ key }}">{{ key }}: {{ value | safe }}</li>
              {% end %}{% end %}{% end %}
          </ul>
        {% end %}</div>
    </div>
  </div>

  <script src="http://cdn.amazeui.org/amazeui/2.4.0/js/amazeui.min.js"></script>
</body>
</html>
  
**output_template.html**

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>직무 설명서 자동 생성</title>
  <link rel="stylesheet" href="http://cdn.amazeui.org/amazeui/2.4.0/css/amazeui.min.css">
  <link rel="icon" href="favicon.ico">

  <script>
    function startGeneration() {
      const status = document.getElementById("genStatus");
      status.innerHTML = '<span class="am-active">처리 중...<i class="am-icon-spinner am-icon-spin"></i></span>';
      status.style.color = "#c60a00";
      return true;
    }
  </script>
</head>
<body>
  <div class="am-topbar">
    <h1 class="am-active">온라인 시연 환경</h1>
  </div>

  <div class="am-g">
    <div class="am-u-sm-6 am-u-sm-centered">
      <div class="am-intro-left" style="height:180px">
        <label class="am-active"><em>사용 안내</em></label>
        <p class="am-serif">직무명과 생성 문장 수를 입력한 후 제출하면 관련 콘텐츠가 생성됩니다.</p>
      </div>

      <form class="am-form-inline" action="/generate" method="post" onsubmit="return startGeneration()">
        <input type="text" name="source" class="am-form-field am-radius" style="width:500px" placeholder="직무 이름 입력..." value="{{ source }}" autofocus="true">
        <input type="number" name="num" min="1" max="50" class="am-form-field am-round" value="{{ num }}" title="생성 문장 수">
        <button type="submit" class="am-btn am-btn-primary">생성</button>
      </form>
    </div>

    <div class="am-u-sm-6 am-u-sm-centered">
      <div id="genStatus">결과 표시: <a href="/parse" title="분석하기">분석 페이지로 이동</a></div>
      <div id="generatedList" style="background-color:#f8f8f8">
        <ul>
          {% for i, sentence in enumerate(result) %}
            <li>{{ i+1 }}. {{ sentence }}</li>
          {% end %}</ul>
      </div>
    </div>
  </div>

  <script src="http://cdn.amazeui.org/amazeui/2.4.0/js/amazeui.min.js"></script>
</body>
</html>
  

태그: Tornado python web framework template rendering asynchronous server

7월 25일 10:59에 게시됨