mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-13 07:26:45 +00:00
feat(provider): add Baidu Qianfan and JDCloud support with base URL presets
This commit is contained in:
@@ -279,67 +279,17 @@ class LLMProviderManager(metaclass=Singleton):
|
||||
)
|
||||
|
||||
catalog_openai_providers = (
|
||||
("302ai", "302.AI", "https://api.302.ai/v1"),
|
||||
("abacus", "Abacus", "https://routellm.abacus.ai/v1"),
|
||||
("abliteration-ai", "abliteration.ai", "https://api.abliteration.ai/v1"),
|
||||
("baseten", "Baseten", "https://inference.baseten.co/v1"),
|
||||
("berget", "Berget.AI", "https://api.berget.ai/v1"),
|
||||
("chutes", "Chutes", "https://llm.chutes.ai/v1"),
|
||||
("clarifai", "Clarifai", "https://api.clarifai.com/v2/ext/openai/v1"),
|
||||
("cloudferro-sherlock", "CloudFerro Sherlock", "https://api-sherlock.cloudferro.com/openai/v1/"),
|
||||
("cloudflare-workers-ai", "Cloudflare Workers AI", "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1"),
|
||||
("cortecs", "Cortecs", "https://api.cortecs.ai/v1"),
|
||||
("digitalocean", "DigitalOcean", "https://inference.do-ai.run/v1"),
|
||||
("dinference", "DInference", "https://api.dinference.com/v1"),
|
||||
("drun", "D.Run (China)", "https://chat.d.run/v1"),
|
||||
("evroc", "evroc", "https://models.think.evroc.com/v1"),
|
||||
("fastrouter", "FastRouter", "https://go.fastrouter.ai/api/v1"),
|
||||
("fireworks-ai", "Fireworks AI", "https://api.fireworks.ai/inference/v1/"),
|
||||
("firmware", "Firmware", "https://app.frogbot.ai/api/v1"),
|
||||
("friendli", "Friendli", "https://api.friendli.ai/serverless/v1"),
|
||||
("helicone", "Helicone", "https://ai-gateway.helicone.ai/v1"),
|
||||
("hpc-ai", "HPC-AI", "https://api.hpc-ai.com/inference/v1"),
|
||||
("huggingface", "Hugging Face", "https://router.huggingface.co/v1"),
|
||||
("iflowcn", "iFlow", "https://apis.iflow.cn/v1"),
|
||||
("inception", "Inception", "https://api.inceptionlabs.ai/v1/"),
|
||||
("inference", "Inference", "https://inference.net/v1"),
|
||||
("io-net", "IO.NET", "https://api.intelligence.io.solutions/api/v1"),
|
||||
("jiekou", "Jiekou.AI", "https://api.jiekou.ai/openai"),
|
||||
("jiekou", "接口 AI", "https://api.jiekou.ai/openai"),
|
||||
("kilo", "Kilo Gateway", "https://api.kilo.ai/api/gateway"),
|
||||
("kuae-cloud-coding-plan", "KUAE Cloud Coding Plan", "https://coding-plan-endpoint.kuaecloud.net/v1"),
|
||||
("llama", "Llama", "https://api.llama.com/compat/v1/"),
|
||||
("llmgateway", "LLM Gateway", "https://api.llmgateway.io/v1"),
|
||||
("lucidquery", "LucidQuery AI", "https://lucidquery.com/api/v1"),
|
||||
("meganova", "Meganova", "https://api.meganova.ai/v1"),
|
||||
("mixlayer", "Mixlayer", "https://models.mixlayer.ai/v1"),
|
||||
("moark", "Moark", "https://moark.com/v1"),
|
||||
("modelscope", "ModelScope", "https://api-inference.modelscope.cn/v1"),
|
||||
("morph", "Morph", "https://api.morphllm.com/v1"),
|
||||
("nano-gpt", "NanoGPT", "https://nano-gpt.com/api/v1"),
|
||||
("nebius", "Nebius Token Factory", "https://api.tokenfactory.nebius.com/v1"),
|
||||
("neuralwatt", "Neuralwatt", "https://api.neuralwatt.com/v1"),
|
||||
("nova", "Nova", "https://api.nova.amazon.com/v1"),
|
||||
("novita-ai", "NovitaAI", "https://api.novita.ai/openai"),
|
||||
("ovhcloud", "OVHcloud AI Endpoints", "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1"),
|
||||
("perplexity-agent", "Perplexity Agent", "https://api.perplexity.ai/v1"),
|
||||
("fireworks-ai", "Fireworks AI", "https://api.fireworks.ai/inference/v1/"),
|
||||
("poe", "Poe", "https://api.poe.com/v1"),
|
||||
("privatemode-ai", "Privatemode AI", "http://localhost:8080/v1"),
|
||||
("qihang-ai", "QiHang", "https://api.qhaigc.net/v1"),
|
||||
("qiniu-ai", "Qiniu", "https://api.qnaigc.com/v1"),
|
||||
("regolo-ai", "Regolo AI", "https://api.regolo.ai/v1"),
|
||||
("requesty", "Requesty", "https://router.requesty.ai/v1"),
|
||||
("scaleway", "Scaleway", "https://api.scaleway.ai/v1"),
|
||||
("stackit", "STACKIT", "https://api.openai-compat.model-serving.eu01.onstackit.cloud/v1"),
|
||||
("stepfun", "StepFun", "https://api.stepfun.com/v1"),
|
||||
("submodel", "submodel", "https://llm.submodel.ai/v1"),
|
||||
("synthetic", "Synthetic", "https://api.synthetic.new/openai/v1"),
|
||||
("the-grid-ai", "The Grid AI", "https://api.thegrid.ai/v1"),
|
||||
("upstage", "Upstage", "https://api.upstage.ai/v1/solar"),
|
||||
("vivgrid", "Vivgrid", "https://api.vivgrid.com/v1"),
|
||||
("vultr", "Vultr", "https://api.vultrinference.com/v1"),
|
||||
("wafer.ai", "Wafer", "https://pass.wafer.ai/v1"),
|
||||
("wandb", "Weights & Biases", "https://api.inference.wandb.ai/v1"),
|
||||
("zenmux", "ZenMux", "https://zenmux.ai/api/v1"),
|
||||
("qihang-ai", "启航 AI", "https://api.qhaigc.net/v1"),
|
||||
("qiniu-ai", "七牛", "https://api.qnaigc.com/v1"),
|
||||
)
|
||||
catalog_openai_overrides = {
|
||||
"cloudflare-workers-ai": {
|
||||
@@ -353,6 +303,18 @@ class LLMProviderManager(metaclass=Singleton):
|
||||
}
|
||||
|
||||
providers = [
|
||||
ProviderSpec(
|
||||
id="openai",
|
||||
name="OpenAI 兼容",
|
||||
runtime="openai_compatible",
|
||||
default_base_url="",
|
||||
base_url_editable=True,
|
||||
requires_base_url=True,
|
||||
supports_api_key=True,
|
||||
api_key_hint="通用 OpenAI-compatible 兜底入口,需要手动填写 Base URL。",
|
||||
description="通用 OpenAI-compatible 模型服务。",
|
||||
sort_order=1,
|
||||
),
|
||||
ProviderSpec(
|
||||
id="chatgpt",
|
||||
name="ChatGPT",
|
||||
@@ -574,6 +536,46 @@ class LLMProviderManager(metaclass=Singleton):
|
||||
api_key_hint="填写 DashScope / Alibaba API Key,可在中国内地、国际站与 Coding Plan 端点间切换。",
|
||||
description="阿里云百炼兼容端点。",
|
||||
),
|
||||
ProviderSpec(
|
||||
id="baidu-qianfan-coding-plan",
|
||||
name="百度千帆",
|
||||
runtime="openai_compatible",
|
||||
default_base_url="https://qianfan.baidubce.com/v2",
|
||||
base_url_presets=(
|
||||
url_preset(
|
||||
label="通用 API",
|
||||
value="https://qianfan.baidubce.com/v2",
|
||||
),
|
||||
url_preset(
|
||||
label="Coding Plan",
|
||||
value="https://qianfan.baidubce.com/v2/coding",
|
||||
),
|
||||
),
|
||||
api_key_hint="填写百度千帆 API Key,可在通用 API 与 Coding Plan 端点间切换。通用 API 请使用 https://qianfan.baidubce.com/v2;Coding Plan 请切换到 https://qianfan.baidubce.com/v2/coding。",
|
||||
supports_model_refresh=False,
|
||||
description="百度千帆 OpenAI-compatible V2 端点,支持通用 API 与 Coding Plan 地址预设。",
|
||||
sort_order=72,
|
||||
),
|
||||
ProviderSpec(
|
||||
id="jdcloud",
|
||||
name="京东云",
|
||||
runtime="openai_compatible",
|
||||
default_base_url="https://modelservice.jdcloud.com/v1",
|
||||
base_url_presets=(
|
||||
url_preset(
|
||||
label="通用 API",
|
||||
value="https://modelservice.jdcloud.com/v1",
|
||||
),
|
||||
url_preset(
|
||||
label="Coding Plan",
|
||||
value="https://modelservice.jdcloud.com/coding/openai/v1",
|
||||
),
|
||||
),
|
||||
api_key_hint="填写京东云 JoyBuilder API Key。通用 API 请使用 https://modelservice.jdcloud.com/v1;Coding Plan 请切换到 https://modelservice.jdcloud.com/coding/openai/v1,不要把 /v1 当成 Coding Plan 地址。",
|
||||
supports_model_refresh=False,
|
||||
description="京东云 JoyBuilder OpenAI-compatible 端点,支持通用 API 与 Coding Plan 地址预设。",
|
||||
sort_order=74,
|
||||
),
|
||||
ProviderSpec(
|
||||
id="volcengine",
|
||||
name="火山方舟",
|
||||
@@ -718,14 +720,6 @@ class LLMProviderManager(metaclass=Singleton):
|
||||
api_key_hint="填写 Xiaomi API Key,可在标准端点与各区域 Token Plan 端点间切换。",
|
||||
description="小米 Mimo 兼容端点。",
|
||||
),
|
||||
catalog_openai_provider(
|
||||
provider_id="lmstudio",
|
||||
name="LM Studio",
|
||||
default_base_url="http://127.0.0.1:1234/v1",
|
||||
sort_order=135,
|
||||
api_key_hint="如未启用鉴权,可填写任意占位值。",
|
||||
description="LM Studio 本地 OpenAI-compatible 端点。",
|
||||
),
|
||||
]
|
||||
|
||||
for sort_order, (provider_id, name, base_url) in enumerate(
|
||||
@@ -743,21 +737,6 @@ class LLMProviderManager(metaclass=Singleton):
|
||||
description=overrides.get("description"),
|
||||
)
|
||||
)
|
||||
|
||||
providers.append(
|
||||
ProviderSpec(
|
||||
id="openai",
|
||||
name="OpenAI Compatible",
|
||||
runtime="openai_compatible",
|
||||
default_base_url="",
|
||||
base_url_editable=True,
|
||||
requires_base_url=True,
|
||||
supports_api_key=True,
|
||||
api_key_hint="通用 OpenAI-compatible 兜底入口,需要手动填写 Base URL。",
|
||||
description="通用 OpenAI-compatible 模型服务。",
|
||||
sort_order=1000,
|
||||
)
|
||||
)
|
||||
return tuple(providers)
|
||||
|
||||
def _cached_models_dev_payload(self) -> dict[str, Any]:
|
||||
|
||||
@@ -71,6 +71,10 @@ LLM_PROVIDER_DEFAULTS = {
|
||||
"model": "claude-sonnet-4-0",
|
||||
"base_url": "https://api.anthropic.com/v1",
|
||||
},
|
||||
"baidu-qianfan-coding-plan": {
|
||||
"model": "",
|
||||
"base_url": "https://qianfan.baidubce.com/v2",
|
||||
},
|
||||
"openrouter": {
|
||||
"model": "openai/gpt-4.1-mini",
|
||||
"base_url": "https://openrouter.ai/api/v1",
|
||||
@@ -79,14 +83,20 @@ LLM_PROVIDER_DEFAULTS = {
|
||||
"model": "llama-3.3-70b-versatile",
|
||||
"base_url": "https://api.groq.com/openai/v1",
|
||||
},
|
||||
"jdcloud": {
|
||||
"model": "",
|
||||
"base_url": "https://modelservice.jdcloud.com/v1",
|
||||
},
|
||||
}
|
||||
LLM_PROVIDER_FALLBACK_CHOICES = {
|
||||
"deepseek": "DeepSeek",
|
||||
"openai": "OpenAI Compatible",
|
||||
"google": "Google",
|
||||
"anthropic": "Anthropic",
|
||||
"baidu-qianfan-coding-plan": "百度千帆",
|
||||
"openrouter": "OpenRouter",
|
||||
"groq": "Groq",
|
||||
"jdcloud": "京东云",
|
||||
}
|
||||
RUNTIME_PACKAGE = {
|
||||
"name": "moviepilot-frontend-runtime",
|
||||
|
||||
@@ -210,6 +210,42 @@ class LlmProviderRegistryTest(unittest.TestCase):
|
||||
self.assertEqual([item["id"] for item in models], ["frog-1"])
|
||||
self.assertEqual(models[0]["source"], "models.dev")
|
||||
|
||||
def test_builtin_provider_includes_baidu_qianfan_base_url_presets(self):
|
||||
manager = LLMProviderManager()
|
||||
|
||||
provider = manager.get_provider("baidu-qianfan-coding-plan")
|
||||
|
||||
self.assertEqual(provider.name, "百度千帆")
|
||||
self.assertEqual(provider.runtime, "openai_compatible")
|
||||
self.assertEqual(provider.default_base_url, "https://qianfan.baidubce.com/v2")
|
||||
self.assertEqual(
|
||||
tuple((preset.label, preset.value) for preset in provider.base_url_presets),
|
||||
(
|
||||
("通用 API", "https://qianfan.baidubce.com/v2"),
|
||||
("Coding Plan", "https://qianfan.baidubce.com/v2/coding"),
|
||||
),
|
||||
)
|
||||
self.assertIsNone(provider.models_dev_provider_id)
|
||||
self.assertFalse(provider.supports_model_refresh)
|
||||
|
||||
def test_builtin_provider_includes_jdcloud_base_url_presets(self):
|
||||
manager = LLMProviderManager()
|
||||
|
||||
provider = manager.get_provider("jdcloud")
|
||||
|
||||
self.assertEqual(provider.name, "京东云")
|
||||
self.assertEqual(provider.runtime, "openai_compatible")
|
||||
self.assertEqual(provider.default_base_url, "https://modelservice.jdcloud.com/v1")
|
||||
self.assertEqual(
|
||||
tuple((preset.label, preset.value) for preset in provider.base_url_presets),
|
||||
(
|
||||
("通用 API", "https://modelservice.jdcloud.com/v1"),
|
||||
("Coding Plan", "https://modelservice.jdcloud.com/coding/openai/v1"),
|
||||
),
|
||||
)
|
||||
self.assertIsNone(provider.models_dev_provider_id)
|
||||
self.assertFalse(provider.supports_model_refresh)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -184,6 +184,27 @@ class LocalSetupLlmProviderPromptTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(provider, "my-provider_01")
|
||||
|
||||
def test_fallback_provider_choices_include_baidu_and_jdcloud(self):
|
||||
module = load_local_setup_module()
|
||||
|
||||
self.assertEqual(
|
||||
module.LLM_PROVIDER_FALLBACK_CHOICES["baidu-qianfan-coding-plan"],
|
||||
"百度千帆",
|
||||
)
|
||||
self.assertEqual(module.LLM_PROVIDER_FALLBACK_CHOICES["jdcloud"], "京东云")
|
||||
|
||||
def test_local_setup_defaults_include_baidu_and_jdcloud_base_urls(self):
|
||||
module = load_local_setup_module()
|
||||
|
||||
self.assertEqual(
|
||||
module.LLM_PROVIDER_DEFAULTS["baidu-qianfan-coding-plan"]["base_url"],
|
||||
"https://qianfan.baidubce.com/v2",
|
||||
)
|
||||
self.assertEqual(
|
||||
module.LLM_PROVIDER_DEFAULTS["jdcloud"]["base_url"],
|
||||
"https://modelservice.jdcloud.com/v1",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user