openfree commited on
Commit
434dc20
·
verified ·
1 Parent(s): 1d68b76

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -121
app.py CHANGED
@@ -5,34 +5,34 @@ 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",
@@ -51,41 +51,41 @@ def create_deepseek_interface():
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
  }
@@ -94,138 +94,138 @@ def create_deepseek_interface():
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
- # 검색 결과 파싱 포맷팅 (Markdown 형식으로 출력)
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 i, result in enumerate(organic_results[:5], 1): # 상위 5 결과만 표시
137
- title = result.get("title", "제목 없음")
138
- snippet = result.get("snippet", "내용 없음")
139
  link = result.get("link", "#")
140
  displayed_link = result.get("displayed_link", link)
141
 
142
- # Markdown 형식으로 출력 (번호 링크 포함)
143
  formatted_results.append(
144
  f"### {i}. [{title}]({link})\n\n"
145
  f"{snippet}\n\n"
146
- f"**출처**: [{displayed_link}]({link})\n\n"
147
  f"---\n\n"
148
  )
149
 
150
- print(f"검색 결과 {len(organic_results)} 찾음")
151
  return "".join(formatted_results)
152
 
153
- # 결과가 없거나 예상치 못한 구조인 경우
154
- print("검색 결과 없음 또는 예상치 못한 응답 구조")
155
- print(f"응답 구조 상세: {search_results.keys() if hasattr(search_results, 'keys') else '불명확한 구조'}")
156
 
157
- # 응답 내용에서 오류 메시지 찾기
158
- error_msg = "검색 결과가 없거나 응답 형식이 예상과 다릅니다"
159
  if "error" in search_results:
160
  error_msg = search_results["error"]
161
  elif "message" in search_results:
162
  error_msg = search_results["message"]
163
 
164
- return f"## 검색어 '{search_query}'에 대한 결과\n\n{error_msg}"
165
 
166
  except Exception as e:
167
- error_msg = f"검색 오류 발생: {str(e)}"
168
  print(error_msg)
169
  import traceback
170
  print(traceback.format_exc())
171
 
172
- # 디버깅 목적으로 API 요청 상세 정보 추가 (Markdown 형식)
173
- return f"## 오류 발생\n\n" + \
174
- f"검색 오류가 발생했습니다: **{str(e)}**\n\n" + \
175
- f"### API 요청 상세 정보:\n" + \
176
  f"- **URL**: {url}\n" + \
177
- f"- **검색어**: {search_query}\n" + \
178
- f"- **파라미터**: {params}\n"
179
 
180
- # 스트리밍 방식으로 DeepSeek API 호출 함수
181
  def query_deepseek_streaming(message, history, use_deep_research):
182
  if not api_key:
183
- yield history, "환경 변수 FW_API_KEY 설정되지 않았습니다. 서버에서 환경 변수를 확인해주세요."
184
  return
185
 
186
  search_context = ""
187
  search_info = ""
188
  if use_deep_research:
189
  try:
190
- # 검색 수행 ( 메시지 전달)
191
- yield history + [(message, "🔍 최적의 키워드 추출 검색 중...")], ""
192
 
193
- # 검색 실행 - 디버깅을 위한 로그 추가
194
- print(f"Deep Research 활성화됨: 메시지 '{message}'에 대한 검색 시작")
195
  search_results = search_with_serphouse(message)
196
- print(f"검색 결과 수신 완료: {search_results[:100]}...") # 결과 앞부분만 출력
197
 
198
- if not search_results.startswith("검색 오류 발생") and not search_results.startswith("SERPHOUSE_API_KEY"):
199
  search_context = f"""
200
- 다음은 사용자 질문과 관련된 최신 검색 결과입니다. 정보를 참고하여 정확하고 최신 정보가 반영된 응답을 제공하세요:
201
 
202
  {search_results}
203
 
204
- 검색 결과를 기반으로 사용자의 다음 질문에 답변하세요. 검색 결과에서 명확한 답변을 찾을 없는 경우, 당신의 지식을 활용하여 최선의 답변을 제공하세요.
205
- 검색 결과를 인용할 때는 출처를 명시하고, 답변이 최신 정보를 반영하도록 하세요.
206
  """
