diff --git a/api/app/controllers/emotion_config_controller.py b/api/app/controllers/emotion_config_controller.py index 752f4c49..b1630ee6 100644 --- a/api/app/controllers/emotion_config_controller.py +++ b/api/app/controllers/emotion_config_controller.py @@ -7,10 +7,11 @@ Routes: GET /memory/config/emotion - 获取情绪引擎配置 POST /memory/config/emotion - 更新情绪引擎配置 """ +import uuid from fastapi import APIRouter, Depends, Query, HTTPException, status from pydantic import BaseModel, Field -from typing import Optional +from typing import Optional, Union from sqlalchemy.orm import Session from uuid import UUID @@ -38,7 +39,7 @@ class EmotionConfigQuery(BaseModel): class EmotionConfigUpdate(BaseModel): """情绪配置更新请求模型""" - config_id: UUID = Field(..., description="配置ID") + config_id: Union[uuid.UUID, int, str]= Field(..., description="配置ID") emotion_enabled: bool = Field(..., description="是否启用情绪提取") emotion_model_id: Optional[str] = Field(None, description="情绪分析专用模型ID") emotion_extract_keywords: bool = Field(..., description="是否提取情绪关键词") @@ -159,6 +160,7 @@ def update_emotion_config( } } """ + config.config_id=resolve_config_id(config.config_id, db) try: api_logger.info( f"用户 {current_user.username} 请求更新情绪配置", diff --git a/api/app/controllers/memory_reflection_controller.py b/api/app/controllers/memory_reflection_controller.py index dbf3bf16..7941be35 100644 --- a/api/app/controllers/memory_reflection_controller.py +++ b/api/app/controllers/memory_reflection_controller.py @@ -45,6 +45,7 @@ async def save_reflection_config( """Save reflection configuration to data_comfig table""" try: config_id = request.config_id + config_id = resolve_config_id(config_id, db) if not config_id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -164,6 +165,7 @@ async def start_reflection_configs( db: Session = Depends(get_db), ) -> dict: """通过config_id查询memory_config表中的反思配置信息""" + config_id = resolve_config_id(config_id, db) try: config_id=resolve_config_id(config_id,db) api_logger.info(f"用户 {current_user.username} 查询反思配置,config_id: {config_id}") diff --git a/api/app/controllers/memory_storage_controller.py b/api/app/controllers/memory_storage_controller.py index f4773bc3..73394c86 100644 --- a/api/app/controllers/memory_storage_controller.py +++ b/api/app/controllers/memory_storage_controller.py @@ -33,6 +33,7 @@ from app.services.memory_storage_service import ( search_entity, search_statement, ) +from app.utils.config_utils import resolve_config_id # Get API logger api_logger = get_api_logger() @@ -81,7 +82,6 @@ def create_config( db: Session = Depends(get_db), ) -> dict: workspace_id = current_user.current_workspace_id - # 检查用户是否已选择工作空间 if workspace_id is None: api_logger.warning(f"用户 {current_user.username} 尝试创建配置但未选择工作空间") @@ -101,7 +101,7 @@ def create_config( @router.delete("/delete_config", response_model=ApiResponse) # 删除数据库中的内容(按配置名称) def delete_config( - config_id: UUID, + config_id: UUID|int, force: bool = Query(False, description="是否强制删除(即使有终端用户正在使用)"), current_user: User = Depends(get_current_user), db: Session = Depends(get_db), @@ -117,7 +117,7 @@ def delete_config( force: 设置为 true 可强制删除(即使有终端用户正在使用) """ workspace_id = current_user.current_workspace_id - + config_id=resolve_config_id(config_id, db) # 检查用户是否已选择工作空间 if workspace_id is None: api_logger.warning(f"用户 {current_user.username} 尝试删除配置但未选择工作空间") @@ -180,7 +180,7 @@ def update_config( db: Session = Depends(get_db), ) -> dict: workspace_id = current_user.current_workspace_id - + payload.config_id = resolve_config_id(payload.config_id, db) # 检查用户是否已选择工作空间 if workspace_id is None: api_logger.warning(f"用户 {current_user.username} 尝试更新配置但未选择工作空间") @@ -203,7 +203,7 @@ def update_config_extracted( db: Session = Depends(get_db), ) -> dict: workspace_id = current_user.current_workspace_id - + payload.config_id = resolve_config_id(payload.config_id, db) # 检查用户是否已选择工作空间 if workspace_id is None: api_logger.warning(f"用户 {current_user.username} 尝试更新提取配置但未选择工作空间") @@ -230,7 +230,7 @@ def read_config_extracted( db: Session = Depends(get_db), ) -> dict: workspace_id = current_user.current_workspace_id - + config_id = resolve_config_id(config_id, db) # 检查用户是否已选择工作空间 if workspace_id is None: api_logger.warning(f"用户 {current_user.username} 尝试读取提取配置但未选择工作空间") @@ -278,6 +278,7 @@ async def pilot_run( f"Pilot run requested: config_id={payload.config_id}, " f"dialogue_text_length={len(payload.dialogue_text)}" ) + payload.config_id = resolve_config_id(payload.config_id, db) svc = DataConfigService(db) return StreamingResponse( svc.pilot_run_stream(payload), diff --git a/api/app/controllers/model_controller.py b/api/app/controllers/model_controller.py index 509f7cad..d76f0b1d 100644 --- a/api/app/controllers/model_controller.py +++ b/api/app/controllers/model_controller.py @@ -7,7 +7,7 @@ from app.core.error_codes import BizCode from app.core.exceptions import BusinessException from app.db import get_db from app.dependencies import get_current_user -from app.models.models_model import ModelProvider, ModelType +from app.models.models_model import ModelProvider, ModelType, LoadBalanceStrategy from app.models.user_model import User from app.repositories.model_repository import ModelConfigRepository from app.schemas import model_schema @@ -33,6 +33,10 @@ def get_model_types(): def get_model_providers(): return success(msg="获取模型提供商成功", data=list(ModelProvider)) +@router.get("/strategy", response_model=ApiResponse) +def get_model_strategies(): + return success(msg="获取模型策略成功", data=list(LoadBalanceStrategy)) + @router.get("", response_model=ApiResponse) def get_model_list( @@ -91,7 +95,7 @@ def get_model_list( @router.get("/new", response_model=ApiResponse) -def get_model_list( +def get_model_list_new( type: Optional[list[str]] = Query(None, description="模型类型筛选(支持多个,如 ?type=LLM 或 ?type=LLM,EMBEDDING)"), provider: Optional[model_schema.ModelProvider] = Query(None, description="提供商筛选(基于ModelConfig)"), is_active: Optional[bool] = Query(None, description="激活状态筛选"), @@ -198,6 +202,10 @@ def update_model_base( ): """更新基础模型""" + # 不允许更改type类型 + if data.type is not None or data.provider is not None: + raise BusinessException("不允许更改模型类型和供应商", BizCode.INVALID_PARAMETER) + result = ModelBaseService.update_model_base(db=db, model_base_id=model_base_id, data=data) return success(data=model_schema.ModelBase.model_validate(result), msg="基础模型更新成功") @@ -318,6 +326,8 @@ async def update_composite_model( api_logger.info(f"更新组合模型请求: model_id={model_id}, 用户: {current_user.username}") try: + if model_data.type is not None: + raise BusinessException("不允许更改模型类型和供应商", BizCode.INVALID_PARAMETER) result_orm = await ModelConfigService.update_composite_model(db=db, model_id=model_id, model_data=model_data, tenant_id=current_user.tenant_id) api_logger.info(f"组合模型更新成功: {result_orm.name} (ID: {model_id})") @@ -460,8 +470,8 @@ async def create_model_api_key_by_provider( created_keys = await ModelApiKeyService.create_api_key_by_provider(db=db, data=create_data) api_logger.info(f"API Key创建成功: 关联{len(created_keys)}个模型") - result_list = [model_schema.ModelApiKey.model_validate(key) for key in created_keys] - return success(data=result_list, msg=f"成功为 {len(created_keys)} 个模型创建API Key") + # result_list = [model_schema.ModelApiKey.model_validate(key) for key in created_keys] + return success(data=f"成功为 {len(created_keys)} 个模型创建API Key", msg=f"成功为 {len(created_keys)} 个模型创建API Key") except Exception as e: api_logger.error(f"创建API Key失败: {str(e)}") raise diff --git a/api/app/controllers/service/app_api_controller.py b/api/app/controllers/service/app_api_controller.py index 94d7b60b..31e799d2 100644 --- a/api/app/controllers/service/app_api_controller.py +++ b/api/app/controllers/service/app_api_controller.py @@ -235,11 +235,11 @@ async def chat( message=payload.message, conversation_id=conversation.id, # 使用已创建的会话 ID - user_id=new_end_user.id, # 转换为字符串 + user_id=end_user_id, # 转换为字符串 variables=payload.variables, config=config, web_search=web_search, - memory=payload.memory, + memory=memory, storage_type=storage_type, user_rag_memory_id=user_rag_memory_id, app_id=app.id, @@ -268,11 +268,11 @@ async def chat( message=payload.message, conversation_id=conversation.id, # 使用已创建的会话 ID - user_id=new_end_user.id, # 转换为字符串 + user_id=end_user_id, # 转换为字符串 variables=payload.variables, config=config, web_search=web_search, - memory=payload.memory, + memory=memory, storage_type=storage_type, user_rag_memory_id=user_rag_memory_id, app_id=app.id, diff --git a/api/app/core/models/scripts/__init__.py b/api/app/core/models/scripts/__init__.py new file mode 100644 index 00000000..657b12fd --- /dev/null +++ b/api/app/core/models/scripts/__init__.py @@ -0,0 +1 @@ +"""模型配置脚本模块""" diff --git a/api/app/core/models/scripts/bedrock_models.yaml b/api/app/core/models/scripts/bedrock_models.yaml new file mode 100644 index 00000000..e561310d --- /dev/null +++ b/api/app/core/models/scripts/bedrock_models.yaml @@ -0,0 +1,174 @@ +provider: bedrock +enabled: true +models: +- name: ai21 + type: llm + provider: bedrock + description: AI21 Labs大语言模型,completion生成模式,256000上下文窗口 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + logo: bedrock +- name: amazon nova + type: llm + provider: bedrock + description: Amazon Nova大语言模型,支持智能体思考、工具调用、流式工具调用、视觉能力,300000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - stream-tool-call + - vision + logo: bedrock +- name: anthropic claude + type: llm + provider: bedrock + description: Anthropic Claude大语言模型,支持智能体思考、视觉能力、工具调用、流式工具调用、文档处理,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - vision + - tool-call + - stream-tool-call + - document + logo: bedrock +- name: cohere + type: llm + provider: bedrock + description: Cohere大语言模型,支持智能体思考、工具调用、流式工具调用,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - stream-tool-call + logo: bedrock +- name: deepseek + type: llm + provider: bedrock + description: DeepSeek大语言模型,支持智能体思考、视觉能力、工具调用、流式工具调用,32768上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - vision + - tool-call + - stream-tool-call + logo: bedrock +- name: meta + type: llm + provider: bedrock + description: Meta Llama大语言模型,支持智能体思考、工具调用,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + logo: bedrock +- name: mistral + type: llm + provider: bedrock + description: Mistral AI大语言模型,支持智能体思考、工具调用,32000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + logo: bedrock +- name: openai + type: llm + provider: bedrock + description: OpenAI大语言模型,支持智能体思考、工具调用、流式工具调用,32768上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - stream-tool-call + logo: bedrock +- name: qwen + type: llm + provider: bedrock + description: Qwen大语言模型,支持智能体思考、工具调用、流式工具调用,32768上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - stream-tool-call + logo: bedrock +- name: amazon.rerank-v1:0 + type: rerank + provider: bedrock + description: amazon.rerank-v1:0重排序模型,5120上下文窗口 + is_deprecated: false + is_official: true + tags: + - 重排序模型 + logo: bedrock +- name: cohere.rerank-v3-5:0 + type: rerank + provider: bedrock + description: cohere.rerank-v3-5:0重排序模型,5120上下文窗口 + is_deprecated: false + is_official: true + tags: + - 重排序模型 + logo: bedrock +- name: amazon.nova-2-multimodal-embeddings-v1:0 + type: embedding + provider: bedrock + description: amazon.nova-2-multimodal-embeddings-v1:0文本嵌入模型,支持视觉能力,8192上下文窗口 + is_deprecated: false + is_official: true + tags: + - 文本嵌入模型 + - vision + logo: bedrock +- name: amazon.titan-embed-text-v1 + type: embedding + provider: bedrock + description: amazon.titan-embed-text-v1文本嵌入模型,8192上下文窗口 + is_deprecated: false + is_official: true + tags: + - 文本嵌入模型 + logo: bedrock +- name: amazon.titan-embed-text-v2:0 + type: embedding + provider: bedrock + description: amazon.titan-embed-text-v2:0文本嵌入模型,8192上下文窗口 + is_deprecated: false + is_official: true + tags: + - 文本嵌入模型 + logo: bedrock +- name: cohere.embed-english-v3 + type: embedding + provider: bedrock + description: Cohere Embed 3 English文本嵌入模型,512上下文窗口 + is_deprecated: false + is_official: true + tags: + - 文本嵌入模型 + logo: bedrock +- name: cohere.embed-multilingual-v3 + type: embedding + provider: bedrock + description: Cohere Embed 3 Multilingual文本嵌入模型,512上下文窗口 + is_deprecated: false + is_official: true + tags: + - 文本嵌入模型 + logo: bedrock diff --git a/api/app/core/models/scripts/dashscope_models.yaml b/api/app/core/models/scripts/dashscope_models.yaml new file mode 100644 index 00000000..c02ca2cb --- /dev/null +++ b/api/app/core/models/scripts/dashscope_models.yaml @@ -0,0 +1,820 @@ +provider: dashscope +enabled: true +models: +- name: deepseek-r1-distill-qwen-14b + type: llm + provider: dashscope + description: DeepSeek-R1-Distill-Qwen-14B大语言模型,支持智能体思考,32000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: dashscope +- name: deepseek-r1-distill-qwen-32b + type: llm + provider: dashscope + description: DeepSeek-R1-Distill-Qwen-32B大语言模型,支持智能体思考,32000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: dashscope +- name: deepseek-r1 + type: llm + provider: dashscope + description: DeepSeek-R1大语言模型,支持智能体思考,131072超大上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: dashscope +- name: deepseek-v3.1 + type: llm + provider: dashscope + description: DeepSeek-V3.1大语言模型,支持智能体思考,131072超大上下文窗口,对话模式,支持丰富生成参数调节 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: dashscope +- name: deepseek-v3.2-exp + type: llm + provider: dashscope + description: DeepSeek-V3.2-exp实验版大语言模型,支持智能体思考,131072超大上下文窗口,对话模式,支持丰富生成参数调节 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: dashscope +- name: deepseek-v3.2 + type: llm + provider: dashscope + description: DeepSeek-V3.2大语言模型,支持智能体思考,131072超大上下文窗口,对话模式,支持丰富生成参数调节 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: dashscope +- name: deepseek-v3 + type: llm + provider: dashscope + description: DeepSeek-V3大语言模型,支持智能体思考,64000上下文窗口,对话模式,支持文本与JSON格式输出 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: dashscope +- name: farui-plus + type: llm + provider: dashscope + description: farui-plus大语言模型,支持多工具调用、智能体思考、流式工具调用,12288上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: glm-4.7 + type: llm + provider: dashscope + description: GLM-4.7大语言模型,支持多工具调用、智能体思考、流式工具调用,202752超大上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qvq-max-latest + type: llm + provider: dashscope + description: qvq-max-latest大语言模型,支持视觉、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - vision + - agent-thought + - stream-tool-call + logo: dashscope +- name: qvq-max + type: llm + provider: dashscope + description: qvq-max大语言模型,支持视觉、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - vision + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-coder-turbo-0919 + type: llm + provider: dashscope + description: qwen-coder-turbo-0919代码专用大语言模型,支持智能体思考,131072上下文窗口,对话模式,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - 代码模型 + - agent-thought + logo: dashscope +- name: qwen-max-latest + type: llm + provider: dashscope + description: qwen-max-latest大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,支持联网搜索 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-max-longcontext + type: llm + provider: dashscope + description: qwen-max-longcontext长上下文大语言模型,支持多工具调用、智能体思考、流式工具调用,32000上下文窗口,对话模式,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-max + type: llm + provider: dashscope + description: qwen-max大语言模型,支持多工具调用、智能体思考、流式工具调用,32768上下文窗口,对话模式,支持联网搜索 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-mt-plus + type: llm + provider: dashscope + description: qwen-mt-plus多语言翻译大语言模型,支持智能体思考,16384上下文窗口,对话模式,支持多语种互译与领域翻译适配 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 翻译模型 + - agent-thought + logo: dashscope +- name: qwen-mt-turbo + type: llm + provider: dashscope + description: qwen-mt-turbo轻量化多语言翻译大语言模型,支持智能体思考,16384上下文窗口,对话模式,支持多语种互译与领域翻译适配 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 翻译模型 + - agent-thought + logo: dashscope +- name: qwen-plus-0112 + type: llm + provider: dashscope + description: qwen-plus-0112大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,支持联网搜索,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-plus-0125 + type: llm + provider: dashscope + description: qwen-plus-0125大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,支持联网搜索,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-plus-0723 + type: llm + provider: dashscope + description: qwen-plus-0723大语言模型,支持多工具调用、智能体思考、流式工具调用,32000上下文窗口,对话模式,支持联网搜索,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-plus-0806 + type: llm + provider: dashscope + description: qwen-plus-0806大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,支持联网搜索,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-plus-0919 + type: llm + provider: dashscope + description: qwen-plus-0919大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,支持联网搜索,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-plus-1125 + type: llm + provider: dashscope + description: qwen-plus-1125大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,支持联网搜索,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-plus-1127 + type: llm + provider: dashscope + description: qwen-plus-1127大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,支持联网搜索,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-plus-1220 + type: llm + provider: dashscope + description: qwen-plus-1220大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen-vl-max + type: llm + provider: dashscope + description: qwen-vl-max多模态大模型,支持视觉理解、智能体思考、视频理解,131072上下文窗口,对话模式,未废弃 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwen-vl-plus-0809 + type: llm + provider: dashscope + description: qwen-vl-plus-0809多模态大模型,支持视觉理解、智能体思考、视频理解,32768上下文窗口,对话模式,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwen-vl-plus-2025-01-02 + type: llm + provider: dashscope + description: qwen-vl-plus-2025-01-02多模态大模型,支持视觉理解、智能体思考、视频理解,32768上下文窗口,对话模式,未废弃 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwen-vl-plus-2025-01-25 + type: llm + provider: dashscope + description: qwen-vl-plus-2025-01-25多模态大模型,支持视觉理解、智能体思考、视频理解,131072上下文窗口,对话模式,未废弃 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwen-vl-plus-latest + type: llm + provider: dashscope + description: qwen-vl-plus-latest多模态大模型,支持视觉理解、智能体思考、视频理解,131072上下文窗口,对话模式,未废弃 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwen-vl-plus + type: llm + provider: dashscope + description: qwen-vl-plus多模态大模型,支持视觉理解、智能体思考、视频理解,131072上下文窗口,对话模式,未废弃 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwen2.5-0.5b-instruct + type: llm + provider: dashscope + description: qwen2.5-0.5b-instruct大语言模型,支持多工具调用、智能体思考、流式工具调用,32768上下文窗口,对话模式,未废弃 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-14b + type: llm + provider: dashscope + description: qwen3-14b大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-235b-a22b-instruct-2507 + type: llm + provider: dashscope + description: qwen3-235b-a22b-instruct-2507大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-235b-a22b-thinking-2507 + type: llm + provider: dashscope + description: qwen3-235b-a22b-thinking-2507大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-235b-a22b + type: llm + provider: dashscope + description: qwen3-235b-a22b大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-30b-a3b-instruct-2507 + type: llm + provider: dashscope + description: qwen3-30b-a3b-instruct-2507大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-30b-a3b + type: llm + provider: dashscope + description: qwen3-30b-a3b大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-32b + type: llm + provider: dashscope + description: qwen3-32b大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-4b + type: llm + provider: dashscope + description: qwen3-4b大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-8b + type: llm + provider: dashscope + description: qwen3-8b大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-coder-30b-a3b-instruct + type: llm + provider: dashscope + description: qwen3-coder-30b-a3b-instruct大语言模型,支持智能体思考,262144上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 代码模型 + - agent-thought + logo: dashscope +- name: qwen3-coder-480b-a35b-instruct + type: llm + provider: dashscope + description: qwen3-coder-480b-a35b-instruct大语言模型,支持智能体思考,262144上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 代码模型 + - agent-thought + logo: dashscope +- name: qwen3-coder-plus-2025-09-23 + type: llm + provider: dashscope + description: qwen3-coder-plus-2025-09-23大语言模型,支持智能体思考,1000000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 代码模型 + - agent-thought + logo: dashscope +- name: qwen3-coder-plus + type: llm + provider: dashscope + description: qwen3-coder-plus大语言模型,支持智能体思考,1000000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 代码模型 + - agent-thought + logo: dashscope +- name: qwen3-max-2025-09-23 + type: llm + provider: dashscope + description: qwen3-max-2025-09-23大语言模型,支持多工具调用、智能体思考、流式工具调用,262144上下文窗口,对话模式,支持联网搜索 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - 联网搜索 + logo: dashscope +- name: qwen3-max-2026-01-23 + type: llm + provider: dashscope + description: qwen3-max-2026-01-23大语言模型,支持多工具调用、智能体思考、流式工具调用,262144上下文窗口,对话模式,支持联网搜索 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - 联网搜索 + logo: dashscope +- name: qwen3-max-preview + type: llm + provider: dashscope + description: qwen3-max-preview大语言模型,支持多工具调用、智能体思考、流式工具调用,262144上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-max + type: llm + provider: dashscope + description: qwen3-max大语言模型,支持多工具调用、智能体思考、流式工具调用,262144上下文窗口,对话模式,支持联网搜索 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - 联网搜索 + logo: dashscope +- name: qwen3-next-80b-a3b-instruct + type: llm + provider: dashscope + description: qwen3-next-80b-a3b-instruct大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-next-80b-a3b-thinking + type: llm + provider: dashscope + description: qwen3-next-80b-a3b-thinking大语言模型,支持多工具调用、智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwen3-omni-flash-2025-12-01 + type: llm + provider: dashscope + description: qwen3-omni-flash-2025-12-01多模态大语言模型,支持视觉、智能体思考、视频、音频能力,65536上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + - audio + logo: dashscope +- name: qwen3-vl-235b-a22b-instruct + type: llm + provider: dashscope + description: qwen3-vl-235b-a22b-instruct多模态大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉、视频能力,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + - video + logo: dashscope +- name: qwen3-vl-235b-a22b-thinking + type: llm + provider: dashscope + description: qwen3-vl-235b-a22b-thinking多模态大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉、视频能力,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + - video + logo: dashscope +- name: qwen3-vl-30b-a3b-instruct + type: llm + provider: dashscope + description: qwen3-vl-30b-a3b-instruct多模态大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉、视频能力,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + - video + logo: dashscope +- name: qwen3-vl-30b-a3b-thinking + type: llm + provider: dashscope + description: qwen3-vl-30b-a3b-thinking多模态大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉、视频能力,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + - video + logo: dashscope +- name: qwen3-vl-flash + type: llm + provider: dashscope + description: qwen3-vl-flash多模态大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉、视频能力,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + - video + logo: dashscope +- name: qwen3-vl-plus-2025-09-23 + type: llm + provider: dashscope + description: qwen3-vl-plus-2025-09-23多模态大语言模型,支持视觉、智能体思考、视频能力,262144上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwen3-vl-plus + type: llm + provider: dashscope + description: qwen3-vl-plus多模态大语言模型,支持视觉、智能体思考、视频能力,262144上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - 多模态模型 + - vision + - agent-thought + - video + logo: dashscope +- name: qwq-32b + type: llm + provider: dashscope + description: qwq-32b大语言模型,支持智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwq-plus-0305 + type: llm + provider: dashscope + description: qwq-plus-0305大语言模型,支持智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - stream-tool-call + logo: dashscope +- name: qwq-plus + type: llm + provider: dashscope + description: qwq-plus大语言模型,支持智能体思考、流式工具调用,131072上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - stream-tool-call + logo: dashscope +- name: gte-rerank-v2 + type: rerank + provider: dashscope + description: gte-rerank-v2重排序模型,4000上下文窗口 + is_deprecated: false + is_official: true + tags: + - 重排序模型 + logo: dashscope +- name: gte-rerank + type: rerank + provider: dashscope + description: gte-rerank重排序模型,4000上下文窗口 + is_deprecated: false + is_official: true + tags: + - 重排序模型 + logo: dashscope +- name: multimodal-embedding-v1 + type: embedding + provider: dashscope + description: multimodal-embedding-v1多模态嵌入模型,支持视觉能力,8192上下文窗口,最大分块数10 + is_deprecated: false + is_official: true + tags: + - 嵌入模型 + - 多模态模型 + - vision + logo: dashscope +- name: text-embedding-v1 + type: embedding + provider: dashscope + description: text-embedding-v1文本嵌入模型,2048上下文窗口,最大分块数25 + is_deprecated: false + is_official: true + tags: + - 嵌入模型 + - 文本嵌入 + logo: dashscope +- name: text-embedding-v2 + type: embedding + provider: dashscope + description: text-embedding-v2文本嵌入模型,2048上下文窗口,最大分块数25 + is_deprecated: false + is_official: true + tags: + - 嵌入模型 + - 文本嵌入 + logo: dashscope +- name: text-embedding-v3 + type: embedding + provider: dashscope + description: text-embedding-v3文本嵌入模型,8192上下文窗口,最大分块数10 + is_deprecated: false + is_official: true + tags: + - 嵌入模型 + - 文本嵌入 + logo: dashscope +- name: text-embedding-v4 + type: embedding + provider: dashscope + description: text-embedding-v4文本嵌入模型,8192上下文窗口,最大分块数10 + is_deprecated: false + is_official: true + tags: + - 嵌入模型 + - 文本嵌入 + logo: dashscope diff --git a/api/app/core/models/scripts/loader.py b/api/app/core/models/scripts/loader.py new file mode 100644 index 00000000..6469656c --- /dev/null +++ b/api/app/core/models/scripts/loader.py @@ -0,0 +1,143 @@ +"""模型配置加载器 - 用于将预定义模型批量导入到数据库""" + +import os +from pathlib import Path +from typing import Callable + +import yaml +from sqlalchemy.orm import Session +from app.models.models_model import ModelBase, ModelProvider + + +def _load_yaml_config(provider: ModelProvider) -> list[dict]: + """从YAML文件加载指定供应商的模型配置""" + config_dir = Path(__file__).parent + config_file = config_dir / f"{provider.value}_models.yaml" + + if not config_file.exists(): + return [] + + with open(config_file, 'r', encoding='utf-8') as f: + data = yaml.safe_load(f) + + # 检查是否需要加载(默认为 true) + if not data.get('enabled', True): + return [] + + return data.get('models', []) + + +def _disable_yaml_config(provider: ModelProvider) -> None: + """将YAML文件的enabled标志设置为false""" + config_dir = Path(__file__).parent + config_file = config_dir / f"{provider.value}_models.yaml" + + if not config_file.exists(): + return + + with open(config_file, 'r', encoding='utf-8') as f: + data = yaml.safe_load(f) + + data['enabled'] = False + + with open(config_file, 'w', encoding='utf-8') as f: + yaml.dump(data, f, allow_unicode=True, sort_keys=False) + + +def load_models(db: Session, providers: list[str] = None, silent: bool = False) -> dict: + """ + 加载模型配置到数据库 + + Args: + db: 数据库会话 + providers: 要加载的供应商列表,None表示加载所有 + silent: 是否静默模式(不输出详细日志) + + Returns: + dict: 加载结果统计 {"success": int, "skipped": int, "failed": int} + """ + result = {"success": 0, "skipped": 0, "failed": 0} + + # 确定要加载的供应商 + if providers: + target_providers = [ModelProvider(p) if isinstance(p, str) else p for p in providers] + else: + target_providers = [p for p in ModelProvider if p != ModelProvider.COMPOSITE] + + for provider in target_providers: + # 从YAML文件加载模型配置 + models = _load_yaml_config(provider) + + if not models: + if not silent: + print(f"警告: 供应商 '{provider.value}' 暂无预定义模型") + continue + + if not silent: + print(f"\n正在加载 {provider.value} 的 {len(models)} 个模型...") + + # provider_success = 0 + for model_data in models: + try: + # 检查模型是否已存在 + existing = db.query(ModelBase).filter( + ModelBase.name == model_data["name"], + ModelBase.provider == model_data["provider"] + ).first() + + if existing: + # 更新现有模型配置 + for key, value in model_data.items(): + setattr(existing, key, value) + db.commit() + if not silent: + print(f"更新成功: {model_data['name']}") + result["success"] += 1 + # provider_success += 1 + else: + # 创建新模型 + model = ModelBase(**model_data) + db.add(model) + db.commit() + if not silent: + print(f"添加成功: {model_data['name']}") + result["success"] += 1 + # provider_success += 1 + + except Exception as e: + db.rollback() + if not silent: + print(f"添加失败: {model_data['name']} - {str(e)}") + result["failed"] += 1 + + # 如果该供应商的模型全部加载成功,将enabled设置为false + # if provider_success == len(models): + _disable_yaml_config(provider) + + return result + + +def load_models_by_provider(db: Session, provider: str) -> dict: + """ + 加载指定供应商的模型配置 + + Args: + db: 数据库会话 + provider: 供应商名称(字符串或ModelProvider枚举) + + Returns: + dict: 加载结果统计 + """ + provider_enum = ModelProvider(provider) if isinstance(provider, str) else provider + return load_models(db, providers=[provider_enum]) + + +def get_available_providers() -> list[Callable[[], str]]: + """获取所有可用的供应商列表(从ModelProvider枚举获取,排除COMPOSITE)""" + return [p.value for p in ModelProvider if p != ModelProvider.COMPOSITE] + + +def get_models_by_provider(provider: str) -> list[dict]: + """获取指定供应商的模型配置列表""" + provider_enum = ModelProvider(provider) if isinstance(provider, str) else provider + return _load_yaml_config(provider_enum) diff --git a/api/app/core/models/scripts/openai_models.yaml b/api/app/core/models/scripts/openai_models.yaml new file mode 100644 index 00000000..c114d53f --- /dev/null +++ b/api/app/core/models/scripts/openai_models.yaml @@ -0,0 +1,294 @@ +provider: openai +enabled: true +models: +- name: chatgpt-4o-latest + type: llm + provider: openai + description: chatgpt-4o-latest大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉能力,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + logo: openai +- name: gpt-3.5-turbo-0125 + type: llm + provider: openai + description: gpt-3.5-turbo-0125大语言模型,支持多工具调用、智能体思考、流式工具调用,16385上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: openai +- name: gpt-3.5-turbo-1106 + type: llm + provider: openai + description: gpt-3.5-turbo-1106大语言模型,支持多工具调用、智能体思考、流式工具调用,16385上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: openai +- name: gpt-3.5-turbo-16k + type: llm + provider: openai + description: gpt-3.5-turbo-16k大语言模型,支持多工具调用、智能体思考、流式工具调用,16385上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: openai +- name: gpt-3.5-turbo-instruct + type: llm + provider: openai + description: gpt-3.5-turbo-instruct大语言模型,4096上下文窗口,文本补全模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + logo: openai +- name: gpt-3.5-turbo + type: llm + provider: openai + description: gpt-3.5-turbo大语言模型,支持多工具调用、智能体思考、流式工具调用,16385上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: openai +- name: gpt-4-0125-preview + type: llm + provider: openai + description: gpt-4-0125-preview大语言模型,支持多工具调用、智能体思考、流式工具调用,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: openai +- name: gpt-4-1106-preview + type: llm + provider: openai + description: gpt-4-1106-preview大语言模型,支持多工具调用、智能体思考、流式工具调用,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: openai +- name: gpt-4-turbo-2024-04-09 + type: llm + provider: openai + description: gpt-4-turbo-2024-04-09大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉能力,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + logo: openai +- name: gpt-4-turbo-preview + type: llm + provider: openai + description: gpt-4-turbo-preview大语言模型,支持多工具调用、智能体思考、流式工具调用,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + logo: openai +- name: gpt-4-turbo + type: llm + provider: openai + description: gpt-4-turbo大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉能力,128000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + logo: openai +- name: o1-preview + type: llm + provider: openai + description: o1-preview大语言模型,支持智能体思考,128000上下文窗口,对话模式,已废弃 + is_deprecated: true + is_official: true + tags: + - 大语言模型 + - agent-thought + logo: openai +- name: o1 + type: llm + provider: openai + description: o1大语言模型,支持多工具调用、智能体思考、流式工具调用、视觉能力、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - multi-tool-call + - agent-thought + - stream-tool-call + - vision + - structured-output + logo: openai +- name: o3-2025-04-16 + type: llm + provider: openai + description: o3-2025-04-16大语言模型,支持智能体思考、工具调用、视觉能力、流式工具调用、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - vision + - stream-tool-call + - structured-output + logo: openai +- name: o3-mini-2025-01-31 + type: llm + provider: openai + description: o3-mini-2025-01-31大语言模型,支持智能体思考、工具调用、流式工具调用、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - stream-tool-call + - structured-output + logo: openai +- name: o3-mini + type: llm + provider: openai + description: o3-mini大语言模型,支持智能体思考、工具调用、流式工具调用、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - stream-tool-call + - structured-output + logo: openai +- name: o3-pro-2025-06-10 + type: llm + provider: openai + description: o3-pro-2025-06-10大语言模型,支持智能体思考、工具调用、视觉能力、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - vision + - structured-output + logo: openai +- name: o3-pro + type: llm + provider: openai + description: o3-pro大语言模型,支持智能体思考、工具调用、视觉能力、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - vision + - structured-output + logo: openai +- name: o3 + type: llm + provider: openai + description: o3大语言模型,支持智能体思考、视觉能力、工具调用、流式工具调用、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - vision + - tool-call + - stream-tool-call + - structured-output + logo: openai +- name: o4-mini-2025-04-16 + type: llm + provider: openai + description: o4-mini-2025-04-16大语言模型,支持智能体思考、工具调用、视觉能力、流式工具调用、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - vision + - stream-tool-call + - structured-output + logo: openai +- name: o4-mini + type: llm + provider: openai + description: o4-mini大语言模型,支持智能体思考、工具调用、视觉能力、流式工具调用、结构化输出,200000上下文窗口,对话模式 + is_deprecated: false + is_official: true + tags: + - 大语言模型 + - agent-thought + - tool-call + - vision + - stream-tool-call + - structured-output + logo: openai +- name: text-embedding-3-large + type: embedding + provider: openai + description: text-embedding-3-large文本向量模型,8191上下文窗口,最大分块数32 + is_deprecated: false + is_official: true + tags: + - 文本向量模型 + logo: openai +- name: text-embedding-3-small + type: embedding + provider: openai + description: text-embedding-3-small文本向量模型,8191上下文窗口,最大分块数32 + is_deprecated: false + is_official: true + tags: + - 文本向量模型 + logo: openai +- name: text-embedding-ada-002 + type: embedding + provider: openai + description: text-embedding-ada-002文本向量模型,8097上下文窗口,最大分块数32 + is_deprecated: false + is_official: true + tags: + - 文本向量模型 + logo: openai diff --git a/api/app/main.py b/api/app/main.py index 87bfecf8..7e16d2c0 100644 --- a/api/app/main.py +++ b/api/app/main.py @@ -16,6 +16,8 @@ from app.core.error_codes import BizCode, HTTP_MAPPING from app.core.exceptions import BusinessException from app.core.logging_config import LoggingConfig, get_logger from app.core.response_utils import fail +from app.core.models.scripts.loader import load_models +from app.db import get_db_context # Initialize logging system LoggingConfig.setup_logging() @@ -47,6 +49,15 @@ async def lifespan(app: FastAPI): else: logger.info("自动数据库升级已禁用 (DB_AUTO_UPGRADE=false)") + # 加载预定义模型 + logger.info("开始加载预定义模型...") + try: + with get_db_context() as db: + result = load_models(db, silent=True) + logger.info(f"预定义模型加载完成: 成功{result['success']}个, 跳过{result['skipped']}个, 失败{result['failed']}个") + except Exception as e: + logger.warning(f"加载预定义模型时出错: {str(e)}") + logger.info("应用程序启动完成") yield # 应用关闭事件 diff --git a/api/app/models/models_model.py b/api/app/models/models_model.py index a8918c7c..3e378f17 100644 --- a/api/app/models/models_model.py +++ b/api/app/models/models_model.py @@ -5,6 +5,7 @@ from enum import StrEnum from sqlalchemy import Column, String, Boolean, DateTime, Text, ForeignKey, Enum as SQLEnum, UniqueConstraint, Integer, ARRAY, Table from sqlalchemy.dialects.postgresql import UUID, JSON from sqlalchemy.orm import relationship +from sqlalchemy.sql import func from app.db import Base @@ -23,6 +24,8 @@ class ModelType(StrEnum): CHAT = "chat" EMBEDDING = "embedding" RERANK = "rerank" + # TTS = "tts" + # SPEECH2TEXT = "speech2text" # IMAGE = "image" # AUDIO = "audio" # VISION = "vision" @@ -48,8 +51,7 @@ class ModelProvider(StrEnum): class LoadBalanceStrategy(StrEnum): """API Key负载均衡策略枚举""" ROUND_ROBIN = "round_robin" # 轮询 - WEIGHTED_ROUND_ROBIN = "weighted_round_robin" # 加权轮询 - RANDOM = "random" # 随机 + NONE = "none" # 无 # 多对多关联表 @@ -90,7 +92,8 @@ class ModelConfig(BaseModel): # 状态管理 is_public = Column(Boolean, default=False, nullable=False, comment="是否公开") - load_balance_strategy = Column(String, nullable=True, comment="负载均衡策略") + load_balance_strategy = Column(String, nullable=True, comment="负载均衡策略", default=LoadBalanceStrategy.NONE, + server_default=LoadBalanceStrategy.NONE) # 关联关系 model_base = relationship("ModelBase", back_populates="configs") @@ -151,6 +154,7 @@ class ModelBase(Base): is_official = Column(Boolean, default=True, comment="是否供应商官方模型(区分自定义)") tags = Column(ARRAY(String), default=list, nullable=False, comment="模型标签(如['聊天', '创作'])") add_count = Column(Integer, default=0, nullable=False, comment="模型被用户添加的次数") + created_at = Column(DateTime, default=datetime.datetime.now, comment="创建时间", server_default=func.now()) # 关联关系 configs = relationship("ModelConfig", back_populates="model_base", cascade="all, delete-orphan") diff --git a/api/app/repositories/model_repository.py b/api/app/repositories/model_repository.py index 8e4632cc..36f7062f 100644 --- a/api/app/repositories/model_repository.py +++ b/api/app/repositories/model_repository.py @@ -165,7 +165,7 @@ class ModelConfigRepository: total = base_query.count() # 分页查询 - models = base_query.order_by(desc(ModelConfig.updated_at)).offset( + models = base_query.order_by(desc(ModelConfig.created_at)).offset( (query.page - 1) * query.pagesize ).limit(query.pagesize).all() @@ -234,7 +234,7 @@ class ModelConfigRepository: # 获取总数 total = base_query.count() - query_results = base_query.order_by(desc(ModelConfig.updated_at)).all() + query_results = base_query.order_by(desc(ModelConfig.created_at)).all() provider_groups: Dict[str, List[ModelConfig]] = {} for model_config in query_results: @@ -433,6 +433,7 @@ class ModelConfigRepository: ModelConfig.is_public ), ModelBase.provider == provider, + ModelConfig.is_active, ~ModelConfig.is_composite ) ).distinct().all() @@ -621,7 +622,7 @@ class ModelBaseRepository: if filters: q = q.filter(and_(*filters)) - return q.order_by(ModelBase.add_count.desc()).all() + return q.order_by(ModelBase.add_count.desc(), ModelBase.created_at.desc()).all() @staticmethod def create(db: Session, data: dict) -> 'ModelBase': @@ -636,6 +637,17 @@ class ModelBaseRepository: return None for key, value in data.items(): setattr(model_base, key, value) + + # 同步更新绑定的非组合模型配置 + if any(k in data for k in ['name', 'description', 'logo']): + db.query(ModelConfig).filter( + ModelConfig.model_id == model_base_id, + ModelConfig.is_composite == False + ).update({ + k: v for k, v in data.items() + if k in ['name', 'description', 'logo'] + }, synchronize_session=False) + return model_base @staticmethod diff --git a/api/app/schemas/memory_reflection_schemas.py b/api/app/schemas/memory_reflection_schemas.py index df841fb1..88454364 100644 --- a/api/app/schemas/memory_reflection_schemas.py +++ b/api/app/schemas/memory_reflection_schemas.py @@ -1,5 +1,7 @@ +import uuid + from pydantic import BaseModel, Field -from typing import Optional +from typing import Optional, Union from uuid import UUID from enum import Enum @@ -10,7 +12,7 @@ class OptimizationStrategy(str, Enum): ACCURACY_FIRST = "accuracy_first" BALANCED = "balanced" class Memory_Reflection(BaseModel): - config_id: Optional[UUID] = None + config_id: Union[uuid.UUID, int, str] = None reflection_enabled: bool reflection_period_in_hours: str reflexion_range: Optional[str] = "partial" diff --git a/api/app/schemas/memory_storage_schema.py b/api/app/schemas/memory_storage_schema.py index b855d57d..5fda0a1d 100644 --- a/api/app/schemas/memory_storage_schema.py +++ b/api/app/schemas/memory_storage_schema.py @@ -147,7 +147,7 @@ class ReflexionResultSchema(BaseModel): # Composite key identifying a config row class ConfigKey(BaseModel): # 配置参数键模型 model_config = ConfigDict(populate_by_name=True, extra="forbid") - config_id: Union[uuid.UUID, int] = Field(..., description="配置唯一标识(UUID或int)") + config_id:Union[uuid.UUID, int, str] = Field(..., description="配置唯一标识(UUID或int)") user_id: str = Field("user_id", description="用户标识(字符串)") apply_id: str = Field("apply_id", description="应用或场景标识(字符串)") @@ -238,17 +238,17 @@ class ConfigParamsCreate(BaseModel): # 创建配置参数模型(仅 body, class ConfigParamsDelete(BaseModel): # 删除配置参数模型(请求体) model_config = ConfigDict(populate_by_name=True, extra="forbid") # config_name: str = Field("配置名称", description="配置名称(字符串)") - config_id: uuid.UUID = Field("配置ID", description="配置ID(UUID)") + config_id:Union[uuid.UUID, int, str] = Field(..., description="配置ID(支持UUID、整数或字符串)") class ConfigUpdate(BaseModel): # 更新记忆萃取引擎配置参数时使用的模型 - config_id: Optional[uuid.UUID] = None + config_id: Union[uuid.UUID, int, str] = None config_name: str = Field("配置名称", description="配置名称(字符串)") config_desc: str = Field("配置描述", description="配置描述(字符串)") class ConfigUpdateExtracted(BaseModel): # 更新记忆萃取引擎配置参数时使用的模型 - config_id: Optional[uuid.UUID] = None + config_id:Union[uuid.UUID, int, str] = None llm_id: Optional[str] = Field(None, description="LLM模型配置ID") embedding_id: Optional[str] = Field(None, description="嵌入模型配置ID") rerank_id: Optional[str] = Field(None, description="重排序模型配置ID") @@ -315,14 +315,14 @@ class ConfigUpdateExtracted(BaseModel): # 更新记忆萃取引擎配置参数 class ConfigUpdateForget(BaseModel): # 更新遗忘引擎配置参数时使用的模型 # 遗忘引擎配置参数更新模型 - config_id: Optional[uuid.UUID] = None + config_id:Union[uuid.UUID, int, str] = None lambda_time: Optional[float] = Field(0.5, ge=0.0, le=1.0, description="最低保持度,0-1 小数;默认 0.5") lambda_mem: Optional[float] = Field(0.5, ge=0.0, le=1.0, description="遗忘率,0-1 小数;默认 0.5") offset: Optional[float] = Field(0.0, ge=0.0, le=1.0, description="偏移度,0-1 小数;默认 0.0") class ConfigPilotRun(BaseModel): # 试运行触发请求模型 - config_id: uuid.UUID = Field(..., description="配置ID(唯一)") + config_id:Union[uuid.UUID, int, str] = Field(..., description="配置ID(唯一,支持UUID、整数或字符串)") dialogue_text: str = Field(..., description="前端传入的对话文本,格式如 '用户: ...\nAI: ...' 可多行,试运行必填") model_config = ConfigDict(populate_by_name=True, extra="forbid") @@ -330,7 +330,7 @@ class ConfigPilotRun(BaseModel): # 试运行触发请求模型 class ConfigFilter(BaseModel): # 查询配置参数时使用的模型 model_config = ConfigDict(populate_by_name=True, extra="forbid") - config_id: Optional[uuid.UUID] = None + config_id: Union[uuid.UUID, int, str] = None user_id: Optional[str] = None apply_id: Optional[str] = None @@ -406,7 +406,7 @@ class ForgettingConfigResponse(BaseModel): """遗忘引擎配置响应模型""" model_config = ConfigDict(populate_by_name=True, extra="forbid") - config_id: uuid.UUID = Field(..., description="配置ID") + config_id: Union[uuid.UUID, int, str] = Field(..., description="配置ID(支持UUID、整数或字符串)") decay_constant: float = Field(..., description="衰减常数 d") lambda_time: float = Field(..., description="时间衰减参数") lambda_mem: float = Field(..., description="记忆衰减参数") diff --git a/api/app/schemas/model_schema.py b/api/app/schemas/model_schema.py index ce1b36bb..a2d3650a 100644 --- a/api/app/schemas/model_schema.py +++ b/api/app/schemas/model_schema.py @@ -3,14 +3,12 @@ from typing import Optional, List, Dict, Any import datetime import uuid -from app.models.models_model import ModelProvider, ModelType +from app.models.models_model import ModelProvider, ModelType, LoadBalanceStrategy from app.core.logging_config import get_business_logger schema_logger = get_business_logger() - - # ModelConfig Schemas class ModelConfigBase(BaseModel): """模型配置基础Schema""" @@ -22,6 +20,7 @@ class ModelConfigBase(BaseModel): config: Optional[Dict[str, Any]] = Field({}, description="模型配置参数") is_active: bool = Field(True, description="是否激活") is_public: bool = Field(False, description="是否公开") + load_balance_strategy: Optional[str] = Field(LoadBalanceStrategy.NONE.value, description="负载均衡策略") class ApiKeyCreateNested(BaseModel): @@ -44,13 +43,14 @@ class ModelConfigCreate(ModelConfigBase): class CompositeModelCreate(BaseModel): """创建组合模型Schema""" name: str = Field(..., description="组合模型名称", max_length=255) - type: ModelType = Field(..., description="模型类型") + type: Optional[ModelType] = Field(None, description="模型类型") logo: Optional[str] = Field(None, description="模型logo图片URL", max_length=255) description: Optional[str] = Field(None, description="模型描述") config: Optional[Dict[str, Any]] = Field({}, description="模型配置参数") is_active: bool = Field(True, description="是否激活") is_public: bool = Field(False, description="是否公开") api_key_ids: List[uuid.UUID] = Field(..., description="绑定的API Key ID列表") + load_balance_strategy: Optional[str] = Field(default=LoadBalanceStrategy.NONE.value, description="负载均衡策略") class ModelConfigUpdate(BaseModel): diff --git a/api/app/services/memory_reflection_service.py b/api/app/services/memory_reflection_service.py index 402a40a1..b92a5d06 100644 --- a/api/app/services/memory_reflection_service.py +++ b/api/app/services/memory_reflection_service.py @@ -18,6 +18,7 @@ from app.repositories.neo4j.neo4j_connector import Neo4jConnector from app.models.app_model import App from app.models.app_release_model import AppRelease from app.models.end_user_model import EndUser +from app.utils.config_utils import resolve_config_id api_logger = get_api_logger() @@ -88,38 +89,36 @@ class WorkspaceAppService: for release in app_releases: memory_content = self._extract_memory_content(release.config) - - + memory_content=resolve_config_id(memory_content, self.db) if memory_content and memory_content in processed_configs: continue - + release_info = { "app_id": str(release.app_id), "config": memory_content } - + if memory_content: processed_configs.add(memory_content) memory_config_info = self._get_memory_config(memory_content) - if memory_config_info: if not any(dc["config_id"] == memory_config_info["config_id"] for dc in app_info["memory_configs"]): app_info["memory_configs"].append(memory_config_info) - + app_info["releases"].append(release_info) - + def _extract_memory_content(self, config: Any) -> str: """Extract memory_comtent from config""" if not config or not isinstance(config, dict): return None - + memory_obj = config.get('memory') if memory_obj and isinstance(memory_obj, dict): return memory_obj.get('memory_content') - + return None - + def _get_memory_config(self, memory_content: str) -> Dict[str, Any]: """Retrieve memory_config information based on memory_content""" try: @@ -129,7 +128,7 @@ class WorkspaceAppService: # memory_config_result = self.db.execute(text(memory_config_query), memory_config_params).fetchone() # if memory_config_result is None: # return None - + if memory_config_result: return { "config_id": memory_config_result.config_id, @@ -144,20 +143,22 @@ class WorkspaceAppService: } except Exception as e: api_logger.warning(f"查询memory_config失败,memory_content: {memory_content}, 错误: {str(e)}") - + return None - + def _process_end_users(self, app: App, app_info: Dict[str, Any]) -> None: """Processing end-user information for applications""" end_users = self.db.query(EndUser).filter(EndUser.app_id == app.id).all() - + for end_user in end_users: end_user_info = { "id": str(end_user.id), "app_id": str(end_user.app_id) } app_info["end_users"].append(end_user_info) - + print(100*'-') + print(app_info) + def get_end_user_reflection_time(self, end_user_id: str) -> Optional[Any]: """ Read the reflection time of end users @@ -176,7 +177,7 @@ class WorkspaceAppService: except Exception as e: api_logger.error(f"读取用户反思时间失败,end_user_id: {end_user_id}, 错误: {str(e)}") return None - + def update_end_user_reflection_time(self, end_user_id: str) -> bool: """ Update the reflection time of end users to the current time @@ -189,7 +190,7 @@ class WorkspaceAppService: """ try: from datetime import datetime - + end_user = self.db.query(EndUser).filter(EndUser.id == end_user_id).first() if end_user: end_user.reflection_time = datetime.now() @@ -207,7 +208,7 @@ class WorkspaceAppService: class MemoryReflectionService: """Memory reflection service category""" - + def __init__(self,db: Session = Depends(get_db)): self.db=db @@ -252,22 +253,22 @@ class MemoryReflectionService: "end_user_id": end_user_id, "config_data": config_data } - + async def start_reflection_from_data(self, config_data: Dict[str, Any], end_user_id: str) -> Dict[str, Any]: """ Starting Reflection from Configuration Data - + Args: config_data: Configure data dictionary, including reflective configuration information end_user_id: end_user_id - + Returns: Reflect on the execution results """ try: config_id = config_data.get("config_id") api_logger.info(f"从配置数据启动反思,config_id: {config_id}, end_user_id: {end_user_id}") - + if not config_data.get("enable_self_reflexion", False): return { @@ -277,7 +278,7 @@ class MemoryReflectionService: "end_user_id": end_user_id, "config_data": config_data } - + config_data_id=config_data['config_id'] reflection_config=WorkspaceAppService(self.db)._get_memory_config(config_data_id) diff --git a/api/app/services/model_service.py b/api/app/services/model_service.py index 5b2ab7e6..ceb9cd70 100644 --- a/api/app/services/model_service.py +++ b/api/app/services/model_service.py @@ -347,7 +347,9 @@ class ModelConfigService: "is_public": model_data.is_public, "is_composite": True } - + if "load_balance_strategy" in model_data.model_fields_set: + model_config_data["load_balance_strategy"] = model_data.load_balance_strategy + model = ModelConfigRepository.create(db, model_config_data) db.flush() @@ -380,7 +382,7 @@ class ModelConfigService: for model_config in api_key.model_configs: compatible_types = {ModelType.LLM, ModelType.CHAT} config_type = model_config.type - request_type = model_data.type + request_type = existing_model.type if not (config_type == request_type or (config_type in compatible_types and request_type in compatible_types)): @@ -391,12 +393,14 @@ class ModelConfigService: # 更新基本信息 existing_model.name = model_data.name - existing_model.type = model_data.type + # existing_model.type = model_data.type existing_model.logo = model_data.logo existing_model.description = model_data.description existing_model.config = model_data.config existing_model.is_active = model_data.is_active existing_model.is_public = model_data.is_public + if "load_balance_strategy" in model_data.model_fields_set: + existing_model.load_balance_strategy = model_data.load_balance_strategy # 更新 API Keys 关联 existing_model.api_keys.clear() diff --git a/api/app/services/prompt_optimizer_service.py b/api/app/services/prompt_optimizer_service.py index c6142c01..9e447214 100644 --- a/api/app/services/prompt_optimizer_service.py +++ b/api/app/services/prompt_optimizer_service.py @@ -16,7 +16,7 @@ from app.models.prompt_optimizer_model import ( PromptOptimizerSession, RoleType ) -from app.repositories.model_repository import ModelConfigRepository +from app.repositories.model_repository import ModelConfigRepository, ModelApiKeyRepository from app.repositories.prompt_optimizer_repository import ( PromptOptimizerSessionRepository ) @@ -168,7 +168,8 @@ class PromptOptimizerService: logger.info(f"Prompt optimization started, user_id={user_id}, session_id={session_id}") # Create LLM instance - api_config: ModelApiKey = model_config.api_keys[0] + api_keys = ModelApiKeyRepository.get_by_model_config(self.db, model_config.id) + api_config: ModelApiKey = api_keys[0] if api_keys else None llm = RedBearLLM(RedBearModelConfig( model_name=api_config.model_name, provider=api_config.provider, diff --git a/api/app/utils/config_utils.py b/api/app/utils/config_utils.py index f75b0aab..8863ea78 100644 --- a/api/app/utils/config_utils.py +++ b/api/app/utils/config_utils.py @@ -21,8 +21,18 @@ def resolve_config_id(config_id: UUID | int, db: Session) -> UUID: Raises: ValueError: 当找不到对应的配置时 """ + from app.models.memory_config_model import MemoryConfig + if isinstance(config_id, UUID): + return config_id + if isinstance(config_id, str) and len(config_id)<=6: + memory_config = db.query(MemoryConfig).filter( + MemoryConfig.config_id_old == config_id + ).first() + + if not memory_config: + raise ValueError(f"未找到 config_id_old={config_id} 对应的配置") + return memory_config.config_id if isinstance(config_id, int): - from app.models.memory_config_model import MemoryConfig memory_config = db.query(MemoryConfig).filter( MemoryConfig.config_id_old == config_id ).first() diff --git a/api/migrations/versions/5ca246ee7dd4_202601291352.py b/api/migrations/versions/5ca246ee7dd4_202601291352.py new file mode 100644 index 00000000..74931287 --- /dev/null +++ b/api/migrations/versions/5ca246ee7dd4_202601291352.py @@ -0,0 +1,30 @@ +"""202601291352 + +Revision ID: 5ca246ee7dd4 +Revises: 915bed077f8d +Create Date: 2026-01-29 13:52:47.647306 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = '5ca246ee7dd4' +down_revision: Union[str, None] = '915bed077f8d' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('model_bases', sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True, comment='创建时间')) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('model_bases', 'created_at') + # ### end Alembic commands ### diff --git a/api_key_mcp_server.py b/api_key_mcp_server.py deleted file mode 100644 index f611dc59..00000000 --- a/api_key_mcp_server.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -"""API Key认证MCP服务器""" - -from fastapi import FastAPI, HTTPException, Depends, Header -from typing import Optional -import uvicorn -from mcp_base import MCPRequest, handle_mcp_request, TOOLS - -app = FastAPI(title="API Key MCP Server", version="1.0.0") - -# API Key配置 -API_KEYS = {"test-api-key", "demo-key-123"} - -def verify_api_key(x_api_key: Optional[str] = Header(None)): - """验证API Key""" - if x_api_key and x_api_key in API_KEYS: - return True - raise HTTPException(status_code=401, detail="Invalid API Key") - -@app.get("/") -async def root(): - return {"name": "API Key MCP Server", "version": "1.0.0", "auth_type": "api_key"} - -@app.get("/health") -async def health(): - return {"status": "healthy", "tools": len(TOOLS), "auth_type": "api_key"} - -@app.post("/mcp") -async def mcp_handler(request: MCPRequest, _: bool = Depends(verify_api_key)): - return await handle_mcp_request(request, "API Key MCP Server") - -if __name__ == "__main__": - print("启动API Key认证MCP服务器...") - print("访问 http://localhost:8004 查看服务状态") - print("MCP端点: http://localhost:8004/mcp") - print("认证方式: API Key (Header: X-API-Key)") - print("测试API Keys: test-api-key, demo-key-123") - uvicorn.run(app, host="0.0.0.0", port=8004) \ No newline at end of file diff --git a/basic_auth_mcp_server.py b/basic_auth_mcp_server.py deleted file mode 100644 index 11bb5595..00000000 --- a/basic_auth_mcp_server.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -"""Basic Auth认证MCP服务器""" - -from fastapi import FastAPI, HTTPException, Depends, Header -from typing import Optional -import uvicorn -import base64 -from mcp_base import MCPRequest, handle_mcp_request, TOOLS - -app = FastAPI(title="Basic Auth MCP Server", version="1.0.0") - -# Basic Auth配置 -BASIC_AUTH_USERS = {"admin": "password", "user": "secret"} - -def verify_basic_auth(authorization: Optional[str] = Header(None)): - """验证Basic Auth""" - if authorization and authorization.startswith("Basic "): - try: - credentials = base64.b64decode(authorization.split(" ")[1]).decode() - username, password = credentials.split(":", 1) - if username in BASIC_AUTH_USERS and BASIC_AUTH_USERS[username] == password: - return True - except: - pass - raise HTTPException(status_code=401, detail="Invalid Basic Auth") - -@app.get("/") -async def root(): - return {"name": "Basic Auth MCP Server", "version": "1.0.0", "auth_type": "basic_auth"} - -@app.get("/health") -async def health(): - return {"status": "healthy", "tools": len(TOOLS), "auth_type": "basic_auth"} - -@app.post("/mcp") -async def mcp_handler(request: MCPRequest, _: bool = Depends(verify_basic_auth)): - return await handle_mcp_request(request, "Basic Auth MCP Server") - -if __name__ == "__main__": - print("启动Basic Auth认证MCP服务器...") - print("访问 http://localhost:8006 查看服务状态") - print("MCP端点: http://localhost:8006/mcp") - print("认证方式: Basic Auth (Header: Authorization: Basic )") - print("测试用户: admin:password, user:secret") - uvicorn.run(app, host="0.0.0.0", port=8006) \ No newline at end of file diff --git a/bearer_token_mcp_server.py b/bearer_token_mcp_server.py deleted file mode 100644 index 57d27f2f..00000000 --- a/bearer_token_mcp_server.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -"""Bearer Token认证MCP服务器""" - -from fastapi import FastAPI, HTTPException, Depends, Header -from typing import Optional -import uvicorn -from mcp_base import MCPRequest, handle_mcp_request, TOOLS - -app = FastAPI(title="Bearer Token MCP Server", version="1.0.0") - -# Bearer Token配置 -BEARER_TOKENS = {"bearer-token-123", "demo-bearer-token"} - -def verify_bearer_token(authorization: Optional[str] = Header(None)): - """验证Bearer Token""" - if authorization and authorization.startswith("Bearer "): - token = authorization.split(" ")[1] - if token in BEARER_TOKENS: - return True - raise HTTPException(status_code=401, detail="Invalid Bearer Token") - -@app.get("/") -async def root(): - return {"name": "Bearer Token MCP Server", "version": "1.0.0", "auth_type": "bearer_token"} - -@app.get("/health") -async def health(): - return {"status": "healthy", "tools": len(TOOLS), "auth_type": "bearer_token"} - -@app.post("/mcp") -async def mcp_handler(request: MCPRequest, _: bool = Depends(verify_bearer_token)): - return await handle_mcp_request(request, "Bearer Token MCP Server") - -if __name__ == "__main__": - print("启动Bearer Token认证MCP服务器...") - print("访问 http://localhost:8005 查看服务状态") - print("MCP端点: http://localhost:8005/mcp") - print("认证方式: Bearer Token (Header: Authorization: Bearer )") - print("测试Bearer Tokens: bearer-token-123, demo-bearer-token") - uvicorn.run(app, host="0.0.0.0", port=8005) \ No newline at end of file diff --git a/mcp_base.py b/mcp_base.py deleted file mode 100644 index f571e2fa..00000000 --- a/mcp_base.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python3 -"""MCP服务器基础模块 - 共享的模型和处理逻辑""" - -from pydantic import BaseModel -from typing import Dict, Any - -class MCPRequest(BaseModel): - jsonrpc: str = "2.0" - id: str - method: str - params: Dict[str, Any] = {} - -class MCPResponse(BaseModel): - jsonrpc: str = "2.0" - id: str - result: Any = None - error: Dict[str, Any] = None - -# 工具定义 -TOOLS = [ - { - "name": "calculator", - "description": "简单计算器", - "inputSchema": { - "type": "object", - "properties": { - "expression": {"type": "string", "description": "数学表达式"} - }, - "required": ["expression"] - } - }, - { - "name": "echo", - "description": "回显工具", - "inputSchema": { - "type": "object", - "properties": { - "message": {"type": "string", "description": "要回显的消息"} - }, - "required": ["message"] - } - } -] - -async def handle_mcp_request(request: MCPRequest, server_name: str = "MCP Server"): - """处理MCP请求""" - try: - if request.method == "initialize": - return MCPResponse( - id=request.id, - result={ - "protocolVersion": "2024-11-05", - "capabilities": {"tools": {"listChanged": True}}, - "serverInfo": {"name": server_name, "version": "1.0.0"} - } - ) - - elif request.method == "tools/list": - return MCPResponse( - id=request.id, - result={"tools": TOOLS} - ) - - elif request.method == "tools/call": - tool_name = request.params.get("name") - arguments = request.params.get("arguments", {}) - - if tool_name == "calculator": - try: - expression = arguments.get("expression", "") - result = eval(expression) - return MCPResponse( - id=request.id, - result={"content": [{"type": "text", "text": f"结果: {result}"}]} - ) - except Exception as e: - return MCPResponse( - id=request.id, - error={"code": -1, "message": f"计算错误: {str(e)}"} - ) - - elif tool_name == "echo": - message = arguments.get("message", "") - return MCPResponse( - id=request.id, - result={"content": [{"type": "text", "text": f"Echo: {message}"}]} - ) - - else: - return MCPResponse( - id=request.id, - error={"code": -1, "message": f"未知工具: {tool_name}"} - ) - - elif request.method == "ping": - return MCPResponse( - id=request.id, - result={"status": "pong"} - ) - - else: - return MCPResponse( - id=request.id, - error={"code": -1, "message": f"未知方法: {request.method}"} - ) - - except Exception as e: - return MCPResponse( - id=request.id, - error={"code": -1, "message": str(e)} - ) \ No newline at end of file diff --git a/simple_mcp_server.py b/simple_mcp_server.py deleted file mode 100644 index fa299e37..00000000 --- a/simple_mcp_server.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -"""简化的MCP服务器 - 用于测试MCP工具集成""" - -from fastapi import FastAPI, HTTPException -from pydantic import BaseModel -from typing import Dict, Any, List -import uvicorn - -app = FastAPI(title="Simple MCP Server", version="1.0.0") - -class MCPRequest(BaseModel): - jsonrpc: str = "2.0" - id: str - method: str - params: Dict[str, Any] = {} - -class MCPResponse(BaseModel): - jsonrpc: str = "2.0" - id: str - result: Any = None - error: Dict[str, Any] = None - -# 可用工具定义 -TOOLS = [ - { - "name": "calculator", - "description": "简单计算器", - "inputSchema": { - "type": "object", - "properties": { - "expression": {"type": "string", "description": "数学表达式"} - }, - "required": ["expression"] - } - }, - { - "name": "echo", - "description": "回显工具", - "inputSchema": { - "type": "object", - "properties": { - "message": {"type": "string", "description": "要回显的消息"} - }, - "required": ["message"] - } - } -] - -@app.get("/") -async def root(): - return {"name": "Simple MCP Server", "version": "1.0.0"} - -@app.get("/health") -async def health(): - return {"status": "healthy", "tools": len(TOOLS)} - -@app.post("/mcp") -async def mcp_handler(request: MCPRequest): - """处理MCP请求""" - try: - if request.method == "initialize": - return MCPResponse( - id=request.id, - result={ - "protocolVersion": "2024-11-05", - "capabilities": {"tools": {"listChanged": True}}, - "serverInfo": {"name": "Simple MCP Server", "version": "1.0.0"} - } - ) - - elif request.method == "tools/list": - return MCPResponse( - id=request.id, - result={"tools": TOOLS} - ) - - elif request.method == "tools/call": - tool_name = request.params.get("name") - arguments = request.params.get("arguments", {}) - - if tool_name == "calculator": - try: - expression = arguments.get("expression", "") - result = eval(expression) # 注意:生产环境不要用eval - return MCPResponse( - id=request.id, - result={"content": [{"type": "text", "text": f"结果: {result}"}]} - ) - except Exception as e: - return MCPResponse( - id=request.id, - error={"code": -1, "message": f"计算错误: {str(e)}"} - ) - - elif tool_name == "echo": - message = arguments.get("message", "") - return MCPResponse( - id=request.id, - result={"content": [{"type": "text", "text": f"Echo: {message}"}]} - ) - - else: - return MCPResponse( - id=request.id, - error={"code": -1, "message": f"未知工具: {tool_name}"} - ) - - elif request.method == "ping": - return MCPResponse( - id=request.id, - result={"status": "pong"} - ) - - else: - return MCPResponse( - id=request.id, - error={"code": -1, "message": f"未知方法: {request.method}"} - ) - - except Exception as e: - return MCPResponse( - id=request.id, - error={"code": -1, "message": str(e)} - ) - -if __name__ == "__main__": - print("启动简化MCP服务器...") - print("访问 http://localhost:8002 查看服务状态") - print("MCP端点: http://localhost:8002/mcp") - uvicorn.run(app, host="0.0.0.0", port=8002) \ No newline at end of file diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index ea45ea6d..c3e1d98b 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -546,7 +546,10 @@ export const en = { tags: 'Tags', createCustomModel: 'Add Custom Model', edit: 'Edit', - selectOneTip: 'Model API KEY not configured, please configure in Model Plaza first', + selectOneTip: 'Model API KEY not configured, please configure it in the model list first', + load_balance_strategy: 'Concurrency Strategy', + round_robin: 'Sequential Execution - Call each model in order', + none: 'None', api_key: 'API KEY', api_base: 'API Base URL', @@ -554,6 +557,7 @@ export const en = { add: 'Add', item: 'item', apiKeyNum: ' API Keys', + official: 'Official', llm: 'LLM', chat: 'Chat', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index 0e5c9288..e1410981 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -1118,7 +1118,10 @@ export const zh = { tags: '标签', createCustomModel: '添加自定义模型', edit: '编辑', - selectOneTip: '模型未配置API KEY,请先在模型广场配置', + selectOneTip: '模型未配置API KEY,请先在模型列表配置', + load_balance_strategy: '并发策略', + round_robin: '顺序执行 - 按顺序依次调用每个模型', + none: '无', api_key: 'API KEY', api_base: 'API Base URL', @@ -1126,6 +1129,7 @@ export const zh = { add: '添加', item: '个', apiKeyNum: '个 API Key', + official: '官方', llm: 'LLM', chat: 'Chat', diff --git a/web/src/views/ModelManagement/List.tsx b/web/src/views/ModelManagement/List.tsx index 4f8fb665..bb799752 100644 --- a/web/src/views/ModelManagement/List.tsx +++ b/web/src/views/ModelManagement/List.tsx @@ -23,7 +23,6 @@ const ModelList: FC<{ query: any }> = ({ query }) => { getModelNewList({ ...query, is_composite: false, - is_active: true, }) .then(res => { setList((res || []) as ProviderModelItem[]) diff --git a/web/src/views/ModelManagement/Square.tsx b/web/src/views/ModelManagement/Square.tsx index ad5d2441..f52d158e 100644 --- a/web/src/views/ModelManagement/Square.tsx +++ b/web/src/views/ModelManagement/Square.tsx @@ -56,7 +56,10 @@ const ModelSquare = forwardRef {t(`modelNew.${item.type}`)}} + subTitle={ + {t(`modelNew.${item.type}`)} + {item.is_official && {t(`modelNew.official`)}} + } avatarUrl={getLogoUrl(item.logo)} avatar={
diff --git a/web/src/views/ModelManagement/components/CustomModelModal.tsx b/web/src/views/ModelManagement/components/CustomModelModal.tsx index d22fbcdd..66c16111 100644 --- a/web/src/views/ModelManagement/components/CustomModelModal.tsx +++ b/web/src/views/ModelManagement/components/CustomModelModal.tsx @@ -44,7 +44,8 @@ const CustomModelModal = forwardRef( }; const handleUpdate = (data: CustomModelForm) => { setLoading(true) - const res = isEdit ? updateCustomModel(model.id, data) : addCustomModel(data) + const { type, provider, ...rest} = data + const res = isEdit ? updateCustomModel(model.id, rest) : addCustomModel(data) res.then(() => { refresh && refresh() @@ -129,6 +130,7 @@ const CustomModelModal = forwardRef( items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))} /> @@ -141,6 +143,7 @@ const CustomModelModal = forwardRef( items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))} /> diff --git a/web/src/views/ModelManagement/components/GroupModelModal.tsx b/web/src/views/ModelManagement/components/GroupModelModal.tsx index 6ae54d4c..e8734114 100644 --- a/web/src/views/ModelManagement/components/GroupModelModal.tsx +++ b/web/src/views/ModelManagement/components/GroupModelModal.tsx @@ -1,5 +1,5 @@ import { forwardRef, useImperativeHandle, useState } from 'react'; -import { Form, Input, App } from 'antd'; +import { Form, Input, App, Select } from 'antd'; import { useTranslation } from 'react-i18next'; import type { ModelListItem, CompositeModelForm, GroupModelModalRef, GroupModelModalProps, ModelApiKey } from '../types'; @@ -75,8 +75,9 @@ const GroupModelModal = forwardRef(({ const handleUpdate = (data: CompositeModelForm) => { setLoading(true) + const { type, ...rest } = data const res = isEdit - ? updateCompositeModel(model.id, data) + ? updateCompositeModel(model.id, { ...rest }) : addCompositeModel(data) res.then(() => { @@ -106,6 +107,7 @@ const GroupModelModal = forwardRef(({
(({ + +