openfree commited on
Commit
2284074
ยท
verified ยท
1 Parent(s): 6ce4225

Create app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +385 -0
app-backup.py ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import requests
4
+ import json
5
+ import time
6
+ from dotenv import load_dotenv
7
+
8
+ # .env ํŒŒ์ผ ๋กœ๋“œ (์žˆ๋Š” ๊ฒฝ์šฐ)
9
+ load_dotenv()
10
+
11
+ def create_deepseek_interface():
12
+ # ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ API ํ‚ค ๊ฐ€์ ธ์˜ค๊ธฐ
13
+ api_key = os.getenv("FW_API_KEY")
14
+ serphouse_api_key = os.getenv("SERPHOUSE_API_KEY")
15
+
16
+ if not api_key:
17
+ print("๊ฒฝ๊ณ : FW_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
18
+ if not serphouse_api_key:
19
+ print("๊ฒฝ๊ณ : SERPHOUSE_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
20
+
21
+ # ํ‚ค์›Œ๋“œ ์ถ”์ถœ ํ•จ์ˆ˜ (LLM ๊ธฐ๋ฐ˜)
22
+ def extract_keywords_with_llm(query):
23
+ if not api_key:
24
+ return "LLM ํ‚ค์›Œ๋“œ ์ถ”์ถœ์„ ์œ„ํ•œ FW_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.", query
25
+
26
+ # LLM์„ ์‚ฌ์šฉํ•˜์—ฌ ํ‚ค์›Œ๋“œ ์ถ”์ถœ (DeepSeek ๋ชจ๋ธ ์‚ฌ์šฉ)
27
+ url = "https://api.fireworks.ai/inference/v1/chat/completions"
28
+ payload = {
29
+ "model": "accounts/fireworks/models/deepseek-v3-0324",
30
+ "max_tokens": 200,
31
+ "temperature": 0.1, # ์ผ๊ด€๋œ ๊ฒฐ๊ณผ๋ฅผ ์œ„ํ•ด ๋‚ฎ์€ ์˜จ๋„ ์‚ฌ์šฉ
32
+ "messages": [
33
+ {
34
+ "role": "system",
35
+ "content": "์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์—์„œ ์›น ๊ฒ€์ƒ‰์— ํšจ๊ณผ์ ์ธ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”์ถœํ•˜์„ธ์š”. ํ‚ค์›Œ๋“œ ์‚ฌ์ด์— ์‰ผํ‘œ๋‚˜ ๊ณต๋ฐฑ์„ ๋„ฃ์ง€ ๋ง๊ณ  ํ•˜๋‚˜์˜ ๊ฒ€์ƒ‰์–ด์ฒ˜๋Ÿผ ์ˆ˜์ •ํ•ด์„œ ์ œ๊ณตํ•˜์„ธ์š”. ์˜ˆ๋ฅผ ๋“ค์–ด 'ํ•œ๋•์ˆ˜ ๊ตญ๋ฌด์ด๋ฆฌ ํƒ„ํ•ต ๊ฒฐ๊ณผ'์ฒ˜๋Ÿผ ๊ณต๋ฐฑ์œผ๋กœ๋งŒ ๊ตฌ๋ถ„ํ•˜์„ธ์š”."
36
+ },
37
+ {
38
+ "role": "user",
39
+ "content": query
40
+ }
41
+ ]
42
+ }
43
+ headers = {
44
+ "Accept": "application/json",
45
+ "Content-Type": "application/json",
46
+ "Authorization": f"Bearer {api_key}"
47
+ }
48
+
49
+ try:
50
+ response = requests.post(url, headers=headers, json=payload)
51
+ response.raise_for_status()
52
+ result = response.json()
53
+
54
+ # ์‘๋‹ต์—์„œ ํ‚ค์›Œ๋“œ ์ถ”์ถœ
55
+ keywords = result["choices"][0]["message"]["content"].strip()
56
+
57
+ # ํ‚ค์›Œ๋“œ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๊ฑฐ๋‚˜ ํ˜•์‹์ด ์ž˜๋ชป๋œ ๊ฒฝ์šฐ ์›๋ณธ ์ฟผ๋ฆฌ ์‚ฌ์šฉ
58
+ if len(keywords) > 100:
59
+ return f"์ถ”์ถœ๋œ ํ‚ค์›Œ๋“œ: {keywords}", query
60
+
61
+ return f"์ถ”์ถœ๋œ ํ‚ค์›Œ๋“œ: {keywords}", keywords
62
+
63
+ except Exception as e:
64
+ print(f"ํ‚ค์›Œ๋“œ ์ถ”์ถœ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
65
+ return f"ํ‚ค์›Œ๋“œ ์ถ”์ถœ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", query
66
+
67
+ # SerpHouse API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ ํ•จ์ˆ˜
68
+ def search_with_serphouse(query):
69
+ if not serphouse_api_key:
70
+ return "SERPHOUSE_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค."
71
+
72
+ try:
73
+ # ํ‚ค์›Œ๋“œ ์ถ”์ถœ
74
+ extraction_result, search_query = extract_keywords_with_llm(query)
75
+ print(f"์›๋ณธ ์ฟผ๋ฆฌ: {query}")
76
+ print(extraction_result)
77
+
78
+ # ๋ฌธ์„œ ์ฝ”๋“œ๋ฅผ ๋” ์ž์„ธํžˆ ๋ถ„์„ํ•ด ๋ณด๋‹ˆ ๊ธฐ๋ณธ GET ๋ฐฉ์‹ ํ™œ์šฉ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค
79
+ url = "https://api.serphouse.com/serp/live"
80
+
81
+ # ํ•œ๊ธ€ ๊ฒ€์ƒ‰์–ด์ธ์ง€ ํ™•์ธ
82
+ is_korean = any('\uAC00' <= c <= '\uD7A3' for c in search_query)
83
+
84
+ # ๊ฐ„์†Œํ™”๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์‹œ๋„
85
+ params = {
86
+ "q": search_query,
87
+ "domain": "google.com",
88
+ "serp_type": "web", # ๊ธฐ๋ณธ ์›น ๊ฒ€์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ
89
+ "device": "desktop",
90
+ "lang": "ko" if is_korean else "en"
91
+ }
92
+
93
+ headers = {
94
+ "Authorization": f"Bearer {serphouse_api_key}"
95
+ }
96
+
97
+ print(f"SerpHouse API ํ˜ธ์ถœ ์ค‘... ๊ธฐ๋ณธ GET ๋ฐฉ์‹์œผ๋กœ ์‹œ๋„")
98
+ print(f"๊ฒ€์ƒ‰์–ด: {search_query}")
99
+ print(f"์š”์ฒญ URL: {url} - ํŒŒ๋ผ๋ฏธํ„ฐ: {params}")
100
+
101
+ # GET ์š”์ฒญ ์ˆ˜ํ–‰
102
+ response = requests.get(url, headers=headers, params=params)
103
+ response.raise_for_status()
104
+
105
+ print(f"SerpHouse API ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: {response.status_code}")
106
+ search_results = response.json()
107
+
108
+ # ์‘๋‹ต ๊ตฌ์กฐ ํ™•์ธ
109
+ print(f"์‘๋‹ต ๊ตฌ์กฐ: {list(search_results.keys()) if isinstance(search_results, dict) else '๋”•์…”๋„ˆ๋ฆฌ ์•„๋‹˜'}")
110
+
111
+ # ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํŒŒ์‹ฑ ๋ฐ ํฌ๋งทํŒ…
112
+ formatted_results = []
113
+ formatted_results.append(f"๊ฒ€์ƒ‰์–ด: {search_query}\n\n")
114
+
115
+ # ๋‹ค์–‘ํ•œ ๊ฐ€๋Šฅํ•œ ์‘๋‹ต ๊ตฌ์กฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ
116
+ organic_results = None
117
+
118
+ # ๊ฐ€๋Šฅํ•œ ์‘๋‹ต ๊ตฌ์กฐ 1
119
+ if "results" in search_results and "organic" in search_results["results"]:
120
+ organic_results = search_results["results"]["organic"]
121
+
122
+ # ๊ฐ€๋Šฅํ•œ ์‘๋‹ต ๊ตฌ์กฐ 2
123
+ elif "organic" in search_results:
124
+ organic_results = search_results["organic"]
125
+
126
+ # ๊ฐ€๋Šฅํ•œ ์‘๋‹ต ๊ตฌ์กฐ 3 (์ค‘์ฒฉ๋œ results)
127
+ elif "results" in search_results and "results" in search_results["results"]:
128
+ if "organic" in search_results["results"]["results"]:
129
+ organic_results = search_results["results"]["results"]["organic"]
130
+
131
+ # organic_results๊ฐ€ ์žˆ์œผ๋ฉด ์ฒ˜๋ฆฌ
132
+ if organic_results and len(organic_results) > 0:
133
+ # ์‘๋‹ต ๊ตฌ์กฐ ์ถœ๋ ฅ
134
+ print(f"์ฒซ๋ฒˆ์งธ organic ๊ฒฐ๊ณผ ๊ตฌ์กฐ: {organic_results[0].keys() if len(organic_results) > 0 else 'empty'}")
135
+
136
+ for result in organic_results[:5]: # ์ƒ์œ„ 5๊ฐœ ๊ฒฐ๊ณผ๋งŒ ํ‘œ์‹œ
137
+ title = result.get("title", "์ œ๋ชฉ ์—†์Œ")
138
+ snippet = result.get("snippet", "๋‚ด์šฉ ์—†์Œ")
139
+ link = result.get("link", "#")
140
+
141
+ formatted_results.append(
142
+ f"์ œ๋ชฉ: {title}\n"
143
+ f"๋‚ด์šฉ: {snippet}\n"
144
+ f"๋งํฌ: {link}\n\n"
145
+ )
146
+
147
+ print(f"๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ {len(organic_results)}๊ฐœ ์ฐพ์Œ")
148
+ return "".join(formatted_results)
149
+
150
+ # ๊ฒฐ๊ณผ๊ฐ€ ์—†๊ฑฐ๋‚˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ตฌ์กฐ์ธ ๊ฒฝ์šฐ
151
+ print("๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์—†์Œ ๋˜๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์‘๋‹ต ๊ตฌ์กฐ")
152
+ print(f"์‘๋‹ต ๊ตฌ์กฐ ์ƒ์„ธ: {search_results.keys() if hasattr(search_results, 'keys') else '๋ถˆ๋ช…ํ™•ํ•œ ๊ตฌ์กฐ'}")
153
+
154
+ # ์‘๋‹ต ๋‚ด์šฉ์—์„œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ์ฐพ๊ธฐ
155
+ error_msg = "๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†๊ฑฐ๋‚˜ ์‘๋‹ต ํ˜•์‹์ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค"
156
+ if "error" in search_results:
157
+ error_msg = search_results["error"]
158
+ elif "message" in search_results:
159
+ error_msg = search_results["message"]
160
+
161
+ return f"๊ฒ€์ƒ‰์–ด '{search_query}'์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ: {error_msg}"
162
+
163
+ except Exception as e:
164
+ error_msg = f"๊ฒ€์ƒ‰ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
165
+ print(error_msg)
166
+ import traceback
167
+ print(traceback.format_exc())
168
+
169
+ # ๋””๋ฒ„๊น… ๋ชฉ์ ์œผ๋กœ API ์š”์ฒญ ์ƒ์„ธ ์ •๋ณด ์ถ”๊ฐ€
170
+ return f"๊ฒ€์ƒ‰ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}\n\n" + \
171
+ f"API ์š”์ฒญ ์ƒ์„ธ ์ •๋ณด:\n" + \
172
+ f"- URL: {url}\n" + \
173
+ f"- ๊ฒ€์ƒ‰์–ด: {search_query}\n" + \
174
+ f"- ํŒŒ๋ผ๋ฏธํ„ฐ: {params}\n"
175
+
176
+ # ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ DeepSeek API ํ˜ธ์ถœ ํ•จ์ˆ˜
177
+ def query_deepseek_streaming(message, history, use_deep_research):
178
+ if not api_key:
179
+ yield history, "ํ™˜๊ฒฝ ๋ณ€์ˆ˜ FW_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„์—์„œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
180
+ return
181
+
182
+ search_context = ""
183
+ search_info = ""
184
+ if use_deep_research:
185
+ try:
186
+ # ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ (์ฒซ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ)
187
+ yield history + [(message, "๐Ÿ” ์ตœ์ ์˜ ํ‚ค์›Œ๋“œ ์ถ”์ถœ ๋ฐ ์›น ๊ฒ€์ƒ‰ ์ค‘...")], ""
188
+
189
+ # ๊ฒ€์ƒ‰ ์‹คํ–‰ - ๋””๋ฒ„๊น…์„ ์œ„ํ•œ ๋กœ๊ทธ ์ถ”๊ฐ€
190
+ print(f"Deep Research ํ™œ์„ฑํ™”๋จ: ๋ฉ”์‹œ์ง€ '{message}'์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰ ์‹œ์ž‘")
191
+ search_results = search_with_serphouse(message)
192
+ print(f"๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ˆ˜์‹  ์™„๋ฃŒ: {search_results[:100]}...") # ๊ฒฐ๊ณผ ์•ž๋ถ€๋ถ„๋งŒ ์ถœ๋ ฅ
193
+
194
+ if not search_results.startswith("๊ฒ€์ƒ‰ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ") and not search_results.startswith("SERPHOUSE_API_KEY"):
195
+ search_context = f"""
196
+ ๋‹ค์Œ์€ ์‚ฌ์šฉ์ž ์งˆ๋ฌธ๊ณผ ๊ด€๋ จ๋œ ์ตœ์‹  ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. ์ด ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ •ํ™•ํ•˜๊ณ  ์ตœ์‹  ์ •๋ณด๊ฐ€ ๋ฐ˜์˜๋œ ์‘๋‹ต์„ ์ œ๊ณตํ•˜์„ธ์š”:
197
+ {search_results}
198
+ ์œ„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ๋‹ค์Œ ์งˆ๋ฌธ์— ๋‹ต๋ณ€ํ•˜์„ธ์š”. ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์—์„œ ๋ช…ํ™•ํ•œ ๋‹ต๋ณ€์„ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ, ๋‹น์‹ ์˜ ์ง€์‹์„ ํ™œ์šฉํ•˜์—ฌ ์ตœ์„ ์˜ ๋‹ต๋ณ€์„ ์ œ๊ณตํ•˜์„ธ์š”.
199
+ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ์ธ์šฉํ•  ๋•Œ๋Š” ์ถœ์ฒ˜๋ฅผ ๋ช…์‹œํ•˜๊ณ , ๋‹ต๋ณ€์ด ์ตœ์‹  ์ •๋ณด๋ฅผ ๋ฐ˜์˜ํ•˜๋„๋ก ํ•˜์„ธ์š”.
200
+ """
201
+ search_info = f"๐Ÿ” Deep Research ๊ธฐ๋Šฅ ํ™œ์„ฑํ™”: ๊ด€๋ จ ์›น ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‘๋‹ต ์ƒ์„ฑ ์ค‘..."
202
+ else:
203
+ print(f"๊ฒ€์ƒ‰ ์‹คํŒจ ๋˜๋Š” ๊ฒฐ๊ณผ ์—†์Œ: {search_results}")
204
+ except Exception as e:
205
+ print(f"Deep Research ์ฒ˜๋ฆฌ ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: {str(e)}")
206
+ search_info = f"๐Ÿ” Deep Research ๊ธฐ๋Šฅ ์˜ค๋ฅ˜: {str(e)}"
207
+
208
+ # API ์š”์ฒญ์„ ์œ„ํ•œ ๋Œ€ํ™” ๊ธฐ๋ก ์ค€๋น„
209
+ messages = []
210
+ for user, assistant in history:
211
+ messages.append({"role": "user", "content": user})
212
+ messages.append({"role": "assistant", "content": assistant})
213
+
214
+ # ๊ฒ€์ƒ‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
215
+ if search_context:
216
+ # DeepSeek ๋ชจ๋ธ์€ ์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค
217
+ messages.insert(0, {"role": "system", "content": search_context})
218
+
219
+ # ์ƒˆ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
220
+ messages.append({"role": "user", "content": message})
221
+
222
+ # API ์š”์ฒญ ์ค€๋น„
223
+ url = "https://api.fireworks.ai/inference/v1/chat/completions"
224
+ payload = {
225
+ "model": "accounts/fireworks/models/deepseek-v3-0324",
226
+ "max_tokens": 20480,
227
+ "top_p": 1,
228
+ "top_k": 40,
229
+ "presence_penalty": 0,
230
+ "frequency_penalty": 0,
231
+ "temperature": 0.6,
232
+ "messages": messages,
233
+ "stream": True # ์ŠคํŠธ๋ฆฌ๋ฐ ํ™œ์„ฑํ™”
234
+ }
235
+ headers = {
236
+ "Accept": "application/json",
237
+ "Content-Type": "application/json",
238
+ "Authorization": f"Bearer {api_key}"
239
+ }
240
+
241
+ try:
242
+ # ์ŠคํŠธ๋ฆฌ๋ฐ ์‘๋‹ต ์š”์ฒญ
243
+ response = requests.request("POST", url, headers=headers, data=json.dumps(payload), stream=True)
244
+ response.raise_for_status() # HTTP ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ
245
+
246
+ # ๋ฉ”์‹œ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ดˆ๊ธฐ ์‘๋‹ต์œผ๋กœ ์‹œ์ž‘
247
+ new_history = history.copy()
248
+
249
+ # search_info๊ฐ€ ์žˆ์œผ๋ฉด ์‹œ์ž‘ ๋ฉ”์‹œ์ง€์— ํฌํ•จ
250
+ start_msg = search_info if search_info else ""
251
+ new_history.append((message, start_msg))
252
+
253
+ # ์‘๋‹ต ์ „์ฒด ํ…์ŠคํŠธ
254
+ full_response = start_msg
255
+
256
+ # ์ŠคํŠธ๋ฆฌ๋ฐ ์‘๋‹ต ์ฒ˜๋ฆฌ
257
+ for line in response.iter_lines():
258
+ if line:
259
+ line_text = line.decode('utf-8')
260
+
261
+ # 'data: ' ์ ‘๋‘์‚ฌ ์ œ๊ฑฐ
262
+ if line_text.startswith("data: "):
263
+ line_text = line_text[6:]
264
+
265
+ # ์ŠคํŠธ๋ฆผ ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ํ™•์ธ
266
+ if line_text == "[DONE]":
267
+ break
268
+
269
+ try:
270
+ # JSON ํŒŒ์‹ฑ
271
+ chunk = json.loads(line_text)
272
+ chunk_content = chunk.get("choices", [{}])[0].get("delta", {}).get("content", "")
273
+
274
+ if chunk_content:
275
+ full_response += chunk_content
276
+ # ์ฑ„ํŒ… ๊ธฐ๋ก ์—…๋ฐ์ดํŠธ
277
+ new_history[-1] = (message, full_response)
278
+ yield new_history, ""
279
+ except json.JSONDecodeError:
280
+ continue
281
+
282
+ # ์ตœ์ข… ์‘๋‹ต ๋ฐ˜ํ™˜
283
+ yield new_history, ""
284
+
285
+ except requests.exceptions.RequestException as e:
286
+ error_msg = f"API ์˜ค๋ฅ˜: {str(e)}"
287
+ if hasattr(e, 'response') and e.response and e.response.status_code == 401:
288
+ error_msg = "์ธ์ฆ ์‹คํŒจ. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ FW_API_KEY๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
289
+ yield history, error_msg
290
+
291
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ
292
+ with gr.Blocks(theme="soft", fill_height=True) as demo:
293
+ # ํ—ค๋” ์„น์…˜
294
+ gr.Markdown(
295
+ """
296
+ # ๐Ÿค– DeepSeek V3 ์ŠคํŠธ๋ฆฌ๋ฐ ์ธํ„ฐํŽ˜์ด์Šค
297
+ ### Fireworks AI๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ณ ๊ธ‰ AI ๋ชจ๋ธ - ์‹ค์‹œ๊ฐ„ ์‘๋‹ต ์ง€์›
298
+ """
299
+ )
300
+
301
+ # ๋ฉ”์ธ ๋ ˆ์ด์•„์›ƒ
302
+ with gr.Row():
303
+ # ๋ฉ”์ธ ์ฝ˜ํ…์ธ  ์˜์—ญ
304
+ with gr.Column():
305
+ # ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค
306
+ chatbot = gr.Chatbot(
307
+ height=500,
308
+ show_label=False,
309
+ container=True
310
+ )
311
+
312
+ # Deep Research ํ† ๊ธ€ ๋ฐ ์ƒํƒœ ํ‘œ์‹œ ์ถ”๊ฐ€
313
+ with gr.Row():
314
+ with gr.Column(scale=3):
315
+ use_deep_research = gr.Checkbox(
316
+ label="Deep Research ํ™œ์„ฑํ™”",
317
+ info="์ตœ์ ์˜ ํ‚ค์›Œ๋“œ ์ถ”์ถœ ๋ฐ ์›น ๊ฒ€์ƒ‰์„ ํ†ตํ•œ ์ตœ์‹  ์ •๋ณด ํ™œ์šฉ",
318
+ value=False
319
+ )
320
+ with gr.Column(scale=1):
321
+ api_status = gr.Markdown("API ์ƒํƒœ: ์ค€๋น„๋จ")
322
+
323
+ # API ํ‚ค ์ƒํƒœ ํ™•์ธ ๋ฐ ํ‘œ์‹œ
324
+ if not serphouse_api_key:
325
+ api_status.value = "โš ๏ธ SERPHOUSE_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค"
326
+ if not api_key:
327
+ api_status.value = "โš ๏ธ FW_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค"
328
+ if api_key and serphouse_api_key:
329
+ api_status.value = "โœ… API ํ‚ค ์„ค์ • ์™„๋ฃŒ"
330
+
331
+ # ์ž…๏ฟฝ๏ฟฝ๏ฟฝ ์˜์—ญ
332
+ with gr.Row():
333
+ msg = gr.Textbox(
334
+ label="๋ฉ”์‹œ์ง€",
335
+ placeholder="์—ฌ๊ธฐ์— ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...",
336
+ show_label=False,
337
+ scale=9
338
+ )
339
+ submit = gr.Button("์ „์†ก", variant="primary", scale=1)
340
+
341
+ # ๋Œ€ํ™” ์ดˆ๊ธฐํ™” ๋ฒ„ํŠผ
342
+ with gr.Row():
343
+ clear = gr.ClearButton([msg, chatbot], value="๐Ÿงน ๋Œ€ํ™” ์ดˆ๊ธฐํ™”")
344
+
345
+ # ์˜ˆ์ œ ์ฟผ๋ฆฌ
346
+ gr.Examples(
347
+ examples=[
348
+ "๋”ฅ๋Ÿฌ๋‹์—์„œ ํŠธ๋žœ์Šคํฌ๋จธ์™€ RNN์˜ ์ฐจ์ด์ ์„ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.",
349
+ "ํŠน์ • ๋ฒ”์œ„ ๋‚ด์˜ ์†Œ์ˆ˜๋ฅผ ์ฐพ๋Š” ํŒŒ์ด์ฌ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.",
350
+ "๊ฐ•ํ™”ํ•™์Šต์˜ ์ฃผ์š” ๊ฐœ๋…์„ ์š”์•ฝํ•ด์ฃผ์„ธ์š”."
351
+ ],
352
+ inputs=msg
353
+ )
354
+
355
+ # ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
356
+ error_box = gr.Markdown("")
357
+
358
+ # ๋ฒ„ํŠผ๊ณผ ๊ธฐ๋Šฅ ์—ฐ๊ฒฐ
359
+ submit.click(
360
+ query_deepseek_streaming,
361
+ inputs=[msg, chatbot, use_deep_research],
362
+ outputs=[chatbot, error_box]
363
+ ).then(
364
+ lambda: "",
365
+ None,
366
+ [msg]
367
+ )
368
+
369
+ # Enter ํ‚ค ์ œ์ถœ ํ—ˆ์šฉ
370
+ msg.submit(
371
+ query_deepseek_streaming,
372
+ inputs=[msg, chatbot, use_deep_research],
373
+ outputs=[chatbot, error_box]
374
+ ).then(
375
+ lambda: "",
376
+ None,
377
+ [msg]
378
+ )
379
+
380
+ return demo
381
+
382
+ # ์ธํ„ฐํŽ˜์ด์Šค ์‹คํ–‰
383
+ if __name__ == "__main__":
384
+ demo = create_deepseek_interface()
385
+ demo.launch(debug=True)