Текстовый файл из учебного комплекта, не свидетельство установленного 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"] = {}