|
|
import base64 |
|
|
import os |
|
|
from io import BytesIO |
|
|
from typing import Dict, List, Optional |
|
|
|
|
|
from openai import APIConnectionError, AuthenticationError, OpenAI, RateLimitError |
|
|
from PIL import Image |
|
|
|
|
|
|
|
|
|
|
|
API_KEY_ENV_VAR = "OPENAI_API_KEY" |
|
|
DEFAULT_TEXT_MODEL = "gpt-4o-mini" |
|
|
DEFAULT_VISION_MODEL = "gpt-4o" |
|
|
|
|
|
|
|
|
def _get_api_key(provided_key: Optional[str] = None) -> Optional[str]: |
|
|
""" |
|
|
Returns the provided key if valid, otherwise falls back to the environment variable. |
|
|
""" |
|
|
if provided_key and provided_key.strip(): |
|
|
return provided_key.strip() |
|
|
return os.getenv(API_KEY_ENV_VAR) |
|
|
|
|
|
|
|
|
def call_api(messages: List[Dict], model_name: Optional[str] = None, image: Optional[Image.Image] = None, api_key: Optional[str] = None, **kwargs): |
|
|
""" |
|
|
Calls the OpenAI API (GPT models). |
|
|
""" |
|
|
|
|
|
final_api_key = _get_api_key(api_key) |
|
|
|
|
|
if not final_api_key: |
|
|
return "Error: Authentication required. Please provide an OpenAI API Key." |
|
|
|
|
|
|
|
|
try: |
|
|
client = OpenAI(api_key=final_api_key) |
|
|
except Exception as e: |
|
|
return f"Error: Failed to initialize OpenAI client. {e}" |
|
|
|
|
|
|
|
|
final_messages = [] |
|
|
|
|
|
|
|
|
if image: |
|
|
print("Making a VISION call to OpenAI.") |
|
|
buffered = BytesIO() |
|
|
image.save(buffered, format="PNG") |
|
|
image_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8") |
|
|
|
|
|
|
|
|
user_text = "Analyze this image." |
|
|
for msg in messages: |
|
|
if msg["role"] == "user": |
|
|
user_text = msg["content"] |
|
|
break |
|
|
|
|
|
|
|
|
content = [{"type": "text", "text": user_text}, {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_base64}"}}] |
|
|
|
|
|
|
|
|
for msg in messages: |
|
|
if msg["role"] == "system": |
|
|
final_messages.append(msg) |
|
|
|
|
|
final_messages.append({"role": "user", "content": content}) |
|
|
final_model = model_name or DEFAULT_VISION_MODEL |
|
|
|
|
|
|
|
|
else: |
|
|
print("Making a TEXT call to OpenAI.") |
|
|
final_messages = messages |
|
|
final_model = model_name or DEFAULT_TEXT_MODEL |
|
|
|
|
|
|
|
|
try: |
|
|
print(f"Calling OpenAI API with model: {final_model}") |
|
|
completion = client.chat.completions.create(model=final_model, messages=final_messages, **kwargs) |
|
|
return completion.choices[0].message.content |
|
|
except AuthenticationError as e: |
|
|
raise ValueError(f"Authentication Failed: {e.body.get('message', str(e)) if e.body else str(e)}") |
|
|
except RateLimitError: |
|
|
raise RuntimeError("Rate Limit Exceeded (429). Please try again later.") |
|
|
except APIConnectionError: |
|
|
raise ConnectionError("Failed to connect to API. Check your internet.") |
|
|
except Exception as e: |
|
|
raise RuntimeError(f"API Error: {str(e)}") |
|
|
|