一、具体工作

1、核心功能模块实现

1.1 基础用户与宠物信息管理

1.1.1 前后端联调中的典型问题与解决

前端请求无响应:浏览器控制台报 Failed to resolve import “@/utils/request”。原因是 Vite 默认不支持 @ 别名。解决方案:在 vite.config.js 中配置 resolve.alias 或改用相对路径导入。同时添加 console.log 调试,发现表单验证 canSubmit 为 false,测试手机号格式不对(使用了 12345678901 而正则要求第二位 3-9)。修正测试数据后请求成功发出。
后端 500 错误:注册时未传 email 字段,但数据库 email 列定义为 NOT NULL。经讨论,产品设计允许邮箱为空,因此将模型中的 email 改为 nullable=True,并在注册接口中允许 email 为 None。前端注册请求不再携带 email 字段。
Token 存储 key 不一致:前端路由守卫检查 localStorage 中的 petai_token,而后端返回字段为 access_token。统一约定前端存储 key 为 petai_token,后端保持 access_token,前端在登录成功后将 data.access_token 存入 localStorage.setItem(‘petai_token’, …)。

1.2 音频采集与上传

需求:支持本地音频上传,格式 MP3/WAV,单文件 ≤50MB;支持预览、删除;上传成功率 ≥95%;文件与宠物信息精准关联。

1.2.1 上传接口设计

接口:POST /api/audio/upload,参数:pet_id(必填)、audio(文件)。处理流程:

验证登录态,获取 current_user_id

校验 pet_id 是否属于当前用户

校验文件格式(mp3/wav)和大小(≤50MB)

将文件保存到 backend/static/uploads/,命名规则:{pet_id}{timestamp}{original_filename}

使用 librosa 提取音频信息:时长、采样率、文件大小

插入 audio_records 表,状态为 uploaded(待分析)

返回 record_id、文件 URL 等信息

1.2.2 文件存储优化

最初音频文件保存在临时目录(tempfile.gettempdir()),服务重启后会丢失。改为永久存储目录,并使用 shutil.copy 将临时文件移动到目标位置,再删除临时文件。这样即使服务重启,音频文件依然可用。

1.3 宠物情绪识别

这是项目的核心技术难点,涉及音频特征提取、大模型调用以及结果解析。

1.3.1 音频特征提取与自然语言转换

原始特征:使用 librosa 提取 MFCC 前 5 维均值、能量均值、过零率均值等数值。然而,通用大模型无法理解这些声学数值,导致模型总是返回“平静”。解决方案:新增自然语言转换层,将数值映射为可读描述。

转换规则示例:

if energy_mean < 0.02:
    energy_desc = "音量很低,声音微弱"
elif energy_mean < 0.05:
    energy_desc = "音量适中,正常响度"
elif energy_mean < 0.1:
    energy_desc = "音量较大,声音明显"
else:
    energy_desc = "音量很大,声音响亮"

if zcr_mean > 0.2:
    zcr_desc = "声音变化非常频繁,可能处于紧张状态"
else:
    zcr_desc = "声音变化平稳"

最终构建的自然语言特征描述类似:

音量较大,声音明显;音调波动明显;声音变化频繁;整体声音呈现尖锐特征。

1.3.2 大模型 API 迁移与调试

最初使用阿里云 DashScope 通义千问,但因稳定性问题迁移至 SophNet 平台(提供 OpenAI 兼容接口)。在 config.py 中配置新 API Key 和 Base URL。

遇到的问题:使用 Python requests 调用时返回 HTTP 500,而平台提供的 curl 命令可以正常调用。通过添加调试日志,对比请求头差异,发现 SophNet 网关会检查 User-Agent 字段,默认的 python-requests/2.x 被拒绝。解决方案:在请求头中伪装成 curl/7.68.0。

headers = {
    "Authorization": f"Bearer {self.api_key}",
    "Content-Type": "application/json",
    "User-Agent": "curl/7.68.0"   # 关键修复
}

模型选择:对比了 qwen-turbo、qwen-max 等模型的效果,最终选用 qwen-max,其对情绪描述的敏感度和准确率更高。

1.3.3 情绪分析接口

接口:POST /api/audio/analyze,参数:record_id(音频记录 ID)。流程:
根据 record_id 获取音频记录,验证 pet_id 属于当前用户
读取音频文件路径,重新提取特征(或使用已有特征)
将自然语言特征传入大模型,获取情绪结果
解析模型返回的 JSON:{ “emotion”: “兴奋”, “confidence”: 0.92, “analysis”: “…” }
将情绪结果入库 emotion_results 表,关联 record_id
更新 audio_records 状态为 analyzed
返回情绪结果给前端
情绪类型枚举映射:大模型返回中文情绪(兴奋/焦虑/痛苦/应激/平静),数据库中存储枚举值(excited/anxious/pain/stress/normal)。建立显式映射:

