|
import gradio as gr |
|
import os |
|
import requests |
|
import json |
|
import time |
|
from dotenv import load_dotenv |
|
|
|
|
|
load_dotenv() |
|
|
|
def create_deepseek_interface(): |
|
|
|
api_key = os.getenv("FW_API_KEY") |
|
serphouse_api_key = os.getenv("SERPHOUSE_API_KEY") |
|
|
|
if not api_key: |
|
print("๊ฒฝ๊ณ : FW_API_KEY ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") |
|
if not serphouse_api_key: |
|
print("๊ฒฝ๊ณ : SERPHOUSE_API_KEY ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") |
|
|
|
|
|
def extract_keywords_with_llm(query): |
|
if not api_key: |
|
return "LLM ํค์๋ ์ถ์ถ์ ์ํ FW_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.", query |
|
|
|
|
|
url = "https://api.fireworks.ai/inference/v1/chat/completions" |
|
payload = { |
|
"model": "accounts/fireworks/models/deepseek-v3-0324", |
|
"max_tokens": 200, |
|
"temperature": 0.1, |
|
"messages": [ |
|
{ |
|
"role": "system", |
|
"content": "์ฌ์ฉ์์ ์ง๋ฌธ์์ ์น ๊ฒ์์ ํจ๊ณผ์ ์ธ ํต์ฌ ํค์๋๋ฅผ ์ถ์ถํ์ธ์. ํค์๋ ์ฌ์ด์ ์ผํ๋ ๊ณต๋ฐฑ์ ๋ฃ์ง ๋ง๊ณ ํ๋์ ๊ฒ์์ด์ฒ๋ผ ์์ ํด์ ์ ๊ณตํ์ธ์. ์๋ฅผ ๋ค์ด 'ํ๋์ ๊ตญ๋ฌด์ด๋ฆฌ ํํต ๊ฒฐ๊ณผ'์ฒ๋ผ ๊ณต๋ฐฑ์ผ๋ก๋ง ๊ตฌ๋ถํ์ธ์." |
|
}, |
|
{ |
|
"role": "user", |
|
"content": query |
|
} |
|
] |
|
} |
|
headers = { |
|
"Accept": "application/json", |
|
"Content-Type": "application/json", |
|
"Authorization": f"Bearer {api_key}" |
|
} |
|
|
|
try: |
|
response = requests.post(url, headers=headers, json=payload) |
|
response.raise_for_status() |
|
result = response.json() |
|
|
|
|
|
keywords = result["choices"][0]["message"]["content"].strip() |
|
|
|
|
|
if len(keywords) > 100: |
|
return f"์ถ์ถ๋ ํค์๋: {keywords}", query |
|
|
|
return f"์ถ์ถ๋ ํค์๋: {keywords}", keywords |
|
|
|
except Exception as e: |
|
print(f"ํค์๋ ์ถ์ถ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") |
|
return f"ํค์๋ ์ถ์ถ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}", query |
|
|
|
|
|
def search_with_serphouse(query): |
|
if not serphouse_api_key: |
|
return "SERPHOUSE_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค." |
|
|
|
try: |
|
|
|
extraction_result, search_query = extract_keywords_with_llm(query) |
|
print(f"์๋ณธ ์ฟผ๋ฆฌ: {query}") |
|
print(extraction_result) |
|
|
|
|
|
is_korean = any('\uAC00' <= c <= '\uD7A3' for c in search_query) |
|
lang = "ko" if is_korean else "en" |
|
loc = "kr" if is_korean else "us" |
|
|
|
|
|
from datetime import datetime, timedelta |
|
now = datetime.utcnow() |
|
yesterday = now - timedelta(days=1) |
|
date_range = f"{yesterday.strftime('%Y-%m-%d')},{now.strftime('%Y-%m-%d')}" |
|
|
|
|
|
url = "https://api.serphouse.com/serp/live" |
|
|
|
|
|
payload = { |
|
"data": { |
|
"q": search_query.replace(',', ' ').strip(), |
|
"domain": "google.com", |
|
"loc": loc, |
|
"lang": lang, |
|
"device": "desktop", |
|
"serp_type": "news", |
|
"page": "1", |
|
"num": "5", |
|
"date_range": date_range, |
|
"sort_by": "date" |
|
} |
|
} |
|
|
|
headers = { |
|
"accept": "application/json", |
|
"content-type": "application/json", |
|
"authorization": f"Bearer {serphouse_api_key}" |
|
} |
|
|
|
print(f"SerpHouse API ํธ์ถ ์ค... ๊ฒ์์ด: {search_query}") |
|
print(f"์์ฒญ ๋ฐฉ์: POST, ํ์ด๋ก๋: {payload}") |
|
|
|
|
|
session = requests.Session() |
|
retries = requests.packages.urllib3.util.retry.Retry( |
|
total=5, |
|
backoff_factor=1, |
|
status_forcelist=[500, 502, 503, 504, 429], |
|
allowed_methods=["POST"] |
|
) |
|
adapter = requests.adapters.HTTPAdapter(max_retries=retries) |
|
session.mount('http://', adapter) |
|
session.mount('https://', adapter) |
|
|
|
response = session.post( |
|
url, |
|
json=payload, |
|
headers=headers, |
|
timeout=(30, 30) |
|
) |
|
|
|
response.raise_for_status() |
|
|
|
print(f"SerpHouse API ์๋ต ์ํ ์ฝ๋: {response.status_code}") |
|
search_results = response.json() |
|
|
|
|
|
print(f"์๋ต ๊ตฌ์กฐ: {list(search_results.keys()) if isinstance(search_results, dict) else '๋์
๋๋ฆฌ ์๋'}") |
|
|
|
|
|
formatted_results = [] |
|
formatted_results.append(f"๊ฒ์์ด: {search_query}\n\n") |
|
|
|
|
|
if "results" in search_results and "results" in search_results["results"]: |
|
|
|
news_results = search_results["results"]["results"].get("news", []) |
|
if news_results: |
|
for result in news_results[:5]: |
|
title = result.get("title", "์ ๋ชฉ ์์") |
|
snippet = result.get("snippet", "๋ด์ฉ ์์") |
|
url = result.get("url", result.get("link", "#")) |
|
source = result.get("source", result.get("channel", "์ ์ ์์")) |
|
time = result.get("time", result.get("date", "์๊ฐ ์ ๋ณด ์์")) |
|
|
|
formatted_results.append( |
|
f"์ ๋ชฉ: {title}\n" |
|
f"์ถ์ฒ: {source}\n" |
|
f"์๊ฐ: {time}\n" |
|
f"๋ด์ฉ: {snippet}\n" |
|
f"๋งํฌ: {url}\n\n" |
|
) |
|
|
|
print(f"๊ฒ์ ๊ฒฐ๊ณผ {len(news_results)}๊ฐ ์ฐพ์") |
|
return "".join(formatted_results) |
|
|
|
print("๊ฒ์ ๊ฒฐ๊ณผ ์์ ๋๋ ์๋ต ํ์ ๋ถ์ผ์น") |
|
print(f"์๋ต ๋ด์ฉ ๋ฏธ๋ฆฌ๋ณด๊ธฐ: {str(search_results)[:300]}...") |
|
return f"๊ฒ์์ด '{search_query}'์ ๋ํ ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์๊ฑฐ๋ API ์๋ต ํ์์ด ์์๊ณผ ๋ค๋ฆ
๋๋ค." |
|
|
|
except Exception as e: |
|
error_msg = f"๊ฒ์ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
|
print(error_msg) |
|
import traceback |
|
print(traceback.format_exc()) |
|
return error_msg |
|
|
|
|
|
def query_deepseek_streaming(message, history, use_deep_research): |
|
if not api_key: |
|
yield history, "ํ๊ฒฝ ๋ณ์ FW_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค. ์๋ฒ์์ ํ๊ฒฝ ๋ณ์๋ฅผ ํ์ธํด์ฃผ์ธ์." |
|
return |
|
|
|
search_context = "" |
|
search_info = "" |
|
if use_deep_research: |
|
try: |
|
|
|
yield history + [(message, "๐ ์ต์ ์ ํค์๋ ์ถ์ถ ๋ฐ ์น ๊ฒ์ ์ค...")], "" |
|
|
|
|
|
print(f"Deep Research ํ์ฑํ๋จ: ๋ฉ์์ง '{message}'์ ๋ํ ๊ฒ์ ์์") |
|
search_results = search_with_serphouse(message) |
|
print(f"๊ฒ์ ๊ฒฐ๊ณผ ์์ ์๋ฃ: {search_results[:100]}...") |
|
|
|
if not search_results.startswith("๊ฒ์ ์ค ์ค๋ฅ ๋ฐ์") and not search_results.startswith("SERPHOUSE_API_KEY"): |
|
search_context = f""" |
|
๋ค์์ ์ฌ์ฉ์ ์ง๋ฌธ๊ณผ ๊ด๋ จ๋ ์ต์ ๊ฒ์ ๊ฒฐ๊ณผ์
๋๋ค. ์ด ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ ํํ๊ณ ์ต์ ์ ๋ณด๊ฐ ๋ฐ์๋ ์๋ต์ ์ ๊ณตํ์ธ์: |
|
|
|
{search_results} |
|
|
|
์ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฌ์ฉ์์ ๋ค์ ์ง๋ฌธ์ ๋ต๋ณํ์ธ์. ๊ฒ์ ๊ฒฐ๊ณผ์์ ๋ช
ํํ ๋ต๋ณ์ ์ฐพ์ ์ ์๋ ๊ฒฝ์ฐ, ๋น์ ์ ์ง์์ ํ์ฉํ์ฌ ์ต์ ์ ๋ต๋ณ์ ์ ๊ณตํ์ธ์. |
|
๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ์ธ์ฉํ ๋๋ ์ถ์ฒ๋ฅผ ๋ช
์ํ๊ณ , ๋ต๋ณ์ด ์ต์ ์ ๋ณด๋ฅผ ๋ฐ์ํ๋๋ก ํ์ธ์. |
|
""" |
|
search_info = f"๐ Deep Research ๊ธฐ๋ฅ ํ์ฑํ: ๊ด๋ จ ์น ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋ต ์์ฑ ์ค..." |
|
else: |
|
print(f"๊ฒ์ ์คํจ ๋๋ ๊ฒฐ๊ณผ ์์: {search_results}") |
|
except Exception as e: |
|
print(f"Deep Research ์ฒ๋ฆฌ ์ค ์์ธ ๋ฐ์: {str(e)}") |
|
search_info = f"๐ Deep Research ๊ธฐ๋ฅ ์ค๋ฅ: {str(e)}" |
|
|
|
|
|
messages = [] |
|
for user, assistant in history: |
|
messages.append({"role": "user", "content": user}) |
|
messages.append({"role": "assistant", "content": assistant}) |
|
|
|
|
|
if search_context: |
|
|
|
messages.insert(0, {"role": "system", "content": search_context}) |
|
|
|
|
|
messages.append({"role": "user", "content": message}) |
|
|
|
|
|
url = "https://api.fireworks.ai/inference/v1/chat/completions" |
|
payload = { |
|
"model": "accounts/fireworks/models/deepseek-v3-0324", |
|
"max_tokens": 20480, |
|
"top_p": 1, |
|
"top_k": 40, |
|
"presence_penalty": 0, |
|
"frequency_penalty": 0, |
|
"temperature": 0.6, |
|
"messages": messages, |
|
"stream": True |
|
} |
|
headers = { |
|
"Accept": "application/json", |
|
"Content-Type": "application/json", |
|
"Authorization": f"Bearer {api_key}" |
|
} |
|
|
|
try: |
|
|
|
response = requests.request("POST", url, headers=headers, data=json.dumps(payload), stream=True) |
|
response.raise_for_status() |
|
|
|
|
|
new_history = history.copy() |
|
|
|
|
|
start_msg = search_info if search_info else "" |
|
new_history.append((message, start_msg)) |
|
|
|
|
|
full_response = start_msg |
|
|
|
|
|
for line in response.iter_lines(): |
|
if line: |
|
line_text = line.decode('utf-8') |
|
|
|
|
|
if line_text.startswith("data: "): |
|
line_text = line_text[6:] |
|
|
|
|
|
if line_text == "[DONE]": |
|
break |
|
|
|
try: |
|
|
|
chunk = json.loads(line_text) |
|
chunk_content = chunk.get("choices", [{}])[0].get("delta", {}).get("content", "") |
|
|
|
if chunk_content: |
|
full_response += chunk_content |
|
|
|
new_history[-1] = (message, full_response) |
|
yield new_history, "" |
|
except json.JSONDecodeError: |
|
continue |
|
|
|
|
|
yield new_history, "" |
|
|
|
except requests.exceptions.RequestException as e: |
|
error_msg = f"API ์ค๋ฅ: {str(e)}" |
|
if hasattr(e, 'response') and e.response and e.response.status_code == 401: |
|
error_msg = "์ธ์ฆ ์คํจ. ํ๊ฒฝ ๋ณ์ FW_API_KEY๋ฅผ ํ์ธํด์ฃผ์ธ์." |
|
yield history, error_msg |
|
|
|
|
|
with gr.Blocks(theme="soft", fill_height=True) as demo: |
|
|
|
gr.Markdown( |
|
""" |
|
# ๐ค DeepSeek V3 ์คํธ๋ฆฌ๋ฐ ์ธํฐํ์ด์ค |
|
### Fireworks AI๊ฐ ์ ๊ณตํ๋ ๊ณ ๊ธ AI ๋ชจ๋ธ - ์ค์๊ฐ ์๋ต ์ง์ |
|
""" |
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
|
with gr.Column(): |
|
|
|
chatbot = gr.Chatbot( |
|
height=500, |
|
show_label=False, |
|
container=True |
|
) |
|
|
|
|
|
with gr.Row(): |
|
with gr.Column(scale=3): |
|
use_deep_research = gr.Checkbox( |
|
label="Deep Research ํ์ฑํ", |
|
info="์ต์ ์ ํค์๋ ์ถ์ถ ๋ฐ ์น ๊ฒ์์ ํตํ ์ต์ ์ ๋ณด ํ์ฉ", |
|
value=False |
|
) |
|
with gr.Column(scale=1): |
|
api_status = gr.Markdown("API ์ํ: ์ค๋น๋จ") |
|
|
|
|
|
if not serphouse_api_key: |
|
api_status.value = "โ ๏ธ SERPHOUSE_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค" |
|
if not api_key: |
|
api_status.value = "โ ๏ธ FW_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค" |
|
if api_key and serphouse_api_key: |
|
api_status.value = "โ
API ํค ์ค์ ์๋ฃ" |
|
|
|
|
|
with gr.Row(): |
|
msg = gr.Textbox( |
|
label="๋ฉ์์ง", |
|
placeholder="์ฌ๊ธฐ์ ํ๋กฌํํธ๋ฅผ ์
๋ ฅํ์ธ์...", |
|
show_label=False, |
|
scale=9 |
|
) |
|
submit = gr.Button("์ ์ก", variant="primary", scale=1) |
|
|
|
|
|
with gr.Row(): |
|
clear = gr.ClearButton([msg, chatbot], value="๐งน ๋ํ ์ด๊ธฐํ") |
|
|
|
|
|
gr.Examples( |
|
examples=[ |
|
"๋ฅ๋ฌ๋์์ ํธ๋์คํฌ๋จธ์ RNN์ ์ฐจ์ด์ ์ ์ค๋ช
ํด์ฃผ์ธ์.", |
|
"ํน์ ๋ฒ์ ๋ด์ ์์๋ฅผ ์ฐพ๋ ํ์ด์ฌ ํจ์๋ฅผ ์์ฑํด์ฃผ์ธ์.", |
|
"๊ฐํํ์ต์ ์ฃผ์ ๊ฐ๋
์ ์์ฝํด์ฃผ์ธ์." |
|
], |
|
inputs=msg |
|
) |
|
|
|
|
|
error_box = gr.Markdown("") |
|
|
|
|
|
submit.click( |
|
query_deepseek_streaming, |
|
inputs=[msg, chatbot, use_deep_research], |
|
outputs=[chatbot, error_box] |
|
).then( |
|
lambda: "", |
|
None, |
|
[msg] |
|
) |
|
|
|
|
|
msg.submit( |
|
query_deepseek_streaming, |
|
inputs=[msg, chatbot, use_deep_research], |
|
outputs=[chatbot, error_box] |
|
).then( |
|
lambda: "", |
|
None, |
|
[msg] |
|
) |
|
|
|
return demo |
|
|
|
|
|
if __name__ == "__main__": |
|
demo = create_deepseek_interface() |
|
demo.launch(debug=True) |