sources/webrtc-reviewed/src_llm/clients/ollama_chat.py

Текстовый файл из учебного комплекта, не свидетельство установленного runtime. Вернуться к учебнику · Исходный файл

   1 import json
   2 import logging
   3 import time
   4 from typing import Any
   5 
   6 logger = logging.getLogger(__name__)
   7 
   8 INVALID_JSON_RETRIES = 1
   9 INVALID_JSON_RETRY_DELAY_S = 0.25
  10 
  11 
  12 def chat(client, *, model: str, messages: list, tools: list, options: dict, think: bool) -> dict[str, Any]:
  13     payload = {
  14         "model": model,
  15         "messages": messages,
  16         "tools": tools or [],
  17         "options": options or {},
  18         "think": think,
  19         "stream": False,
  20     }
  21     response = _request_json(client, payload)
  22     message = response.get("message", {})
  23     _normalize_tool_calls(message)
  24     return {
  25         "message": message,
  26         "model": response.get("model", model),
  27         "provider": "ollama",
  28     }
  29 
  30 
  31 def _request_json(client, payload: dict[str, Any]) -> dict[str, Any]:
  32     last_error: json.JSONDecodeError | None = None
  33 
  34     for attempt in range(INVALID_JSON_RETRIES + 1):
  35         response = client._request_raw("POST", "/api/chat", json=payload)
  36         try:
  37             data = response.json()
  38         except json.JSONDecodeError as exc:
  39             last_error = exc
  40             preview = response.text[:300].replace("\n", "\\n")
  41             logger.warning(
  42                 "ollama returned invalid JSON attempt=%s content_length=%s preview=%r",
  43                 attempt + 1,
  44                 len(response.content),
  45                 preview,
  46             )
  47             if attempt < INVALID_JSON_RETRIES:
  48                 time.sleep(INVALID_JSON_RETRY_DELAY_S * (attempt + 1))
  49                 continue
  50             break
  51 
  52         if isinstance(data, dict):
  53             return data
  54         raise ValueError("Ollama response must be a JSON object")
  55 
  56     raise ValueError("Ollama returned invalid JSON response") from last_error
  57 
  58 
  59 def _normalize_tool_calls(message: dict) -> None:
  60     for call in message.get("tool_calls") or []:
  61         function = call.get("function") or {}
  62         args = function.get("arguments")
  63         if isinstance(args, str):
  64             try:
  65                 function["arguments"] = json.loads(args)
  66             except json.JSONDecodeError:
  67                 function["arguments"] = {}