Feature/generate cache (#135)
* [feature]Generate emotions, implicit cache * [feature]Generate emotions, implicit cache * [changes]Improve the code based on AI review * [changes]Improve the code based on AI review * [changes]Improve the code * [feature]Generate emotions, implicit cache * [changes]Improve the code based on AI review * [changes]Improve the code
This commit is contained in:
@@ -11,6 +11,7 @@ from app.dependencies import (
|
||||
)
|
||||
from app.models.user_model import User
|
||||
from app.schemas.response_schema import ApiResponse
|
||||
from app.schemas.implicit_memory_schema import GenerateProfileRequest
|
||||
from app.services.implicit_memory_service import ImplicitMemoryService
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -133,7 +134,7 @@ async def get_preference_tags(
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> ApiResponse:
|
||||
"""
|
||||
Get user preference tags with filtering options.
|
||||
Get user preference tags from cache.
|
||||
|
||||
Args:
|
||||
user_id: Target user ID
|
||||
@@ -143,35 +144,56 @@ async def get_preference_tags(
|
||||
end_date: Optional end date filter
|
||||
|
||||
Returns:
|
||||
List of preference tags matching the filters
|
||||
List of preference tags from cache
|
||||
"""
|
||||
api_logger.info(f"Preference tags requested for user: {user_id}")
|
||||
api_logger.info(f"Preference tags requested for user: {user_id} (from cache)")
|
||||
|
||||
try:
|
||||
# Validate inputs
|
||||
validate_user_id(user_id)
|
||||
validate_confidence_threshold(confidence_threshold)
|
||||
validate_date_range(start_date, end_date)
|
||||
|
||||
# Create service with user-specific config
|
||||
service = ImplicitMemoryService(db=db, end_user_id=user_id)
|
||||
|
||||
# Build date range
|
||||
date_range = None
|
||||
if start_date and end_date:
|
||||
from app.schemas.implicit_memory_schema import DateRange
|
||||
date_range = DateRange(start_date=start_date, end_date=end_date)
|
||||
# Get cached profile
|
||||
cached_profile = await service.get_cached_profile(end_user_id=user_id, db=db)
|
||||
|
||||
# Get preference tags
|
||||
tags = await service.get_preference_tags(
|
||||
user_id=user_id,
|
||||
confidence_threshold=confidence_threshold,
|
||||
tag_category=tag_category,
|
||||
date_range=date_range
|
||||
)
|
||||
if cached_profile is None:
|
||||
api_logger.info(f"用户 {user_id} 的画像缓存不存在或已过期")
|
||||
return fail(
|
||||
BizCode.RESOURCE_NOT_FOUND,
|
||||
"画像缓存不存在或已过期,请调用 /generate_profile 接口生成新画像",
|
||||
None
|
||||
)
|
||||
|
||||
api_logger.info(f"Retrieved {len(tags)} preference tags for user: {user_id}")
|
||||
return success(data=[tag.model_dump(mode='json') for tag in tags], msg="偏好标签获取成功")
|
||||
# Extract preferences from cache
|
||||
preferences = cached_profile.get("preferences", [])
|
||||
|
||||
# Apply filters (client-side filtering on cached data)
|
||||
filtered_preferences = []
|
||||
for pref in preferences:
|
||||
# Filter by confidence threshold
|
||||
if confidence_threshold is not None and pref.get("confidence_score", 0) < confidence_threshold:
|
||||
continue
|
||||
|
||||
# Filter by category if specified
|
||||
if tag_category and pref.get("category") != tag_category:
|
||||
continue
|
||||
|
||||
# Filter by date range if specified
|
||||
if start_date or end_date:
|
||||
created_at_ts = pref.get("created_at")
|
||||
if created_at_ts:
|
||||
created_at = datetime.fromtimestamp(created_at_ts / 1000)
|
||||
if start_date and created_at < start_date:
|
||||
continue
|
||||
if end_date and created_at > end_date:
|
||||
continue
|
||||
|
||||
filtered_preferences.append(pref)
|
||||
|
||||
api_logger.info(f"Retrieved {len(filtered_preferences)} preference tags for user: {user_id} (from cache)")
|
||||
return success(data=filtered_preferences, msg="偏好标签获取成功(缓存)")
|
||||
|
||||
except Exception as e:
|
||||
return handle_implicit_memory_error(e, "偏好标签获取", user_id)
|
||||
@@ -186,16 +208,16 @@ async def get_dimension_portrait(
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> ApiResponse:
|
||||
"""
|
||||
Get user's four-dimension personality portrait.
|
||||
Get user's four-dimension personality portrait from cache.
|
||||
|
||||
Args:
|
||||
user_id: Target user ID
|
||||
include_history: Whether to include historical trend data
|
||||
include_history: Whether to include historical trend data (ignored for cached data)
|
||||
|
||||
Returns:
|
||||
Four-dimension personality portrait with scores and evidence
|
||||
Four-dimension personality portrait from cache
|
||||
"""
|
||||
api_logger.info(f"Dimension portrait requested for user: {user_id}")
|
||||
api_logger.info(f"Dimension portrait requested for user: {user_id} (from cache)")
|
||||
|
||||
try:
|
||||
# Validate inputs
|
||||
@@ -204,13 +226,22 @@ async def get_dimension_portrait(
|
||||
# Create service with user-specific config
|
||||
service = ImplicitMemoryService(db=db, end_user_id=user_id)
|
||||
|
||||
portrait = await service.get_dimension_portrait(
|
||||
user_id=user_id,
|
||||
include_history=include_history
|
||||
)
|
||||
# Get cached profile
|
||||
cached_profile = await service.get_cached_profile(end_user_id=user_id, db=db)
|
||||
|
||||
api_logger.info(f"Dimension portrait retrieved for user: {user_id}")
|
||||
return success(data=portrait.model_dump(mode='json'), msg="四维画像获取成功")
|
||||
if cached_profile is None:
|
||||
api_logger.info(f"用户 {user_id} 的画像缓存不存在或已过期")
|
||||
return fail(
|
||||
BizCode.RESOURCE_NOT_FOUND,
|
||||
"画像缓存不存在或已过期,请调用 /generate_profile 接口生成新画像",
|
||||
None
|
||||
)
|
||||
|
||||
# Extract portrait from cache
|
||||
portrait = cached_profile.get("portrait", {})
|
||||
|
||||
api_logger.info(f"Dimension portrait retrieved for user: {user_id} (from cache)")
|
||||
return success(data=portrait, msg="四维画像获取成功(缓存)")
|
||||
|
||||
except Exception as e:
|
||||
return handle_implicit_memory_error(e, "四维画像获取", user_id)
|
||||
@@ -225,16 +256,16 @@ async def get_interest_area_distribution(
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> ApiResponse:
|
||||
"""
|
||||
Get user's interest area distribution across four areas.
|
||||
Get user's interest area distribution from cache.
|
||||
|
||||
Args:
|
||||
user_id: Target user ID
|
||||
include_trends: Whether to include trend analysis data
|
||||
include_trends: Whether to include trend analysis data (ignored for cached data)
|
||||
|
||||
Returns:
|
||||
Interest area distribution with percentages and evidence
|
||||
Interest area distribution from cache
|
||||
"""
|
||||
api_logger.info(f"Interest area distribution requested for user: {user_id}")
|
||||
api_logger.info(f"Interest area distribution requested for user: {user_id} (from cache)")
|
||||
|
||||
try:
|
||||
# Validate inputs
|
||||
@@ -243,13 +274,22 @@ async def get_interest_area_distribution(
|
||||
# Create service with user-specific config
|
||||
service = ImplicitMemoryService(db=db, end_user_id=user_id)
|
||||
|
||||
distribution = await service.get_interest_area_distribution(
|
||||
user_id=user_id,
|
||||
include_trends=include_trends
|
||||
)
|
||||
# Get cached profile
|
||||
cached_profile = await service.get_cached_profile(end_user_id=user_id, db=db)
|
||||
|
||||
api_logger.info(f"Interest area distribution retrieved for user: {user_id}")
|
||||
return success(data=distribution.model_dump(mode='json'), msg="兴趣领域分布获取成功")
|
||||
if cached_profile is None:
|
||||
api_logger.info(f"用户 {user_id} 的画像缓存不存在或已过期")
|
||||
return fail(
|
||||
BizCode.RESOURCE_NOT_FOUND,
|
||||
"画像缓存不存在或已过期,请调用 /generate_profile 接口生成新画像",
|
||||
None
|
||||
)
|
||||
|
||||
# Extract interest areas from cache
|
||||
interest_areas = cached_profile.get("interest_areas", {})
|
||||
|
||||
api_logger.info(f"Interest area distribution retrieved for user: {user_id} (from cache)")
|
||||
return success(data=interest_areas, msg="兴趣领域分布获取成功(缓存)")
|
||||
|
||||
except Exception as e:
|
||||
return handle_implicit_memory_error(e, "兴趣领域分布获取", user_id)
|
||||
@@ -266,7 +306,7 @@ async def get_behavior_habits(
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> ApiResponse:
|
||||
"""
|
||||
Get user's behavioral habits with filtering options.
|
||||
Get user's behavioral habits from cache.
|
||||
|
||||
Args:
|
||||
user_id: Target user ID
|
||||
@@ -275,38 +315,117 @@ async def get_behavior_habits(
|
||||
time_period: Filter by time period (current, past)
|
||||
|
||||
Returns:
|
||||
List of behavioral habits matching the filters
|
||||
List of behavioral habits from cache
|
||||
"""
|
||||
api_logger.info(f"Behavior habits requested for user: {user_id}")
|
||||
api_logger.info(f"Behavior habits requested for user: {user_id} (from cache)")
|
||||
|
||||
try:
|
||||
# Validate inputs
|
||||
validate_user_id(user_id)
|
||||
|
||||
# Convert string confidence level to numerical
|
||||
numerical_confidence = None
|
||||
if confidence_level:
|
||||
confidence_mapping = {
|
||||
"high": 85,
|
||||
"medium": 50,
|
||||
"low": 20
|
||||
}
|
||||
numerical_confidence = confidence_mapping.get(confidence_level.lower())
|
||||
|
||||
# Create service with user-specific config
|
||||
service = ImplicitMemoryService(db=db, end_user_id=user_id)
|
||||
|
||||
habits = await service.get_behavior_habits(
|
||||
user_id=user_id,
|
||||
confidence_level=numerical_confidence,
|
||||
frequency_pattern=frequency_pattern,
|
||||
time_period=time_period
|
||||
)
|
||||
# Get cached profile
|
||||
cached_profile = await service.get_cached_profile(end_user_id=user_id, db=db)
|
||||
|
||||
api_logger.info(f"Retrieved {len(habits)} behavior habits for user: {user_id}")
|
||||
return success(data=[habit.model_dump(mode='json') for habit in habits], msg="行为习惯获取成功")
|
||||
if cached_profile is None:
|
||||
api_logger.info(f"用户 {user_id} 的画像缓存不存在或已过期")
|
||||
return fail(
|
||||
BizCode.RESOURCE_NOT_FOUND,
|
||||
"画像缓存不存在或已过期,请调用 /generate_profile 接口生成新画像",
|
||||
None
|
||||
)
|
||||
|
||||
# Extract habits from cache
|
||||
habits = cached_profile.get("habits", [])
|
||||
|
||||
# Apply filters (client-side filtering on cached data)
|
||||
filtered_habits = []
|
||||
for habit in habits:
|
||||
# Filter by confidence level
|
||||
if confidence_level:
|
||||
confidence_mapping = {
|
||||
"high": 85,
|
||||
"medium": 50,
|
||||
"low": 20
|
||||
}
|
||||
numerical_confidence = confidence_mapping.get(confidence_level.lower())
|
||||
if habit.get("confidence_level", 0) < numerical_confidence:
|
||||
continue
|
||||
|
||||
# Filter by frequency pattern
|
||||
if frequency_pattern and habit.get("frequency_pattern") != frequency_pattern:
|
||||
continue
|
||||
|
||||
# Filter by time period
|
||||
if time_period:
|
||||
is_current = habit.get("is_current", True)
|
||||
if time_period.lower() == "current" and not is_current:
|
||||
continue
|
||||
elif time_period.lower() == "past" and is_current:
|
||||
continue
|
||||
|
||||
filtered_habits.append(habit)
|
||||
|
||||
api_logger.info(f"Retrieved {len(filtered_habits)} behavior habits for user: {user_id} (from cache)")
|
||||
return success(data=filtered_habits, msg="行为习惯获取成功(缓存)")
|
||||
|
||||
except Exception as e:
|
||||
return handle_implicit_memory_error(e, "行为习惯获取", user_id)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@router.post("/generate_profile", response_model=ApiResponse)
|
||||
@cur_workspace_access_guard()
|
||||
async def generate_implicit_memory_profile(
|
||||
request: GenerateProfileRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> ApiResponse:
|
||||
"""
|
||||
Generate complete user profile (all 4 modules) and cache it.
|
||||
|
||||
Args:
|
||||
request: Generate profile request with end_user_id
|
||||
db: Database session
|
||||
current_user: Current authenticated user
|
||||
|
||||
Returns:
|
||||
Complete user profile with all modules
|
||||
"""
|
||||
end_user_id = request.end_user_id
|
||||
api_logger.info(f"Generate profile requested for user: {end_user_id}")
|
||||
|
||||
try:
|
||||
# Validate inputs
|
||||
validate_user_id(end_user_id)
|
||||
|
||||
# Create service with user-specific config
|
||||
service = ImplicitMemoryService(db=db, end_user_id=end_user_id)
|
||||
|
||||
# Generate complete profile (calls LLM for all 4 modules)
|
||||
api_logger.info(f"开始生成完整用户画像: user={end_user_id}")
|
||||
profile_data = await service.generate_complete_profile(user_id=end_user_id)
|
||||
|
||||
# Save to cache
|
||||
await service.save_profile_cache(
|
||||
end_user_id=end_user_id,
|
||||
profile_data=profile_data,
|
||||
db=db,
|
||||
expires_hours=168 # 7 days
|
||||
)
|
||||
|
||||
api_logger.info(f"用户画像生成并缓存成功: user={end_user_id}")
|
||||
|
||||
# Add metadata
|
||||
profile_data["end_user_id"] = end_user_id
|
||||
profile_data["cached"] = False
|
||||
|
||||
return success(data=profile_data, msg="用户画像生成成功")
|
||||
|
||||
except Exception as e:
|
||||
api_logger.error(f"生成用户画像失败: user={end_user_id}, error={str(e)}", exc_info=True)
|
||||
return handle_implicit_memory_error(e, "用户画像生成", end_user_id)
|
||||
|
||||
Reference in New Issue
Block a user