Files
data-ge/app/providers/deepseek.py
2025-10-30 22:38:05 +08:00

102 lines
3.2 KiB
Python

from __future__ import annotations
import logging
import os
from typing import Any, Dict, List
import httpx
from app.exceptions import ProviderAPICallError
from app.models import LLMChoice, LLMMessage, LLMProvider, LLMRequest, LLMResponse
from app.providers.base import LLMProviderClient
logger = logging.getLogger(__name__)
def _resolve_timeout_seconds() -> float:
raw = os.getenv("DEEPSEEK_TIMEOUT_SECONDS")
if raw is None:
return 60.0
try:
return float(raw)
except ValueError:
logger.warning(
"Invalid value for DEEPSEEK_TIMEOUT_SECONDS=%r, falling back to 60 seconds",
raw,
)
return 60.0
DEEPSEEK_TIMEOUT_SECONDS = _resolve_timeout_seconds()
class DeepSeekProvider(LLMProviderClient):
name = LLMProvider.DEEPSEEK.value
api_key_env = "DEEPSEEK_API_KEY"
supports_stream = True
base_url = "https://api.deepseek.com/v1/chat/completions"
async def chat(
self, request: LLMRequest, client: httpx.AsyncClient
) -> LLMResponse:
self.ensure_stream_supported(request.stream)
payload = self.merge_payload(
{
"model": request.model,
"messages": [msg.model_dump() for msg in request.messages],
"temperature": request.temperature,
"top_p": request.top_p,
"max_tokens": request.max_tokens,
"stream": request.stream,
},
request.extra_params,
)
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
}
timeout = httpx.Timeout(DEEPSEEK_TIMEOUT_SECONDS)
try:
response = await client.post(
self.base_url, json=payload, headers=headers, timeout=timeout
)
response.raise_for_status()
except httpx.HTTPStatusError as exc:
status_code = exc.response.status_code
body = exc.response.text
logger.error("DeepSeek upstream returned %s: %s", status_code, body, exc_info=True)
raise ProviderAPICallError(
f"DeepSeek request failed with status {status_code}",
status_code=status_code,
response_text=body,
) from exc
except httpx.HTTPError as exc:
logger.error("DeepSeek transport error: %s", exc, exc_info=True)
raise ProviderAPICallError(f"DeepSeek request failed: {exc}") from exc
data: Dict[str, Any] = response.json()
choices = self._build_choices(data.get("choices", []))
return LLMResponse(
provider=LLMProvider.DEEPSEEK,
model=data.get("model", request.model),
choices=choices,
raw=data,
)
@staticmethod
def _build_choices(choices: List[dict[str, Any]]) -> List[LLMChoice]:
built: List[LLMChoice] = []
for choice in choices:
message_data = choice.get("message") or {}
message = LLMMessage(
role=message_data.get("role", "assistant"),
content=message_data.get("content", ""),
)
built.append(LLMChoice(index=choice.get("index", len(built)), message=message))
return built