Merge #21 into develop from feature/emotion-engine

feature/情绪引擎

* feature/emotion-engine: (7 commits squashed)

  - [feature]Emotion Engine Development

  - [feature]Emotion Engine Development

  - Merge branch 'feature/emotion-engine' of codeup.aliyun.com:redbearai/python/redbear-mem-open into feature/emotion-engine

  - [fix]1.Fix the front-end files;2.Cache Management Deletion;3.Delete "check_code.py"

  - [fix]1.Fix the front-end files;2.Cache Management Deletion;3.Delete "check_code.py"

  - Merge branch 'feature/emotion-engine' of codeup.aliyun.com:redbearai/python/redbear-mem-open into feature/emotion-engine

  - [fix]fix vite.config.ts

Signed-off-by: 乐力齐 <accounts_690c7b0af9007d7e338af636@mail.teambition.com>
Commented-by: aliyun6762716068 <accounts_68cb7c6b61f5dcc4200d6251@mail.teambition.com>
Commented-by: 乐力齐 <accounts_690c7b0af9007d7e338af636@mail.teambition.com>
Reviewed-by: aliyun6762716068 <accounts_68cb7c6b61f5dcc4200d6251@mail.teambition.com>
Merged-by: aliyun6762716068 <accounts_68cb7c6b61f5dcc4200d6251@mail.teambition.com>

CR-link: https://codeup.aliyun.com/redbearai/python/redbear-mem-open/change/21
This commit is contained in:
乐力齐
2025-12-20 07:02:46 +00:00
committed by 孙科
parent 1f0bb1f8af
commit 1f4524c28c
23 changed files with 2453 additions and 67 deletions

View File

@@ -29,6 +29,8 @@ from . import (
public_share_controller,
multi_agent_controller,
workflow_controller,
emotion_controller,
emotion_config_controller,
prompt_optimizer_controller,
)
@@ -60,6 +62,8 @@ manager_router.include_router(public_share_controller.router) # 公开路由(
manager_router.include_router(memory_dashboard_controller.router)
manager_router.include_router(multi_agent_controller.router)
manager_router.include_router(workflow_controller.router)
manager_router.include_router(emotion_controller.router)
manager_router.include_router(emotion_config_controller.router)
manager_router.include_router(prompt_optimizer_controller.router)
manager_router.include_router(memory_reflection_controller.router)
__all__ = ["manager_router"]

View File

