Merge branch 'release/v0.2.2'
# Conflicts: # api/app/repositories/memory_config_repository.py # api/app/services/emotion_analytics_service.py # api/app/utils/config_utils.py
This commit is contained in:
@@ -32,6 +32,8 @@ db_logger = get_db_logger()
|
|||||||
config_logger = get_config_logger()
|
config_logger = get_config_logger()
|
||||||
|
|
||||||
TABLE_NAME = "memory_config"
|
TABLE_NAME = "memory_config"
|
||||||
|
|
||||||
|
|
||||||
class MemoryConfigRepository:
|
class MemoryConfigRepository:
|
||||||
"""记忆配置Repository
|
"""记忆配置Repository
|
||||||
|
|
||||||
@@ -189,7 +191,6 @@ class MemoryConfigRepository:
|
|||||||
raise RuntimeError("reflection config not found")
|
raise RuntimeError("reflection config not found")
|
||||||
return memory_config
|
return memory_config
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build_select_all(workspace_id: uuid.UUID) -> Tuple[str, Dict]:
|
def build_select_all(workspace_id: uuid.UUID) -> Tuple[str, Dict]:
|
||||||
"""构建查询所有配置的语句(SQLAlchemy text() 命名参数)
|
"""构建查询所有配置的语句(SQLAlchemy text() 命名参数)
|
||||||
@@ -289,7 +290,6 @@ class MemoryConfigRepository:
|
|||||||
db_logger.error(f"更新记忆配置失败: config_id={update.config_id} - {str(e)}")
|
db_logger.error(f"更新记忆配置失败: config_id={update.config_id} - {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_extracted(db: Session, update: ConfigUpdateExtracted) -> Optional[MemoryConfig]:
|
def update_extracted(db: Session, update: ConfigUpdateExtracted) -> Optional[MemoryConfig]:
|
||||||
"""更新记忆萃取引擎配置
|
"""更新记忆萃取引擎配置
|
||||||
@@ -412,7 +412,7 @@ class MemoryConfigRepository:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_extracted_config(db: Session, config_id: UUID |int) -> Optional[Dict]:
|
def get_extracted_config(db: Session, config_id: UUID | int) -> Optional[Dict]:
|
||||||
"""获取萃取配置,通过主键查询某条配置
|
"""获取萃取配置,通过主键查询某条配置
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -422,7 +422,7 @@ class MemoryConfigRepository:
|
|||||||
Returns:
|
Returns:
|
||||||
Optional[Dict]: 萃取配置字典,不存在则返回None
|
Optional[Dict]: 萃取配置字典,不存在则返回None
|
||||||
"""
|
"""
|
||||||
config_id=resolve_config_id(config_id,db)
|
config_id = resolve_config_id(config_id, db)
|
||||||
db_logger.debug(f"查询萃取配置: config_id={config_id}")
|
db_logger.debug(f"查询萃取配置: config_id={config_id}")
|
||||||
try:
|
try:
|
||||||
db_config = db.query(MemoryConfig).filter(MemoryConfig.config_id == config_id).first()
|
db_config = db.query(MemoryConfig).filter(MemoryConfig.config_id == config_id).first()
|
||||||
@@ -516,8 +516,9 @@ class MemoryConfigRepository:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
db_logger.error(f"根据ID查询记忆配置失败: config_id={config_id} - {str(e)}")
|
db_logger.error(f"根据ID查询记忆配置失败: config_id={config_id} - {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_config_with_workspace(db: Session, config_id: uuid.UUID) -> Optional[tuple]:
|
def get_config_with_workspace(db: Session, config_id: uuid.UUID | int | str) -> Optional[tuple]:
|
||||||
"""Get memory config and its associated workspace information
|
"""Get memory config and its associated workspace information
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -526,7 +527,6 @@ class MemoryConfigRepository:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[tuple]: (MemoryConfig, Workspace) tuple, None if not found
|
Optional[tuple]: (MemoryConfig, Workspace) tuple, None if not found
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: Raised when config exists but workspace doesn't
|
ValueError: Raised when config exists but workspace doesn't
|
||||||
"""
|
"""
|
||||||
@@ -535,6 +535,7 @@ class MemoryConfigRepository:
|
|||||||
from app.models.workspace_model import Workspace
|
from app.models.workspace_model import Workspace
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
config_id = resolve_config_id(config_id, db)
|
||||||
|
|
||||||
# Log configuration loading start
|
# Log configuration loading start
|
||||||
config_logger.info(
|
config_logger.info(
|
||||||
@@ -552,7 +553,6 @@ class MemoryConfigRepository:
|
|||||||
result = db.query(MemoryConfig, Workspace).join(
|
result = db.query(MemoryConfig, Workspace).join(
|
||||||
Workspace, MemoryConfig.workspace_id == Workspace.id
|
Workspace, MemoryConfig.workspace_id == Workspace.id
|
||||||
).filter(MemoryConfig.config_id == config_id).first()
|
).filter(MemoryConfig.config_id == config_id).first()
|
||||||
|
|
||||||
elapsed_ms = (time.time() - start_time) * 1000
|
elapsed_ms = (time.time() - start_time) * 1000
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
@@ -583,8 +583,10 @@ class MemoryConfigRepository:
|
|||||||
"elapsed_ms": elapsed_ms
|
"elapsed_ms": elapsed_ms
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
db_logger.error(f"Memory config {config_id} references non-existent workspace {config_only.workspace_id}")
|
db_logger.error(
|
||||||
raise ValueError(f"Workspace {config_only.workspace_id} not found for configuration {config_id}")
|
f"Memory config {config_id} references non-existent workspace {config_only.workspace_id}")
|
||||||
|
raise ValueError(
|
||||||
|
f"Workspace {config_only.workspace_id} not found for configuration {config_id}")
|
||||||
|
|
||||||
config_logger.debug(
|
config_logger.debug(
|
||||||
"Configuration not found",
|
"Configuration not found",
|
||||||
@@ -615,7 +617,8 @@ class MemoryConfigRepository:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
db_logger.debug(f"Memory config and workspace query successful: config={config.config_name}, workspace={workspace.name}")
|
db_logger.debug(
|
||||||
|
f"Memory config and workspace query successful: config={config.config_name}, workspace={workspace.name}")
|
||||||
return (config, workspace)
|
return (config, workspace)
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -636,9 +639,9 @@ class MemoryConfigRepository:
|
|||||||
},
|
},
|
||||||
exc_info=True
|
exc_info=True
|
||||||
)
|
)
|
||||||
|
|
||||||
db_logger.error(f"Failed to query memory config and workspace: config_id={config_id} - {str(e)}")
|
db_logger.error(f"Failed to query memory config and workspace: config_id={config_id} - {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all(db: Session, workspace_id: Optional[uuid.UUID] = None) -> List[MemoryConfig]:
|
def get_all(db: Session, workspace_id: Optional[uuid.UUID] = None) -> List[MemoryConfig]:
|
||||||
"""获取所有配置参数
|
"""获取所有配置参数
|
||||||
|
|||||||
@@ -17,12 +17,15 @@ from app.repositories.neo4j.neo4j_connector import Neo4jConnector
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.utils.config_utils import resolve_config_id
|
||||||
|
|
||||||
logger = get_business_logger()
|
logger = get_business_logger()
|
||||||
|
|
||||||
|
|
||||||
class EmotionSuggestion(BaseModel):
|
class EmotionSuggestion(BaseModel):
|
||||||
"""情绪建议模型"""
|
"""情绪建议模型"""
|
||||||
type: str = Field(..., description="建议类型:emotion_balance/activity_recommendation/social_connection/stress_management")
|
type: str = Field(...,
|
||||||
|
description="建议类型:emotion_balance/activity_recommendation/social_connection/stress_management")
|
||||||
title: str = Field(..., description="建议标题")
|
title: str = Field(..., description="建议标题")
|
||||||
content: str = Field(..., description="建议内容")
|
content: str = Field(..., description="建议内容")
|
||||||
priority: str = Field(..., description="优先级:high/medium/low")
|
priority: str = Field(..., description="优先级:high/medium/low")
|
||||||
@@ -55,12 +58,12 @@ class EmotionAnalyticsService:
|
|||||||
logger.info("情绪分析服务初始化完成")
|
logger.info("情绪分析服务初始化完成")
|
||||||
|
|
||||||
async def get_emotion_tags(
|
async def get_emotion_tags(
|
||||||
self,
|
self,
|
||||||
end_user_id: str,
|
end_user_id: str,
|
||||||
emotion_type: Optional[str] = None,
|
emotion_type: Optional[str] = None,
|
||||||
start_date: Optional[str] = None,
|
start_date: Optional[str] = None,
|
||||||
end_date: Optional[str] = None,
|
end_date: Optional[str] = None,
|
||||||
limit: int = 10
|
limit: int = 10
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""获取情绪标签统计
|
"""获取情绪标签统计
|
||||||
|
|
||||||
@@ -71,7 +74,7 @@ class EmotionAnalyticsService:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info(f"获取情绪标签统计: user={end_user_id}, type={emotion_type}, "
|
logger.info(f"获取情绪标签统计: user={end_user_id}, type={emotion_type}, "
|
||||||
f"start={start_date}, end={end_date}, limit={limit}")
|
f"start={start_date}, end={end_date}, limit={limit}")
|
||||||
|
|
||||||
# 调用仓储层查询
|
# 调用仓储层查询
|
||||||
tags = await self.emotion_repo.get_emotion_tags(
|
tags = await self.emotion_repo.get_emotion_tags(
|
||||||
@@ -133,10 +136,10 @@ class EmotionAnalyticsService:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
async def get_emotion_wordcloud(
|
async def get_emotion_wordcloud(
|
||||||
self,
|
self,
|
||||||
end_user_id: str,
|
end_user_id: str,
|
||||||
emotion_type: Optional[str] = None,
|
emotion_type: Optional[str] = None,
|
||||||
limit: int = 50
|
limit: int = 50
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""获取情绪词云数据
|
"""获取情绪词云数据
|
||||||
|
|
||||||
@@ -211,7 +214,7 @@ class EmotionAnalyticsService:
|
|||||||
score = 50.0 # 如果没有非中性情绪,默认为50
|
score = 50.0 # 如果没有非中性情绪,默认为50
|
||||||
|
|
||||||
logger.debug(f"积极率计算: positive={positive_count}, negative={negative_count}, "
|
logger.debug(f"积极率计算: positive={positive_count}, negative={negative_count}, "
|
||||||
f"neutral={neutral_count}, score={score:.2f}")
|
f"neutral={neutral_count}, score={score:.2f}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"score": round(score, 2),
|
"score": round(score, 2),
|
||||||
@@ -250,7 +253,7 @@ class EmotionAnalyticsService:
|
|||||||
score = (1 - min(std_deviation, 1.0)) * 100
|
score = (1 - min(std_deviation, 1.0)) * 100
|
||||||
|
|
||||||
logger.debug(f"稳定性计算: intensities_count={len(intensities)}, "
|
logger.debug(f"稳定性计算: intensities_count={len(intensities)}, "
|
||||||
f"std_deviation={std_deviation:.3f}, score={score:.2f}")
|
f"std_deviation={std_deviation:.3f}, score={score:.2f}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"score": round(score, 2),
|
"score": round(score, 2),
|
||||||
@@ -303,7 +306,7 @@ class EmotionAnalyticsService:
|
|||||||
score = 100.0
|
score = 100.0
|
||||||
|
|
||||||
logger.debug(f"恢复力计算: negative_count={negative_count}, "
|
logger.debug(f"恢复力计算: negative_count={negative_count}, "
|
||||||
f"recovery_count={recovery_count}, score={score:.2f}")
|
f"recovery_count={recovery_count}, score={score:.2f}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"score": round(score, 2),
|
"score": round(score, 2),
|
||||||
@@ -311,9 +314,9 @@ class EmotionAnalyticsService:
|
|||||||
}
|
}
|
||||||
|
|
||||||
async def calculate_emotion_health_index(
|
async def calculate_emotion_health_index(
|
||||||
self,
|
self,
|
||||||
end_user_id: str,
|
end_user_id: str,
|
||||||
time_range: str = "30d"
|
time_range: str = "30d"
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""计算情绪健康指数
|
"""计算情绪健康指数
|
||||||
|
|
||||||
@@ -366,9 +369,9 @@ class EmotionAnalyticsService:
|
|||||||
# 计算综合健康分数
|
# 计算综合健康分数
|
||||||
# 公式:positivity_rate * 0.4 + stability * 0.3 + resilience * 0.3
|
# 公式:positivity_rate * 0.4 + stability * 0.3 + resilience * 0.3
|
||||||
health_score = (
|
health_score = (
|
||||||
positivity_rate["score"] * 0.4 +
|
positivity_rate["score"] * 0.4 +
|
||||||
stability["score"] * 0.3 +
|
stability["score"] * 0.3 +
|
||||||
resilience["score"] * 0.3
|
resilience["score"] * 0.3
|
||||||
)
|
)
|
||||||
|
|
||||||
# 确定健康等级
|
# 确定健康等级
|
||||||
@@ -460,7 +463,7 @@ class EmotionAnalyticsService:
|
|||||||
volatility = "未知"
|
volatility = "未知"
|
||||||
|
|
||||||
logger.debug(f"情绪模式分析: dominant_negative={dominant_negative_emotion}, "
|
logger.debug(f"情绪模式分析: dominant_negative={dominant_negative_emotion}, "
|
||||||
f"high_intensity_count={len(high_intensity_emotions)}, volatility={volatility}")
|
f"high_intensity_count={len(high_intensity_emotions)}, volatility={volatility}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"dominant_negative_emotion": dominant_negative_emotion,
|
"dominant_negative_emotion": dominant_negative_emotion,
|
||||||
@@ -469,9 +472,9 @@ class EmotionAnalyticsService:
|
|||||||
}
|
}
|
||||||
|
|
||||||
async def generate_emotion_suggestions(
|
async def generate_emotion_suggestions(
|
||||||
self,
|
self,
|
||||||
end_user_id: str,
|
end_user_id: str,
|
||||||
db: Session,
|
db: Session,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""生成个性化情绪建议
|
"""生成个性化情绪建议
|
||||||
|
|
||||||
@@ -498,7 +501,7 @@ class EmotionAnalyticsService:
|
|||||||
|
|
||||||
connected_config = get_end_user_connected_config(end_user_id, db)
|
connected_config = get_end_user_connected_config(end_user_id, db)
|
||||||
config_id = connected_config.get("memory_config_id")
|
config_id = connected_config.get("memory_config_id")
|
||||||
|
config_id = resolve_config_id(config_id, db)
|
||||||
if config_id is not None:
|
if config_id is not None:
|
||||||
from app.services.memory_config_service import (
|
from app.services.memory_config_service import (
|
||||||
MemoryConfigService,
|
MemoryConfigService,
|
||||||
@@ -618,10 +621,10 @@ class EmotionAnalyticsService:
|
|||||||
return {"interests": ["未知"]}
|
return {"interests": ["未知"]}
|
||||||
|
|
||||||
async def _build_suggestion_prompt(
|
async def _build_suggestion_prompt(
|
||||||
self,
|
self,
|
||||||
health_data: Dict[str, Any],
|
health_data: Dict[str, Any],
|
||||||
patterns: Dict[str, Any],
|
patterns: Dict[str, Any],
|
||||||
user_profile: Dict[str, Any]
|
user_profile: Dict[str, Any]
|
||||||
) -> str:
|
) -> str:
|
||||||
"""构建情绪建议生成的prompt
|
"""构建情绪建议生成的prompt
|
||||||
|
|
||||||
@@ -707,9 +710,9 @@ class EmotionAnalyticsService:
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def get_cached_suggestions(
|
async def get_cached_suggestions(
|
||||||
self,
|
self,
|
||||||
end_user_id: str,
|
end_user_id: str,
|
||||||
db: Session,
|
db: Session,
|
||||||
) -> Optional[Dict[str, Any]]:
|
) -> Optional[Dict[str, Any]]:
|
||||||
"""从 Redis 缓存获取个性化情绪建议
|
"""从 Redis 缓存获取个性化情绪建议
|
||||||
|
|
||||||
@@ -740,11 +743,11 @@ class EmotionAnalyticsService:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def save_suggestions_cache(
|
async def save_suggestions_cache(
|
||||||
self,
|
self,
|
||||||
end_user_id: str,
|
end_user_id: str,
|
||||||
suggestions_data: Dict[str, Any],
|
suggestions_data: Dict[str, Any],
|
||||||
db: Session,
|
db: Session,
|
||||||
expires_hours: int = 24
|
expires_hours: int = 24
|
||||||
) -> None:
|
) -> None:
|
||||||
"""保存建议到 Redis 缓存
|
"""保存建议到 Redis 缓存
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from uuid import UUID
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
|
||||||
def resolve_config_id(config_id: UUID | int, db: Session) -> UUID:
|
def resolve_config_id(config_id: UUID | int|str, db: Session) -> UUID:
|
||||||
"""
|
"""
|
||||||
解析 config_id,如果是整数则通过 config_id_old 查找对应的 UUID
|
解析 config_id,如果是整数则通过 config_id_old 查找对应的 UUID
|
||||||
|
|
||||||
@@ -21,16 +21,17 @@ def resolve_config_id(config_id: UUID | int, db: Session) -> UUID:
|
|||||||
Raises:
|
Raises:
|
||||||
ValueError: 当找不到对应的配置时
|
ValueError: 当找不到对应的配置时
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from app.models.memory_config_model import MemoryConfig
|
from app.models.memory_config_model import MemoryConfig
|
||||||
if isinstance(config_id, UUID):
|
if isinstance(config_id, UUID):
|
||||||
return config_id
|
return config_id
|
||||||
if isinstance(config_id, str) and len(config_id)<=6:
|
if isinstance(config_id, str) and len(config_id)<=6:
|
||||||
memory_config = db.query(MemoryConfig).filter(
|
memory_config = db.query(MemoryConfig).filter(
|
||||||
MemoryConfig.config_id_old == config_id
|
MemoryConfig.config_id_old == int(config_id)
|
||||||
).first()
|
).first()
|
||||||
|
print(memory_config)
|
||||||
if not memory_config:
|
if not memory_config:
|
||||||
raise ValueError(f"未找到 config_id_old={config_id} 对应的配置")
|
raise ValueError(f"STR 未找到 config_id_old={config_id} 对应的配置")
|
||||||
return memory_config.config_id
|
return memory_config.config_id
|
||||||
if isinstance(config_id, int):
|
if isinstance(config_id, int):
|
||||||
memory_config = db.query(MemoryConfig).filter(
|
memory_config = db.query(MemoryConfig).filter(
|
||||||
@@ -38,7 +39,7 @@ def resolve_config_id(config_id: UUID | int, db: Session) -> UUID:
|
|||||||
).first()
|
).first()
|
||||||
|
|
||||||
if not memory_config:
|
if not memory_config:
|
||||||
raise ValueError(f"未找到 config_id_old={config_id} 对应的配置")
|
raise ValueError(f"INT 未找到 config_id_old={config_id} 对应的配置")
|
||||||
|
|
||||||
return memory_config.config_id
|
return memory_config.config_id
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user