207
- search_info = f"🔍 Deep Research 기능 활성화: 관련 검색 결과를 기반으로 응답 생성 중..."
208
  else:
209
- print(f"검색 실패 또는 결과 없음: {search_results}")
210
  except Exception as e:
211
- print(f"Deep Research 처리 예외 발생: {str(e)}")
212
- search_info = f"🔍 Deep Research 기능 오류: {str(e)}"
213
 
214
- # API 요청을 위한 대화 기록 준비
215
  messages = []
216
  for user, assistant in history:
217
  messages.append({"role": "user", "content": user})
218
  messages.append({"role": "assistant", "content": assistant})
219
 
220
- # 검색 컨텍스트가 있으면 시스템 메시지 추가
221
  if search_context:
222
- # DeepSeek 모델은 시스템 메시지를 지원합니다
223
  messages.insert(0, {"role": "system", "content": search_context})
224
 
225
- # 사용자 메시지 추가
226
  messages.append({"role": "user", "content": message})
227
 
228
- # API 요청 준비
229
  url = "https://api.fireworks.ai/inference/v1/chat/completions"
230
  payload = {
231
  "model": "accounts/fireworks/models/deepseek-v3-0324",
@@ -236,7 +236,7 @@ def create_deepseek_interface():
236
  "frequency_penalty": 0,
237
  "temperature": 0.6,
238
  "messages": messages,
239
- "stream": True # 스트리밍 활성화
240
  }
241
  headers = {
242
  "Accept": "application/json",
@@ -245,123 +245,123 @@ def create_deepseek_interface():
245
  }
246
 
247
  try:
248
- # 스트리밍 응답 요청
249
  response = requests.request("POST", url, headers=headers, data=json.dumps(payload), stream=True)
250
- response.raise_for_status() # HTTP 오류 발생 예외 발생
251
 
252
- # 메시지를 추가하고 초기 응답으로 시작
253
  new_history = history.copy()
254
 
255
- # search_info 있으면 시작 메시지에 포함
256
  start_msg = search_info if search_info else ""
257
  new_history.append((message, start_msg))
258
 
259
- # 응답 전체 텍스트
260
  full_response = start_msg
261
 
262
- # 스트리밍 응답 처리
263
  for line in response.iter_lines():
264
  if line:
265
  line_text = line.decode('utf-8')
266
 
267
- # 'data: ' 접두사 제거
268
  if line_text.startswith("data: "):
269
  line_text = line_text[6:]
270
 
271
- # 스트림 종료 메시지 확인
272
  if line_text == "[DONE]":
273
  break
274
 
275
  try:
276
- # JSON 파싱
277
  chunk = json.loads(line_text)
278
  chunk_content = chunk.get("choices", [{}])[0].get("delta", {}).get("content", "")
279
 
280
  if chunk_content:
281
  full_response += chunk_content
282
- # 채팅 기록 업데이트
283
  new_history[-1] = (message, full_response)
284
  yield new_history, ""
285
  except json.JSONDecodeError:
286
  continue
287
 
288
- # 최종 응답 반환
289
  yield new_history, ""
290
 
291
  except requests.exceptions.RequestException as e:
292
- error_msg = f"API 오류: {str(e)}"
293
  if hasattr(e, 'response') and e.response and e.response.status_code == 401:
294
- error_msg = "인증 실패. 환경 변수 FW_API_KEY 확인해주세요."
295
  yield history, error_msg
296
 
297
- # Gradio 인터페이스 생성
298
  with gr.Blocks(theme="soft", fill_height=True) as demo:
299
- # 헤더 섹션
300
  gr.Markdown(
301
  """
302
- # 🤖 DeepSeek V3-0324 + Reserach
303
- ### DeepSeek V3-0324 최신 모델 + 실시간 'Deep Research' Agentic AI 시스템 @ https://discord.gg/openfreeai
304
  """
305
  )