@@ -0,0 +1,207 @@
# -*- coding: utf-8 -*-
"""情绪配置控制器模块
本模块提供情绪引擎配置管理的API端点包括获取和更新配置。
Routes:
GET /memory/config/emotion - 获取情绪引擎配置
POST /memory/config/emotion - 更新情绪引擎配置
"""
from fastapi import APIRouter, Depends, Query, HTTPException, status
from pydantic import BaseModel, Field
from typing import Optional
from sqlalchemy.orm import Session
from app.core.response_utils import success
from app.dependencies import get_current_user
from app.models.user_model import User
from app.schemas.response_schema import ApiResponse
from app.services.emotion_config_service import EmotionConfigService
from app.core.logging_config import get_api_logger
from app.db import get_db
# 获取API专用日志器
api_logger = get_api_logger()
router = APIRouter(
prefix="/memory/emotion",
tags=["Emotion Config"],
dependencies=[Depends(get_current_user)] # 所有路由都需要认证
)
class EmotionConfigQuery(BaseModel):
"""情绪配置查询请求模型"""
config_id: int = Field(..., description="配置ID")
class EmotionConfigUpdate(BaseModel):
"""情绪配置更新请求模型"""
config_id: int = Field(..., description="配置ID")
emotion_enabled: bool = Field(..., description="是否启用情绪提取")
emotion_model_id: Optional[str] = Field(None, description="情绪分析专用模型ID")
emotion_extract_keywords: bool = Field(..., description="是否提取情绪关键词")
emotion_min_intensity: float = Field(..., ge=0.0, le=1.0, description="最小情绪强度阈值0.0-1.0")
emotion_enable_subject: bool = Field(..., description="是否启用主体分类")
@router.get("/read_config", response_model=ApiResponse)
def get_emotion_config(
config_id: int = Query(..., description="配置ID"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""获取情绪引擎配置
查询指定配置ID的情绪相关配置字段。
Args:
config_id: 配置ID
Returns:
ApiResponse: 包含情绪配置数据
Example Response:
{
"code": 2000,
"msg": "情绪配置获取成功",
"data": {
"config_id": 17,
"emotion_enabled": true,
"emotion_model_id": "gpt-4",
"emotion_extract_keywords": true,
"emotion_min_intensity": 0.1,
"emotion_enable_subject": true
}
}
"""
try:
api_logger.info(
f"用户 {current_user.username} 请求获取情绪配置",
extra={"config_id": config_id}
)
# 初始化服务
config_service = EmotionConfigService(db)
# 调用服务层
data = config_service.get_emotion_config(config_id)
api_logger.info(
"情绪配置获取成功",
extra={
"config_id": config_id,
"emotion_enabled": data.get("emotion_enabled", False)
}
)
return success(data=data, msg="情绪配置获取成功")
except ValueError as e:
api_logger.warning(
f"获取情绪配置失败: {str(e)}",
extra={"config_id": config_id}
)
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(e)
)
except Exception as e:
api_logger.error(
f"获取情绪配置失败: {str(e)}",
extra={"config_id": config_id},
exc_info=True
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取情绪配置失败: {str(e)}"
)
@router.post("/updated_config", response_model=ApiResponse)
def update_emotion_config(
config: EmotionConfigUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""更新情绪引擎配置
更新指定配置ID的情绪相关配置字段。
Args:
config: 配置更新数据包含config_id
Returns:
ApiResponse: 包含更新后的情绪配置数据
Example Request:
{
"config_id": 2,
"emotion_enabled": true,
"emotion_model_id": "gpt-4",
"emotion_extract_keywords": true,
"emotion_min_intensity": 0.1,
"emotion_enable_subject": true
}
Example Response:
{
"code": 2000,
"msg": "情绪配置更新成功",
"data": {
"config_id": 17,
"emotion_enabled": true,
"emotion_model_id": "gpt-4",
"emotion_extract_keywords": true,
"emotion_min_intensity": 0.2,
"emotion_enable_subject": true
}
}
"""
try:
api_logger.info(
f"用户 {current_user.username} 请求更新情绪配置",
extra={
"config_id": config.config_id,
"emotion_enabled": config.emotion_enabled,
"emotion_min_intensity": config.emotion_min_intensity
}
)
# 初始化服务
config_service = EmotionConfigService(db)
# 转换为字典排除config_id因为它作为参数传递
config_data = config.model_dump(exclude={'config_id'})
# 调用服务层
data = config_service.update_emotion_config(config.config_id, config_data)
api_logger.info(
"情绪配置更新成功",
extra={
"config_id": config.config_id,
"emotion_enabled": data.get("emotion_enabled", False)
}
)
return success(data=data, msg="情绪配置更新成功")
except ValueError as e:
api_logger.warning(
f"更新情绪配置失败: {str(e)}",
extra={"config_id": config.config_id}
)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e)
)
except Exception as e:
api_logger.error(
f"更新情绪配置失败: {str(e)}",
extra={"config_id": config.config_id},
exc_info=True
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"更新情绪配置失败: {str(e)}"
)

View File

