Files

202 lines
6.8 KiB
Python

"""
API routes for fetching model lists from various providers.
"""
import json
import aiohttp
from aiohttp import web
try:
from server import PromptServer
HAS_SERVER = True
except ImportError:
HAS_SERVER = False
# Predefined model lists for each provider
PREDEFINED_MODELS = {
"openai": [
"gpt-4o",
"gpt-4o-mini",
"gpt-4-turbo",
"gpt-4",
"gpt-3.5-turbo",
"o1-preview",
"o1-mini",
],
"claude": [
"claude-sonnet-4-20250514",
"claude-3-5-sonnet-20241022",
"claude-3-5-haiku-20241022",
"claude-3-opus-20240229",
"claude-3-sonnet-20240229",
"claude-3-haiku-20240307",
],
"gemini": [
"gemini-2.5-flash-preview-05-20",
"gemini-2.0-flash",
"gemini-2.0-flash-exp",
"gemini-1.5-pro",
"gemini-1.5-flash",
"gemini-2.5-flash-image",
"gemini-3-pro-image-preview",
],
}
async def fetch_openai_models(api_key: str, base_url: str) -> list[str]:
"""Fetch model list from OpenAI-compatible API."""
url = f"{base_url.rstrip('/')}/models"
headers = {"Authorization": f"Bearer {api_key}"}
try:
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, timeout=10) as resp:
if resp.status == 200:
data = await resp.json()
models = [m["id"] for m in data.get("data", [])]
# Return all models, sorted alphabetically
return sorted(models) if models else PREDEFINED_MODELS["openai"]
except Exception as e:
print(f"[SimpleChat] Failed to fetch OpenAI models: {e}")
return PREDEFINED_MODELS["openai"]
async def fetch_claude_models(api_key: str, base_url: str) -> list[str]:
"""
Fetch models for Claude provider.
Tries to hit the /models endpoint (supported by some proxies and newer Anthropic API).
Falls back to predefined list if fails.
"""
# Anthropic API format for models list is /v1/models
# Note: Official Anthropic API recently added models endpoint support
url = f"{base_url.rstrip('/')}/models"
headers = {
"x-api-key": api_key,
"anthropic-version": "2023-06-01"
}
try:
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, timeout=10) as resp:
if resp.status == 200:
data = await resp.json()
# Anthropic format: {"data": [{"id": "...", ...}]} similar to OpenAI
# Some proxies might return OpenAI format
models = []
# Handle both standard formats just in case
items = data.get("data", []) if "data" in data else data.get("models", [])
if isinstance(items, list):
for m in items:
if isinstance(m, dict):
models.append(m.get("id", m.get("name", "")))
elif isinstance(m, str):
models.append(m)
# Filter out empty strings
models = [m for m in models if m]
if models:
return sorted(models)
except Exception as e:
# Silently fail for Claude since it's common for this endpoint to not exist/fail
pass
return PREDEFINED_MODELS["claude"]
async def fetch_gemini_models(api_key: str, base_url: str) -> list[str]:
"""Fetch model list from Gemini API."""
url = f"{base_url.rstrip('/')}/models?key={api_key}"
try:
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=10) as resp:
if resp.status == 200:
data = await resp.json()
models = []
for m in data.get("models", []):
name = m.get("name", "")
# Extract model name from full path (models/gemini-xxx)
if name.startswith("models/"):
name = name[7:]
if name:
models.append(name)
# Return all models
return sorted(models) if models else PREDEFINED_MODELS["gemini"]
except Exception as e:
print(f"[SimpleChat] Failed to fetch Gemini models: {e}")
return PREDEFINED_MODELS["gemini"]
def get_all_predefined_models_list() -> list[str]:
"""Get a flat list of all predefined models."""
all_models = []
for provider_models in PREDEFINED_MODELS.values():
all_models.extend(provider_models)
return all_models
def setup_routes():
"""Setup API routes for SimpleChat."""
if not HAS_SERVER:
return
@PromptServer.instance.routes.get("/simplechat/models/{provider}")
async def get_models(request):
"""
Get available models for a provider.
Query params:
- api_key: API key for the provider
- base_url: (optional) Custom base URL
"""
provider = request.match_info.get("provider", "").lower()
api_key = request.query.get("api_key", "")
base_url = request.query.get("base_url", "")
# Return predefined models if no API key provided
if not api_key:
models = PREDEFINED_MODELS.get(provider, [])
return web.json_response(models)
# Default base URLs
default_urls = {
"openai": "https://api.openai.com/v1",
"claude": "https://api.anthropic.com/v1",
"gemini": "https://generativelanguage.googleapis.com/v1beta",
}
if not base_url:
base_url = default_urls.get(provider, "")
# Fetch models based on provider
if provider == "openai":
models = await fetch_openai_models(api_key, base_url)
elif provider == "claude":
models = await fetch_claude_models(api_key, base_url)
elif provider == "gemini":
models = await fetch_gemini_models(api_key, base_url)
else:
models = []
return web.json_response(models)
@PromptServer.instance.routes.get("/simplechat/models")
async def get_all_models_list(request):
"""
Get all predefined models as a flat list (for COMBO remote input).
Returns a simple array of model names.
"""
return web.json_response(get_all_predefined_models_list())
@PromptServer.instance.routes.get("/simplechat/models_dict")
async def get_all_predefined_models(request):
"""Get all predefined models organized by provider."""
return web.json_response(PREDEFINED_MODELS)
print("[SimpleChat] API routes registered")