海报 PDF 解析从 Gunicorn 后台线程迁移到 Celery Worker,消除 gevent/asyncio.run 冲突和任务卡死。 海报改为紧凑解析,只选择客户资料、保费和核心利益页;排除提领方案、悲观/乐观情景页。 LLM 调用由原来的约 27 次降为 1 次。 补充年缴保费、首年实缴、缴费期、总保费及第 1/5/10/15/20/25/30 年退保价值。 增加真实解析进度、错误信息、任务 ID、心跳和完成时间。 相同用户重复上传同一份计划书时复用现有任务或结果。 前端取消 180 秒本地假超时,改为串行轮询后端真实状态;网络波动不再误判解析失败。 增加服务重启后的过期任务恢复机制。 修复解析结果 JSON 序列化遗漏问题。 关键文件: [extraction.py](D:/work/code/python/coding/baodanagent/api/insurance/ppt/extraction.py) [tasks.py](D:/work/code/python/coding/baodanagent/api/insurance/poster/tasks.py) [celery_tasks.py](D:/work/code/python/coding/baodanagent/api/insurance/generation/celery_tasks.py) [service.py](D:/work/code/python/coding/baodanagent/api/insurance/poster/service.py) [migrate_032.py](D:/work/code/python/coding/baodanagent/api/insurance/db/migrate_032.py) [PosterSourcePanel.vue](D:/work/code/python/coding/baodanagent/frontend/src/components/poster/workspace/PosterSourcePanel.vue) [回归测试](D:/work/code/python/coding/baodanagent/tests/ppt_poster_optimization_test.py)
63 lines
2.2 KiB
Python
63 lines
2.2 KiB
Python
"""迁移 032:海报计划书解析任务进度与文件去重字段。"""
|
||
import logging
|
||
|
||
from sqlalchemy import inspect, text
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def migrate():
|
||
from insurance.db.compat import db
|
||
|
||
table_name = "poster_case_uploads"
|
||
columns = {
|
||
item["name"]
|
||
for item in inspect(db.engine).get_columns(table_name)
|
||
}
|
||
additions = {
|
||
"parse_progress": "INTEGER NOT NULL DEFAULT 0",
|
||
"parse_message": "VARCHAR(500) NOT NULL DEFAULT ''",
|
||
"parse_error": "TEXT",
|
||
"parse_task_id": "VARCHAR(200)",
|
||
"parse_started_at": "TIMESTAMP",
|
||
"parse_heartbeat_at": "TIMESTAMP",
|
||
"parse_finished_at": "TIMESTAMP",
|
||
"file_hash": "VARCHAR(64)",
|
||
}
|
||
for name, column_type in additions.items():
|
||
if name not in columns:
|
||
db.session.execute(text(
|
||
f"ALTER TABLE {table_name} ADD COLUMN {name} {column_type}"
|
||
))
|
||
|
||
indexes = {
|
||
item["name"]
|
||
for item in inspect(db.engine).get_indexes(table_name)
|
||
}
|
||
if "idx_poster_case_owner_hash" not in indexes:
|
||
db.session.execute(text(
|
||
"CREATE INDEX idx_poster_case_owner_hash "
|
||
"ON poster_case_uploads (user_id, file_hash)"
|
||
))
|
||
|
||
db.session.execute(text(
|
||
"UPDATE poster_case_uploads SET parse_status = 'failed', parse_progress = 100, "
|
||
"parse_message = '解析任务已中断', "
|
||
"parse_error = '服务升级后请重新解析', parse_finished_at = CURRENT_TIMESTAMP "
|
||
"WHERE parse_status IN ('queued', 'parsing')"
|
||
))
|
||
db.session.execute(text(
|
||
"UPDATE poster_case_uploads SET parse_progress = 100 "
|
||
"WHERE parse_status IN ('parsed', 'partial', 'failed')"
|
||
))
|
||
db.session.execute(text(
|
||
"UPDATE poster_case_uploads SET parse_message = CASE "
|
||
"WHEN parse_status = 'parsed' THEN '解析完成' "
|
||
"WHEN parse_status = 'partial' THEN '解析完成,部分字段需核对' "
|
||
"WHEN parse_status = 'failed' THEN '解析失败' "
|
||
"ELSE COALESCE(parse_message, '') END "
|
||
"WHERE parse_message IS NULL OR parse_message = ''"
|
||
))
|
||
db.session.commit()
|
||
logger.info("[migrate_032] 海报计划书解析任务字段迁移完成")
|