Fix/memory bug fix (#171)
This commit is contained in:
@@ -299,6 +299,18 @@ class AppRelease(BaseModel):
|
||||
created_at: datetime.datetime
|
||||
updated_at: datetime.datetime
|
||||
|
||||
@field_validator("config", mode="before")
|
||||
@classmethod
|
||||
def parse_config(cls, v):
|
||||
"""处理 config 字段,如果是字符串则解析为字典"""
|
||||
if isinstance(v, str):
|
||||
import json
|
||||
try:
|
||||
return json.loads(v)
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
return v if v is not None else {}
|
||||
|
||||
@field_serializer("created_at", when_used="json")
|
||||
def _serialize_created_at(self, dt: datetime.datetime):
|
||||
return int(dt.timestamp() * 1000) if dt else None
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
"""情绪分析相关的请求和响应模型"""
|
||||
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class EmotionTagsRequest(BaseModel):
|
||||
"""获取情绪标签统计请求"""
|
||||
group_id: str = Field(..., description="组ID")
|
||||
end_user_id: str = Field(..., description="组ID")
|
||||
emotion_type: Optional[str] = Field(None, description="情绪类型过滤(joy/sadness/anger/fear/surprise/neutral)")
|
||||
start_date: Optional[str] = Field(None, description="开始日期(ISO格式,如:2024-01-01)")
|
||||
end_date: Optional[str] = Field(None, description="结束日期(ISO格式,如:2024-12-31)")
|
||||
@@ -14,14 +15,14 @@ class EmotionTagsRequest(BaseModel):
|
||||
|
||||
class EmotionWordcloudRequest(BaseModel):
|
||||
"""获取情绪词云数据请求"""
|
||||
group_id: str = Field(..., description="组ID")
|
||||
end_user_id: str = Field(..., description="组ID")
|
||||
emotion_type: Optional[str] = Field(None, description="情绪类型过滤(joy/sadness/anger/fear/surprise/neutral)")
|
||||
limit: int = Field(50, ge=1, le=200, description="返回词语数量")
|
||||
|
||||
|
||||
class EmotionHealthRequest(BaseModel):
|
||||
"""获取情绪健康指数请求"""
|
||||
group_id: str = Field(..., description="组ID")
|
||||
end_user_id: str = Field(..., description="组ID")
|
||||
time_range: str = Field("30d", description="时间范围(7d/30d/90d)")
|
||||
|
||||
|
||||
@@ -29,8 +30,8 @@ class EmotionHealthRequest(BaseModel):
|
||||
|
||||
class EmotionSuggestionsRequest(BaseModel):
|
||||
"""获取个性化情绪建议请求"""
|
||||
group_id: str = Field(..., description="组ID")
|
||||
config_id: Optional[int] = Field(None, description="配置ID(用于指定LLM模型)")
|
||||
end_user_id: str = Field(..., description="组ID")
|
||||
config_id: Optional[UUID] = Field(None, description="配置ID(用于指定LLM模型)")
|
||||
|
||||
|
||||
class EmotionGenerateSuggestionsRequest(BaseModel):
|
||||
|
||||
@@ -7,11 +7,11 @@ class UserInput(BaseModel):
|
||||
message: str
|
||||
history: list[dict]
|
||||
search_switch: str
|
||||
group_id: str
|
||||
end_user_id: str
|
||||
config_id: Optional[str] = None
|
||||
|
||||
|
||||
class Write_UserInput(BaseModel):
|
||||
messages: list[dict]
|
||||
group_id: str
|
||||
config_id: Optional[str] = None
|
||||
end_user_id: str
|
||||
config_id: Optional[str] = None
|
||||
@@ -35,7 +35,7 @@ class ConfigurationError(Exception):
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
config_id: Optional[int] = None,
|
||||
config_id: Optional[UUID] = None,
|
||||
workspace_id: Optional[UUID] = None,
|
||||
context: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
@@ -72,7 +72,7 @@ class WorkspaceNotFoundError(ConfigurationError):
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: UUID,
|
||||
config_id: Optional[int] = None,
|
||||
config_id: Optional[UUID] = None,
|
||||
message: Optional[str] = None,
|
||||
):
|
||||
if message is None:
|
||||
@@ -89,7 +89,7 @@ class ModelNotFoundError(ConfigurationError):
|
||||
self,
|
||||
model_id: Union[str, UUID],
|
||||
model_type: str,
|
||||
config_id: Optional[int] = None,
|
||||
config_id: Optional[UUID] = None,
|
||||
workspace_id: Optional[UUID] = None,
|
||||
message: Optional[str] = None,
|
||||
):
|
||||
@@ -112,7 +112,7 @@ class ModelInactiveError(ConfigurationError):
|
||||
model_id: Union[str, UUID],
|
||||
model_name: str,
|
||||
model_type: str,
|
||||
config_id: Optional[int] = None,
|
||||
config_id: Optional[UUID] = None,
|
||||
workspace_id: Optional[UUID] = None,
|
||||
message: Optional[str] = None,
|
||||
):
|
||||
@@ -136,7 +136,7 @@ class InvalidConfigError(ConfigurationError):
|
||||
message: str,
|
||||
field_name: Optional[str] = None,
|
||||
invalid_value: Optional[Any] = None,
|
||||
config_id: Optional[int] = None,
|
||||
config_id: Optional[UUID] = None,
|
||||
workspace_id: Optional[UUID] = None,
|
||||
):
|
||||
context = {}
|
||||
@@ -155,7 +155,7 @@ class InvalidConfigError(ConfigurationError):
|
||||
class MemoryConfigValidation(BaseModel):
|
||||
"""Pydantic model for validating memory configuration data from database."""
|
||||
|
||||
config_id: int = Field(..., gt=0, description="Configuration ID must be positive")
|
||||
config_id: UUID = Field(..., description="Configuration ID (UUID)")
|
||||
config_name: str = Field(..., min_length=1, max_length=255)
|
||||
workspace_id: UUID = Field(..., description="Workspace UUID")
|
||||
workspace_name: str = Field(..., min_length=1, max_length=255)
|
||||
@@ -275,7 +275,7 @@ class ModelValidation(BaseModel):
|
||||
|
||||
|
||||
def validate_memory_config_data(
|
||||
config_data: Dict[str, Any], config_id: Optional[int] = None
|
||||
config_data: Dict[str, Any], config_id: Optional[UUID] = None
|
||||
) -> MemoryConfigValidation:
|
||||
"""Validate memory configuration data using Pydantic model."""
|
||||
try:
|
||||
@@ -302,7 +302,7 @@ def validate_memory_config_data(
|
||||
|
||||
|
||||
def validate_workspace_data(
|
||||
workspace_data: Dict[str, Any], config_id: Optional[int] = None
|
||||
workspace_data: Dict[str, Any], config_id: Optional[UUID] = None
|
||||
) -> WorkspaceValidation:
|
||||
"""Validate workspace data using Pydantic model."""
|
||||
try:
|
||||
@@ -331,7 +331,7 @@ def validate_workspace_data(
|
||||
|
||||
|
||||
def validate_model_data(
|
||||
model_data: Dict[str, Any], config_id: Optional[int] = None
|
||||
model_data: Dict[str, Any], config_id: Optional[UUID] = None
|
||||
) -> ModelValidation:
|
||||
"""Validate model data using Pydantic model."""
|
||||
try:
|
||||
@@ -364,7 +364,7 @@ def validate_model_data(
|
||||
class MemoryConfig:
|
||||
"""Immutable memory configuration loaded from database."""
|
||||
|
||||
config_id: int
|
||||
config_id: UUID
|
||||
config_name: str
|
||||
workspace_id: UUID
|
||||
workspace_name: str
|
||||
|
||||
@@ -4,7 +4,7 @@ from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.models.memory_perceptual_model import PerceptualType, FileStorageType
|
||||
from app.models.memory_perceptual_model import PerceptualType, FileStorageService
|
||||
|
||||
|
||||
class PerceptualFilter(BaseModel):
|
||||
@@ -38,12 +38,14 @@ class PerceptualMemoryItem(BaseModel):
|
||||
"""感知记忆项"""
|
||||
id: uuid.UUID = Field(..., description="Unique memory ID")
|
||||
perceptual_type: PerceptualType = Field(..., description="Type of perception, e.g., text, audio, or video")
|
||||
storage_service: FileStorageService = Field(..., description="Storage service for file")
|
||||
file_path: str = Field(..., description="File path in the storage service")
|
||||
file_ext: str = Field(..., description="File extension")
|
||||
file_name: str = Field(..., description="File name")
|
||||
file_ext: str = Field(..., description="File extension")
|
||||
summary: Optional[str] = Field(None, description="summary")
|
||||
storage_type: FileStorageType = Field(..., description="Storage type for file")
|
||||
meta_data: Optional[dict] = Field(None, description="Metadata information")
|
||||
created_time: int = Field(..., description="create time")
|
||||
|
||||
topic: str = Field(..., description="topic")
|
||||
domain: str = Field(..., description="domain")
|
||||
keywords: list[str] = Field(..., description="keywords")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
from enum import Enum
|
||||
|
||||
|
||||
@@ -9,7 +10,7 @@ class OptimizationStrategy(str, Enum):
|
||||
ACCURACY_FIRST = "accuracy_first"
|
||||
BALANCED = "balanced"
|
||||
class Memory_Reflection(BaseModel):
|
||||
config_id: Optional[int] = None
|
||||
config_id: Optional[UUID] = None
|
||||
reflection_enabled: bool
|
||||
reflection_period_in_hours: str
|
||||
reflexion_range: Optional[str] = "partial"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
所有的内容是放错误地方了,应该放在models
|
||||
|
||||
"""
|
||||
|
||||
from typing import Any, Optional, List, Dict, Literal, Union
|
||||
@@ -8,20 +8,8 @@ import uuid
|
||||
from pydantic import BaseModel, Field, ConfigDict, field_validator, model_validator
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 原 UserInput 相关 Schema (保留原有功能)
|
||||
# ============================================================================
|
||||
class UserInput(BaseModel):
|
||||
message: str
|
||||
history: list[dict]
|
||||
search_switch: str
|
||||
group_id: str
|
||||
|
||||
|
||||
class Write_UserInput(BaseModel):
|
||||
message: str
|
||||
group_id: str
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 从 json_schema.py 迁移的 Schema
|
||||
@@ -159,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: int = Field("config_id", description="配置唯一标识(字符串)")
|
||||
config_id: uuid.UUID = Field("config_id", description="配置唯一标识(UUID)")
|
||||
user_id: str = Field("user_id", description="用户标识(字符串)")
|
||||
apply_id: str = Field("apply_id", description="应用或场景标识(字符串)")
|
||||
|
||||
@@ -250,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: int = Field("配置ID", description="配置ID(字符串)")
|
||||
config_id: uuid.UUID = Field("配置ID", description="配置ID(UUID)")
|
||||
|
||||
|
||||
class ConfigUpdate(BaseModel): # 更新记忆萃取引擎配置参数时使用的模型
|
||||
config_id: Optional[int] = None
|
||||
config_id: Optional[uuid.UUID] = None
|
||||
config_name: str = Field("配置名称", description="配置名称(字符串)")
|
||||
config_desc: str = Field("配置描述", description="配置描述(字符串)")
|
||||
|
||||
|
||||
class ConfigUpdateExtracted(BaseModel): # 更新记忆萃取引擎配置参数时使用的模型
|
||||
config_id: Optional[int] = None
|
||||
config_id: Optional[uuid.UUID] = 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")
|
||||
@@ -327,14 +315,14 @@ class ConfigUpdateExtracted(BaseModel): # 更新记忆萃取引擎配置参数
|
||||
|
||||
class ConfigUpdateForget(BaseModel): # 更新遗忘引擎配置参数时使用的模型
|
||||
# 遗忘引擎配置参数更新模型
|
||||
config_id: Optional[int] = None
|
||||
config_id: Optional[uuid.UUID] = 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: int = Field(..., description="配置ID(唯一)")
|
||||
config_id: uuid.UUID = Field(..., description="配置ID(唯一)")
|
||||
dialogue_text: str = Field(..., description="前端传入的对话文本,格式如 '用户: ...\nAI: ...' 可多行,试运行必填")
|
||||
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
||||
|
||||
@@ -342,7 +330,7 @@ class ConfigPilotRun(BaseModel): # 试运行触发请求模型
|
||||
class ConfigFilter(BaseModel): # 查询配置参数时使用的模型
|
||||
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
||||
|
||||
config_id: Optional[int] = None
|
||||
config_id: Optional[uuid.UUID] = None
|
||||
user_id: Optional[str] = None
|
||||
apply_id: Optional[str] = None
|
||||
|
||||
@@ -418,7 +406,7 @@ class ForgettingConfigResponse(BaseModel):
|
||||
"""遗忘引擎配置响应模型"""
|
||||
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
||||
|
||||
config_id: int = Field(..., description="配置ID")
|
||||
config_id: uuid.UUID = Field(..., description="配置ID")
|
||||
decay_constant: float = Field(..., description="衰减常数 d")
|
||||
lambda_time: float = Field(..., description="时间衰减参数")
|
||||
lambda_mem: float = Field(..., description="记忆衰减参数")
|
||||
@@ -436,7 +424,7 @@ class ForgettingConfigUpdateRequest(BaseModel):
|
||||
"""遗忘引擎配置更新请求模型"""
|
||||
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
||||
|
||||
config_id: int = Field(..., description="配置ID")
|
||||
config_id: uuid.UUID = Field(..., description="配置ID")
|
||||
decay_constant: Optional[float] = Field(None, ge=0.0, le=1.0, description="衰减常数 d")
|
||||
lambda_time: Optional[float] = Field(None, ge=0.0, le=1.0, description="时间衰减参数")
|
||||
lambda_mem: Optional[float] = Field(None, ge=0.0, le=1.0, description="记忆衰减参数")
|
||||
@@ -511,7 +499,7 @@ class ForgettingCurveRequest(BaseModel):
|
||||
|
||||
importance_score: float = Field(0.5, ge=0.0, le=1.0, description="重要性分数(0-1)")
|
||||
days: int = Field(60, ge=1, le=365, description="模拟天数(默认60天)")
|
||||
config_id: Optional[int] = Field(None, description="配置ID(可选,如果为None则使用默认配置)")
|
||||
config_id: Optional[uuid.UUID] = Field(None, description="配置ID(可选,如果为None则使用默认配置)")
|
||||
|
||||
|
||||
class ForgettingCurveResponse(BaseModel):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from pydantic import BaseModel, Field, field_serializer, ConfigDict
|
||||
from pydantic import BaseModel, Field, field_serializer, field_validator, ConfigDict
|
||||
from typing import Optional, List, Dict, Any
|
||||
import datetime
|
||||
import uuid
|
||||
@@ -91,6 +91,18 @@ class ModelApiKey(ModelApiKeyBase):
|
||||
created_at: datetime.datetime
|
||||
updated_at: datetime.datetime
|
||||
|
||||
@field_validator("config", mode="before")
|
||||
@classmethod
|
||||
def parse_config(cls, v):
|
||||
"""处理 config 字段,如果是字符串则解析为字典"""
|
||||
if isinstance(v, str):
|
||||
import json
|
||||
try:
|
||||
return json.loads(v)
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
return v
|
||||
|
||||
@field_serializer("created_at", when_used="json")
|
||||
def _serialize_created_at(self, dt: datetime.datetime):
|
||||
return int(dt.timestamp() * 1000) if dt else None
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import uuid
|
||||
import datetime
|
||||
from typing import Optional, List, Dict, Any
|
||||
from pydantic import BaseModel, Field, ConfigDict, field_serializer
|
||||
from pydantic import BaseModel, Field, ConfigDict, field_serializer, field_validator
|
||||
|
||||
|
||||
# ---------- Input Schemas ----------
|
||||
@@ -88,6 +88,18 @@ class SharedReleaseInfo(BaseModel):
|
||||
# 嵌入配置
|
||||
allow_embed: bool
|
||||
|
||||
@field_validator("config", mode="before")
|
||||
@classmethod
|
||||
def parse_config(cls, v):
|
||||
"""处理 config 字段,如果是字符串则解析为字典"""
|
||||
if isinstance(v, str):
|
||||
import json
|
||||
try:
|
||||
return json.loads(v)
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
return v if v is not None else {}
|
||||
|
||||
|
||||
class EmbedCode(BaseModel):
|
||||
"""嵌入代码"""
|
||||
|
||||
Reference in New Issue
Block a user