|
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/llama4-scout-instruct-basic", |
|
"max_tokens": 200, |
|
"temperature": 0.1, |
|
"messages": [ |
|
{ |
|
"role": "system", |
|
"content": "๋ฐ๋์ ํ๊ธ๋ก ๋ต๋ณํ๋ผ. You are a deep thinking AI, you may use extremely long chains of thought to deeply consider the problem and deliberate with yourself via systematic reasoning processes to help come to a correct solution prior to answering. You should enclose your thoughts and internal monologue inside tags, and then provide your solution or response to the problem.์ฌ์ฉ์์ ์ง๋ฌธ์์ ์น ๊ฒ์์ ํจ๊ณผ์ ์ธ ํต์ฌ ํค์๋๋ฅผ ์ถ์ถํ์ธ์. ํค์๋ ์ฌ์ด์ ์ผํ๋ ๊ณต๋ฐฑ์ ๋ฃ์ง ๋ง๊ณ ํ๋์ ๊ฒ์์ด์ฒ๋ผ ์์ ํด์ ์ ๊ณตํ์ธ์. ์๋ฅผ ๋ค์ด 'ํ๋์ ๊ตญ๋ฌด์ด๋ฆฌ ํํต ๊ฒฐ๊ณผ'์ฒ๋ผ ๊ณต๋ฐฑ์ผ๋ก๋ง ๊ตฌ๋ถํ์ธ์." |
|
}, |
|
{ |
|
"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) |
|
|
|
|
|
url = "https://api.serphouse.com/serp/live" |
|
|
|
|
|
is_korean = any('\uAC00' <= c <= '\uD7A3' for c in search_query) |
|
|
|
|
|
params = { |
|
"q": search_query, |
|
"domain": "google.com", |
|
"serp_type": "web", |
|
"device": "desktop", |
|
"lang": "ko" if is_korean else "en" |
|
} |
|
|
|
headers = { |
|
"Authorization": f"Bearer {serphouse_api_key}" |
|
} |
|
|
|
print(f"SerpHouse API ํธ์ถ ์ค... ๊ธฐ๋ณธ GET ๋ฐฉ์์ผ๋ก ์๋") |
|
print(f"๊ฒ์์ด: {search_query}") |
|
print(f"์์ฒญ URL: {url} - ํ๋ผ๋ฏธํฐ: {params}") |
|
|
|
|
|
response = requests.get(url, headers=headers, params=params) |
|
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") |
|
|
|
|
|
organic_results = None |
|
|
|
|
|
if "results" in search_results and "organic" in search_results["results"]: |
|
organic_results = search_results["results"]["organic"] |
|
|
|
|
|
elif "organic" in search_results: |
|
organic_results = search_results["organic"] |
|
|
|
|
|
elif "results" in search_results and "results" in search_results["results"]: |
|
if "organic" in search_results["results"]["results"]: |
|
organic_results = search_results["results"]["results"]["organic"] |
|
|
|
|
|
if organic_results and len(organic_results) > 0: |
|
|
|
print(f"์ฒซ๋ฒ์งธ organic ๊ฒฐ๊ณผ ๊ตฌ์กฐ: {organic_results[0].keys() if len(organic_results) > 0 else 'empty'}") |
|
|
|
for i, result in enumerate(organic_results[:5], 1): |
|
title = result.get("title", "์ ๋ชฉ ์์") |
|
snippet = result.get("snippet", "๋ด์ฉ ์์") |
|
link = result.get("link", "#") |
|
displayed_link = result.get("displayed_link", link) |
|
|
|
|
|
formatted_results.append( |
|
f"### {i}. [{title}]({link})\n\n" |
|
f"{snippet}\n\n" |
|
f"**์ถ์ฒ**: [{displayed_link}]({link})\n\n" |
|
f"---\n\n" |
|
) |
|
|
|
print(f"๊ฒ์ ๊ฒฐ๊ณผ {len(organic_results)}๊ฐ ์ฐพ์") |
|
return "".join(formatted_results) |
|
|
|
|
|
print("๊ฒ์ ๊ฒฐ๊ณผ ์์ ๋๋ ์์์น ๋ชปํ ์๋ต ๊ตฌ์กฐ") |
|
print(f"์๋ต ๊ตฌ์กฐ ์์ธ: {search_results.keys() if hasattr(search_results, 'keys') else '๋ถ๋ช
ํํ ๊ตฌ์กฐ'}") |
|
|
|
|
|
error_msg = "๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์๊ฑฐ๋ ์๋ต ํ์์ด ์์๊ณผ ๋ค๋ฆ
๋๋ค" |
|
if "error" in search_results: |
|
error_msg = search_results["error"] |
|
elif "message" in search_results: |
|
error_msg = search_results["message"] |
|
|
|
return f"## ๊ฒ์์ด '{search_query}'์ ๋ํ ๊ฒฐ๊ณผ\n\n{error_msg}" |
|
|
|
except Exception as e: |
|
error_msg = f"๊ฒ์ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
|
print(error_msg) |
|
import traceback |
|
print(traceback.format_exc()) |
|
|
|
|
|
return f"## ์ค๋ฅ ๋ฐ์\n\n" + \ |
|
f"๊ฒ์ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: **{str(e)}**\n\n" + \ |
|
f"### API ์์ฒญ ์์ธ ์ ๋ณด:\n" + \ |
|
f"- **URL**: {url}\n" + \ |
|
f"- **๊ฒ์์ด**: {search_query}\n" + \ |
|
f"- **ํ๋ผ๋ฏธํฐ**: {params}\n" |
|
|
|
|
|
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/llama4-scout-instruct-basic", |
|
"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( |
|
""" |
|
# ๐ค Llama-4-Scout-17B + Research |
|
### Llama-4-Scout-17B Model + Real-time 'Deep Research' Agentic AI System @ https://discord.gg/openfreeai |
|
""" |
|
) |
|
|
|
|
|
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) |