@@ -0,0 +1,255 @@
# -*- coding: utf-8 -*-
"""情绪分析控制器模块
本模块提供情绪分析相关的API端点包括情绪标签、词云、健康指数和个性化建议。
Routes:
POST /emotion/tags - 获取情绪标签统计
POST /emotion/wordcloud - 获取情绪词云数据
POST /emotion/health - 获取情绪健康指数
POST /emotion/suggestions - 获取个性化情绪建议
"""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app.core.response_utils import success, fail
from app.core.error_codes import BizCode
from app.dependencies import get_current_user, get_db
from app.models.user_model import User
from app.schemas.response_schema import ApiResponse
from app.schemas.emotion_schema import (
EmotionTagsRequest,
EmotionWordcloudRequest,
EmotionHealthRequest,
EmotionSuggestionsRequest
)
from app.services.emotion_analytics_service import EmotionAnalyticsService
from app.core.logging_config import get_api_logger
# 获取API专用日志器
api_logger = get_api_logger()
router = APIRouter(
prefix="/memory/emotion",
tags=["Emotion Analysis"],
dependencies=[Depends(get_current_user)] # 所有路由都需要认证
)
# 初始化情绪分析服务uv
emotion_service = EmotionAnalyticsService()
@router.post("/tags", response_model=ApiResponse)
async def get_emotion_tags(
request: EmotionTagsRequest,
current_user: User = Depends(get_current_user),
):
try:
api_logger.info(
f"用户 {current_user.username} 请求获取情绪标签统计",
extra={
"group_id": request.group_id,
"emotion_type": request.emotion_type,
"start_date": request.start_date,
"end_date": request.end_date,
"limit": request.limit
}
)
# 调用服务层
data = await emotion_service.get_emotion_tags(
end_user_id=request.group_id,
emotion_type=request.emotion_type,
start_date=request.start_date,
end_date=request.end_date,
limit=request.limit
)
api_logger.info(
"情绪标签统计获取成功",
extra={
"group_id": request.group_id,
"total_count": data.get("total_count", 0),
"tags_count": len(data.get("tags", []))
}
)
return success(data=data, msg="情绪标签获取成功")
except Exception as e:
api_logger.error(
f"获取情绪标签统计失败: {str(e)}",
extra={"group_id": request.group_id},
exc_info=True
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取情绪标签统计失败: {str(e)}"
)
@router.post("/wordcloud", response_model=ApiResponse)
async def get_emotion_wordcloud(
request: EmotionWordcloudRequest,
current_user: User = Depends(get_current_user),
):
try:
api_logger.info(
f"用户 {current_user.username} 请求获取情绪词云数据",
extra={
"group_id": request.group_id,
"emotion_type": request.emotion_type,
"limit": request.limit
}
)
# 调用服务层
data = await emotion_service.get_emotion_wordcloud(
end_user_id=request.group_id,
emotion_type=request.emotion_type,
limit=request.limit
)
api_logger.info(
"情绪词云数据获取成功",
extra={
"group_id": request.group_id,
"total_keywords": data.get("total_keywords", 0)
}
)
return success(data=data, msg="情绪词云获取成功")
except Exception as e:
api_logger.error(
f"获取情绪词云数据失败: {str(e)}",
extra={"group_id": request.group_id},
exc_info=True
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取情绪词云数据失败: {str(e)}"
)
@router.post("/health", response_model=ApiResponse)
async def get_emotion_health(
request: EmotionHealthRequest,
current_user: User = Depends(get_current_user),
):
try:
# 验证时间范围参数
if request.time_range not in ["7d", "30d", "90d"]:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="时间范围参数无效,必须是 7d、30d 或 90d"
)
api_logger.info(
f"用户 {current_user.username} 请求获取情绪健康指数",
extra={
"group_id": request.group_id,
"time_range": request.time_range
}
)
# 调用服务层
data = await emotion_service.calculate_emotion_health_index(
end_user_id=request.group_id,
time_range=request.time_range
)
api_logger.info(
"情绪健康指数获取成功",
extra={
"group_id": request.group_id,
"health_score": data.get("health_score", 0),
"level": data.get("level", "未知")
}
)
return success(data=data, msg="情绪健康指数获取成功")
except HTTPException:
raise
except Exception as e:
api_logger.error(
f"获取情绪健康指数失败: {str(e)}",
extra={"group_id": request.group_id},
exc_info=True
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取情绪健康指数失败: {str(e)}"
)
@router.post("/suggestions", response_model=ApiResponse)
async def get_emotion_suggestions(
request: EmotionSuggestionsRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""获取个性化情绪建议
Args:
request: 包含 group_id 和可选的 config_id
db: 数据库会话
current_user: 当前用户
Returns:
个性化情绪建议响应
"""
try:
# 验证 config_id如果提供
config_id = request.config_id
if config_id is not None:
from app.controllers.memory_agent_controller import validate_config_id
try:
config_id = validate_config_id(config_id, db)
except ValueError as e:
return fail(BizCode.INVALID_PARAMETER, "配置ID无效", str(e))
api_logger.info(
f"用户 {current_user.username} 请求获取个性化情绪建议",
extra={
"group_id": request.group_id,
"config_id": config_id
}
)
# 调用服务层
data = await emotion_service.generate_emotion_suggestions(
end_user_id=request.group_id,
config_id=config_id
)
api_logger.info(
"个性化建议获取成功",
extra={
"group_id": request.group_id,
"suggestions_count": len(data.get("suggestions", []))
}
)
return success(data=data, msg="个性化建议获取成功")
except Exception as e:
api_logger.error(
f"获取个性化建议失败: {str(e)}",
extra={"group_id": request.group_id},
exc_info=True
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取个性化建议失败: {str(e)}"
)