"""Generic OpenAI-compatible provider (OpenAI, Together, etc.).""" from __future__ import annotations import logging import os import requests from .base import ModelInfo, ProviderResponse logger = logging.getLogger(__name__) # OpenAI-compat specific env vars OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "") OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1") OPENAI_MODEL = os.environ.get("OPENAI_MODEL", "gpt-4o-mini") MODELS = { "gpt-4o-mini": ModelInfo( id="gpt-4o-mini", vision=True, cost_per_input_token=0.00000015, cost_per_output_token=0.0000006, notes="Cheap, fast, decent vision", ), "gpt-4o": ModelInfo( id="gpt-4o", vision=True, cost_per_input_token=0.0000025, cost_per_output_token=0.00001, notes="Best OpenAI vision model", ), } class OpenAICompatProvider: name = "openai" models = MODELS def __init__(self): self.api_key = OPENAI_API_KEY self.base_url = OPENAI_BASE_URL self.model = OPENAI_MODEL self.endpoint = f"{self.base_url.rstrip('/')}/chat/completions" self.headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", } def call(self, image_b64: str, prompt: str) -> ProviderResponse: payload = { "model": self.model, "messages": [{ "role": "user", "content": [ {"type": "text", "text": prompt}, {"type": "image_url", "image_url": { "url": f"data:image/jpeg;base64,{image_b64}", }}, ], }], "max_tokens": 150, } resp = requests.post(self.endpoint, headers=self.headers, json=payload, timeout=30) resp.raise_for_status() data = resp.json() answer = data["choices"][0]["message"]["content"].strip() total_tokens = data.get("usage", {}).get("total_tokens", 0) return ProviderResponse(answer=answer, total_tokens=total_tokens)