clean up
Browse files- app/internal/constants.py +1 -1
- app/routers/duckduckgo.py +9 -16
app/internal/constants.py
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
DUCKDUCKGO_CHAT_ENDPOINT = 'https://duckduckgo.com/duckchat/v1/chat'
|
2 |
DUCKDUCKGO_STATUS_ENDPOINT = 'https://duckduckgo.com/duckchat/v1/status'
|
3 |
-
|
|
|
1 |
DUCKDUCKGO_CHAT_ENDPOINT = 'https://duckduckgo.com/duckchat/v1/chat'
|
2 |
DUCKDUCKGO_STATUS_ENDPOINT = 'https://duckduckgo.com/duckchat/v1/status'
|
3 |
+
SESSION_KEY = 'x-vqd-4'
|
app/routers/duckduckgo.py
CHANGED
@@ -4,8 +4,8 @@ from fastapi import APIRouter, HTTPException, Header, Request, Response
|
|
4 |
from httpx_sse import EventSource
|
5 |
from sse_starlette.sse import EventSourceResponse
|
6 |
from starlette.background import BackgroundTask
|
7 |
-
from app.internal.constants import
|
8 |
-
from typing import Annotated, List, Literal
|
9 |
from pydantic import BaseModel
|
10 |
|
11 |
DONE = '[DONE]'
|
@@ -60,30 +60,23 @@ router = APIRouter()
|
|
60 |
})
|
61 |
async def chat(input: Chat, request: Request, response: Response, x_session_id: Annotated[str | None, Header()] = None):
|
62 |
http_client: httpx.AsyncClient = request.state.http_client
|
63 |
-
session_id = x_session_id or (await http_client.get(DUCKDUCKGO_STATUS_ENDPOINT, headers={
|
64 |
-
'x-vqd-accept': '1',
|
65 |
-
'user-agent': DEFAULT_USER_AGENT,
|
66 |
-
})).headers.get('x-vqd-4')
|
67 |
|
68 |
req = http_client.build_request('POST', DUCKDUCKGO_CHAT_ENDPOINT,
|
69 |
json=input.model_dump(exclude={'stream'}),
|
70 |
-
headers={
|
71 |
-
|
72 |
-
'user-agent': DEFAULT_USER_AGENT
|
73 |
-
})
|
74 |
-
resp = await http_client.send(req, stream=input.stream)
|
75 |
|
76 |
if resp.status_code != 200:
|
77 |
raise HTTPException(status_code=400)
|
78 |
|
79 |
-
async def agenerator():
|
80 |
async for event in EventSource(resp).aiter_sse():
|
81 |
if event.data == DONE:
|
82 |
return
|
83 |
|
84 |
-
|
85 |
-
|
86 |
-
yield content
|
87 |
|
88 |
async def event_generator():
|
89 |
async for chunk in agenerator():
|
@@ -97,7 +90,7 @@ async def chat(input: Chat, request: Request, response: Response, x_session_id:
|
|
97 |
|
98 |
yield DONE
|
99 |
|
100 |
-
response.headers['x-session-id'] = resp.headers.get(
|
101 |
|
102 |
if input.stream:
|
103 |
return EventSourceResponse(event_generator(), background=BackgroundTask(resp.aclose), headers=response.headers)
|
|
|
4 |
from httpx_sse import EventSource
|
5 |
from sse_starlette.sse import EventSourceResponse
|
6 |
from starlette.background import BackgroundTask
|
7 |
+
from app.internal.constants import DUCKDUCKGO_CHAT_ENDPOINT, DUCKDUCKGO_STATUS_ENDPOINT, SESSION_KEY
|
8 |
+
from typing import Annotated, AsyncIterator, List, Literal
|
9 |
from pydantic import BaseModel
|
10 |
|
11 |
DONE = '[DONE]'
|
|
|
60 |
})
|
61 |
async def chat(input: Chat, request: Request, response: Response, x_session_id: Annotated[str | None, Header()] = None):
|
62 |
http_client: httpx.AsyncClient = request.state.http_client
|
63 |
+
session_id = x_session_id or (await http_client.get(DUCKDUCKGO_STATUS_ENDPOINT, headers={'x-vqd-accept': '1'})).headers.get(SESSION_KEY)
|
|
|
|
|
|
|
64 |
|
65 |
req = http_client.build_request('POST', DUCKDUCKGO_CHAT_ENDPOINT,
|
66 |
json=input.model_dump(exclude={'stream'}),
|
67 |
+
headers={SESSION_KEY: session_id})
|
68 |
+
resp = await http_client.send(req, stream=True)
|
|
|
|
|
|
|
69 |
|
70 |
if resp.status_code != 200:
|
71 |
raise HTTPException(status_code=400)
|
72 |
|
73 |
+
async def agenerator() -> AsyncIterator[str]:
|
74 |
async for event in EventSource(resp).aiter_sse():
|
75 |
if event.data == DONE:
|
76 |
return
|
77 |
|
78 |
+
if 'message' in (decoded := event.json()):
|
79 |
+
yield decoded['message']
|
|
|
80 |
|
81 |
async def event_generator():
|
82 |
async for chunk in agenerator():
|
|
|
90 |
|
91 |
yield DONE
|
92 |
|
93 |
+
response.headers['x-session-id'] = resp.headers.get(SESSION_KEY)
|
94 |
|
95 |
if input.stream:
|
96 |
return EventSourceResponse(event_generator(), background=BackgroundTask(resp.aclose), headers=response.headers)
|