306
 
307
- # 메인 레이아웃
308
  with gr.Row():
309
- # 메인 콘텐츠 영역
310
  with gr.Column():
311
- # 채팅 인터페이스
312
  chatbot = gr.Chatbot(
313
  height=500,
314
  show_label=False,
315
  container=True
316
  )
317
 
318
- # Deep Research 토글 상태 표시 추가
319
  with gr.Row():
320
  with gr.Column(scale=3):
321
  use_deep_research = gr.Checkbox(
322
- label="Deep Research 활성화",
323
- info="최적의 키워드 추출 검색을 통한 최신 정보 활용",
324
  value=False
325
  )
326
  with gr.Column(scale=1):
327
- api_status = gr.Markdown("API 상태: 준비됨")
328
 
329
- # API 상태 확인 표시
330
  if not serphouse_api_key:
331
- api_status.value = "⚠️ SERPHOUSE_API_KEY 설정되지 않았습니다"
332
  if not api_key:
333
- api_status.value = "⚠️ FW_API_KEY 설정되지 않았습니다"
334
  if api_key and serphouse_api_key:
335
- api_status.value = "✅ API 설정 완료"
336
 
337
- # 입력 영역
338
  with gr.Row():
339
  msg = gr.Textbox(
340
- label="메시지",
341
- placeholder="여기에 프롬프트를 입력하세요...",
342
  show_label=False,
343
  scale=9
344
  )
345
- submit = gr.Button("전송", variant="primary", scale=1)
346
 
347
- # 대화 초기화 버튼
348
  with gr.Row():
349
- clear = gr.ClearButton([msg, chatbot], value="🧹 대화 초기화")
350
 
351
- # 예제 쿼리
352
  gr.Examples(
353
  examples=[
354
- "딥러닝에서 트랜스포머와 RNN의 차이점을 설명해주세요.",
355
- "특정 범위 내의 소수를 찾는 파이썬 함수를 작성해주세요.",
356
- "강화학습의 주요 개념을 요약해주세요."
357
  ],
358
  inputs=msg
359
  )
360
 
361
- # 오류 메시지 표시
362
  error_box = gr.Markdown("")
363
 
364
- # 버튼과 기능 연결
365
  submit.click(
366
  query_deepseek_streaming,
367
  inputs=[msg, chatbot, use_deep_research],
@@ -372,7 +372,7 @@ def create_deepseek_interface():
372
  [msg]
373
  )
374
 
