99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
"""
|
||
合规检查模块:检查生成的标书是否响应了招标关键要求
|
||
"""
|
||
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()
|