Update app.py
Browse files
app.py
CHANGED
|
@@ -135,6 +135,30 @@ footer, .footer, .gradio-container footer, .built-with, [class*="footer"], .grad
|
|
| 135 |
box-shadow: 2px 2px 0 #1F2937;
|
| 136 |
}
|
| 137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
.gr-panel, .gr-box, .gr-form, .block, .gr-group {
|
| 139 |
background: #FFF !important;
|
| 140 |
border: 3px solid #1F2937 !important;
|
|
@@ -225,6 +249,58 @@ textarea:focus, input[type="text"]:focus {
|
|
| 225 |
font-size: 1.5rem;
|
| 226 |
}
|
| 227 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
label, .gr-input-label, .gr-block-label {
|
| 229 |
color: #1F2937 !important;
|
| 230 |
font-family: 'Comic Neue', cursive !important;
|
|
@@ -799,14 +875,14 @@ def convert_hwp_to_markdown(input_path: str) -> tuple:
|
|
| 799 |
# ============== LLM API ==============
|
| 800 |
def call_groq_api_stream(messages: List[Dict], api_key: str) -> Generator[str, None, None]:
|
| 801 |
if not api_key:
|
| 802 |
-
yield "β Groq API ν€κ° μ€μ λμ§ μμμ΅λλ€."
|
| 803 |
return
|
| 804 |
try:
|
| 805 |
response = requests.post(
|
| 806 |
"https://api.groq.com/openai/v1/chat/completions",
|
| 807 |
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
|
| 808 |
json={
|
| 809 |
-
"model": "
|
| 810 |
"messages": messages,
|
| 811 |
"temperature": 0.7,
|
| 812 |
"max_tokens": 8192,
|
|
@@ -833,7 +909,7 @@ def call_groq_api_stream(messages: List[Dict], api_key: str) -> Generator[str, N
|
|
| 833 |
|
| 834 |
def call_fireworks_api_stream(messages: List[Dict], image_base64: str, mime_type: str, api_key: str) -> Generator[str, None, None]:
|
| 835 |
if not api_key:
|
| 836 |
-
yield "β Fireworks API ν€κ° μ€μ λμ§ μμμ΅λλ€."
|
| 837 |
return
|
| 838 |
try:
|
| 839 |
formatted_messages = [{"role": m["role"], "content": m["content"]} for m in messages[:-1]]
|
|
@@ -849,7 +925,7 @@ def call_fireworks_api_stream(messages: List[Dict], image_base64: str, mime_type
|
|
| 849 |
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
|
| 850 |
json={
|
| 851 |
"model": "accounts/fireworks/models/qwen3-vl-235b-a22b-thinking",
|
| 852 |
-
"max_tokens":
|
| 853 |
"temperature": 0.6,
|
| 854 |
"messages": formatted_messages,
|
| 855 |
"stream": True
|
|
@@ -885,25 +961,28 @@ def process_file(file_path: str) -> tuple:
|
|
| 885 |
if is_hwp_file(file_path) or is_hwpx_file(file_path):
|
| 886 |
text, error = extract_text_from_hwp_or_hwpx(file_path)
|
| 887 |
if text and len(text.strip()) > 20:
|
| 888 |
-
|
|
|
|
|
|
|
| 889 |
return "error", f"νκΈ λ¬Έμ μΆμΆ μ€ν¨: {error}", None
|
| 890 |
|
| 891 |
if is_pdf_file(file_path):
|
| 892 |
text = extract_text_from_pdf(file_path)
|
| 893 |
if text:
|
| 894 |
-
|
|
|
|
| 895 |
return "error", "PDF μΆμΆ μ€ν¨", None
|
| 896 |
|
| 897 |
if is_text_file(file_path):
|
| 898 |
text = extract_text_from_txt(file_path)
|
| 899 |
if text:
|
| 900 |
-
return "text",
|
| 901 |
return "error", "ν
μ€νΈ μ½κΈ° μ€ν¨", None
|
| 902 |
|
| 903 |
return "unsupported", f"μ§μνμ§ μλ νμ: {filename}", None
|
| 904 |
|
| 905 |
def chat_response(message: str, history: List[Dict], file: Optional[str],
|
| 906 |
-
session_id: str
|
| 907 |
if history is None:
|
| 908 |
history = []
|
| 909 |
if not message.strip() and not file:
|
|
@@ -914,10 +993,12 @@ def chat_response(message: str, history: List[Dict], file: Optional[str],
|
|
| 914 |
|
| 915 |
file_type, file_content, file_mime = None, None, None
|
| 916 |
file_info = None
|
|
|
|
| 917 |
|
| 918 |
if file:
|
|
|
|
| 919 |
file_type, file_content, file_mime = process_file(file)
|
| 920 |
-
file_info = json.dumps({"type": file_type, "filename":
|
| 921 |
|
| 922 |
if file_type == "error":
|
| 923 |
history = history + [
|
|
@@ -934,41 +1015,104 @@ def chat_response(message: str, history: List[Dict], file: Optional[str],
|
|
| 934 |
yield history, session_id
|
| 935 |
return
|
| 936 |
|
|
|
|
| 937 |
user_msg = message
|
| 938 |
if file:
|
| 939 |
-
filename = os.path.basename(file)
|
| 940 |
user_msg = f"π {filename}\n\n{message}" if message else f"π {filename}"
|
| 941 |
|
| 942 |
history = history + [{"role": "user", "content": user_msg}, {"role": "assistant", "content": ""}]
|
| 943 |
yield history, session_id
|
| 944 |
|
|
|
|
| 945 |
db_messages = get_session_messages(session_id, limit=10)
|
| 946 |
-
api_messages = [{
|
| 947 |
-
"role": "system",
|
| 948 |
-
"content": "λΉμ μ λμμ΄ λλ AI μ΄μμ€ν΄νΈμ
λλ€. νκ΅μ΄λ‘ μμ°μ€λ½κ² λννλ©°, νμΌμ΄ 첨λΆλλ©΄ λ΄μ©μ μμΈν λΆμνμ¬ λ΅λ³ν©λλ€. λ¬Έμμ ν΅μ¬ λ΄μ©μ νμ
νκ³ , μ¬μ©μμ μ§λ¬Έμ μ ννκ² λ΅λ³νμΈμ."
|
| 949 |
-
}]
|
| 950 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 951 |
for m in db_messages:
|
| 952 |
api_messages.append({"role": m["role"], "content": m["content"]})
|
| 953 |
|
| 954 |
-
|
| 955 |
if file_type == "text" and file_content:
|
| 956 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 957 |
|
| 958 |
api_messages.append({"role": "user", "content": current_content})
|
| 959 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 960 |
full_response = ""
|
| 961 |
if file_type == "image":
|
| 962 |
-
for chunk in call_fireworks_api_stream(api_messages, file_content, file_mime,
|
| 963 |
full_response += chunk
|
| 964 |
history[-1] = {"role": "assistant", "content": full_response}
|
| 965 |
yield history, session_id
|
| 966 |
else:
|
| 967 |
-
for chunk in call_groq_api_stream(api_messages,
|
| 968 |
full_response += chunk
|
| 969 |
history[-1] = {"role": "assistant", "content": full_response}
|
| 970 |
yield history, session_id
|
| 971 |
|
|
|
|
| 972 |
save_message(session_id, "user", current_content, file_info)
|
| 973 |
save_message(session_id, "assistant", full_response)
|
| 974 |
|
|
@@ -1056,7 +1200,7 @@ def convert_hwp(file, output_format, progress=gr.Progress()):
|
|
| 1056 |
f.write(text)
|
| 1057 |
ext = ".txt"
|
| 1058 |
|
| 1059 |
-
elif output_format == "
|
| 1060 |
text, error = convert_hwp_to_markdown(input_path)
|
| 1061 |
if text:
|
| 1062 |
output_path = os.path.join(tmp_dir, "output.md")
|
|
@@ -1146,6 +1290,14 @@ with gr.Blocks(title="HWP AI μ΄μμ€ν΄νΈ", css=COMIC_CSS, delete_cache=(60,
|
|
| 1146 |
</div>
|
| 1147 |
""")
|
| 1148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1149 |
session_state = gr.State("")
|
| 1150 |
|
| 1151 |
with gr.Tabs():
|
|
@@ -1167,12 +1319,6 @@ with gr.Blocks(title="HWP AI μ΄μμ€ν΄νΈ", css=COMIC_CSS, delete_cache=(60,
|
|
| 1167 |
|
| 1168 |
with gr.Row():
|
| 1169 |
with gr.Column(scale=1):
|
| 1170 |
-
gr.HTML('<div class="info-box">βοΈ <b>μ€μ </b></div>')
|
| 1171 |
-
|
| 1172 |
-
with gr.Accordion("π API ν€ μ€μ ", open=True):
|
| 1173 |
-
groq_key = gr.Textbox(label="Groq API Key", type="password", value=GROQ_API_KEY, placeholder="gsk_...")
|
| 1174 |
-
fireworks_key = gr.Textbox(label="Fireworks API Key", type="password", value=FIREWORKS_API_KEY, placeholder="fw_...")
|
| 1175 |
-
|
| 1176 |
gr.HTML("""
|
| 1177 |
<div class="info-box">
|
| 1178 |
π <b>μ§μ νμΌ νμ</b><br><br>
|
|
@@ -1220,6 +1366,45 @@ with gr.Blocks(title="HWP AI μ΄μμ€ν΄νΈ", css=COMIC_CSS, delete_cache=(60,
|
|
| 1220 |
</div>
|
| 1221 |
""")
|
| 1222 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1223 |
with gr.Row():
|
| 1224 |
with gr.Column():
|
| 1225 |
gr.HTML('<div class="info-box">π€ <b>νμΌ μ
λ‘λ</b></div>')
|
|
@@ -1229,8 +1414,8 @@ with gr.Blocks(title="HWP AI μ΄μμ€ν΄νΈ", css=COMIC_CSS, delete_cache=(60,
|
|
| 1229 |
elem_classes=["upload-box"]
|
| 1230 |
)
|
| 1231 |
format_select = gr.Radio(
|
| 1232 |
-
["
|
| 1233 |
-
value="
|
| 1234 |
label="π λ³ν νμ"
|
| 1235 |
)
|
| 1236 |
convert_btn = gr.Button("π λ³ννκΈ°", variant="primary", size="lg")
|
|
@@ -1245,7 +1430,7 @@ with gr.Blocks(title="HWP AI μ΄μμ€ν΄νΈ", css=COMIC_CSS, delete_cache=(60,
|
|
| 1245 |
|
| 1246 |
gr.HTML("""
|
| 1247 |
<div class="info-box">
|
| 1248 |
-
βΉοΈ <b>μλ΄</b>: HWPX νμΌμ
|
| 1249 |
</div>
|
| 1250 |
""")
|
| 1251 |
|
|
@@ -1255,20 +1440,21 @@ with gr.Blocks(title="HWP AI μ΄μμ€ν΄νΈ", css=COMIC_CSS, delete_cache=(60,
|
|
| 1255 |
<p style="font-family:'Bangers',cursive;font-size:1.8rem;letter-spacing:2px">π HWP AI μ΄μμ€ν΄νΈ π€</p>
|
| 1256 |
<p>AIκ° HWP νμΌμ μ½κ³ , λ³΄κ³ , λ§νλ©°, μκ°νκ³ κΈ°μ΅ν©λλ€!</p>
|
| 1257 |
<p>π READ β’ ποΈ SEE β’ π¬ SPEAK β’ π§ THINK β’ πΎ MEMORY</p>
|
|
|
|
| 1258 |
<p style="margin-top:10px"><a href="https://www.humangen.ai" target="_blank" style="color:#FACC15;text-decoration:none;font-weight:bold;">π www.humangen.ai</a></p>
|
| 1259 |
</div>
|
| 1260 |
""")
|
| 1261 |
|
| 1262 |
# ============== μ΄λ²€νΈ νΈλ€λ¬ ==============
|
| 1263 |
-
def on_submit(msg, hist, f, sid
|
| 1264 |
if hist is None:
|
| 1265 |
hist = []
|
| 1266 |
-
for r in chat_response(msg, hist, f, sid
|
| 1267 |
yield r[0], r[1], "", None
|
| 1268 |
|
| 1269 |
-
submit_btn.click(on_submit, [msg_input, chatbot, file_upload, session_state
|
| 1270 |
[chatbot, session_state, msg_input, file_upload])
|
| 1271 |
-
msg_input.submit(on_submit, [msg_input, chatbot, file_upload, session_state
|
| 1272 |
[chatbot, session_state, msg_input, file_upload])
|
| 1273 |
|
| 1274 |
new_btn.click(lambda: ([], create_session(), None, ""), outputs=[chatbot, session_state, file_upload, msg_input])
|
|
|
|
| 135 |
box-shadow: 2px 2px 0 #1F2937;
|
| 136 |
}
|
| 137 |
|
| 138 |
+
/* λ¬΄λ£ μλΉμ€ μλ΄ λ°μ€ */
|
| 139 |
+
.free-service-notice {
|
| 140 |
+
text-align: center;
|
| 141 |
+
padding: 10px 15px;
|
| 142 |
+
background: linear-gradient(135deg, #FEE2E2 0%, #FECACA 100%);
|
| 143 |
+
border: 3px solid #1F2937;
|
| 144 |
+
border-radius: 8px;
|
| 145 |
+
margin: 10px 0;
|
| 146 |
+
box-shadow: 4px 4px 0 #1F2937;
|
| 147 |
+
font-family: 'Comic Neue', cursive;
|
| 148 |
+
font-weight: 700;
|
| 149 |
+
color: #991B1B;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
.free-service-notice a {
|
| 153 |
+
color: #1D4ED8;
|
| 154 |
+
text-decoration: none;
|
| 155 |
+
font-weight: 700;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.free-service-notice a:hover {
|
| 159 |
+
text-decoration: underline;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
.gr-panel, .gr-box, .gr-form, .block, .gr-group {
|
| 163 |
background: #FFF !important;
|
| 164 |
border: 3px solid #1F2937 !important;
|
|
|
|
| 249 |
font-size: 1.5rem;
|
| 250 |
}
|
| 251 |
|
| 252 |
+
/* Markdown κ°μ‘° λ°μ€ */
|
| 253 |
+
.markdown-highlight-box {
|
| 254 |
+
background: linear-gradient(135deg, #EC4899 0%, #F472B6 100%) !important;
|
| 255 |
+
border: 4px solid #1F2937 !important;
|
| 256 |
+
border-radius: 12px !important;
|
| 257 |
+
padding: 20px !important;
|
| 258 |
+
margin: 15px 0 !important;
|
| 259 |
+
box-shadow: 6px 6px 0 #1F2937 !important;
|
| 260 |
+
animation: pulse-glow 2s ease-in-out infinite;
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
@keyframes pulse-glow {
|
| 264 |
+
0%, 100% { box-shadow: 6px 6px 0 #1F2937; }
|
| 265 |
+
50% { box-shadow: 8px 8px 0 #1F2937, 0 0 20px rgba(236, 72, 153, 0.5); }
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
.markdown-title {
|
| 269 |
+
font-family: 'Bangers', cursive !important;
|
| 270 |
+
font-size: 2rem !important;
|
| 271 |
+
color: #FFF !important;
|
| 272 |
+
text-shadow: 3px 3px 0 #1F2937 !important;
|
| 273 |
+
letter-spacing: 2px !important;
|
| 274 |
+
margin-bottom: 15px !important;
|
| 275 |
+
text-align: center !important;
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
.markdown-benefits {
|
| 279 |
+
display: grid;
|
| 280 |
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
| 281 |
+
gap: 12px;
|
| 282 |
+
margin-top: 10px;
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
.markdown-benefit-item {
|
| 286 |
+
background: rgba(255,255,255,0.95) !important;
|
| 287 |
+
border: 3px solid #1F2937 !important;
|
| 288 |
+
border-radius: 8px !important;
|
| 289 |
+
padding: 12px !important;
|
| 290 |
+
box-shadow: 3px 3px 0 #1F2937 !important;
|
| 291 |
+
font-family: 'Comic Neue', cursive !important;
|
| 292 |
+
font-weight: 700 !important;
|
| 293 |
+
font-size: 0.95rem !important;
|
| 294 |
+
color: #1F2937 !important;
|
| 295 |
+
text-align: center !important;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
.markdown-benefit-icon {
|
| 299 |
+
font-size: 1.8rem !important;
|
| 300 |
+
display: block !important;
|
| 301 |
+
margin-bottom: 5px !important;
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
label, .gr-input-label, .gr-block-label {
|
| 305 |
color: #1F2937 !important;
|
| 306 |
font-family: 'Comic Neue', cursive !important;
|
|
|
|
| 875 |
# ============== LLM API ==============
|
| 876 |
def call_groq_api_stream(messages: List[Dict], api_key: str) -> Generator[str, None, None]:
|
| 877 |
if not api_key:
|
| 878 |
+
yield "β Groq API ν€κ° μ€μ λμ§ μμμ΅λλ€. νκ²½λ³μ GROQ_API_KEYλ₯Ό μ€μ ν΄μ£ΌμΈμ."
|
| 879 |
return
|
| 880 |
try:
|
| 881 |
response = requests.post(
|
| 882 |
"https://api.groq.com/openai/v1/chat/completions",
|
| 883 |
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
|
| 884 |
json={
|
| 885 |
+
"model": "mopenai/gpt-oss-120b",
|
| 886 |
"messages": messages,
|
| 887 |
"temperature": 0.7,
|
| 888 |
"max_tokens": 8192,
|
|
|
|
| 909 |
|
| 910 |
def call_fireworks_api_stream(messages: List[Dict], image_base64: str, mime_type: str, api_key: str) -> Generator[str, None, None]:
|
| 911 |
if not api_key:
|
| 912 |
+
yield "β Fireworks API ν€κ° μ€μ λμ§ μμμ΅λλ€. νκ²½λ³μ FIREWORKS_API_KEYλ₯Ό μ€μ ν΄μ£ΌμΈμ."
|
| 913 |
return
|
| 914 |
try:
|
| 915 |
formatted_messages = [{"role": m["role"], "content": m["content"]} for m in messages[:-1]]
|
|
|
|
| 925 |
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
|
| 926 |
json={
|
| 927 |
"model": "accounts/fireworks/models/qwen3-vl-235b-a22b-thinking",
|
| 928 |
+
"max_tokens": 8000,
|
| 929 |
"temperature": 0.6,
|
| 930 |
"messages": formatted_messages,
|
| 931 |
"stream": True
|
|
|
|
| 961 |
if is_hwp_file(file_path) or is_hwpx_file(file_path):
|
| 962 |
text, error = extract_text_from_hwp_or_hwpx(file_path)
|
| 963 |
if text and len(text.strip()) > 20:
|
| 964 |
+
print(f"π [λ¬Έμ λ΄μ© μΆμΆ μλ£] {len(text)} κΈμ")
|
| 965 |
+
print(f"π [λ¬Έμ 미리보기] {text[:500]}...")
|
| 966 |
+
return "text", text, None
|
| 967 |
return "error", f"νκΈ λ¬Έμ μΆμΆ μ€ν¨: {error}", None
|
| 968 |
|
| 969 |
if is_pdf_file(file_path):
|
| 970 |
text = extract_text_from_pdf(file_path)
|
| 971 |
if text:
|
| 972 |
+
print(f"π [PDF λ΄μ© μΆμΆ μλ£] {len(text)} κΈμ")
|
| 973 |
+
return "text", text, None
|
| 974 |
return "error", "PDF μΆμΆ μ€ν¨", None
|
| 975 |
|
| 976 |
if is_text_file(file_path):
|
| 977 |
text = extract_text_from_txt(file_path)
|
| 978 |
if text:
|
| 979 |
+
return "text", text, None
|
| 980 |
return "error", "ν
μ€νΈ μ½κΈ° μ€ν¨", None
|
| 981 |
|
| 982 |
return "unsupported", f"μ§μνμ§ μλ νμ: {filename}", None
|
| 983 |
|
| 984 |
def chat_response(message: str, history: List[Dict], file: Optional[str],
|
| 985 |
+
session_id: str) -> Generator[tuple, None, None]:
|
| 986 |
if history is None:
|
| 987 |
history = []
|
| 988 |
if not message.strip() and not file:
|
|
|
|
| 993 |
|
| 994 |
file_type, file_content, file_mime = None, None, None
|
| 995 |
file_info = None
|
| 996 |
+
filename = None
|
| 997 |
|
| 998 |
if file:
|
| 999 |
+
filename = os.path.basename(file)
|
| 1000 |
file_type, file_content, file_mime = process_file(file)
|
| 1001 |
+
file_info = json.dumps({"type": file_type, "filename": filename})
|
| 1002 |
|
| 1003 |
if file_type == "error":
|
| 1004 |
history = history + [
|
|
|
|
| 1015 |
yield history, session_id
|
| 1016 |
return
|
| 1017 |
|
| 1018 |
+
# μ¬μ©μ λ©μμ§ νμ
|
| 1019 |
user_msg = message
|
| 1020 |
if file:
|
|
|
|
| 1021 |
user_msg = f"π {filename}\n\n{message}" if message else f"π {filename}"
|
| 1022 |
|
| 1023 |
history = history + [{"role": "user", "content": user_msg}, {"role": "assistant", "content": ""}]
|
| 1024 |
yield history, session_id
|
| 1025 |
|
| 1026 |
+
# μ΄μ λν λΆλ¬μ€κΈ°
|
| 1027 |
db_messages = get_session_messages(session_id, limit=10)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1028 |
|
| 1029 |
+
# μμ€ν
ν둬ννΈ - λ¬Έμ λΆμ κ°ν
|
| 1030 |
+
system_prompt = """λΉμ μ λ¬Έμ λΆμ μ λ¬Έ AI μ΄μμ€ν΄νΈμ
λλ€.
|
| 1031 |
+
|
| 1032 |
+
## ν΅μ¬ μν
|
| 1033 |
+
- μ¬μ©μκ° μ
λ‘λν λ¬Έμμ λ΄μ©μ **μ ννκ² λΆμ**νκ³ **ꡬ체μ μΌλ‘ λ΅λ³**ν©λλ€.
|
| 1034 |
+
- λ¬Έμμ μλ **μ€μ λ΄μ©**μ κΈ°λ°μΌλ‘λ§ λ΅λ³ν©λλ€.
|
| 1035 |
+
- λ¬Έμμ μλ λ΄μ©μ μΆμΈ‘νμ§ μμ΅λλ€.
|
| 1036 |
+
|
| 1037 |
+
## λ¬Έμ λΆμ λ°©λ²
|
| 1038 |
+
1. **λ¬Έμκ° μ 곡λλ©΄**: λ¬Έμ μ 체 λ΄μ©μ κΌΌκΌΌν μ½κ³ ν΅μ¬ μ 보λ₯Ό νμ
ν©λλ€.
|
| 1039 |
+
2. **μμ½ μμ² μ**: λ¬Έμμ μ£Όμ , λͺ©μ , ν΅μ¬ λ΄μ©, μ£Όμ νλͺ©μ ꡬ쑰ννμ¬ μμ½ν©λλ€.
|
| 1040 |
+
3. **μ§λ¬Έ μλ΅ μ**: λ¬Έμμμ κ΄λ ¨ λ΄μ©μ μ°Ύμ **μ§μ μΈμ©νκ±°λ ꡬ체μ μΌλ‘ μ€λͺ
**ν©λλ€.
|
| 1041 |
+
|
| 1042 |
+
## λ΅λ³ νμ
|
| 1043 |
+
- νκ΅μ΄λ‘ μμ°μ€λ½κ³ λͺ
ννκ² λ΅λ³ν©λλ€.
|
| 1044 |
+
- λ¬Έμ λ΄μ©μ μΈμ©ν λλ ꡬ체μ μΌλ‘ μΈκΈν©λλ€.
|
| 1045 |
+
- κΈ΄ λ¬Έμλ μΉμ
λ³λ‘ λλμ΄ μ 리ν©λλ€.
|
| 1046 |
+
|
| 1047 |
+
## μ£Όμμ¬ν
|
| 1048 |
+
- λ¬Έμμ **μ€μ λ‘ μλ λ΄μ©λ§** λ΅λ³μ ν¬ν¨ν©λλ€.
|
| 1049 |
+
- λΆνμ€ν λ΄μ©μ "λ¬Έμμμ νμΈλμ§ μμ΅λλ€"λΌκ³ λͺ
μν©λλ€."""
|
| 1050 |
+
|
| 1051 |
+
api_messages = [{"role": "system", "content": system_prompt}]
|
| 1052 |
+
|
| 1053 |
+
# μ΄μ λν μΆκ°
|
| 1054 |
for m in db_messages:
|
| 1055 |
api_messages.append({"role": m["role"], "content": m["content"]})
|
| 1056 |
|
| 1057 |
+
# νμ¬ λ©μμ§ κ΅¬μ± - λ¬Έμ λ΄μ©μ λͺ
ννκ² κ΅¬λΆ
|
| 1058 |
if file_type == "text" and file_content:
|
| 1059 |
+
if message:
|
| 1060 |
+
current_content = f"""## π μ
λ‘λλ λ¬Έμ λ΄μ© ({filename})
|
| 1061 |
+
|
| 1062 |
+
λ€μμ μ¬μ©μκ° μ
λ‘λν λ¬Έμμ μ 체 λ΄μ©μ
λλ€:
|
| 1063 |
+
|
| 1064 |
+
---
|
| 1065 |
+
{file_content}
|
| 1066 |
+
---
|
| 1067 |
+
|
| 1068 |
+
## π¬ μ¬μ©μ μ§λ¬Έ
|
| 1069 |
+
{message}
|
| 1070 |
+
|
| 1071 |
+
μ λ¬Έμ λ΄μ©μ λ°νμΌλ‘ μ¬μ©μμ μ§λ¬Έμ **ꡬ체μ μ΄κ³ μ ννκ²** λ΅λ³ν΄μ£ΌμΈμ."""
|
| 1072 |
+
else:
|
| 1073 |
+
current_content = f"""## π μ
λ‘λλ λ¬Έμ λ΄μ© ({filename})
|
| 1074 |
+
|
| 1075 |
+
λ€μμ μ¬μ©μκ° μ
λ‘λν λ¬Έμμ μ 체 λ΄μ©μ
λλ€:
|
| 1076 |
+
|
| 1077 |
+
---
|
| 1078 |
+
{file_content}
|
| 1079 |
+
---
|
| 1080 |
+
|
| 1081 |
+
## π μμ²μ¬ν
|
| 1082 |
+
μ λ¬Έμμ λ΄μ©μ λ€μ νμμΌλ‘ **μμΈνκ² μμ½**ν΄μ£ΌμΈμ:
|
| 1083 |
+
|
| 1084 |
+
1. **λ¬Έμ μ λͺ©/μ£Όμ **: λ¬Έμκ° λ€λ£¨λ μ£Όμ μ£Όμ
|
| 1085 |
+
2. **λ¬Έμ λͺ©μ **: μ΄ λ¬Έμμ μμ± λͺ©μ
|
| 1086 |
+
3. **ν΅μ¬ λ΄μ©**: κ°μ₯ μ€μν λ΄μ© 3-5οΏ½οΏ½οΏ½μ§
|
| 1087 |
+
4. **μΈλΆ νλͺ©**: λ¬Έμμ ν¬ν¨λ μ£Όμ μΉμ
μ΄λ νλͺ©
|
| 1088 |
+
5. **κ²°λ‘ /μμ½**: λ¬Έμμ ν΅μ¬ λ©μμ§"""
|
| 1089 |
+
else:
|
| 1090 |
+
current_content = message or ""
|
| 1091 |
|
| 1092 |
api_messages.append({"role": "user", "content": current_content})
|
| 1093 |
|
| 1094 |
+
# λλ²κ·Έ λ‘κ·Έ
|
| 1095 |
+
print(f"\nπ€ [API μμ²]")
|
| 1096 |
+
print(f" - λ©μμ§ μ: {len(api_messages)}")
|
| 1097 |
+
print(f" - νμΌ νμ
: {file_type}")
|
| 1098 |
+
print(f" - λ¬Έμ κΈΈμ΄: {len(file_content) if file_content else 0} κΈμ")
|
| 1099 |
+
if file_content:
|
| 1100 |
+
print(f" - λ¬Έμ 미리보기: {file_content[:200]}...")
|
| 1101 |
+
|
| 1102 |
+
# μλ΅ μμ±
|
| 1103 |
full_response = ""
|
| 1104 |
if file_type == "image":
|
| 1105 |
+
for chunk in call_fireworks_api_stream(api_messages, file_content, file_mime, FIREWORKS_API_KEY):
|
| 1106 |
full_response += chunk
|
| 1107 |
history[-1] = {"role": "assistant", "content": full_response}
|
| 1108 |
yield history, session_id
|
| 1109 |
else:
|
| 1110 |
+
for chunk in call_groq_api_stream(api_messages, GROQ_API_KEY):
|
| 1111 |
full_response += chunk
|
| 1112 |
history[-1] = {"role": "assistant", "content": full_response}
|
| 1113 |
yield history, session_id
|
| 1114 |
|
| 1115 |
+
# DB μ μ₯
|
| 1116 |
save_message(session_id, "user", current_content, file_info)
|
| 1117 |
save_message(session_id, "assistant", full_response)
|
| 1118 |
|
|
|
|
| 1200 |
f.write(text)
|
| 1201 |
ext = ".txt"
|
| 1202 |
|
| 1203 |
+
elif output_format == "β MARKDOWN (μΆμ²)":
|
| 1204 |
text, error = convert_hwp_to_markdown(input_path)
|
| 1205 |
if text:
|
| 1206 |
output_path = os.path.join(tmp_dir, "output.md")
|
|
|
|
| 1290 |
</div>
|
| 1291 |
""")
|
| 1292 |
|
| 1293 |
+
# λ¬΄λ£ μλΉμ€ μλ΄
|
| 1294 |
+
gr.HTML("""
|
| 1295 |
+
<div class="free-service-notice">
|
| 1296 |
+
π λ³Έ μλΉμ€λ <b>λ¬΄λ£ λ²μ </b>μΌλ‘ μΌλΆ κΈ°λ₯μ μ μ½μ΄ μμ΅λλ€.<br>
|
| 1297 |
+
π§ λ¬Έμ: <a href="mailto:arxivgpt@gmail.com">arxivgpt@gmail.com</a>
|
| 1298 |
+
</div>
|
| 1299 |
+
""")
|
| 1300 |
+
|
| 1301 |
session_state = gr.State("")
|
| 1302 |
|
| 1303 |
with gr.Tabs():
|
|
|
|
| 1319 |
|
| 1320 |
with gr.Row():
|
| 1321 |
with gr.Column(scale=1):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1322 |
gr.HTML("""
|
| 1323 |
<div class="info-box">
|
| 1324 |
π <b>μ§μ νμΌ νμ</b><br><br>
|
|
|
|
| 1366 |
</div>
|
| 1367 |
""")
|
| 1368 |
|
| 1369 |
+
# Markdown κ°μ‘° λ°μ€
|
| 1370 |
+
gr.HTML("""
|
| 1371 |
+
<div class="markdown-highlight-box">
|
| 1372 |
+
<div class="markdown-title">β MARKDOWN λ³ν μΆμ²! β</div>
|
| 1373 |
+
<div class="markdown-benefits">
|
| 1374 |
+
<div class="markdown-benefit-item">
|
| 1375 |
+
<span class="markdown-benefit-icon">π€</span>
|
| 1376 |
+
<b>AI/LLM μ΅μ ν</b><br>
|
| 1377 |
+
ChatGPT, Claude λ± AIμ λ°λ‘ μ
λ ₯ κ°λ₯
|
| 1378 |
+
</div>
|
| 1379 |
+
<div class="markdown-benefit-item">
|
| 1380 |
+
<span class="markdown-benefit-icon">π</span>
|
| 1381 |
+
<b>λ²μ© ν¬λ§·</b><br>
|
| 1382 |
+
GitHub, Notion, λΈλ‘κ·Έ λ± μ΄λμλ μ¬μ©
|
| 1383 |
+
</div>
|
| 1384 |
+
<div class="markdown-benefit-item">
|
| 1385 |
+
<span class="markdown-benefit-icon">π</span>
|
| 1386 |
+
<b>ꡬ쑰 μ μ§</b><br>
|
| 1387 |
+
μ λͺ©, λͺ©λ‘, ν λ± λ¬Έμ ꡬ쑰 보쑴
|
| 1388 |
+
</div>
|
| 1389 |
+
<div class="markdown-benefit-item">
|
| 1390 |
+
<span class="markdown-benefit-icon">β‘</span>
|
| 1391 |
+
<b>κ°λ³κ³ λΉ λ¦</b><br>
|
| 1392 |
+
μ©λμ΄ μκ³ μ²λ¦¬ μλ λΉ λ¦
|
| 1393 |
+
</div>
|
| 1394 |
+
<div class="markdown-benefit-item">
|
| 1395 |
+
<span class="markdown-benefit-icon">π</span>
|
| 1396 |
+
<b>λ³ν μ©μ΄</b><br>
|
| 1397 |
+
HTML, PDF, Word λ±μΌλ‘ μ¬λ³ν κ°λ₯
|
| 1398 |
+
</div>
|
| 1399 |
+
<div class="markdown-benefit-item">
|
| 1400 |
+
<span class="markdown-benefit-icon">βοΈ</span>
|
| 1401 |
+
<b>νΈμ§ κ°νΈ</b><br>
|
| 1402 |
+
λ©λͺ¨μ₯μΌλ‘λ λ°λ‘ μμ κ°λ₯
|
| 1403 |
+
</div>
|
| 1404 |
+
</div>
|
| 1405 |
+
</div>
|
| 1406 |
+
""")
|
| 1407 |
+
|
| 1408 |
with gr.Row():
|
| 1409 |
with gr.Column():
|
| 1410 |
gr.HTML('<div class="info-box">π€ <b>νμΌ μ
λ‘λ</b></div>')
|
|
|
|
| 1414 |
elem_classes=["upload-box"]
|
| 1415 |
)
|
| 1416 |
format_select = gr.Radio(
|
| 1417 |
+
["β MARKDOWN (μΆμ²)", "TXT (ν
μ€νΈ)", "HTML", "ODT (OpenDocument)", "XML"],
|
| 1418 |
+
value="β MARKDOWN (μΆμ²)",
|
| 1419 |
label="π λ³ν νμ"
|
| 1420 |
)
|
| 1421 |
convert_btn = gr.Button("π λ³ννκΈ°", variant="primary", size="lg")
|
|
|
|
| 1430 |
|
| 1431 |
gr.HTML("""
|
| 1432 |
<div class="info-box">
|
| 1433 |
+
βΉοΈ <b>μλ΄</b>: HWPX νμΌμ MARKDOWN, TXT, XML λ³νλ§ μ§μλ©λλ€.
|
| 1434 |
</div>
|
| 1435 |
""")
|
| 1436 |
|
|
|
|
| 1440 |
<p style="font-family:'Bangers',cursive;font-size:1.8rem;letter-spacing:2px">π HWP AI μ΄μμ€ν΄νΈ π€</p>
|
| 1441 |
<p>AIκ° HWP νμΌμ μ½κ³ , λ³΄κ³ , λ§νλ©°, μκ°νκ³ κΈ°μ΅ν©λλ€!</p>
|
| 1442 |
<p>π READ β’ ποΈ SEE β’ π¬ SPEAK β’ π§ THINK β’ πΎ MEMORY</p>
|
| 1443 |
+
<p style="margin-top:8px;font-size:0.9rem;">π λ¬΄λ£ μλΉμ€ (μΌλΆ κΈ°λ₯ μ ν) | π§ arxivgpt@gmail.com</p>
|
| 1444 |
<p style="margin-top:10px"><a href="https://www.humangen.ai" target="_blank" style="color:#FACC15;text-decoration:none;font-weight:bold;">π www.humangen.ai</a></p>
|
| 1445 |
</div>
|
| 1446 |
""")
|
| 1447 |
|
| 1448 |
# ============== μ΄λ²€νΈ νΈλ€λ¬ ==============
|
| 1449 |
+
def on_submit(msg, hist, f, sid):
|
| 1450 |
if hist is None:
|
| 1451 |
hist = []
|
| 1452 |
+
for r in chat_response(msg, hist, f, sid):
|
| 1453 |
yield r[0], r[1], "", None
|
| 1454 |
|
| 1455 |
+
submit_btn.click(on_submit, [msg_input, chatbot, file_upload, session_state],
|
| 1456 |
[chatbot, session_state, msg_input, file_upload])
|
| 1457 |
+
msg_input.submit(on_submit, [msg_input, chatbot, file_upload, session_state],
|
| 1458 |
[chatbot, session_state, msg_input, file_upload])
|
| 1459 |
|
| 1460 |
new_btn.click(lambda: ([], create_session(), None, ""), outputs=[chatbot, session_state, file_upload, msg_input])
|