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