From d291c241d58bfe993806e84e7bc3d17701377192 Mon Sep 17 00:00:00 2001 From: Timebomb2018 <18868801967@163.com> Date: Thu, 29 Jan 2026 15:21:06 +0800 Subject: [PATCH 1/3] fix(model): the model type does not allow modification, delete tts and speech2text type --- api/app/controllers/model_controller.py | 2 + .../core/models/scripts/dashscope_models.yaml | 30 ----------- .../core/models/scripts/openai_models.yaml | 54 ------------------- api/app/models/models_model.py | 4 +- api/app/schemas/model_schema.py | 2 +- api/app/services/model_service.py | 4 +- 6 files changed, 7 insertions(+), 89 deletions(-) diff --git a/api/app/controllers/model_controller.py b/api/app/controllers/model_controller.py index e5a1cec3..d76f0b1d 100644 --- a/api/app/controllers/model_controller.py +++ b/api/app/controllers/model_controller.py @@ -326,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})") diff --git a/api/app/core/models/scripts/dashscope_models.yaml b/api/app/core/models/scripts/dashscope_models.yaml index 24997728..c02ca2cb 100644 --- a/api/app/core/models/scripts/dashscope_models.yaml +++ b/api/app/core/models/scripts/dashscope_models.yaml @@ -767,26 +767,6 @@ models: tags: - 重排序模型 logo: dashscope -- name: paraformer-realtime-v1 - type: speech2text - provider: dashscope - description: paraformer-realtime-v1语音转文字模型,支持多格式音频/视频文件,文件上传限制100MB - is_deprecated: false - is_official: true - tags: - - 语音识别 - - 语音转文字 - logo: dashscope -- name: paraformer-realtime-v2 - type: speech2text - provider: dashscope - description: paraformer-realtime-v2语音转文字模型,支持多格式音频/视频文件,文件上传限制100MB - is_deprecated: false - is_official: true - tags: - - 语音识别 - - 语音转文字 - logo: dashscope - name: multimodal-embedding-v1 type: embedding provider: dashscope @@ -838,13 +818,3 @@ models: - 嵌入模型 - 文本嵌入 logo: dashscope -- name: tts-1 - type: tts - provider: dashscope - description: tts-1语音合成模型,默认音色知茹(新闻女声),支持多语言多音色,最大文本长度7000字,输出MP3格式 - is_deprecated: false - is_official: true - tags: - - 语音合成 - - 文字转语音 - logo: dashscope diff --git a/api/app/core/models/scripts/openai_models.yaml b/api/app/core/models/scripts/openai_models.yaml index 7ae2cfce..c114d53f 100644 --- a/api/app/core/models/scripts/openai_models.yaml +++ b/api/app/core/models/scripts/openai_models.yaml @@ -265,33 +265,6 @@ models: - stream-tool-call - structured-output logo: openai -- name: gpt-4o-mini-transcribe - type: speech2text - provider: openai - description: gpt-4o-mini-transcribe语音转文本模型,文件上传限制25MB,支持flac,mp3,mp4,mpeg,mpga,m4a,ogg,wav,webm格式 - is_deprecated: false - is_official: true - tags: - - 语音转文本模型 - logo: openai -- name: gpt-4o-transcribe - type: speech2text - provider: openai - description: gpt-4o-transcribe语音转文本模型,文件上传限制25MB,支持flac,mp3,mp4,mpeg,mpga,m4a,ogg,wav,webm格式 - is_deprecated: false - is_official: true - tags: - - 语音转文本模型 - logo: openai -- name: whisper-1 - type: speech2text - provider: openai - description: whisper-1语音转文本模型,文件上传限制25MB,支持flac,mp3,mp4,mpeg,mpga,m4a,ogg,wav,webm格式 - is_deprecated: false - is_official: true - tags: - - 语音转文本模型 - logo: openai - name: text-embedding-3-large type: embedding provider: openai @@ -319,30 +292,3 @@ models: tags: - 文本向量模型 logo: openai -- name: gpt-4o-mini-tts - type: tts - provider: openai - description: gpt-4o-mini-tts文本转语音模型,输出音频格式mp3,支持多语种语音,字数限制3500 - is_deprecated: false - is_official: true - tags: - - 文本转语音模型 - logo: openai -- name: tts-1-hd - type: tts - provider: openai - description: tts-1-hd高清文本转语音模型,输出音频格式mp3,支持多语种语音,字数限制3500 - is_deprecated: false - is_official: true - tags: - - 文本转语音模型 - logo: openai -- name: tts-1 - type: tts - provider: openai - description: tts-1文本转语音模型,输出音频格式mp3,支持多语种语音,字数限制3500 - is_deprecated: false - is_official: true - tags: - - 文本转语音模型 - logo: openai diff --git a/api/app/models/models_model.py b/api/app/models/models_model.py index 11a869a6..3e378f17 100644 --- a/api/app/models/models_model.py +++ b/api/app/models/models_model.py @@ -24,8 +24,8 @@ class ModelType(StrEnum): CHAT = "chat" EMBEDDING = "embedding" RERANK = "rerank" - TTS = "tts" - SPEECH2TEXT = "speech2text" + # TTS = "tts" + # SPEECH2TEXT = "speech2text" # IMAGE = "image" # AUDIO = "audio" # VISION = "vision" diff --git a/api/app/schemas/model_schema.py b/api/app/schemas/model_schema.py index 73f60936..a2d3650a 100644 --- a/api/app/schemas/model_schema.py +++ b/api/app/schemas/model_schema.py @@ -43,7 +43,7 @@ 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="模型配置参数") diff --git a/api/app/services/model_service.py b/api/app/services/model_service.py index 729fc192..ceb9cd70 100644 --- a/api/app/services/model_service.py +++ b/api/app/services/model_service.py @@ -382,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)): @@ -393,7 +393,7 @@ 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 From ab9a97db223f22c25b1babecb1b2c3bb19623bc2 Mon Sep 17 00:00:00 2001 From: Timebomb2018 <18868801967@163.com> Date: Thu, 29 Jan 2026 15:25:25 +0800 Subject: [PATCH 2/3] fix(model): bug fix --- api/app/services/prompt_optimizer_service.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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, From 17a695120ab8b7207cecc270582ad851fcaed607 Mon Sep 17 00:00:00 2001 From: lixinyue11 <94037597+lixinyue11@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:03:44 +0800 Subject: [PATCH 3/3] Add/develop memory (#239) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 遗漏的历史映射 * 遗漏的历史映射 * 遗漏的历史映射 --- .../controllers/emotion_config_controller.py | 6 ++- .../memory_reflection_controller.py | 2 + .../controllers/memory_storage_controller.py | 14 +++--- api/app/schemas/memory_reflection_schemas.py | 6 ++- api/app/schemas/memory_storage_schema.py | 16 +++---- api/app/services/memory_reflection_service.py | 47 ++++++++++--------- 6 files changed, 50 insertions(+), 41 deletions(-) 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 f24d2f70..ae372d3b 100644 --- a/api/app/controllers/memory_storage_controller.py +++ b/api/app/controllers/memory_storage_controller.py @@ -35,6 +35,8 @@ from fastapi import APIRouter, Depends from fastapi.responses import StreamingResponse from sqlalchemy.orm import Session +from app.utils.config_utils import resolve_config_id + # Get API logger api_logger = get_api_logger() @@ -141,7 +143,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} 尝试创建配置但未选择工作空间") @@ -161,12 +162,12 @@ def create_config( @router.delete("/delete_config", response_model=ApiResponse) # 删除数据库中的内容(按配置名称) def delete_config( - config_id: UUID, + config_id: UUID|int, current_user: User = Depends(get_current_user), 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} 尝试删除配置但未选择工作空间") @@ -188,7 +189,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} 尝试更新配置但未选择工作空间") @@ -211,7 +212,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} 尝试更新提取配置但未选择工作空间") @@ -238,7 +239,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} 尝试读取提取配置但未选择工作空间") @@ -286,6 +287,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/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/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)