375
- # Enter 제출 허용
376
  msg.submit(
377
  query_deepseek_streaming,
378
  inputs=[msg, chatbot, use_deep_research],
@@ -385,7 +385,7 @@ def create_deepseek_interface():
385
 
386
  return demo
387
 
388
- # 인터페이스 실행
389
  if __name__ == "__main__":
390
  demo = create_deepseek_interface()
391
  demo.launch(debug=True)
 
5
  import time
6
  from dotenv import load_dotenv
7
 
8
+ # Load .env file (if it exists)
9
  load_dotenv()
10
 
11
  def create_deepseek_interface():
12
+ # Get API keys from environment variables
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("Warning: FW_API_KEY environment variable is not set.")
18
  if not serphouse_api_key:
19
+ print("Warning: SERPHOUSE_API_KEY environment variable is not set.")
20
 
21
+ # Keyword extraction function (LLM-based)
22
  def extract_keywords_with_llm(query):
23
  if not api_key:
24
+ return "FW_API_KEY not set for LLM keyword extraction.", query
25
 
26
+ # Extract keywords using LLM (DeepSeek model)
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, # Low temperature for consistent results
32
  "messages": [
33
  {
34
  "role": "system",
35
+ "content": "Extract key search terms from the user's question that would be effective for web searches. Provide these as a search query with words separated by spaces only, without commas. For example: 'Prime Minister Han Duck-soo impeachment results'"
36
  },
37
  {
38
  "role": "user",
 
51
  response.raise_for_status()
52
  result = response.json()
53
 
54
+ # Extract keywords from response
55
  keywords = result["choices"][0]["message"]["content"].strip()
56
 
57
+ # Use original query if keywords are too long or improperly formatted
58
  if len(keywords) > 100:
59
+ return f"Extracted keywords: {keywords}", query
60
 
61
+ return f"Extracted keywords: {keywords}", keywords
62
 
63
  except Exception as e:
64
+ print(f"Error during keyword extraction: {str(e)}")
65
+ return f"Error during keyword extraction: {str(e)}", query
66
 
67
+ # Search function using SerpHouse API
68
  def search_with_serphouse(query):
69
  if not serphouse_api_key:
70
+ return "SERPHOUSE_API_KEY is not set."
71
 
72
  try:
73
+ # Extract keywords
74
  extraction_result, search_query = extract_keywords_with_llm(query)
75
+ print(f"Original query: {query}")
76
  print(extraction_result)
77
 
78
+ # Basic GET method seems best after analyzing documentation
79
  url = "https://api.serphouse.com/serp/live"
80
 
81
+ # Check if query is in Korean
82
  is_korean = any('\uAC00' <= c <= '\uD7A3' for c in search_query)
83
 
84
+ # Simplified parameters
85
  params = {
86
  "q": search_query,
87
  "domain": "google.com",
88
+ "serp_type": "web", # Changed to basic web search
89
  "device": "desktop",
90
  "lang": "ko" if is_korean else "en"
91
  }
 
94
  "Authorization": f"Bearer {serphouse_api_key}"
95
  }
96
 
97
+ print(f"Calling SerpHouse API with basic GET method...")
98
+ print(f"Search term: {search_query}")
99
+ print(f"Request URL: {url} - Parameters: {params}")
100
 
101
+ # Execute GET request
102
  response = requests.get(url, headers=headers, params=params)
103
  response.raise_for_status()
104
 
105
+ print(f"SerpHouse API response status code: {response.status_code}")
106
  search_results = response.json()
107
 
108
+ # Check response structure
109
+ print(f"Response structure: {list(search_results.keys()) if isinstance(search_results, dict) else 'Not a dictionary'}")
110
 
111
+ # Parse and format search results (in Markdown)
112
  formatted_results = []
113
+ formatted_results.append(f"## Search term: {search_query}\n\n")
114
 
115
+ # Handle various possible response structures
116
  organic_results = None
117
 
118
+ # Possible response structure 1
119
  if "results" in search_results and "organic" in search_results["results"]:
120
  organic_results = search_results["results"]["organic"]
121
 
122
+ # Possible response structure 2
123
  elif "organic" in search_results:
124
  organic_results = search_results["organic"]
125
 
126
+ # Possible response structure 3 (nested 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
+ # Process organic results if available
132
  if organic_results and len(organic_results) > 0:
133
+ # Output response structure
134
+ print(f"First organic result structure: {organic_results[0].keys() if len(organic_results) > 0 else 'empty'}")
135
 
136
+ for i, result in enumerate(organic_results[:5], 1): # Show only top 5 results
137
+ title = result.get("title", "No title")
138
+ snippet = result.get("snippet", "No content")
139
  link = result.get("link", "#")
140
  displayed_link = result.get("displayed_link", link)
141
 
142
+ # Format in Markdown (including number and link)
143
  formatted_results.append(
144
  f"### {i}. [{title}]({link})\n\n"
145
  f"{snippet}\n\n"
146
+ f"**Source**: [{displayed_link}]({link})\n\n"
147
  f"---\n\n"
148
  )
149
 
150
+ print(f"Found {len(organic_results)} search results")
151
  return "".join(formatted_results)
152
 
153
+ # Handle case with no results or unexpected structure
154
+ print("No search results or unexpected response structure")
155
+ print(f"Detailed response structure: {search_results.keys() if hasattr(search_results, 'keys') else 'Unclear structure'}")
156
 
157
+ # Find error messages in response
158
+ error_msg = "No search results found or response format is different than expected"
159
  if "error" in search_results:
160
  error_msg = search_results["error"]
161
  elif "message" in search_results:
162
  error_msg = search_results["message"]
163
 
164
+ return f"## Results for '{search_query}'\n\n{error_msg}"
165
 
166
  except Exception as e:
167
+ error_msg = f"Error during search: {str(e)}"
168
  print(error_msg)
169
  import traceback
170
  print(traceback.format_exc())
171
 
172
+ # Add API request details for debugging (in Markdown)
173
+ return f"## Error Occurred\n\n" + \
174
+ f"An error occurred during search: **{str(e)}**\n\n" + \
175
+ f"### API Request Details:\n" + \
176
  f"- **URL**: {url}\n" + \
177
+ f"- **Search Term**: {search_query}\n" + \
178
+ f"- **Parameters**: {params}\n"
179
 
180
+ # Function to call DeepSeek API with streaming
181
  def query_deepseek_streaming(message, history, use_deep_research):
182
  if not api_key:
183
+ yield history, "Environment variable FW_API_KEY is not set. Please check the environment variables on the server."
184
  return
185
 
186
  search_context = ""
187
  search_info = ""
188
  if use_deep_research:
189
  try:
190
+ # Start search (first message)
191
+ yield history + [(message, "🔍 Extracting optimal keywords and searching the web...")], ""
192
 
193
+ # Execute search - add logs for debugging
194
+ print(f"Deep Research activated: Starting search for '{message}'")
195
  search_results = search_with_serphouse(message)
196
+ print(f"Search results received: {search_results[:100]}...") # Output first part of results
197
 
198
+ if not search_results.startswith("Error during search") and not search_results.startswith("SERPHOUSE_API_KEY"):
199
  search_context = f"""
200
+ Here are recent search results related to the user's question. Use this information to provide an accurate response with the latest information:
201
 
202
  {search_results}
203
 
204
+ Based on the above search results, answer the user's question. If you cannot find a clear answer in the search results, use your knowledge to provide the best answer.
205
+ When citing search results, mention the source, and ensure your answer reflects the latest information.
206
  """
207
+ search_info = f"🔍 Deep Research feature activated: Generating response based on relevant web search results..."
208
  else:
209
+ print(f"Search failed or no results: {search_results}")
210
  except Exception as e:
211
+ print(f"Exception occurred during Deep Research: {str(e)}")
212
+ search_info = f"🔍 Deep Research feature error: {str(e)}"
213
 
214
+ # Prepare conversation history for API request
215
  messages = []
216
  for user, assistant in history:
217
  messages.append({"role": "user", "content": user})
218
  messages.append({"role": "assistant", "content": assistant})
219
 
220
+ # Add system message with search context if available
221
  if search_context:
222
+ # DeepSeek model supports system messages
223
  messages.insert(0, {"role": "system", "content": search_context})
224
 
225
+ # Add new user message
226
  messages.append({"role": "user", "content": message})
227
 
228
+ # Prepare API request
229
  url = "https://api.fireworks.ai/inference/v1/chat/completions"
230
  payload = {
231
  "model": "accounts/fireworks/models/deepseek-v3-0324",
 
236
  "frequency_penalty": 0,
237
  "temperature": 0.6,
238
  "messages": messages,
239
+ "stream": True # Enable streaming
240
  }
241
  headers = {
242
  "Accept": "application/json",
 
245
  }
246
 
247
  try:
248
+ # Request streaming response
249
  response = requests.request("POST", url, headers=headers, data=json.dumps(payload), stream=True)
250
+ response.raise_for_status() # Raise exception for HTTP errors
251
 
252
+ # Add message and start with initial response
253
  new_history = history.copy()
254
 
255
+ # Include search_info in starting message if available
256
  start_msg = search_info if search_info else ""
257
  new_history.append((message, start_msg))
258
 
259
+ # Full response text
260
  full_response = start_msg
261
 
262
+ # Process streaming response
263
  for line in response.iter_lines():
264
  if line:
265
  line_text = line.decode('utf-8')
266
 
267
+ # Remove 'data: ' prefix
268
  if line_text.startswith("data: "):
269
  line_text = line_text[6:]
270
 
271
+ # Check for stream end message
272
  if line_text == "[DONE]":
273
  break
274
 
275
  try:
276
+ # Parse JSON
277
  chunk = json.loads(line_text)
278
  chunk_content = chunk.get("choices", [{}])[0].get("delta", {}).get("content", "")
279
 
280
  if chunk_content:
281
  full_response += chunk_content
282
+ # Update chat history
283
  new_history[-1] = (message, full_response)
284
  yield new_history, ""
285
  except json.JSONDecodeError:
286
  continue
287
 
288
+ # Return final response
289
  yield new_history, ""
290
 
291
  except requests.exceptions.RequestException as e:
292
+ error_msg = f"API error: {str(e)}"
293
  if hasattr(e, 'response') and e.response and e.response.status_code == 401:
294
+ error_msg = "Authentication failed. Please check your FW_API_KEY environment variable."
295
  yield history, error_msg
296
 
297
+ # Create Gradio interface
298
  with gr.Blocks(theme="soft", fill_height=True) as demo:
299
+ # Header section
300
  gr.Markdown(
301
  """
302
+ # 🤖 DeepSeek V3-0324 + Research
303
+ ### DeepSeek V3-0324 Latest Model + Real-time 'Deep Research' Agentic AI System @ https://discord.gg/openfreeai
304
  """
305
  )
306
 
307
+ # Main layout
308
  with gr.Row():
309
+ # Main content area
310
  with gr.Column():
311
+ # Chat interface
312
  chatbot = gr.Chatbot(
313
  height=500,
314
  show_label=False,
315
  container=True
316
  )
317
 
318
+ # Add Deep Research toggle and status display
319
  with gr.Row():
320
  with gr.Column(scale=3):
321
  use_deep_research = gr.Checkbox(
322
+ label="Enable Deep Research",
323
+ info="Utilize optimal keyword extraction and web search for latest information",
324
  value=False
325
  )
326
  with gr.Column(scale=1):
327
+ api_status = gr.Markdown("API Status: Ready")
328
 
329
+ # Check and display API key status
330
  if not serphouse_api_key:
331
+ api_status.value = "⚠️ SERPHOUSE_API_KEY is not set"
332
  if not api_key:
333
+ api_status.value = "⚠️ FW_API_KEY is not set"
334
  if api_key and serphouse_api_key:
335
+ api_status.value = "✅ API keys configured"
336
 
337
+ # Input area
338
  with gr.Row():
339
  msg = gr.Textbox(
340
+ label="Message",
341
+ placeholder="Enter your prompt here...",
342
  show_label=False,
343
  scale=9
344
  )
345
+ submit = gr.Button("Send", variant="primary", scale=1)
346
 
347
+ # Clear conversation button
348
  with gr.Row():
349
+ clear = gr.ClearButton([msg, chatbot], value="🧹 Clear Conversation")
350
 
351
+ # Example queries
352
  gr.Examples(
353
  examples=[
354
+ "Explain the difference between Transformers and RNNs in deep learning.",
355
+ "Write a Python function to find prime numbers within a specific range.",
356
+ "Summarize the key concepts of reinforcement learning."
357
  ],
358
  inputs=msg
359
  )
360
 
361
+ # Error message display
362
  error_box = gr.Markdown("")
363
 
364
+ # Connect buttons to functions
365
  submit.click(
366
  query_deepseek_streaming,
367
  inputs=[msg, chatbot, use_deep_research],
 
372
  [msg]
373
  )
374
 
375
+ # Allow Enter key submission
376
  msg.submit(
377
  query_deepseek_streaming,
378
  inputs=[msg, chatbot, use_deep_research],
 
385
 
386
  return demo
387
 
388
+ # Run interface
389
  if __name__ == "__main__":
390
  demo = create_deepseek_interface()
391
  demo.launch(debug=True)