ffai-cli 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ffai/providers.py ADDED
@@ -0,0 +1,122 @@
1
+ """Built-in OpenAI-compatible provider presets.
2
+
3
+ Endpoint and suggested-model values follow the providers' current API
4
+ documentation. Models remain editable because availability varies by account and
5
+ region.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+
12
+
13
+ @dataclass(frozen=True, slots=True)
14
+ class ProviderPreset:
15
+ id: str
16
+ name: str
17
+ base_url: str | None
18
+ default_model: str | None
19
+ docs_url: str | None = None
20
+ api_key_url: str | None = None
21
+ note: str | None = None
22
+ name_zh: str | None = None
23
+ note_zh: str | None = None
24
+
25
+
26
+ PROVIDERS: tuple[ProviderPreset, ...] = (
27
+ ProviderPreset(
28
+ id="openai",
29
+ name="OpenAI",
30
+ base_url="https://api.openai.com/v1",
31
+ default_model="gpt-5.4-mini",
32
+ docs_url="https://developers.openai.com/api/docs/models/gpt-5.4-mini",
33
+ api_key_url="https://platform.openai.com/api-keys",
34
+ ),
35
+ ProviderPreset(
36
+ id="openrouter",
37
+ name="OpenRouter",
38
+ base_url="https://openrouter.ai/api/v1",
39
+ default_model="openai/gpt-5.4-mini",
40
+ docs_url="https://openrouter.ai/docs/quickstart",
41
+ api_key_url="https://openrouter.ai/keys",
42
+ note="Model IDs are vendor-prefixed, for example openai/gpt-5.4-mini.",
43
+ note_zh="模型 ID 带供应商前缀,例如 openai/gpt-5.4-mini。",
44
+ ),
45
+ ProviderPreset(
46
+ id="deepseek",
47
+ name="DeepSeek",
48
+ base_url="https://api.deepseek.com",
49
+ default_model="deepseek-flash",
50
+ docs_url="https://api-docs.deepseek.com/",
51
+ api_key_url="https://platform.deepseek.com/api_keys",
52
+ ),
53
+ ProviderPreset(
54
+ id="glm",
55
+ name="GLM (Zhipu)",
56
+ base_url="https://open.bigmodel.cn/api/paas/v4",
57
+ default_model="glm-5.3",
58
+ docs_url="https://docs.bigmodel.cn/cn/guide/models/text/glm-5.3",
59
+ api_key_url="https://bigmodel.cn/usercenter/proj-mgmt/apikeys",
60
+ note="Uses Zhipu's OpenAI Chat Completions-compatible endpoint.",
61
+ note_zh="使用智谱的 OpenAI Chat Completions 兼容端点。",
62
+ ),
63
+ ProviderPreset(
64
+ id="kimi",
65
+ name="Kimi (Moonshot)",
66
+ base_url="https://api.moonshot.cn/v1",
67
+ default_model="kimi-k3.1-pro",
68
+ docs_url="https://platform.kimi.com/docs/get-api-key",
69
+ api_key_url="https://platform.kimi.com/console/api-keys",
70
+ ),
71
+ ProviderPreset(
72
+ id="qwen",
73
+ name="Qwen (DashScope)",
74
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
75
+ default_model="qwen3.8-flash",
76
+ docs_url="https://www.alibabacloud.com/help/zh/model-studio/base-url",
77
+ api_key_url="https://modelstudio.console.alibabacloud.com/",
78
+ note=(
79
+ "China-region endpoint. Use your region's compatible-mode URL and a "
80
+ "matching regional API key."
81
+ ),
82
+ note_zh="此为中国区端点。其他区域请使用对应区域的 compatible-mode URL 和 API Key。",
83
+ ),
84
+ )
85
+
86
+ CUSTOM_PROVIDER = ProviderPreset(
87
+ id="custom",
88
+ name="Custom (OpenAI-compatible)",
89
+ base_url=None,
90
+ default_model=None,
91
+ note="Any OpenAI-compatible endpoint that accepts a bearer API key.",
92
+ name_zh="自定义(OpenAI 兼容)",
93
+ note_zh="支持任何接受 Bearer API Key 的 OpenAI 兼容端点。",
94
+ )
95
+
96
+ PROVIDER_CHOICES: tuple[ProviderPreset, ...] = (*PROVIDERS, CUSTOM_PROVIDER)
97
+
98
+ _BY_ID = {provider.id: provider for provider in PROVIDER_CHOICES}
99
+
100
+
101
+ def get_provider(provider_id: str) -> ProviderPreset:
102
+ try:
103
+ return _BY_ID[provider_id]
104
+ except KeyError as exc:
105
+ raise KeyError(f"Unknown provider preset: {provider_id}") from exc
106
+
107
+
108
+ def identify_provider(base_url: str | None) -> ProviderPreset | None:
109
+ """Return the preset matching *base_url*, or ``None`` for a custom endpoint."""
110
+
111
+ if base_url is None:
112
+ return get_provider("openai")
113
+ normalized = base_url.rstrip("/")
114
+ for provider in PROVIDERS:
115
+ if provider.base_url and provider.base_url.rstrip("/") == normalized:
116
+ return provider
117
+ return None
118
+
119
+
120
+ def provider_name_for(base_url: str | None) -> str:
121
+ provider = identify_provider(base_url)
122
+ return provider.name if provider is not None else CUSTOM_PROVIDER.name