diff --git a/src/agents/extract_people_agent.py b/src/agents/extract_people_agent.py index 1e62721..9ef9029 100644 --- a/src/agents/extract_people_agent.py +++ b/src/agents/extract_people_agent.py @@ -21,7 +21,7 @@ class ExtractPeopleAgent(BaseAgent): "身高(cm) height\n" "婚姻状况 marital_status\n" "择偶要求 match_requirement\n" - "以上信息需要严格按照 JSON 格式输出 字段名与条目中英文保持一致。\n" + "以上信息需要严格按照 JSON 格式输出 字段名与条目中英文保持一致; 若未识别到以上的某项,则不返回该字段,不要自行填写“未知”,“未填写”等类似字眼。\n" "其中,'年龄 age' 和 '身高(cm) height' 必须是一个整数,不能是一个字符串;\n" "并且,'性别 gender' 根据识别结果,必须从 男,女,未知 三选一填写。\n" "除了上述基本信息,还有一个字段\n" diff --git a/src/models/people.py b/src/models/people.py index 2a73c4e..68bbadc 100644 --- a/src/models/people.py +++ b/src/models/people.py @@ -4,6 +4,7 @@ import json import logging from typing import Dict +from datetime import datetime from sqlalchemy import Column, Integer, String, Text, DateTime, func from utils.rldb import RLDBBaseModel from utils.error import ErrorCode, error @@ -26,6 +27,37 @@ class PeopleRLDBModel(RLDBBaseModel): deleted_at = Column(DateTime(timezone=True), nullable=True, index=True) +class Comment: + # 评论内容 + content: str + # 评论人 + author: str + # 创建时间 + created_at: datetime + # 更新时间 + updated_at: datetime + + def __init__(self, **kwargs): + self.content = kwargs.get('content', '') + self.author = kwargs.get('author', '') + self.created_at = kwargs.get('created_at', datetime.now()) + self.updated_at = kwargs.get('updated_at', datetime.now()) + + def to_dict(self) -> dict: + return { + 'content': self.content, + 'author': self.author, + 'created_at': int(self.created_at.timestamp()), + 'updated_at': int(self.updated_at.timestamp()), + } + + @classmethod + def from_dict(cls, data: dict): + data['created_at'] = datetime.fromtimestamp(data['created_at']) + data['updated_at'] = datetime.fromtimestamp(data['updated_at']) + return cls(**data) + + class People: # 数据库 ID id: str @@ -46,9 +78,11 @@ class People: # 个人介绍 introduction: Dict[str, str] # 总结评价 - comments: Dict[str, str] + comments: Dict[str, "Comment"] # 封面 cover: str = None + # 创建时间 + created_at: datetime = None def __init__(self, **kwargs): # 初始化所有属性,从kwargs中获取值,如果不存在则设置默认值 @@ -63,19 +97,17 @@ class People: self.introduction = kwargs.get('introduction', {}) if kwargs.get('introduction', {}) is not None else {} self.comments = kwargs.get('comments', {}) if kwargs.get('comments', {}) is not None else {} self.cover = kwargs.get('cover', None) if kwargs.get('cover', None) is not None else None + self.created_at = kwargs.get('created_at', None) def __str__(self) -> str: # 返回对象的字符串表示,包含所有属性 return (f"People(id={self.id}, name={self.name}, contact={self.contact}, gender={self.gender}, " f"age={self.age}, height={self.height}, marital_status={self.marital_status}, " f"match_requirement={self.match_requirement}, introduction={self.introduction}, " - f"comments={self.comments}, cover={self.cover})") + f"comments={self.comments}, cover={self.cover}, created_at={self.created_at})") @classmethod def from_dict(cls, data: dict): - if 'created_at' in data: - # 移除 created_at 字段,避免类型错误 - del data['created_at'] if 'updated_at' in data: # 移除 updated_at 字段,避免类型错误 del data['updated_at'] @@ -97,8 +129,9 @@ class People: marital_status=data.marital_status, match_requirement=data.match_requirement, introduction=json.loads(data.introduction) if data.introduction else {}, - comments=json.loads(data.comments) if data.comments else {}, + comments={k: Comment.from_dict(v) for k, v in json.loads(data.comments).items()} if data.comments else {}, cover=data.cover, + created_at=data.created_at, ) def to_dict(self) -> dict: @@ -113,8 +146,9 @@ class People: 'marital_status': self.marital_status, 'match_requirement': self.match_requirement, 'introduction': self.introduction, - 'comments': self.comments, + 'comments': {k: v.to_dict() for k, v in self.comments.items()}, 'cover': self.cover, + 'created_at': int(self.created_at.timestamp()) if self.created_at else None, } def to_rldb_model(self) -> PeopleRLDBModel: @@ -129,22 +163,22 @@ class People: marital_status=self.marital_status, match_requirement=self.match_requirement, introduction=json.dumps(self.introduction, ensure_ascii=False), - comments=json.dumps(self.comments, ensure_ascii=False), + comments=json.dumps({k: v.to_dict() for k, v in self.comments.items()}, ensure_ascii=False), cover=self.cover, ) def validate(self) -> error: err = error(ErrorCode.SUCCESS, "") if not self.name: - logging.error("Name is required") - err = error(ErrorCode.MODEL_ERROR, "Name is required") + logging.error("Name is required, use default") + self.name = "" if not self.gender in ['男', '女', '未知']: - logging.error("Gender must be '男', '女', or '未知'") - err = error(ErrorCode.MODEL_ERROR, "Gender must be '男', '女', or '未知'") - if not isinstance(self.age, int) or self.age <= 0: - logging.error("Age must be an integer and greater than 0") - err = error(ErrorCode.MODEL_ERROR, "Age must be an integer and greater than 0") - if not isinstance(self.height, int) or self.height <= 0: - logging.error("Height must be an integer and greater than 0") - err = error(ErrorCode.MODEL_ERROR, "Height must be an integer and greater than 0") + logging.error("Gender must be '男', '女', or '未知', use default") + self.gender = "未知" + if not isinstance(self.age, int) or self.age < 0: + logging.error("Age must be an integer and greater than 0, use default") + self.age = 0 + if not isinstance(self.height, int) or self.height < 0: + logging.error("Height must be an integer and greater than 0, use default") + self.height = 0 return err diff --git a/src/services/people.py b/src/services/people.py index 0baac9a..c05369f 100644 --- a/src/services/people.py +++ b/src/services/people.py @@ -1,8 +1,10 @@ +import logging import uuid -from models.people import People, PeopleRLDBModel +from models.people import People, PeopleRLDBModel, Comment +from datetime import datetime from utils.error import ErrorCode, error from utils import rldb @@ -66,6 +68,50 @@ class PeopleService: return peoples, error(ErrorCode.SUCCESS, "") + def save_remark(self, people_id: str, content: str) -> error: + """ + 为人物添加或更新备注 + + :param people_id: 人物ID + :param content: 备注内容 + :return: 错误对象 + """ + people: People + err: error + people, err = self.get(people_id) + logging.info(f"get people before save remark: {people}") + if not err.success: + return err + remark = people.comments.get("remark", None) + if remark is not None: + remark.content = content + remark.updated_at = datetime.now() + else: + people.comments["remark"] = Comment(content=content) + logging.info(f"save remark for people {people}") + _, err = self.save(people) + return err + + def delete_remark(self, people_id: str) -> error: + """ + 删除人物备注 + + :param people_id: 人物ID + :return: 错误对象 + """ + people: People + err: error + people, err = self.get(people_id) + if not err.success: + return err + + if "remark" in people.comments: + del people.comments["remark"] + _, err = self.save(people) + return err + + return error(ErrorCode.SUCCESS, "") + people_service = None diff --git a/src/web/api.py b/src/web/api.py index 5f04e04..511571f 100644 --- a/src/web/api.py +++ b/src/web/api.py @@ -150,3 +150,24 @@ async def get_peoples( peoples = [people.to_dict() for people in results] return BaseResponse(error_code=0, error_info="success", data=peoples) + +class RemarkRequest(BaseModel): + content: str + + +@api.post("/people/{people_id}/remark") +async def post_remark(people_id: str, request: RemarkRequest): + service = get_people_service() + error = service.save_remark(people_id, request.content) + if not error.success: + return BaseResponse(error_code=error.code, error_info=error.info) + return BaseResponse(error_code=0, error_info="success") + + +@api.delete("/people/{people_id}/remark") +async def delete_remark(people_id: str): + service = get_people_service() + error = service.delete_remark(people_id) + if not error.success: + return BaseResponse(error_code=error.code, error_info=error.info) + return BaseResponse(error_code=0, error_info="success")