diff --git a/api/apps/services/models_api_service.py b/api/apps/services/models_api_service.py
index 5ebcfdb485..5b16e7dd99 100644
--- a/api/apps/services/models_api_service.py
+++ b/api/apps/services/models_api_service.py
@@ -130,13 +130,7 @@ def _get_model_info(tenant_id: str, default_model: str, model_type: str):
logging.warning(f"Model '{model_name}' is disabled")
return None
- return {
- "model_provider": provider_name,
- "model_instance": instance_name,
- "model_name": model_name,
- "model_type": model_type,
- "enable": True
- }
+ return {"model_provider": provider_name, "model_instance": instance_name, "model_name": model_name, "model_type": model_type, "enable": True}
def _check_model_available(tenant_id: str, provider_name: str, instance_name: str, model_name: str, model_type: str):
@@ -292,14 +286,23 @@ def list_tenant_added_models(tenant_id: str, model_type_filter: str = None):
target_type_records = [record for record in model_records if record.model_type & model_type_filter_bin] if model_type_filter_bin else model_records
factory_rank_mapping = {factory["name"]: -_to_int(factory.get("rank", "500")) for factory in FACTORY_LLM_INFOS}
- added_models = [{
- "model_type": get_model_type_human(model_record.model_type),
- "name": model_record.model_name,
- "provider_id": model_record.provider_id,
- "provider_name": provider_info_map[model_record.provider_id].provider_name,
- "instance_id": model_record.instance_id,
- "instance_name": instance_info_map[model_record.instance_id].instance_name
- } for model_record in target_type_records]
+ model_rank_map: dict = {}
+ for factory in FACTORY_LLM_INFOS:
+ for llm in factory.get("llm", []):
+ model_rank_map[(factory["name"], llm["llm_name"])] = _to_int(llm.get("rank", 500))
+
+ added_models = [
+ {
+ "model_type": get_model_type_human(model_record.model_type),
+ "name": model_record.model_name,
+ "provider_id": model_record.provider_id,
+ "provider_name": provider_info_map[model_record.provider_id].provider_name,
+ "instance_id": model_record.instance_id,
+ "instance_name": instance_info_map[model_record.instance_id].instance_name,
+ "rank": model_rank_map.get((provider_info_map[model_record.provider_id].provider_name, model_record.model_name), 500),
+ }
+ for model_record in target_type_records
+ ]
# Add TEI Builtin embedding model if configured
compose_profiles = os.getenv("COMPOSE_PROFILES", "")
@@ -316,10 +319,10 @@ def list_tenant_added_models(tenant_id: str, model_type_filter: str = None):
"provider_name": "Builtin",
"instance_id": "",
"instance_name": "default",
+ "rank": model_rank_map.get(("Builtin", tei_model), 500),
}
)
- added_models.sort(
- key=lambda x: (factory_rank_mapping.get(x["provider_name"]), x["provider_name"], x["instance_name"]))
+ added_models.sort(key=lambda x: (factory_rank_mapping.get(x["provider_name"]), x["provider_name"], x["instance_name"], -x["rank"], x["name"]))
return True, added_models
diff --git a/api/apps/services/provider_api_service.py b/api/apps/services/provider_api_service.py
index e508ca2d0c..9f3f075895 100644
--- a/api/apps/services/provider_api_service.py
+++ b/api/apps/services/provider_api_service.py
@@ -20,7 +20,7 @@ import asyncio
from common.constants import LLMType, ActiveStatusEnum, ModelVerifyStatusEnum
from common.settings import FACTORY_LLM_INFOS
-from api.db.joint_services.tenant_model_service import get_model_config_from_provider_instance, delete_models_by_instance_ids, delete_instances_by_provider_ids, _decode_api_key_config
+from api.db.joint_services.tenant_model_service import get_model_config_from_provider_instance, delete_models_by_instance_ids, delete_instances_by_provider_ids
from api.db.services.tenant_model_provider_service import TenantModelProviderService
from api.db.services.tenant_model_instance_service import TenantModelInstanceService
from api.db.services.tenant_model_service import TenantModelService
@@ -214,7 +214,7 @@ async def list_provider_models(provider_id_or_name: str, api_key: str = None, ba
remote_models = await ModelMeta[provider_name](api_key, model_base_url).get_model_list()
if not static_llms and not remote_models:
- return False, f"No models found for provider '{provider_id_or_name}'"
+ return True, []
# Merge static and remote models, preferring remote_models on name conflicts
merged = {m["name"]: m for m in static_llms}
@@ -257,7 +257,9 @@ def show_provider_model(provider_id_or_name: str, model_name: str):
}
-async def update_provider_instance(tenant_id: str, provider_id_or_name: str, instance_id_or_name: str, instance_name: str, api_key: str|dict, base_url: str, region: str, model_info: list[dict]=None, verify: bool=True):
+async def update_provider_instance(
+ tenant_id: str, provider_id_or_name: str, instance_id_or_name: str, instance_name: str, api_key: str | dict, base_url: str, region: str, model_info: list[dict] = None, verify: bool = True
+):
"""
Update a provider instance.
@@ -420,12 +422,9 @@ async def update_provider_instance(tenant_id: str, provider_id_or_name: str, ins
if verify:
verify_status = model_verify_result.get(llm_name, ModelVerifyStatusEnum.UNKNOWN.value)
extra_fields["verify"] = verify_status
- success, _msg = add_model_to_instance(tenant_id, provider_name, effective_instance_name, **{
- "model_type": _factory_model_types(llm),
- "model_name": llm_name,
- "max_tokens": llm["max_tokens"],
- "extra": extra_fields
- })
+ success, _msg = add_model_to_instance(
+ tenant_id, provider_name, effective_instance_name, **{"model_type": _factory_model_types(llm), "model_name": llm_name, "max_tokens": llm["max_tokens"], "extra": extra_fields}
+ )
if not success:
msg += _msg
@@ -511,16 +510,21 @@ async def create_provider_instance(tenant_id: str, provider_id_or_name: str, ins
factory_llms = factory_info[0]["llm"]
for llm in factory_llms:
llm_name = _factory_llm_name(llm)
- success, _msg = add_model_to_instance(tenant_id, provider_name, instance_name, **{
- "model_type": _factory_model_types(llm),
- "model_name": llm_name,
- "max_tokens": llm["max_tokens"],
- "extra": {
- "is_tools": llm.get("is_tools", False),
- "thinking": "thinking" in llm.get("features", []),
- "verify": model_verify_result.get(llm_name, ModelVerifyStatusEnum.UNKNOWN.value)
- }
- })
+ success, _msg = add_model_to_instance(
+ tenant_id,
+ provider_name,
+ instance_name,
+ **{
+ "model_type": _factory_model_types(llm),
+ "model_name": llm_name,
+ "max_tokens": llm["max_tokens"],
+ "extra": {
+ "is_tools": llm.get("is_tools", False),
+ "thinking": "thinking" in llm.get("features", []),
+ "verify": model_verify_result.get(llm_name, ModelVerifyStatusEnum.UNKNOWN.value),
+ },
+ },
+ )
if not success:
msg += _msg
if msg:
@@ -552,12 +556,7 @@ async def create_name_only_provider_instance(tenant_id: str, provider_name: str,
if not provider_obj:
return False, f"Provider '{provider_name}' does not exist"
- TenantModelInstanceService.create_instance(
- provider_id=provider_obj.id,
- instance_name=instance_name,
- api_key="",
- extra=json.dumps({})
- )
+ TenantModelInstanceService.create_instance(provider_id=provider_obj.id, instance_name=instance_name, api_key="", extra=json.dumps({}))
return True, "success"
@@ -634,10 +633,15 @@ async def verify_api_key(provider_id_or_name: str, api_key: str | dict, base_url
return False, f"Provider '{provider_id_or_name}' not found", {}
if model_info:
- factory_llms = [{
- "model_type": _type,
- "llm_name": model.get("model_name", ""),
- } for model in model_info if model for _type in model.get("model_type", [])]
+ factory_llms = [
+ {
+ "model_type": _type,
+ "llm_name": model.get("model_name", ""),
+ }
+ for model in model_info
+ if model
+ for _type in model.get("model_type", [])
+ ]
if not factory_llms:
return False, f"No valid models found for provider '{provider_id_or_name}'", {}
else:
@@ -820,7 +824,7 @@ def show_provider_instance(tenant_id: str, provider_id_or_name: str, instance_id
"region": extra_fields.get("region", ""),
"base_url": extra_fields.get("base_url", ""),
"api_key": instance_obj.api_key,
- "status": instance_obj.status
+ "status": instance_obj.status,
}
@@ -888,10 +892,17 @@ def list_instance_models(tenant_id: str, provider_id_or_name: str, instance_id_o
if not factory_info:
return False, f"Provider '{provider_id_or_name}' not found"
llms = factory_info[0].get("llm", [])
- models = [{"name": llm["llm_name"]} for llm in llms]
- models.sort(key=lambda x: x["name"])
+ models = [{"name": llm["llm_name"], "rank": _to_int(llm.get("rank", 500))} for llm in llms]
+ models.sort(key=lambda x: (-x["rank"], x["name"]))
return True, models
+ # Build rank mapping from LLM dictionary for the provider
+ factory_info = [f for f in FACTORY_LLM_INFOS if f["name"] == provider_obj.provider_name]
+ model_rank_map = {}
+ if factory_info:
+ for llm in factory_info[0].get("llm", []):
+ model_rank_map[llm["llm_name"]] = _to_int(llm.get("rank", 500))
+
# Get instance
instance_obj = None
if instance_id_or_name:
@@ -907,14 +918,18 @@ def list_instance_models(tenant_id: str, provider_id_or_name: str, instance_id_o
model_list = []
for model in model_objs:
model_extra = json.loads(model.extra)
- model_list.append({
- "name": model.model_name,
- "model_type": get_model_type_human(model.model_type),
- "max_tokens": model_extra.get("max_tokens", 8192) if model.extra else 8192,
- "status": model.status,
- "verify": model_extra.get("verify", ModelVerifyStatusEnum.UNKNOWN.value),
- "features": (["is_tools"] if model_extra.get("is_tools") else []) + (["thinking"] if model_extra.get("thinking") else [])
- })
+ model_list.append(
+ {
+ "name": model.model_name,
+ "model_type": get_model_type_human(model.model_type),
+ "max_tokens": model_extra.get("max_tokens", 8192) if model.extra else 8192,
+ "status": model.status,
+ "verify": model_extra.get("verify", ModelVerifyStatusEnum.UNKNOWN.value),
+ "features": (["is_tools"] if model_extra.get("is_tools") else []) + (["thinking"] if model_extra.get("thinking") else []),
+ "rank": model_rank_map.get(model.model_name, 500),
+ }
+ )
+ model_list.sort(key=lambda x: (-x["rank"], x["name"]))
return True, model_list
@@ -984,13 +999,7 @@ def add_model_to_instance(tenant_id: str, provider_id_or_name: str, instance_id_
extra_fields.update({"thinking": "thinking" in target_model[0].get("features", [])})
if extra:
extra_fields.update(extra)
- TenantModelService.insert(
- model_name=model_name,
- provider_id=provider_obj.id,
- instance_id=instance_obj.id,
- model_type=model_type_bin,
- extra=json.dumps(extra_fields)
- )
+ TenantModelService.insert(model_name=model_name, provider_id=provider_obj.id, instance_id=instance_obj.id, model_type=model_type_bin, extra=json.dumps(extra_fields))
return True, "success"
diff --git a/api/db/services/document_service.py b/api/db/services/document_service.py
index b9642dffa0..06f32c5b11 100644
--- a/api/db/services/document_service.py
+++ b/api/db/services/document_service.py
@@ -1210,12 +1210,7 @@ def get_pending_task_count(priority=None):
query = (
Task.select(fn.COUNT(Task.id))
.join(Document, on=(Task.doc_id == Document.id))
- .where(
- (Task.progress == 0)
- & ((Document.run.is_null(True)) | (Document.run != TaskStatus.CANCEL.value))
- & (Document.progress >= 0)
- & (Document.status == StatusEnum.VALID.value)
- )
+ .where((Task.progress == 0) & ((Document.run.is_null(True)) | (Document.run != TaskStatus.CANCEL.value)) & (Document.progress >= 0) & (Document.status == StatusEnum.VALID.value))
)
if priority is not None:
query = query.where(Task.priority == priority)
diff --git a/api/db/services/memory_service.py b/api/db/services/memory_service.py
index 5dab6361df..933ea613c2 100644
--- a/api/db/services/memory_service.py
+++ b/api/db/services/memory_service.py
@@ -109,8 +109,7 @@ class MemoryService(CommonService):
@classmethod
@DB.connection_context()
- def create_memory(cls, tenant_id: str, name: str, memory_type: List[str], embd_id: str, llm_id: str,
- tenant_embd_id: str | None = None, tenant_llm_id: str | None = None):
+ def create_memory(cls, tenant_id: str, name: str, memory_type: List[str], embd_id: str, llm_id: str, tenant_embd_id: str | None = None, tenant_llm_id: str | None = None):
# Deduplicate name within tenant
memory_name = duplicate_name(cls.query, name=name, tenant_id=tenant_id)
if len(memory_name) > MEMORY_NAME_LIMIT:
diff --git a/conf/models/aliyun.json b/conf/models/aliyun.json
index 66a569bfa7..aac841b531 100644
--- a/conf/models/aliyun.json
+++ b/conf/models/aliyun.json
@@ -1,5 +1,5 @@
{
- "name": "Aliyun",
+ "name": "Tongyi-Qianwen",
"rank": 983,
"url": {
"default": "https://dashscope.aliyuncs.com",
@@ -50,4 +50,4 @@
]
}
}
-}
\ No newline at end of file
+}
diff --git a/conf/models/avian.json b/conf/models/avian.json
index 40c0d4f524..b926350b1e 100644
--- a/conf/models/avian.json
+++ b/conf/models/avian.json
@@ -1,5 +1,5 @@
{
- "name": "avian",
+ "name": "Avian",
"url": {
"default": "https://api.avian.io"
},
diff --git a/conf/models/baichuan.json b/conf/models/baichuan.json
index c7bc5f1c0d..9a41310afa 100644
--- a/conf/models/baichuan.json
+++ b/conf/models/baichuan.json
@@ -1,5 +1,5 @@
{
- "name": "Baichuan",
+ "name": "BaiChuan",
"url": {
"default": "https://api.baichuan-ai.com/v1"
},
@@ -87,4 +87,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/conf/models/baidu.json b/conf/models/baidu.json
index b165465269..21985aa3cd 100644
--- a/conf/models/baidu.json
+++ b/conf/models/baidu.json
@@ -1,5 +1,5 @@
{
- "name": "Baidu",
+ "name": "BaiduYiyan",
"url": {
"default": "https://qianfan.baidubce.com/v2"
},
@@ -44,7 +44,7 @@
{
"name": "qwen3-32b",
"max_tokens": 30720,
- "model_types":[
+ "model_types": [
"chat"
]
},
@@ -84,4 +84,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/conf/models/cohere.json b/conf/models/cohere.json
index 98a2c1d576..a985534485 100644
--- a/conf/models/cohere.json
+++ b/conf/models/cohere.json
@@ -1,5 +1,5 @@
{
- "name": "CoHere",
+ "name": "Cohere",
"rank": 990,
"url": {
"default": "https://api.cohere.com"
diff --git a/conf/models/fishaudio.json b/conf/models/fishaudio.json
index aa6beda964..836cd215d2 100644
--- a/conf/models/fishaudio.json
+++ b/conf/models/fishaudio.json
@@ -1,5 +1,5 @@
{
- "name": "FishAudio",
+ "name": "Fish Audio",
"url": {
"default": "https://api.fish.audio"
},
@@ -33,4 +33,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/conf/models/gitee.json b/conf/models/gitee.json
index 629a7e2892..6ab71759f1 100644
--- a/conf/models/gitee.json
+++ b/conf/models/gitee.json
@@ -1,5 +1,5 @@
{
- "name": "Gitee",
+ "name": "GiteeAI",
"url": {
"default": "https://api.moark.ai/v1",
"china": "https://api.moark.com/v1",
diff --git a/conf/models/google.json b/conf/models/google.json
index 96bbb22c4f..d821be59f1 100644
--- a/conf/models/google.json
+++ b/conf/models/google.json
@@ -1,5 +1,5 @@
{
- "name": "Google",
+ "name": "Gemini",
"rank": 997,
"url": {
"default": "https://generativelanguage.googleapis.com"
@@ -42,4 +42,4 @@
]
}
}
-}
\ No newline at end of file
+}
diff --git a/conf/models/hunyuan.json b/conf/models/hunyuan.json
index 5ec80244c1..04fd0602d1 100644
--- a/conf/models/hunyuan.json
+++ b/conf/models/hunyuan.json
@@ -1,5 +1,5 @@
{
- "name": "HunYuan",
+ "name": "Tencent Hunyuan",
"url": {
"default": "https://api.hunyuan.cloud.tencent.com/v1"
},
diff --git a/conf/models/jiekouai.json b/conf/models/jiekouai.json
index 4591c4e5a9..c5f46cae10 100644
--- a/conf/models/jiekouai.json
+++ b/conf/models/jiekouai.json
@@ -1,5 +1,5 @@
{
- "name": "JieKouAI",
+ "name": "Jiekou.AI",
"url": {
"default": "https://api.jiekou.ai"
},
@@ -103,4 +103,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/conf/models/lmstudio.json b/conf/models/lmstudio.json
index a5293ffb9d..4c0f4b989e 100644
--- a/conf/models/lmstudio.json
+++ b/conf/models/lmstudio.json
@@ -1,9 +1,9 @@
{
- "name": "lmstudio",
+ "name": "LM-Studio",
"url_suffix": {
"chat": "chat/completions",
"models": "models",
"embedding": "embeddings"
},
"class": "local"
-}
\ No newline at end of file
+}
diff --git a/conf/models/localai.json b/conf/models/localai.json
index 9222a95218..301e3b5f30 100644
--- a/conf/models/localai.json
+++ b/conf/models/localai.json
@@ -1,5 +1,5 @@
{
- "name": "localai",
+ "name": "LocalAI",
"url_suffix": {
"chat": "chat/completions",
"models": "models",
diff --git a/conf/models/modelscope.json b/conf/models/modelscope.json
index 02a9ebe0f8..691789ddd0 100644
--- a/conf/models/modelscope.json
+++ b/conf/models/modelscope.json
@@ -1,5 +1,5 @@
{
- "name": "modelscope",
+ "name": "ModelScope",
"url_suffix": {
"chat": "v1/chat/completions",
"models": "v1/models"
diff --git a/conf/models/novita.json b/conf/models/novita.json
index dfc11e0382..2f2612d05d 100644
--- a/conf/models/novita.json
+++ b/conf/models/novita.json
@@ -1,5 +1,5 @@
{
- "name": "Novita",
+ "name": "NovitaAI",
"url": {
"default": "https://api.novita.ai"
},
diff --git a/conf/models/nvidia.json b/conf/models/nvidia.json
index b711b76145..608db40a35 100644
--- a/conf/models/nvidia.json
+++ b/conf/models/nvidia.json
@@ -1,5 +1,5 @@
{
- "name": "Nvidia",
+ "name": "NVIDIA",
"url": {
"default": "https://integrate.api.nvidia.com/v1"
},
@@ -370,4 +370,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/conf/models/ollama.json b/conf/models/ollama.json
index 3a470d2a45..cab76fe2c4 100644
--- a/conf/models/ollama.json
+++ b/conf/models/ollama.json
@@ -1,5 +1,5 @@
{
- "name": "ollama",
+ "name": "Ollama",
"rank": 978,
"url_suffix": {
"chat": "api/chat",
@@ -7,4 +7,4 @@
"embedding": "api/embed"
},
"class": "local"
-}
\ No newline at end of file
+}
diff --git a/conf/models/siliconflow.json b/conf/models/siliconflow.json
index d7b8e18f3d..f1d6b523b0 100644
--- a/conf/models/siliconflow.json
+++ b/conf/models/siliconflow.json
@@ -1,5 +1,5 @@
{
- "name": "SiliconFlow",
+ "name": "SILICONFLOW",
"rank": 980,
"url": {
"default": "https://api.siliconflow.cn/v1"
diff --git a/conf/models/vllm.json b/conf/models/vllm.json
index 2a8d8157f0..5ab96a4cd1 100644
--- a/conf/models/vllm.json
+++ b/conf/models/vllm.json
@@ -1,5 +1,5 @@
{
- "name": "vllm",
+ "name": "VLLM",
"rank": 975,
"url_suffix": {
"chat": "chat/completions",
@@ -8,4 +8,4 @@
"rerank": "rerank"
},
"class": "local"
-}
\ No newline at end of file
+}
diff --git a/conf/models/voyage.json b/conf/models/voyage.json
index 8ad059cf0f..2873ff4539 100644
--- a/conf/models/voyage.json
+++ b/conf/models/voyage.json
@@ -1,5 +1,5 @@
{
- "name": "Voyage",
+ "name": "Voyage AI",
"url": {
"default": "https://api.voyageai.com"
},
diff --git a/conf/models/xinference.json b/conf/models/xinference.json
index cf8fb61fa9..b77e9de00b 100644
--- a/conf/models/xinference.json
+++ b/conf/models/xinference.json
@@ -1,5 +1,5 @@
{
- "name": "xinference",
+ "name": "Xinference",
"url_suffix": {
"chat": "v1/chat/completions",
"embedding": "v1/embeddings",
diff --git a/conf/models/xunfei.json b/conf/models/xunfei.json
index 6ab0385b55..4473b74e3b 100644
--- a/conf/models/xunfei.json
+++ b/conf/models/xunfei.json
@@ -1,5 +1,5 @@
{
- "name": "XunFei",
+ "name": "XunFei Spark",
"url": {
"default": "https://spark-api-open.xf-yun.com"
},
@@ -20,4 +20,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/docs/release_notes.md b/docs/release_notes.md
index 1f8b3cc3cf..574c123da3 100644
--- a/docs/release_notes.md
+++ b/docs/release_notes.md
@@ -425,7 +425,7 @@ Released on December 31, 2025.
### Fixed issues
-- Memory:
+- Memory:
- The RAGFlow server failed to start if an empty memory object existed.
- Unable to delete a newly created empty Memory.
- RAG: MDX file parsing was not supported.
@@ -661,7 +661,7 @@ Ecommerce Customer Service Workflow: A template designed to handle enquiries abo
### Fixed issues
-- Dataset:
+- Dataset:
- Unable to share resources with the team.
- Inappropriate restrictions on the number and size of uploaded files.
- Chat:
@@ -677,13 +677,13 @@ Released on August 20, 2025.
### Improvements
-- Revamps the user interface for the **Datasets**, **Chat**, and **Search** pages.
+- Revamps the user interface for the **Datasets**, **Chat**, and **Search** pages.
- Search and Chat: Introduces document-level metadata filtering, allowing automatic or manual filtering during chats or searches.
- Search: Supports creating search apps tailored to various business scenarios
- Chat: Supports comparing answer performance of up to three chat model settings on a single **Chat** page.
-- Agent:
- - Implements a toggle in the **Agent** component to enable or disable citation.
- - Introduces a drag-and-drop method for creating components.
+- Agent:
+ - Implements a toggle in the **Agent** component to enable or disable citation.
+ - Introduces a drag-and-drop method for creating components.
- Documentation: Corrects inaccuracies in the API reference.
### New Agent templates
@@ -693,8 +693,8 @@ Released on August 20, 2025.
### Fixed issues
- The timeout mechanism introduced in v0.20.0 caused tasks like GraphRAG to halt.
-- Predefined opening greeting in the **Agent** component was missing during conversations.
-- An automatic line break issue in the prompt editor.
+- Predefined opening greeting in the **Agent** component was missing during conversations.
+- An automatic line break issue in the prompt editor.
- A memory leak issue caused by PyPDF. [#9469](https://github.com/infiniflow/ragflow/pull/9469)
### API changes
@@ -778,7 +778,7 @@ Released on June 23, 2025.
### Newly supported models
-- Qwen 3 Embedding. [#8184](https://github.com/infiniflow/ragflow/pull/8184)
+- Qwen 3 Embedding. [#8184](https://github.com/infiniflow/ragflow/pull/8184)
- Voyage Multimodal 3. [#7987](https://github.com/infiniflow/ragflow/pull/7987)
## v0.19.0
diff --git a/internal/development.md b/internal/development.md
index 2a3d24edaa..84f52ecea5 100644
--- a/internal/development.md
+++ b/internal/development.md
@@ -13,7 +13,7 @@ sudo apt update
test -f /usr/share/doc/kitware-archive-keyring/copyright || sudo rm /usr/share/keyrings/kitware-archive-keyring.gpg
sudo apt install -y kitware-archive-keyring
sudo apt update
-sudo apt install -y cmake
+sudo apt install -y cmake
```
### 1.2 Install clang-20
diff --git a/internal/entity/models/aliyun.go b/internal/entity/models/aliyun.go
index a9c22e5e3f..9aeec0f37d 100644
--- a/internal/entity/models/aliyun.go
+++ b/internal/entity/models/aliyun.go
@@ -48,7 +48,7 @@ func (a *AliyunModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (a *AliyunModel) Name() string {
- return "aliyun"
+ return "Tongyi-Qianwen"
}
func (a *AliyunModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/entity/models/avian.go b/internal/entity/models/avian.go
index 9281b2abbd..1d757ed4c9 100644
--- a/internal/entity/models/avian.go
+++ b/internal/entity/models/avian.go
@@ -49,7 +49,7 @@ func (a *AvianModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (a *AvianModel) Name() string {
- return "avian"
+ return "Avian"
}
func (a *AvianModel) chatPayload(modelName string, messages []Message, stream bool, chatModelConfig *ChatConfig) map[string]interface{} {
diff --git a/internal/entity/models/avian_test.go b/internal/entity/models/avian_test.go
index 464c357c51..934a49de25 100644
--- a/internal/entity/models/avian_test.go
+++ b/internal/entity/models/avian_test.go
@@ -63,8 +63,8 @@ func newAvianForTest(baseURL string) *AvianModel {
}
func TestAvianName(t *testing.T) {
- if got := newAvianForTest("http://unused").Name(); got != "avian" {
- t.Errorf("Name()=%q, want avian", got)
+ if got := newAvianForTest("http://unused").Name(); got != "Avian" {
+ t.Errorf("Name()=%q, want Avian", got)
}
}
diff --git a/internal/entity/models/baichuan.go b/internal/entity/models/baichuan.go
index d659eb82be..8c503143ef 100644
--- a/internal/entity/models/baichuan.go
+++ b/internal/entity/models/baichuan.go
@@ -46,7 +46,7 @@ func (b *BaichuanModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (b *BaichuanModel) Name() string {
- return "baichuan"
+ return "BaiChuan"
}
func (b *BaichuanModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/entity/models/baidu.go b/internal/entity/models/baidu.go
index 49ecf22636..1b46cbb1fa 100644
--- a/internal/entity/models/baidu.go
+++ b/internal/entity/models/baidu.go
@@ -47,7 +47,7 @@ func NewBaiduModel(baseURL map[string]string, urlSuffix URLSuffix) *BaiduModel {
}
func (b *BaiduModel) Name() string {
- return "baidu"
+ return "BaiduYiyan"
}
func (b *BaiduModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/entity/models/cohere.go b/internal/entity/models/cohere.go
index f73613d82e..e4d7a5fe7c 100644
--- a/internal/entity/models/cohere.go
+++ b/internal/entity/models/cohere.go
@@ -49,7 +49,7 @@ func NewCoHereModel(baseURL map[string]string, urlSuffix URLSuffix) *CoHereModel
}
func (c *CoHereModel) Name() string {
- return "cohere"
+ return "Cohere"
}
func (c *CoHereModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/entity/models/factory.go b/internal/entity/models/factory.go
index 714c772acc..bd08df771d 100644
--- a/internal/entity/models/factory.go
+++ b/internal/entity/models/factory.go
@@ -43,13 +43,13 @@ func (f *ModelFactory) CreateModelDriver(providerName string, baseURL map[string
return NewMoonshotModel(baseURL, urlSuffix), nil
case "minimax":
return NewMinimaxModel(baseURL, urlSuffix), nil
- case "gitee":
+ case "giteeai":
return NewGiteeModel(baseURL, urlSuffix), nil
case "siliconflow":
return NewSiliconflowModel(baseURL, urlSuffix), nil
- case "google":
+ case "gemini":
return NewGoogleModel(baseURL, urlSuffix), nil
- case "aliyun":
+ case "tongyi-qianwen":
return NewAliyunModel(baseURL, urlSuffix), nil
case "volcengine":
return NewVolcEngine(baseURL, urlSuffix), nil
@@ -57,7 +57,7 @@ func (f *ModelFactory) CreateModelDriver(providerName string, baseURL map[string
return NewVllmModel(baseURL, urlSuffix), nil
case "xai":
return NewXAIModel(baseURL, urlSuffix), nil
- case "lmstudio":
+ case "lm-studio":
return NewLmStudioModel(baseURL, urlSuffix), nil
case "ollama":
return NewOllamaModel(baseURL, urlSuffix), nil
@@ -73,13 +73,13 @@ func (f *ModelFactory) CreateModelDriver(providerName string, baseURL map[string
return NewOpenRouterModel(baseURL, urlSuffix), nil
case "huggingface":
return NewHuggingFaceModel(baseURL, urlSuffix), nil
- case "baidu":
+ case "baiduyiyan":
return NewBaiduModel(baseURL, urlSuffix), nil
case "cohere":
return NewCoHereModel(baseURL, urlSuffix), nil
case "cometapi":
return NewCometAPIModel(baseURL, urlSuffix), nil
- case "fishaudio":
+ case "fish audio":
return NewFishAudioModel(baseURL, urlSuffix), nil
case "mistral":
return NewMistralModel(baseURL, urlSuffix), nil
@@ -101,13 +101,13 @@ func (f *ModelFactory) CreateModelDriver(providerName string, baseURL map[string
return NewModelScopeModel(baseURL, urlSuffix), nil
case "longcat":
return NewLongCatModel(baseURL, urlSuffix), nil
- case "hunyuan":
+ case "tencent hunyuan":
return NewHunyuanModel(baseURL, urlSuffix), nil
case "tokenpony":
return NewTokenPonyModel(baseURL, urlSuffix), nil
case "tokenhub":
return NewTokenHubModel(baseURL, urlSuffix), nil
- case "novita":
+ case "novitaai":
return NewNovitaModel(baseURL, urlSuffix), nil
case "avian":
return NewAvianModel(baseURL, urlSuffix), nil
@@ -117,17 +117,17 @@ func (f *ModelFactory) CreateModelDriver(providerName string, baseURL map[string
return NewTogetherAIModel(baseURL, urlSuffix), nil
case "ppio":
return NewPPIOModel(baseURL, urlSuffix), nil
- case "voyage":
+ case "voyage ai":
return NewVoyageModel(baseURL, urlSuffix), nil
case "paddleocr.net":
return NewPaddleOCRModel(baseURL, urlSuffix), nil
- case "xunfei":
+ case "xunfei spark":
return NewXunFeiModel(baseURL, urlSuffix), nil
case "deepinfra":
return NewDeepInfraModel(baseURL, urlSuffix), nil
case "mineru.net":
return NewMinerUModel(baseURL, urlSuffix), nil
- case "jiekouai":
+ case "jiekou.ai":
return NewJieKouAIModel(baseURL, urlSuffix), nil
case "302.ai":
return NewAI302Model(baseURL, urlSuffix), nil
diff --git a/internal/entity/models/fishaudio.go b/internal/entity/models/fishaudio.go
index 9411df1e34..56a81232af 100644
--- a/internal/entity/models/fishaudio.go
+++ b/internal/entity/models/fishaudio.go
@@ -50,7 +50,7 @@ func (f *FishAudioModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (f *FishAudioModel) Name() string {
- return "fishaudio"
+ return "Fish Audio"
}
func (f *FishAudioModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/entity/models/gitee.go b/internal/entity/models/gitee.go
index 130a625614..2be4b9e716 100644
--- a/internal/entity/models/gitee.go
+++ b/internal/entity/models/gitee.go
@@ -50,7 +50,7 @@ func (g *GiteeModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (g *GiteeModel) Name() string {
- return "gitee"
+ return "GiteeAI"
}
// ChatWithMessages sends multiple messages with roles and returns response
diff --git a/internal/entity/models/google.go b/internal/entity/models/google.go
index fc37ed03a1..11b0fe48b6 100644
--- a/internal/entity/models/google.go
+++ b/internal/entity/models/google.go
@@ -97,7 +97,7 @@ func (g *GoogleModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (g *GoogleModel) Name() string {
- return "google"
+ return "Gemini"
}
func (g *GoogleModel) clientConfig(apiKey string, apiConfig *APIConfig) *genai.ClientConfig {
diff --git a/internal/entity/models/hunyuan.go b/internal/entity/models/hunyuan.go
index 096892fc86..d6b6c333ff 100644
--- a/internal/entity/models/hunyuan.go
+++ b/internal/entity/models/hunyuan.go
@@ -47,7 +47,7 @@ func (h *HunyuanModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (h *HunyuanModel) Name() string {
- return "hunyuan"
+ return "Tencent Hunyuan"
}
func (h *HunyuanModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/entity/models/hunyuan_test.go b/internal/entity/models/hunyuan_test.go
index 5bc42795d9..754c31eca8 100644
--- a/internal/entity/models/hunyuan_test.go
+++ b/internal/entity/models/hunyuan_test.go
@@ -80,13 +80,13 @@ func newHunyuanForTest(baseURL string) *HunyuanModel {
}
func TestHunyuanName(t *testing.T) {
- if got := newHunyuanForTest("http://unused").Name(); got != "hunyuan" {
- t.Errorf("Name()=%q, want %q", got, "hunyuan")
+ if got := newHunyuanForTest("http://unused").Name(); got != "Tencent Hunyuan" {
+ t.Errorf("Name()=%q, want %q", got, "Tencent Hunyuan")
}
}
func TestHunyuanFactory(t *testing.T) {
- driver, err := NewModelFactory().CreateModelDriver("Hunyuan", map[string]string{"default": "http://unused"}, URLSuffix{})
+ driver, err := NewModelFactory().CreateModelDriver("Tencent Hunyuan", map[string]string{"default": "http://unused"}, URLSuffix{})
if err != nil {
t.Fatalf("CreateModelDriver: %v", err)
}
diff --git a/internal/entity/models/lmstudio.go b/internal/entity/models/lmstudio.go
index f3e3ac7818..5d446624d3 100644
--- a/internal/entity/models/lmstudio.go
+++ b/internal/entity/models/lmstudio.go
@@ -49,7 +49,7 @@ func (l *LmStudioModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (l *LmStudioModel) Name() string {
- return "lmstudio"
+ return "LM-Studio"
}
// ChatWithMessages sends multiple messages with roles and returns response
diff --git a/internal/entity/models/localai.go b/internal/entity/models/localai.go
index 8112c2d1d1..6a79db2450 100644
--- a/internal/entity/models/localai.go
+++ b/internal/entity/models/localai.go
@@ -53,7 +53,7 @@ func (l *LocalAIModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (l *LocalAIModel) Name() string {
- return "localai"
+ return "LocalAI"
}
var localAIReasoningFields = []string{"reasoning_content", "reasoning", "thinking"}
diff --git a/internal/entity/models/localai_test.go b/internal/entity/models/localai_test.go
index f8b89da4ae..24f787521d 100644
--- a/internal/entity/models/localai_test.go
+++ b/internal/entity/models/localai_test.go
@@ -37,8 +37,8 @@ func withLocalAIIdleTimeout(t *testing.T, d time.Duration) {
func TestLocalAIName(t *testing.T) {
l := newLocalAIForTest("http://unused")
- if got := l.Name(); got != "localai" {
- t.Errorf("Name()=%q, want %q", got, "localai")
+ if got := l.Name(); got != "LocalAI" {
+ t.Errorf("Name()=%q, want %q", got, "LocalAI")
}
}
diff --git a/internal/entity/models/model_test.go b/internal/entity/models/model_test.go
index 76686cf92b..fa5029d540 100644
--- a/internal/entity/models/model_test.go
+++ b/internal/entity/models/model_test.go
@@ -182,12 +182,12 @@ func TestProviderConfigsLoadURLSuffixKeys(t *testing.T) {
}
pm := GetProviderManager()
- cohere := pm.FindProvider("CoHere")
+ cohere := pm.FindProvider("Cohere")
if cohere == nil {
- t.Fatal("CoHere provider not found")
+ t.Fatal("Cohere provider not found")
}
if cohere.URLSuffix.Embedding != "v2/embed" {
- t.Errorf("CoHere embedding suffix=%q", cohere.URLSuffix.Embedding)
+ t.Errorf("Cohere embedding suffix=%q", cohere.URLSuffix.Embedding)
}
xAI := pm.FindProvider("xAI")
@@ -330,9 +330,9 @@ func TestSiliconFlowProviderConfigLoadsLatestProModels(t *testing.T) {
}
pm := GetProviderManager()
- provider := pm.FindProvider("SiliconFlow")
+ provider := pm.FindProvider("SILICONFLOW")
if provider == nil {
- t.Fatal("SiliconFlow provider not found")
+ t.Fatal("SILICONFLOW provider not found")
}
if provider.URL["default"] != "https://api.siliconflow.cn/v1" {
t.Errorf("default URL=%q", provider.URL["default"])
@@ -343,14 +343,14 @@ func TestSiliconFlowProviderConfigLoadsLatestProModels(t *testing.T) {
if _, ok := provider.ModelDriver.(*SiliconflowModel); !ok {
t.Fatalf("ModelDriver=%T, want *models.SiliconflowModel", provider.ModelDriver)
}
- if provider.ModelDriver.Name() != "siliconflow" {
+ if provider.ModelDriver.Name() != "SILICONFLOW" {
t.Errorf("ModelDriver.Name()=%q", provider.ModelDriver.Name())
}
if len(provider.Models) != 13 {
- t.Fatalf("SiliconFlow model count=%d, want 13", len(provider.Models))
+ t.Fatalf("SILICONFLOW model count=%d, want 13", len(provider.Models))
}
- deepSeekV4Pro, err := pm.GetModelByName("SiliconFlow", "Pro/deepseek-ai/DeepSeek-V4-Pro")
+ deepSeekV4Pro, err := pm.GetModelByName("SILICONFLOW", "Pro/deepseek-ai/DeepSeek-V4-Pro")
if err != nil {
t.Fatalf("GetModelByName DeepSeek-V4-Pro: %v", err)
}
@@ -361,7 +361,7 @@ func TestSiliconFlowProviderConfigLoadsLatestProModels(t *testing.T) {
t.Errorf("DeepSeek-V4-Pro model types=%v, want chat", deepSeekV4Pro.ModelTypes)
}
- kimiK26, err := pm.GetModelByName("SiliconFlow", "Pro/moonshotai/Kimi-K2.6")
+ kimiK26, err := pm.GetModelByName("SILICONFLOW", "Pro/moonshotai/Kimi-K2.6")
if err != nil {
t.Fatalf("GetModelByName Kimi-K2.6: %v", err)
}
diff --git a/internal/entity/models/modelscope.go b/internal/entity/models/modelscope.go
index 97d1d55515..491d1b88ed 100644
--- a/internal/entity/models/modelscope.go
+++ b/internal/entity/models/modelscope.go
@@ -70,7 +70,7 @@ func (m *ModelScopeModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (m *ModelScopeModel) Name() string {
- return "modelscope"
+ return "ModelScope"
}
func normalizeModelScopeBaseURL(base string) string {
diff --git a/internal/entity/models/modelscope_test.go b/internal/entity/models/modelscope_test.go
index 535e9eaabf..d7d597cef7 100644
--- a/internal/entity/models/modelscope_test.go
+++ b/internal/entity/models/modelscope_test.go
@@ -47,8 +47,8 @@ func withModelScopeIdleTimeout(t *testing.T, d time.Duration) {
func TestModelScopeName(t *testing.T) {
m := newModelScopeForTest("http://unused")
- if got := m.Name(); got != "modelscope" {
- t.Errorf("Name()=%q, want %q", got, "modelscope")
+ if got := m.Name(); got != "ModelScope" {
+ t.Errorf("Name()=%q, want %q", got, "ModelScope")
}
}
@@ -70,12 +70,12 @@ func TestNormalizeModelScopeBaseURL(t *testing.T) {
}
func TestModelScopeFactoryRoute(t *testing.T) {
- driver, err := NewModelFactory().CreateModelDriver("modelscope", map[string]string{"default": "http://unused"}, URLSuffix{})
+ driver, err := NewModelFactory().CreateModelDriver("ModelScope", map[string]string{"default": "http://unused"}, URLSuffix{})
if err != nil {
t.Fatalf("CreateModelDriver: %v", err)
}
- if driver.Name() != "modelscope" {
- t.Errorf("driver.Name()=%q, want modelscope", driver.Name())
+ if driver.Name() != "ModelScope" {
+ t.Errorf("driver.Name()=%q, want ModelScope", driver.Name())
}
}
diff --git a/internal/entity/models/novita.go b/internal/entity/models/novita.go
index 15581ab40e..be19bd1ca9 100644
--- a/internal/entity/models/novita.go
+++ b/internal/entity/models/novita.go
@@ -48,7 +48,7 @@ func (n *NovitaModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (n *NovitaModel) Name() string {
- return "novita"
+ return "NovitaAI"
}
const (
diff --git a/internal/entity/models/novita_test.go b/internal/entity/models/novita_test.go
index 82067ed47b..81ad829f7e 100644
--- a/internal/entity/models/novita_test.go
+++ b/internal/entity/models/novita_test.go
@@ -249,7 +249,7 @@ func TestNovitaThinkExtractorLessThanIsNotTagStart(t *testing.T) {
// ---- driver methods ----
func TestNovitaName(t *testing.T) {
- if got := newNovitaForTest("http://unused").Name(); got != "novita" {
+ if got := newNovitaForTest("http://unused").Name(); got != "NovitaAI" {
t.Errorf("Name()=%q", got)
}
}
diff --git a/internal/entity/models/ollama.go b/internal/entity/models/ollama.go
index 1facb4e5b2..734562752d 100644
--- a/internal/entity/models/ollama.go
+++ b/internal/entity/models/ollama.go
@@ -69,7 +69,7 @@ func (o *OllamaModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (o *OllamaModel) Name() string {
- return "ollama"
+ return "Ollama"
}
func (o *OllamaModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/entity/models/siliconflow.go b/internal/entity/models/siliconflow.go
index b2e586202f..0f09768aad 100644
--- a/internal/entity/models/siliconflow.go
+++ b/internal/entity/models/siliconflow.go
@@ -52,7 +52,7 @@ func (s *SiliconflowModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (s *SiliconflowModel) Name() string {
- return "siliconflow"
+ return "SILICONFLOW"
}
// SiliconflowRerankRequest represents SILICONFLOW rerank request
diff --git a/internal/entity/models/sse_scanner_buffer_test.go b/internal/entity/models/sse_scanner_buffer_test.go
index c458921739..0e76d90a36 100644
--- a/internal/entity/models/sse_scanner_buffer_test.go
+++ b/internal/entity/models/sse_scanner_buffer_test.go
@@ -50,16 +50,16 @@ func TestChatStreamLargeChunkNotTruncated(t *testing.T) {
build func(string) chatStreamer
}{
{"deepinfra", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewDeepInfraModel(b, s) })},
- {"vllm", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewVllmModel(b, s) })},
+ {"VLLM", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewVllmModel(b, s) })},
{"openrouter", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewOpenRouterModel(b, s) })},
- {"siliconflow", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewSiliconflowModel(b, s) })},
+ {"SILICONFLOW", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewSiliconflowModel(b, s) })},
{"moonshot", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewMoonshotModel(b, s) })},
{"deepseek", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewDeepSeekModel(b, s) })},
{"nvidia", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewNvidiaModel(b, s) })},
- {"lmstudio", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewLmStudioModel(b, s) })},
- {"gitee", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewGiteeModel(b, s) })},
+ {"LM-Studio", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewLmStudioModel(b, s) })},
+ {"GiteeAI", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewGiteeModel(b, s) })},
{"tokenhub", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewTokenHubModel(b, s) })},
- {"jiekouai", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewJieKouAIModel(b, s) })},
+ {"Jiekou.AI", build(func(b map[string]string, s URLSuffix) chatStreamer { return NewJieKouAIModel(b, s) })},
}
for _, tc := range cases {
diff --git a/internal/entity/models/vllm.go b/internal/entity/models/vllm.go
index 3b78be34e4..af608fcd94 100644
--- a/internal/entity/models/vllm.go
+++ b/internal/entity/models/vllm.go
@@ -49,7 +49,7 @@ func (v *VllmModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (v *VllmModel) Name() string {
- return "vllm"
+ return "VLLM"
}
// ChatWithMessages sends multiple messages with roles and returns response
diff --git a/internal/entity/models/voyage.go b/internal/entity/models/voyage.go
index 3a14428cf6..95b009baaa 100644
--- a/internal/entity/models/voyage.go
+++ b/internal/entity/models/voyage.go
@@ -47,7 +47,7 @@ func (v *VoyageModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (v *VoyageModel) Name() string {
- return "voyage"
+ return "Voyage AI"
}
type voyageEmbeddingData struct {
diff --git a/internal/entity/models/voyage_test.go b/internal/entity/models/voyage_test.go
index accd258959..7fad9cf2e6 100644
--- a/internal/entity/models/voyage_test.go
+++ b/internal/entity/models/voyage_test.go
@@ -46,8 +46,8 @@ func newVoyageForTest(baseURL string) *VoyageModel {
}
func TestVoyageName(t *testing.T) {
- if got := newVoyageForTest("http://unused").Name(); got != "voyage" {
- t.Errorf("Name()=%q, want %q", got, "voyage")
+ if got := newVoyageForTest("http://unused").Name(); got != "Voyage AI" {
+ t.Errorf("Name()=%q, want %q", got, "Voyage AI")
}
}
diff --git a/internal/entity/models/xinference.go b/internal/entity/models/xinference.go
index ebc402c8ee..7908f92f1e 100644
--- a/internal/entity/models/xinference.go
+++ b/internal/entity/models/xinference.go
@@ -72,7 +72,7 @@ func (x *XinferenceModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (x *XinferenceModel) Name() string {
- return "xinference"
+ return "Xinference"
}
func normalizeXinferenceBaseURL(base string) string {
diff --git a/internal/entity/models/xinference_test.go b/internal/entity/models/xinference_test.go
index 5b2ae5f7d9..81a03f222d 100644
--- a/internal/entity/models/xinference_test.go
+++ b/internal/entity/models/xinference_test.go
@@ -33,8 +33,8 @@ func withXinferenceIdleTimeout(t *testing.T, d time.Duration) {
func TestXinferenceName(t *testing.T) {
x := newXinferenceForTest("http://unused")
- if got := x.Name(); got != "xinference" {
- t.Errorf("Name()=%q, want %q", got, "xinference")
+ if got := x.Name(); got != "Xinference" {
+ t.Errorf("Name()=%q, want %q", got, "Xinference")
}
}
@@ -56,12 +56,12 @@ func TestNormalizeXinferenceBaseURL(t *testing.T) {
}
func TestXinferenceFactoryRoute(t *testing.T) {
- driver, err := NewModelFactory().CreateModelDriver("xinference", map[string]string{"default": "http://unused"}, URLSuffix{})
+ driver, err := NewModelFactory().CreateModelDriver("Xinference", map[string]string{"default": "http://unused"}, URLSuffix{})
if err != nil {
t.Fatalf("CreateModelDriver: %v", err)
}
- if driver.Name() != "xinference" {
- t.Errorf("driver.Name()=%q, want xinference", driver.Name())
+ if driver.Name() != "Xinference" {
+ t.Errorf("driver.Name()=%q, want Xinference", driver.Name())
}
}
diff --git a/internal/entity/models/xunfei.go b/internal/entity/models/xunfei.go
index a4229ef859..c331e39a2c 100644
--- a/internal/entity/models/xunfei.go
+++ b/internal/entity/models/xunfei.go
@@ -45,7 +45,7 @@ func (x *XunFeiModel) NewInstance(baseURL map[string]string) ModelDriver {
}
func (x *XunFeiModel) Name() string {
- return "xunfei"
+ return "XunFei Spark"
}
func (x *XunFeiModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
diff --git a/internal/service/deep_researcher.go b/internal/service/deep_researcher.go
index 81ae00209e..06bff70c12 100644
--- a/internal/service/deep_researcher.go
+++ b/internal/service/deep_researcher.go
@@ -66,8 +66,8 @@ Requirements:
4. The missing_information should only be filled when insufficient, otherwise empty array.
`
-const multiQueriesGenTemplate = `You are a query optimization expert.
-The user's original query failed to retrieve sufficient information;
+const multiQueriesGenTemplate = `You are a query optimization expert.
+The user's original query failed to retrieve sufficient information;
please generate multiple complementary improved questions and corresponding queries.
Original query:
@@ -102,8 +102,8 @@ Requirements:
1. Questions array contains 1-3 questions and corresponding queries.
2. Each question length is between 5-200 characters.
3. Each query length is between 1-5 keywords.
-4. Each query MUST be in the same language as the retrieved content in.
-5. DO NOT generate question and query that is similar to the original query.
+4. Each query MUST be in the same language as the retrieved content in.
+5. DO NOT generate question and query that is similar to the original query.
6. Reasoning explains the generation strategy.
`
diff --git a/internal/service/model_service.go b/internal/service/model_service.go
index 0b4f0c90ae..be20d5e6ce 100644
--- a/internal/service/model_service.go
+++ b/internal/service/model_service.go
@@ -2270,9 +2270,9 @@ func (m *ModelProviderService) GetModelTypeByName(tenantID, modelName string) ([
targetFactoryName = "siliconflow_intl"
}
// Use the case-insensitive FindProvider / findModel helpers. The Go's
- // conf/models/*.json files use mixed case ("SiliconFlow") while the
- // Python's conf/llm_factories.json uses all-caps ("SILICONFLOW"); a strict
- // `==` here would fail for any case mismatch. The rest of the Go codebase
+ // conf/models/*.json files now use the same names as the Python's
+ // conf/llm_factories.json (e.g. "SILICONFLOW"); but a strict
+ // `==` here would still fail for any case mismatch. The rest of the Go codebase
// uses these helpers too.
targetProvider := dao.GetModelProviderManager().FindProvider(targetFactoryName)
if targetProvider == nil {
@@ -2602,9 +2602,9 @@ func (m *ModelProviderService) GetModelConfigFromProviderInstance(tenantID strin
targetFactoryName = "siliconflow_intl"
}
// Use the case-insensitive FindProvider / findModel helpers. The Go's
- // conf/models/*.json files use mixed case ("SiliconFlow") while the
- // Python's conf/llm_factories.json uses all-caps ("SILICONFLOW"); a strict
- // `==` here would fail for any case mismatch even though the Python passes
+ // conf/models/*.json files now use the same names as the Python's
+ // conf/llm_factories.json (e.g. "SILICONFLOW"); but a strict
+ // `==` here would still fail for any case mismatch even though the Python passes
// (its FACTORY_LLM_INFOS and the parsed provider_name happen to agree on
// casing). The rest of the Go codebase uses these helpers too.
targetProvider := dao.GetModelProviderManager().FindProvider(targetFactoryName)
diff --git a/rag/svr/task_executor_refactor/task_handler.py b/rag/svr/task_executor_refactor/task_handler.py
index f754a2fcce..cbb37e1399 100644
--- a/rag/svr/task_executor_refactor/task_handler.py
+++ b/rag/svr/task_executor_refactor/task_handler.py
@@ -321,17 +321,11 @@ class TaskHandler:
try:
if ctx.tenant_embd_id:
try:
- embd_model_config = get_model_config_by_id(
- task_tenant_id, ctx.tenant_embd_id
- )
+ embd_model_config = get_model_config_by_id(task_tenant_id, ctx.tenant_embd_id)
except LookupError:
- embd_model_config = get_model_config_from_provider_instance(
- task_tenant_id, LLMType.EMBEDDING, task_embedding_id
- )
+ embd_model_config = get_model_config_from_provider_instance(task_tenant_id, LLMType.EMBEDDING, task_embedding_id)
elif task_embedding_id:
- embd_model_config = get_model_config_from_provider_instance(
- task_tenant_id, LLMType.EMBEDDING, task_embedding_id
- )
+ embd_model_config = get_model_config_from_provider_instance(task_tenant_id, LLMType.EMBEDDING, task_embedding_id)
else:
embd_model_config = get_tenant_default_model_by_type(task_tenant_id, LLMType.EMBEDDING)
embedding_model = LLMBundle(task_tenant_id, embd_model_config, lang=task_language)
diff --git a/ragflow_deps/download_go_deps.py b/ragflow_deps/download_go_deps.py
index d3f1e5ed24..85fae8ebf4 100644
--- a/ragflow_deps/download_go_deps.py
+++ b/ragflow_deps/download_go_deps.py
@@ -36,6 +36,7 @@ import sys
import requests
from typing import Union
+
def get_urls(use_china_mirrors=False) -> list[Union[str, list[str]]]:
if use_china_mirrors:
return [
@@ -91,10 +92,10 @@ def get_urls(use_china_mirrors=False) -> list[Union[str, list[str]]]:
def download_with_progress(url, filename):
response = requests.get(url, stream=True)
- total_size = int(response.headers.get('content-length', 0))
+ total_size = int(response.headers.get("content-length", 0))
block_size = 1024
- with open(filename, 'wb') as file:
+ with open(filename, "wb") as file:
downloaded = 0
for data in response.iter_content(block_size):
file.write(data)
@@ -102,7 +103,7 @@ def download_with_progress(url, filename):
if total_size > 0:
progress = (downloaded / total_size) * 100
- sys.stdout.write(f'\rProgress: {progress:.1f}% ({downloaded}/{total_size} bytes)')
+ sys.stdout.write(f"\rProgress: {progress:.1f}% ({downloaded}/{total_size} bytes)")
sys.stdout.flush()
print()
@@ -123,9 +124,9 @@ if __name__ == "__main__":
# Some mirrors (e.g. archive.ubuntu.com) reject the default urllib
# User-Agent with HTTP 403, so install an opener with a browser-like UA.
-# opener = urllib.request.build_opener()
-# opener.addheaders = [("User-Agent", "Mozilla/5.0")]
-# urllib.request.install_opener(opener)
+ # opener = urllib.request.build_opener()
+ # opener.addheaders = [("User-Agent", "Mozilla/5.0")]
+ # urllib.request.install_opener(opener)
for url in urls:
download_url = url[0] if isinstance(url, list) else url
diff --git a/test/unit_test/api/db/services/test_get_queue_length.py b/test/unit_test/api/db/services/test_get_queue_length.py
index a985fed519..571353efbc 100644
--- a/test/unit_test/api/db/services/test_get_queue_length.py
+++ b/test/unit_test/api/db/services/test_get_queue_length.py
@@ -32,6 +32,7 @@ warnings.filterwarnings(
def _install_cv2_stub_if_unavailable():
try:
import cv2 # noqa: F401
+
return
except (ImportError, OSError) as exc:
# cv2 can fail to import with OSError too (e.g. missing shared libs),
diff --git a/test/unit_test/common/test_llm_request_context.py b/test/unit_test/common/test_llm_request_context.py
index 17af0ec80b..b6748e806c 100644
--- a/test/unit_test/common/test_llm_request_context.py
+++ b/test/unit_test/common/test_llm_request_context.py
@@ -19,6 +19,7 @@ Covers the behaviour flagged in review: (1) session_id is preferred over
user_id, (2) an explicit caller-supplied ``user`` overrides the context value,
and (3) a caller-supplied empty ``user`` suppresses forwarding entirely.
"""
+
import types
import pytest
diff --git a/tools/scripts/mysql_migration.py b/tools/scripts/mysql_migration.py
index 50f255332b..4d871548c6 100644
--- a/tools/scripts/mysql_migration.py
+++ b/tools/scripts/mysql_migration.py
@@ -158,11 +158,7 @@ class MigrationDatabase:
def get_column_type(self, table_name: str, column_name: str) -> str | None:
"""Get the DATA_TYPE of a column from information_schema, returns None if column does not exist"""
- cursor = self.execute_sql(
- "SELECT DATA_TYPE FROM information_schema.columns "
- "WHERE table_schema = %s AND table_name = %s AND column_name = %s",
- (self.config.database, table_name, column_name)
- )
+ cursor = self.execute_sql("SELECT DATA_TYPE FROM information_schema.columns WHERE table_schema = %s AND table_name = %s AND column_name = %s", (self.config.database, table_name, column_name))
row = cursor.fetchone()
return row[0] if row else None
@@ -1304,35 +1300,22 @@ class TenantModelSeedingStage(MigrationStage):
instance_extra_include = None
instance_extra_exclude = None
# Query provider for this factory
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_provider WHERE provider_name = %s",
- (provider_name_filter,)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_provider WHERE provider_name = %s", (provider_name_filter,))
providers = cursor.fetchall()
- for provider_id, in providers:
+ for (provider_id,) in providers:
# Query instances for this provider, with optional extra include/exclude filter
if instance_extra_include and instance_extra_exclude:
cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s AND extra NOT LIKE %s",
- (provider_id, instance_extra_include, instance_extra_exclude)
+ "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s AND extra NOT LIKE %s", (provider_id, instance_extra_include, instance_extra_exclude)
)
elif instance_extra_include:
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s",
- (provider_id, instance_extra_include)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s", (provider_id, instance_extra_include))
elif instance_extra_exclude:
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra NOT LIKE %s",
- (provider_id, instance_extra_exclude)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra NOT LIKE %s", (provider_id, instance_extra_exclude))
else:
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s",
- (provider_id,)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_instance WHERE provider_id = %s", (provider_id,))
instances = cursor.fetchall()
- for instance_id, in instances:
+ for (instance_id,) in instances:
for llm in llm_list:
model_name = llm.get("llm_name", "")
model_types = llm.get("model_type", "chat")
@@ -1340,9 +1323,7 @@ class TenantModelSeedingStage(MigrationStage):
model_types = [model_types]
for mt in model_types:
cursor = self.db.execute_sql(
- "SELECT COUNT(*) FROM tenant_model "
- "WHERE provider_id = %s AND instance_id = %s AND model_name = %s AND model_type = %s",
- (provider_id, instance_id, model_name, mt)
+ "SELECT COUNT(*) FROM tenant_model WHERE provider_id = %s AND instance_id = %s AND model_name = %s AND model_type = %s", (provider_id, instance_id, model_name, mt)
)
if cursor.fetchone()[0] == 0:
total_missing += 1
@@ -1381,9 +1362,7 @@ class TenantModelSeedingStage(MigrationStage):
# Pre-load existing extra values for model_names from tenant_model
# to reuse non-default extra for same model_name across providers
- cursor = self.db.execute_sql(
- "SELECT model_name, extra FROM tenant_model WHERE extra != '{}' AND extra IS NOT NULL"
- )
+ cursor = self.db.execute_sql("SELECT model_name, extra FROM tenant_model WHERE extra != '{}' AND extra IS NOT NULL")
existing_extra_map = {}
for model_name, extra in cursor.fetchall():
if model_name and extra and extra != "{}":
@@ -1391,9 +1370,7 @@ class TenantModelSeedingStage(MigrationStage):
# Pre-load existing status values for model_names from tenant_model
# Prefer non-unsupported status when seeding new records for the same model_name
- cursor = self.db.execute_sql(
- "SELECT model_name, status FROM tenant_model WHERE status != 'unsupported' AND status IS NOT NULL"
- )
+ cursor = self.db.execute_sql("SELECT model_name, status FROM tenant_model WHERE status != 'unsupported' AND status IS NOT NULL")
existing_status_map = {}
for model_name, status in cursor.fetchall():
if model_name and status:
@@ -1423,40 +1400,27 @@ class TenantModelSeedingStage(MigrationStage):
instance_extra_exclude = None
# Query provider for this factory
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_provider WHERE provider_name = %s",
- (provider_name_filter,)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_provider WHERE provider_name = %s", (provider_name_filter,))
providers = cursor.fetchall()
- for provider_id, in providers:
+ for (provider_id,) in providers:
# Query instances for this provider, with optional extra include/exclude filter
if instance_extra_include and instance_extra_exclude:
cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s AND extra NOT LIKE %s",
- (provider_id, instance_extra_include, instance_extra_exclude)
+ "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s AND extra NOT LIKE %s", (provider_id, instance_extra_include, instance_extra_exclude)
)
elif instance_extra_include:
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s",
- (provider_id, instance_extra_include)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra LIKE %s", (provider_id, instance_extra_include))
elif instance_extra_exclude:
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra NOT LIKE %s",
- (provider_id, instance_extra_exclude)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_instance WHERE provider_id = %s AND extra NOT LIKE %s", (provider_id, instance_extra_exclude))
else:
- cursor = self.db.execute_sql(
- "SELECT id FROM tenant_model_instance WHERE provider_id = %s",
- (provider_id,)
- )
+ cursor = self.db.execute_sql("SELECT id FROM tenant_model_instance WHERE provider_id = %s", (provider_id,))
instances = cursor.fetchall()
if not instances:
logger.warning(f"No instances found for provider '{provider_name_filter}' (id={provider_id}), skipping")
continue
- for instance_id, in instances:
+ for (instance_id,) in instances:
for llm in llm_list:
model_name = llm.get("llm_name", "")
if not model_name:
@@ -1484,9 +1448,7 @@ class TenantModelSeedingStage(MigrationStage):
for mt in model_types:
# Check if record already exists
cursor = self.db.execute_sql(
- "SELECT COUNT(*) FROM tenant_model "
- "WHERE provider_id = %s AND instance_id = %s AND model_name = %s AND model_type = %s",
- (provider_id, instance_id, model_name, mt)
+ "SELECT COUNT(*) FROM tenant_model WHERE provider_id = %s AND instance_id = %s AND model_name = %s AND model_type = %s", (provider_id, instance_id, model_name, mt)
)
if cursor.fetchone()[0] > 0:
continue
@@ -1501,8 +1463,7 @@ class TenantModelSeedingStage(MigrationStage):
if self.dry_run:
logger.info(f"[DRY RUN] Would insert {len(all_records)} records")
for model_name, provider_id, instance_id, mt, status, extra in all_records[:5]:
- logger.info(f" model_name={model_name}, provider_id={provider_id}, "
- f"instance_id={instance_id}, model_type={mt}, status={status}, extra={extra}")
+ logger.info(f" model_name={model_name}, provider_id={provider_id}, instance_id={instance_id}, model_type={mt}, status={status}, extra={extra}")
if len(all_records) > 5:
logger.info(f" ... and {len(all_records) - 5} more records")
return len(all_records), self.target_tables
@@ -1510,7 +1471,7 @@ class TenantModelSeedingStage(MigrationStage):
# Insert records in batches
batch_size = 100
for i in range(0, len(all_records), batch_size):
- batch = all_records[i:i + batch_size]
+ batch = all_records[i : i + batch_size]
values = []
for model_name, provider_id, instance_id, mt, status, extra in batch:
record_id = self.generate_uuid()
@@ -1518,17 +1479,19 @@ class TenantModelSeedingStage(MigrationStage):
mt_escaped = mt.replace("'", "''") if mt else ""
extra_escaped = extra.replace("'", "''") if extra else "{}"
status_escaped = status.replace("'", "''") if status else "active"
- values.append(f"('{record_id}', '{model_name_escaped}', '{provider_id}', "
- f"'{instance_id}', '{mt_escaped}', '{status_escaped}', "
- f"'{extra_escaped}', "
- f"{current_ts * 1000}, FROM_UNIXTIME({current_ts}), "
- f"{current_ts * 1000}, FROM_UNIXTIME({current_ts}))")
+ values.append(
+ f"('{record_id}', '{model_name_escaped}', '{provider_id}', "
+ f"'{instance_id}', '{mt_escaped}', '{status_escaped}', "
+ f"'{extra_escaped}', "
+ f"{current_ts * 1000}, FROM_UNIXTIME({current_ts}), "
+ f"{current_ts * 1000}, FROM_UNIXTIME({current_ts}))"
+ )
insert_sql = f"""
INSERT INTO tenant_model
(id, model_name, provider_id, instance_id, model_type, status, extra,
create_time, create_date, update_time, update_date)
- VALUES {', '.join(values)}
+ VALUES {", ".join(values)}
"""
self.db.execute_sql(insert_sql)
rows_inserted += len(batch)
@@ -1568,13 +1531,13 @@ class ModelTypeMergeStage(MigrationStage):
# Mapping from LLMType string values to ModelTypeBinary integer values
MODEL_TYPE_STR_TO_INT = {
- "chat": 1, # 0b0000001
+ "chat": 1, # 0b0000001
"embedding": 2, # 0b0000010
"speech2text": 4, # 0b0000100
"image2text": 8, # 0b0001000
- "rerank": 16, # 0b0010000
- "tts": 32, # 0b0100000
- "ocr": 64, # 0b1000000
+ "rerank": 16, # 0b0010000
+ "tts": 32, # 0b0100000
+ "ocr": 64, # 0b1000000
}
def current_timestamp(self) -> int:
@@ -1616,19 +1579,15 @@ class ModelTypeMergeStage(MigrationStage):
return 0, self.target_tables
# Load all records from tenant_model
- cursor = self.db.execute_sql(
- "SELECT id, model_name, provider_id, instance_id, model_type, status, extra, "
- "create_time, create_date, update_time, update_date "
- "FROM tenant_model ORDER BY id"
- )
+ cursor = self.db.execute_sql("SELECT id, model_name, provider_id, instance_id, model_type, status, extra, create_time, create_date, update_time, update_date FROM tenant_model ORDER BY id")
all_rows = cursor.fetchall()
# Group by (provider_id, instance_id, model_name)
from collections import defaultdict
+
groups = defaultdict(list)
for row in all_rows:
- id_, model_name, provider_id, instance_id, model_type_str, status, extra, \
- create_time, create_date, update_time, update_date = row
+ id_, model_name, provider_id, instance_id, model_type_str, status, extra, create_time, create_date, update_time, update_date = row
groups[(provider_id, instance_id, model_name)].append(row)
# Merge each group into a single record
@@ -1656,18 +1615,13 @@ class ModelTypeMergeStage(MigrationStage):
merged_status = first_non_unsupported_status or "active"
# Use first row's values for all other fields, but replace id, model_type, status
- id_, model_name, provider_id, instance_id, _, _, extra, \
- create_time, create_date, update_time, update_date = first_row
+ id_, model_name, provider_id, instance_id, _, _, extra, create_time, create_date, update_time, update_date = first_row
# Only include records whose merged status is "active"
if merged_status != "active":
continue
- merged_records.append((
- self.generate_uuid(), model_name, provider_id, instance_id,
- merged_type, merged_status, extra,
- create_time, create_date, update_time, update_date
- ))
+ merged_records.append((self.generate_uuid(), model_name, provider_id, instance_id, merged_type, merged_status, extra, create_time, create_date, update_time, update_date))
if not merged_records:
logger.info("No records to merge")
@@ -1676,13 +1630,10 @@ class ModelTypeMergeStage(MigrationStage):
logger.info(f"Merging {len(all_rows)} rows into {len(merged_records)} rows...")
if self.dry_run:
- logger.info(f"[DRY RUN] Would insert {len(merged_records)} merged rows, "
- f"then rename tables")
+ logger.info(f"[DRY RUN] Would insert {len(merged_records)} merged rows, then rename tables")
for rec in merged_records[:5]:
_, model_name, provider_id, instance_id, merged_type, status, extra, *_ = rec
- logger.info(f" model_name={model_name}, provider_id={provider_id}, "
- f"instance_id={instance_id}, model_type={merged_type}, "
- f"status={status}, extra={extra}")
+ logger.info(f" model_name={model_name}, provider_id={provider_id}, instance_id={instance_id}, model_type={merged_type}, status={status}, extra={extra}")
if len(merged_records) > 5:
logger.info(f" ... and {len(merged_records) - 5} more rows")
return len(merged_records), self.target_tables
@@ -1690,11 +1641,10 @@ class ModelTypeMergeStage(MigrationStage):
# Insert merged records into temporary table
batch_size = 100
for i in range(0, len(merged_records), batch_size):
- batch = merged_records[i:i + batch_size]
+ batch = merged_records[i : i + batch_size]
values = []
for rec in batch:
- id_, model_name, provider_id, instance_id, merged_type, status, extra, \
- create_time, create_date, update_time, update_date = rec
+ id_, model_name, provider_id, instance_id, merged_type, status, extra, create_time, create_date, update_time, update_date = rec
model_name_escaped = (model_name.replace("'", "''") if model_name else "") or None
extra_escaped = extra.replace("'", "''") if extra else "{}"
status_escaped = status.replace("'", "''") if status else "active"
@@ -1703,17 +1653,19 @@ class ModelTypeMergeStage(MigrationStage):
update_time_val = update_time if update_time is not None else current_ts * 1000
create_date_sql = f"FROM_UNIXTIME({int(create_time_val / 1000)})" if create_time_val else "NULL"
update_date_sql = f"FROM_UNIXTIME({int(update_time_val / 1000)})" if update_time_val else "NULL"
- values.append(f"('{id_}', '{model_name_escaped}', '{provider_id}', "
- f"'{instance_id}', {merged_type}, '{status_escaped}', "
- f"'{extra_escaped}', "
- f"{create_time_val}, {create_date_sql}, "
- f"{update_time_val}, {update_date_sql})")
+ values.append(
+ f"('{id_}', '{model_name_escaped}', '{provider_id}', "
+ f"'{instance_id}', {merged_type}, '{status_escaped}', "
+ f"'{extra_escaped}', "
+ f"{create_time_val}, {create_date_sql}, "
+ f"{update_time_val}, {update_date_sql})"
+ )
insert_sql = f"""
INSERT INTO tenant_model_merge_tmp
(id, model_name, provider_id, instance_id, model_type, status, extra,
create_time, create_date, update_time, update_date)
- VALUES {', '.join(values)}
+ VALUES {", ".join(values)}
"""
self.db.execute_sql(insert_sql)
rows_inserted += len(batch)
@@ -1825,9 +1777,7 @@ class TenantModelIdMigrationStage(MigrationStage):
has_work = True
break
# Check if there are NULL values that should be populated
- cursor = self.db.execute_sql(
- f"SELECT COUNT(*) FROM `{table_name}` WHERE `{tenant_id_col}` IS NULL OR `{tenant_id_col}` = ''"
- )
+ cursor = self.db.execute_sql(f"SELECT COUNT(*) FROM `{table_name}` WHERE `{tenant_id_col}` IS NULL OR `{tenant_id_col}` = ''")
null_count = cursor.fetchone()[0]
if null_count > 0:
has_work = True
@@ -1860,18 +1810,14 @@ class TenantModelIdMigrationStage(MigrationStage):
# Column does not exist yet — add it as VARCHAR(32)
logger.info(f"Adding column {table_name}.{tenant_id_col} as VARCHAR(32) NULL")
if not self.dry_run:
- self.db.execute_sql(
- f"ALTER TABLE `{table_name}` ADD COLUMN `{tenant_id_col}` VARCHAR(32) NULL"
- )
+ self.db.execute_sql(f"ALTER TABLE `{table_name}` ADD COLUMN `{tenant_id_col}` VARCHAR(32) NULL")
tables_operated.add(table_name)
continue
col_type = self.db.get_column_type(table_name, tenant_id_col)
if col_type and col_type.lower() in ("int", "bigint", "integer"):
logger.info(f"Converting {table_name}.{tenant_id_col} from {col_type} to VARCHAR(32)")
if not self.dry_run:
- self.db.execute_sql(
- f"ALTER TABLE `{table_name}` MODIFY COLUMN `{tenant_id_col}` VARCHAR(32) NULL"
- )
+ self.db.execute_sql(f"ALTER TABLE `{table_name}` MODIFY COLUMN `{tenant_id_col}` VARCHAR(32) NULL")
tables_operated.add(table_name)
# Step 2: Build lookup cache from tenant_model joined with provider + instance
@@ -1893,9 +1839,7 @@ class TenantModelIdMigrationStage(MigrationStage):
# Get rows where tenant_*_id is NULL or empty
cursor = self.db.execute_sql(
- f"SELECT id, `{legacy_col}` FROM `{table_name}` "
- f"WHERE (`{tenant_id_col}` IS NULL OR `{tenant_id_col}` = '') "
- f"AND `{legacy_col}` IS NOT NULL AND `{legacy_col}` != ''"
+ f"SELECT id, `{legacy_col}` FROM `{table_name}` WHERE (`{tenant_id_col}` IS NULL OR `{tenant_id_col}` = '') AND `{legacy_col}` IS NOT NULL AND `{legacy_col}` != ''"
)
# Also need tenant_id for model lookup
@@ -1903,9 +1847,7 @@ class TenantModelIdMigrationStage(MigrationStage):
# For knowledgebase, dialog, memory we also need tenant_id
if table_name == "tenant":
cursor = self.db.execute_sql(
- f"SELECT id, `{legacy_col}` FROM `{table_name}` "
- f"WHERE (`{tenant_id_col}` IS NULL OR `{tenant_id_col}` = '') "
- f"AND `{legacy_col}` IS NOT NULL AND `{legacy_col}` != ''"
+ f"SELECT id, `{legacy_col}` FROM `{table_name}` WHERE (`{tenant_id_col}` IS NULL OR `{tenant_id_col}` = '') AND `{legacy_col}` IS NOT NULL AND `{legacy_col}` != ''"
)
while True:
rows = cursor.fetchmany(self.scan_batch_size)
@@ -1930,9 +1872,7 @@ class TenantModelIdMigrationStage(MigrationStage):
tables_operated.add(table_name)
else:
cursor = self.db.execute_sql(
- f"SELECT id, tenant_id, `{legacy_col}` FROM `{table_name}` "
- f"WHERE (`{tenant_id_col}` IS NULL OR `{tenant_id_col}` = '') "
- f"AND `{legacy_col}` IS NOT NULL AND `{legacy_col}` != ''"
+ f"SELECT id, tenant_id, `{legacy_col}` FROM `{table_name}` WHERE (`{tenant_id_col}` IS NULL OR `{tenant_id_col}` = '') AND `{legacy_col}` IS NOT NULL AND `{legacy_col}` != ''"
)
while True:
rows = cursor.fetchmany(self.scan_batch_size)
diff --git a/tools/scripts/rename_models_providers.py b/tools/scripts/rename_models_providers.py
new file mode 100644
index 0000000000..6538e82097
--- /dev/null
+++ b/tools/scripts/rename_models_providers.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+"""Rename provider name fields in conf/models/*.json to match llm_factories.json."""
+import json, os
+
+REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
+MODELS_DIR = os.path.join(REPO_ROOT, "conf", "models")
+
+# Valid mappings: models current name → llm_factories name
+CHANGES = {
+ "avian": "Avian",
+ "Baichuan": "BaiChuan",
+ "Baidu": "BaiduYiyan",
+ "CoHere": "Cohere",
+ "FishAudio": "Fish Audio",
+ "Gitee": "GiteeAI",
+ "Google": "Gemini",
+ "JieKouAI": "Jiekou.AI",
+ "lmstudio": "LM-Studio",
+ "localai": "LocalAI",
+ "modelscope": "ModelScope",
+ "Novita": "NovitaAI",
+ "Nvidia": "NVIDIA",
+ "ollama": "Ollama",
+ "SiliconFlow": "SILICONFLOW",
+ "HunYuan": "Tencent Hunyuan",
+ "Aliyun": "Tongyi-Qianwen",
+ "vllm": "VLLM",
+ "Voyage": "Voyage AI",
+ "xinference": "Xinference",
+ "XunFei": "XunFei Spark",
+}
+
+def main():
+ # Build current name → filename mapping
+ file_map = {}
+ for fn in os.listdir(MODELS_DIR):
+ if not fn.endswith(".json"):
+ continue
+ with open(os.path.join(MODELS_DIR, fn)) as f:
+ d = json.load(f)
+ file_map[d["name"]] = fn
+
+ for old_name, new_name in CHANGES.items():
+ fn = file_map[old_name]
+ path = os.path.join(MODELS_DIR, fn)
+ with open(path) as f:
+ d = json.load(f)
+ d["name"] = new_name
+ with open(path, "w") as f:
+ json.dump(d, f, indent=2, ensure_ascii=False)
+ f.write("\n")
+ print(f'{fn}: "{old_name}" -> "{new_name}"')
+
+if __name__ == "__main__":
+ main()
diff --git a/web/src/components/memories-form-field.tsx b/web/src/components/memories-form-field.tsx
index 61c5ab0477..7d71cc7ea3 100644
--- a/web/src/components/memories-form-field.tsx
+++ b/web/src/components/memories-form-field.tsx
@@ -52,24 +52,21 @@ export function useDisableDifferenceEmbeddingMemory(name: string) {
}, [memoryIds, memoryList]);
const options = useMemo(() => {
- return memoryList
- .filter(Boolean)
- .map((item: IMemory) => {
- return {
- label: item.name,
- icon: () => (
-
- ),
- suffix: ,
- value: item.id,
- disabled:
- item.embd_id !== selectedEmbedId && selectedEmbedId !== '',
- };
- });
+ return memoryList.filter(Boolean).map((item: IMemory) => {
+ return {
+ label: item.name,
+ icon: () => (
+
+ ),
+ suffix: ,
+ value: item.id,
+ disabled: item.embd_id !== selectedEmbedId && selectedEmbedId !== '',
+ };
+ });
}, [memoryList, selectedEmbedId]);
return {