gingdev commited on
Commit
2ebff9f
1 Parent(s): cfc0cce
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
- DEFAULT_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
 
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 DEFAULT_USER_AGENT, DUCKDUCKGO_CHAT_ENDPOINT, DUCKDUCKGO_STATUS_ENDPOINT
8
- from typing import Annotated, List, Literal, cast
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
- 'x-vqd-4': session_id,
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
- content = cast(dict[str, str], event.json()).get('message')
85
- if content:
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('x-vqd-4')
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)