同步香港 LiteLLM 镜像与多提供商路由
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""Render only credential-ready routes; credentials remain environment references."""
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def oauth_ready(path):
|
||||
try:
|
||||
record = json.loads(path.read_text())
|
||||
return isinstance(record, dict) and bool(record.get('access_token'))
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
|
||||
|
||||
def build_config(catalog, env, exists):
|
||||
routes = []
|
||||
fallbacks = []
|
||||
|
||||
def add(alias, model, key=None, **params):
|
||||
if key:
|
||||
params['api_key'] = 'os.environ/' + key
|
||||
routes.append({'model_name': alias, 'litellm_params': {'model': model, **params}})
|
||||
|
||||
for key, suffix in [('ZENMUX_SUBSCRIPTION_API_KEY', ''), ('ZENMUX_PAYG_API_KEY', '-payg')]:
|
||||
if env.get(key):
|
||||
for alias, model in catalog['zenmux'].items():
|
||||
# Strip only the LiteLLM provider prefix, retaining ZenMux's vendor prefix.
|
||||
add(alias + suffix, 'anthropic/' + model, key,
|
||||
api_base='https://zenmux.ai/api/anthropic')
|
||||
if env.get('ZENMUX_SUBSCRIPTION_API_KEY'):
|
||||
for alias, model in catalog.get('zenmux_chat', {}).items():
|
||||
add(alias, 'openai/' + model, 'ZENMUX_SUBSCRIPTION_API_KEY',
|
||||
api_base='https://zenmux.ai/api/v1')
|
||||
if env.get('OPENROUTER_API_KEY'):
|
||||
for alias, model in catalog['openrouter'].items():
|
||||
primary = catalog.get('zenmux_open_models', {}).get(alias)
|
||||
if primary and env.get('ZENMUX_SUBSCRIPTION_API_KEY'):
|
||||
if primary != model:
|
||||
raise ValueError('Cross-provider model mismatch: ' + alias)
|
||||
add(alias, 'openai/' + primary, 'ZENMUX_SUBSCRIPTION_API_KEY',
|
||||
api_base='https://zenmux.ai/api/v1', max_retries=0)
|
||||
routes[-1]['model_info'] = {'cooldown_time': 60,
|
||||
'allowed_fails_policy': {'RateLimitErrorAllowedFails': 0,
|
||||
'AuthenticationErrorAllowedFails': 0,
|
||||
'InternalServerErrorAllowedFails': 0,
|
||||
'ServiceUnavailableErrorAllowedFails': 0,
|
||||
'TimeoutErrorAllowedFails': 0}}
|
||||
add(alias + '-openrouter', 'openrouter/' + model, 'OPENROUTER_API_KEY')
|
||||
fallbacks.append({alias: [alias + '-openrouter']})
|
||||
else:
|
||||
add(alias, 'openrouter/' + model, 'OPENROUTER_API_KEY')
|
||||
elif env.get('ZENMUX_SUBSCRIPTION_API_KEY'):
|
||||
for alias, model in catalog.get('zenmux_open_models', {}).items():
|
||||
add(alias, 'openai/' + model, 'ZENMUX_SUBSCRIPTION_API_KEY',
|
||||
api_base='https://zenmux.ai/api/v1', max_retries=0)
|
||||
if env.get('GOOGLE_AI_STUDIO_API_KEY'):
|
||||
add('gemini-transcribe-personal', 'gemini/gemini-3.5-transcribe',
|
||||
'GOOGLE_AI_STUDIO_API_KEY', personal_vocabulary=True)
|
||||
for alias, model in catalog['google_ai_studio'].items():
|
||||
add(alias, 'gemini/' + model, 'GOOGLE_AI_STUDIO_API_KEY')
|
||||
if env.get('VERTEXAI_ENABLED', '').lower() == 'true' and env.get('VERTEXAI_PROJECT'):
|
||||
for alias, model in catalog.get('google_vertex', {}).items():
|
||||
add(alias, 'vertex_ai/' + model,
|
||||
vertex_project='os.environ/VERTEXAI_PROJECT',
|
||||
vertex_location='os.environ/VERTEXAI_LOCATION')
|
||||
for provider, token_var, default_dir in [
|
||||
('chatgpt', 'CHATGPT_TOKEN_DIR', '/tokens/chatgpt'),
|
||||
('xai', 'XAI_OAUTH_TOKEN_DIR', '/tokens/xai'),
|
||||
]:
|
||||
if exists(Path(env.get(token_var, default_dir)) / 'auth.json'):
|
||||
for alias, model in catalog[provider].items():
|
||||
extra = {'use_xai_oauth': True} if provider == 'xai' else {}
|
||||
add(alias, provider + '/' + model, **extra)
|
||||
return {
|
||||
'model_list': routes,
|
||||
'general_settings': {
|
||||
'master_key': 'os.environ/LITELLM_MASTER_KEY',
|
||||
'database_url': 'os.environ/DATABASE_URL',
|
||||
'store_model_in_db': False,
|
||||
'disable_env_credential_login': True,
|
||||
},
|
||||
'litellm_settings': {'drop_params': False, 'set_verbose': False},
|
||||
# Only explicitly approved open-model routes have cross-provider fallbacks.
|
||||
'router_settings': {'num_retries': 1, 'timeout': 180, 'fallbacks': fallbacks},
|
||||
}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
catalog = yaml.safe_load(Path('/etc/litellm/models.yaml').read_text())
|
||||
config = build_config(catalog, os.environ, oauth_ready)
|
||||
output = Path('/tmp/litellm.yaml')
|
||||
output.write_text(yaml.safe_dump(config, allow_unicode=True, sort_keys=False))
|
||||
output.chmod(0o600)
|
||||
print('Configured routes:', ', '.join(route['model_name'] for route in config['model_list']))
|
||||
Reference in New Issue
Block a user