2026-04-24 14:44:38 +08:00

99 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
合规检查模块:检查生成的标书是否响应了招标关键要求
"""
import json
import logging
import re
import sqlite3
from utils import ai_client
logger = logging.getLogger(__name__)
CHECK_PROMPT = """你是一位专业的投标文件技术审核专家。请对照以下【技术评分要求】,检查【标书技术内容】的覆盖情况,输出技术合规检查报告。
重要限制(必须遵守):
★ 本次检查范围仅限技术内容,包括:技术方案、实施能力、技术指标、质量保障、人员配置、技术创新等
★ 严禁将商务评分、价格评分、资质评分、报价、合同条款、付款方式等商务内容纳入检查项
★ 若技术评分要求中混有商务条款,直接忽略,不得作为检查项输出
【技术评分要求】
{requirements}
【标书技术内容(各章节摘要)】
{content}
请输出以下格式的 JSON每个 item 均为技术评分项,不含任何商务内容:
{{
"overall_score": 85,
"status": "良好",
"items": [
{{
"requirement": "技术评分要求描述",
"covered": true,
"note": "说明"
}}
],
"missing_points": ["未覆盖的技术要点1", "未覆盖的技术要点2"],
"suggestions": ["技术内容改进建议1", "技术内容改进建议2"]
}}
"""
def check_compliance(db_path: str, project_id: int) -> dict:
"""
执行合规检查,返回检查结果字典。
"""
conn = sqlite3.connect(db_path)
try:
# 获取招标要求
cur = conn.cursor()
cur.execute(
"SELECT summary, rating_requirements FROM tender_data WHERE project_id=?",
(project_id,)
)
td = cur.fetchone()
if not td:
return {'error': '尚未解析招标文件'}
# 只使用技术评分要求作为检查基准,排除 summary 中可能包含的商务内容
requirements = (td[1] or '').strip()
if not requirements:
return {'error': '尚未提取技术评分要求,请先完成步骤一的招标文件解析'}
# 收集已生成的章节内容(取前 500 字)
cur.execute(
"SELECT section_title, content FROM bid_sections WHERE project_id=? AND status='done' ORDER BY order_index",
(project_id,)
)
rows = cur.fetchall()
if not rows:
return {'error': '尚未生成标书内容,请先生成'}
content_parts = []
for title, content in rows:
snippet = (content or '')[:500].replace('\n', ' ')
content_parts.append(f"{title}{snippet}")
content_str = '\n'.join(content_parts)
# 调用 AI 检查
prompt = CHECK_PROMPT.format(requirements=requirements[:3000], content=content_str[:6000])
raw = ai_client.chat(prompt, temperature=0.2, max_tokens=2048)
# 解析 JSON
raw = re.sub(r'```(?:json)?\s*', '', raw).replace('```', '').strip()
m = re.search(r'\{[\s\S]*\}', raw)
if m:
raw = m.group(0)
result = json.loads(raw)
return result
except json.JSONDecodeError as e:
logger.error(f'合规检查结果解析失败: {e}')
return {'error': f'AI 返回格式异常: {e}', 'raw': raw}
except Exception as e:
logger.exception('合规检查失败')
return {'error': str(e)}
finally:
conn.close()