emotion_map = {
    "兴奋": EmotionTypeEnum.excited,
    "焦虑": EmotionTypeEnum.anxious,
    "痛苦": EmotionTypeEnum.pain,
    "应激": EmotionTypeEnum.stress,
    "平静": EmotionTypeEnum.normal
}
1.3.4 事务处理与异常回滚

为保证数据一致性,在保存 audio_record 后使用 db.session.flush() 获取自增 record_id,再保存 emotion_result,最后统一 commit。任何异常均执行 db.session.rollback() 并清理临时文件。

1.4 健康评估与养护建议

本模块负责调用大模型 API,根据宠物基础信息和情绪识别结果生成健康评估与个性化养护建议。
接口:POST /api/advice/generate,参数:pet_id、emotion_result(可选,若未传则使用最近一次识别结果)
Prompt 设计:
python

prompt = f"""
你是专业宠物健康专家。现有宠物信息:
- 品种:{pet.breed},年龄:{pet.age}个月,体重:{pet.weight}kg
- 最近情绪识别:{emotion}(置信度{confidence})

请分析其心理与身体状态,并给出3-5条具体可行的养护建议。
输出JSON格式:
{{
  "psychological_analysis": "心理状态分析...",
  "physical_analysis": "身体状态分析...",
  "suggestions": ["建议1", "建议2", "建议3"]
}}
"""

调用与超时控制:设置 timeout=5 秒,超时或异常时返回降级建议(如“请稍后重试”)。评估结果同步存入 advice_records 表,关联宠物 ID 和用户 ID。
性能:实测响应时间在 3~4 秒内,满足 ≤5 秒的要求。

1.5 历史数据管理

需求:按时间倒序展示识别记录,支持近 7 天/30 天时间范围查询;支持单条记录查看详情、删除;数据仅用户自身可见。
实现:
接口 GET /api/history/,参数:range(week/month/all),默认 week
根据 range 计算起始时间:datetime.now() - timedelta(days=7 or 30)
联表查询 audio_records 和 emotion_results,过滤 user_id(通过 pet 表关联)
按 created_at 倒序排序,返回分页结果(每页 10 条)
删除接口 DELETE /api/history/<record_id>:先验证记录所属用户,再级联删除关联的情绪结果和建议记录。

2、系统安全与权限控制

2.1 登录态校验

所有核心接口(除注册登录外)均添加 @jwt_required() 装饰器,强制要求请求头携带 Authorization: Bearer 。前端 Axios 拦截器自动添加该头。

2.2 数据隔离

每个数据查询操作都显式加入 user_id 过滤。例如获取宠物列表:

pets = Pet.query.filter_by(user_id=current_user_id).all()
对于通过 URL 传递的 pet_id 或 record_id,先查询其所属用户,若与当前用户不匹配则返回 403

2.3 参数合法性校验

手机号格式、密码长度
宠物年龄、体重范围(非负)
文件类型和大小
pet_id 存在性
时间范围参数合法性
使用 marshmallow 或手动校验,避免 SQL 注入(SQLAlchemy 已参数化查询,无需额外转义)。

3、异常处理与容错机制

3.1 音频上传中断

前端捕获 network error,提示用户“网络异常,请重试”
后端在接收文件过程中若发生异常,确保删除已上传的临时文件

3.2 大模型调用失败或超时

设置 timeout=20 秒(情绪识别)和 timeout=5 秒(养护建议)
超时或异常时返回友好错误信息,不抛出未处理异常导致服务崩溃
记录详细日志(包括请求内容、响应状态码、异常堆栈),便于排查

3.3 数据库操作失败

所有写操作包裹在 try-except 中,发生异常时 db.session.rollback()
返回 500 状态码和通用错误消息,避免暴露数据库细节

3.4 降级处理

当养护建议接口超时或大模型不可用时,返回默认建议列表(如“保持良好饮食、定期体检”)
情绪识别若失败,标记音频记录状态为 failed,允许用户重新上传或稍后重试

4、经验与反思

4.1 技术难点与解决

前端路径别名问题:Vite 与 Vue CLI 的差异导致 @ 别名失效,通过配置 resolve.alias 解决。
大模型调用 User-Agent 校验:第三方 API 网关对请求头敏感,伪装成 curl 绕过。
特征数值理解问题:大模型无法直接理解声学数值,通过自然语言转换层解决。
数据库枚举映射:中英文情绪值映射,避免直接存储中文。
事务与 flush 顺序:使用 db.session.flush() 获取自增 ID 后保存关联数据。

4.2 协作经验

接口先行:提前定义好 API 契约,减少联调时的反复修改。
日志调试:在关键路径添加 print 或 logging,快速定位问题。
版本控制:使用 git worktree 同时维护前后端分支,提高开发效率。
及时沟通:遇到阻塞问题(如 API 返回 500、字段名不一致)立即同步,避免各自排查浪费时间。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