Hongtyyuqu commited on
Commit
47e353e
·
verified ·
1 Parent(s): 7ce0e86

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -84
app.py CHANGED
@@ -1,100 +1,72 @@
1
  import os
2
  import json
3
- import httpx
4
- from fastapi import FastAPI, Request
5
  from fastapi.responses import StreamingResponse
6
- from fastapi.middleware.cors import CORSMiddleware
7
  from tavily import TavilyClient
8
 
9
  app = FastAPI()
10
 
11
- app.add_middleware(
12
- CORSMiddleware,
13
- allow_origins=["*"],
14
- allow_credentials=True,
15
- allow_methods=["*"],
16
- allow_headers=["*"],
17
- )
18
 
19
- @app.post("/chat")
20
- async def chat_endpoint(request: Request):
21
- data = await request.json()
22
- messages = data.get("messages", [])
23
 
24
- user_query = ""
25
- for msg in reversed(messages):
26
- if msg.get("role") == "user":
27
- user_query = msg.get("content", "")
28
- break
29
 
30
- tavily_key = os.getenv("TAVILY_API_KEY", "")
31
- openrouter_key = os.getenv("OPENROUTER_API_KEY", "")
 
 
32
 
33
- sources = []
34
- context_text = ""
 
 
 
 
 
 
35
 
36
- if tavily_key and user_query:
37
- try:
38
- tavily_client = TavilyClient(api_key=tavily_key)
39
- search_res = tavily_client.search(query=user_query, max_results=5)
40
-
41
- for item in search_res.get("results", []):
42
- sources.append({
43
- "title": item.get("title", ""),
44
- "url": item.get("url", "")
45
- })
46
- context_text += f"\nTitle: {item.get('title')}\nURL: {item.get('url')}\nContent: {item.get('content')}\n"
47
- except Exception:
48
- pass
49
 
50
- system_prompt = (
51
- "You are a helpful AI assistant with real-time web search capabilities. "
52
- "Use the following search context to answer the user's question accurately.\n"
53
- f"Search Context:\n{context_text}"
 
54
  )
55
 
56
- llm_messages = [{"role": "system", "content": system_prompt}] + messages
57
-
58
- async def event_generator():
59
- async with httpx.AsyncClient(timeout=60.0) as client:
60
- async with client.stream(
61
- "POST",
62
- "https://openrouter.ai/api/v1/chat/completions",
63
- headers={
64
- "Authorization": f"Bearer {openrouter_key}",
65
- "Content-Type": "application/json",
66
- },
67
- json={
68
- "model": "nvidia/nemotron-3-ultra-550b-a55b:free",
69
- "messages": llm_messages,
70
- "stream": True,
71
- "reasoning": {"enabled": True}
72
- }
73
- ) as response:
74
- async for line in response.aiter_lines():
75
- if line.startswith("data: "):
76
- data_str = line[6:].strip()
77
- if data_str == "[DONE]":
78
- break
79
- try:
80
- chunk = json.loads(data_str)
81
- delta = chunk.get("choices", [{}])[0].get("delta", {})
82
-
83
- reasoning = delta.get("reasoning_content") or delta.get("reasoning_details") or delta.get("reasoning")
84
- answer = delta.get("content")
85
-
86
- if reasoning:
87
- payload = json.dumps({"reasoning_content": reasoning}, ensure_ascii=False)
88
- yield f"data: {payload}\n\n"
89
-
90
- if answer:
91
- payload = json.dumps({"answer_content": answer}, ensure_ascii=False)
92
- yield f"data: {payload}\n\n"
93
-
94
- except Exception:
95
- pass
96
-
97
- sources_payload = json.dumps({"sources": sources}, ensure_ascii=False)
98
- yield f"data: {sources_payload}\n\n"
99
 
100
- return StreamingResponse(event_generator(), media_type="text/event-stream")
 
 
 
1
  import os
2
  import json
3
+ import requests
4
+ from fastapi import FastAPI
5
  from fastapi.responses import StreamingResponse
6
+ from pydantic import BaseModel
7
  from tavily import TavilyClient
8
 
9
  app = FastAPI()
10
 
11
+ class ChatRequest(BaseModel):
12
+ query: str
 
 
 
 
 
13
 
14
+ def generate_response(query: str):
15
+ tavily_api_key = os.environ.get("TAVILY_API_KEY", "")
16
+ tavily_client = TavilyClient(api_key=tavily_api_key)
 
17
 
18
+ tavily_res = tavily_client.search(query=query)
19
+
20
+ context = "\n".join([r['content'] for r in tavily_res.get('results', [])])
21
+ sources = [{"title": r['title'], "url": r['url']} for r in tavily_res.get('results', [])]
 
22
 
23
+ messages = [
24
+ {"role": "system", "content": f"Answer based on context:\n{context}"},
25
+ {"role": "user", "content": query}
26
+ ]
27
 
28
+ openrouter_api_key = os.environ.get("OPENROUTER_API_KEY", "")
29
+
30
+ payload = {
31
+ "model": "nvidia/nemotron-3-ultra-550b-a55b:free",
32
+ "messages": messages,
33
+ "stream": True,
34
+ "reasoning": {"enabled": True}
35
+ }
36
 
37
+ headers = {
38
+ "Authorization": f"Bearer {openrouter_api_key}",
39
+ "Content-Type": "application/json"
40
+ }
 
 
 
 
 
 
 
 
 
41
 
42
+ response = requests.post(
43
+ "https://openrouter.ai/api/v1/chat/completions",
44
+ headers=headers,
45
+ json=payload,
46
+ stream=True
47
  )
48
 
49
+ for line in response.iter_lines():
50
+ if line:
51
+ line_str = line.decode('utf-8')
52
+ if line_str.startswith("data: ") and line_str != "data: [DONE]":
53
+ try:
54
+ data = json.loads(line_str[6:])
55
+ delta = data['choices'][0]['delta']
56
+
57
+ reasoning = delta.get('reasoning')
58
+ if reasoning:
59
+ yield f"data: {json.dumps({'type': 'reasoning', 'content': reasoning})}\n\n"
60
+
61
+ content = delta.get('content')
62
+ if content:
63
+ yield f"data: {json.dumps({'type': 'answer', 'content': content})}\n\n"
64
+ except:
65
+ continue
66
+
67
+ yield f"data: {json.dumps({'type': 'sources', 'content': sources})}\n\n"
68
+ yield "data: [DONE]\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ @app.post("/api/search")
71
+ async def search_api(request: ChatRequest):
72
+ return StreamingResponse(generate_response(request.query), media_type="text/event-stream")