添加ai智能体标书接口,修改ai_agent仅暴露一个方法供外部调用

This commit is contained in:
2025-12-02 19:28:37 +08:00
parent 11d857e000
commit bc1f19542f
3 changed files with 259 additions and 58 deletions

View File

@ -8,11 +8,10 @@ from docx import Document
from shutil import which
import requests
from config import OLLAMA_BASE_URL, OLLAMA_MODEL
INPUT_WORD = r"C:\Users\YC\Desktop\1.docx" # 你的招标文件
OUTPUT_WORD = r"C:\Users\YC\Desktop\投标文件-最终版.docx" # 最终输出路径
OLLAMA_MODEL = "alibayram/Qwen3-30B-A3B-Instruct-2507:latest" # 当前最强本地模型
OLLAMA_BASE_URL = "http://192.168.110.5:11434"
# ==================== Ollama 本地调用(支持 128K 上下文 + 长输出)===================
@ -82,7 +81,7 @@ def word_to_md(word_path: str) -> str:
if not pandoc_cmd:
common = [
os.path.expanduser(r"~\AppData\Local\Pandoc\pandoc.exe"),
r"C:\Program Files\Pandoc\pandoc.exe",
r"./util/pandoc.exe",
]
for p in common:
if os.path.exists(p):
@ -110,7 +109,7 @@ def word_to_md(word_path: str) -> str:
# ==================== 新版:两步生成超级目录(永不超时)===================
def generate_full_outline(tender_md: str) -> str:
tender_text = Path(tender_md).read_text(encoding="utf-8")
print(f"招标文件共 {len(tender_text)//2} 字,开始两阶段生成四级目录...")
print(f"招标文件共 {len(tender_text) // 2} 字,开始两阶段生成四级目录...")
# 第一步:先让模型只看前 6 万字生成一个【简洁但完整】的三级目录超快10秒内出
prompt1 = f"""请仔细阅读以下招标文件核心内容只输出一个简洁但完整的三级目录一级用“一、”二级用“1、”三级用“1.1、”)。
@ -143,7 +142,7 @@ def generate_full_outline(tender_md: str) -> str:
# 每 8个三级标题为一组展开四级稳到爆
full_outline = outline_skeleton + "\n"
for i in range(0, len(level3_titles), 8):
batch = level3_titles[i:i+8]
batch = level3_titles[i:i + 8]
batch_text = "\n".join(batch)
prompt2 = f"""你是一位招投标专家,请把下面这几个三级标题分别展开成 1018 个专业四级标题(格式必须是 1.1.1、1.1.2、……)。
@ -157,7 +156,7 @@ def generate_full_outline(tender_md: str) -> str:
直接输出四级标题:"""
print(f" 正在展开第 {i//8 + 1} 组四级标题({len(batch)}个)...")
print(f" 正在展开第 {i // 8 + 1} 组四级标题({len(batch)}个)...")
level4_text = call_llm([{"role": "user", "content": prompt2}],
temperature=0.2, max_tokens=20000)
full_outline += "\n" + level4_text + "\n"
@ -165,7 +164,7 @@ def generate_full_outline(tender_md: str) -> str:
# 保存并返回
Path("output/四级目录.md").write_text(full_outline, encoding="utf-8")
print(f"超级四级目录生成成功!总计约 {len(full_outline)//2} 字(再也不怕超时了!)")
print(f"超级四级目录生成成功!总计约 {len(full_outline) // 2} 字(再也不怕超时了!)")
return full_outline
@ -255,26 +254,37 @@ def update_word_toc(docx_path: str):
print(f"Word目录自动更新失败可手动右键更新{e}")
# ==================== 主流程 ====================
def main():
print("启动本地 Qwen3-30B 投标文件生成器128K上下文版\n")
os.makedirs("output", exist_ok=True)
# ==================== 统一对外暴露的方法(唯一入口)===================
def generate_tender_from_input(input_word_path: str, output_word_path: str) -> bool:
"""
统一对外暴露的投标文件生成方法
# 1. 转换招标文件
tender_md = word_to_md(INPUT_WORD)
tender_text = Path(tender_md).read_text(encoding="utf-8")
Args:
input_word_path: 输入招标文件路径(.docx/.doc
output_word_path: 输出投标文件路径(.docx
# 2. 生成超级详细目录
outline = generate_full_outline(tender_md)
Returns:
bool: 生成成功返回True失败返回False
"""
try:
print("启动投标文件生成器(统一入口)\n")
os.makedirs("output", exist_ok=True)
# 3. 分批生成正文(超长内容
content = batch_fill_content(outline, tender_text)
content = expand_to_50000_words(content)
# 1. 转换招标文件
tender_md = word_to_md(input_word_path)
tender_text = Path(tender_md).read_text(encoding="utf-8")
# 4. 合成最终 Markdown
final_md = f"""# 【投标单位全称】
# 2. 生成超级详细目录
outline = generate_full_outline(tender_md)
## {Path(INPUT_WORD).stem} - 投标文件
# 3. 分批生成正文
content = batch_fill_content(outline, tender_text)
content = expand_to_50000_words(content)
# 4. 合成最终 Markdown
final_md = f"""# 【投标单位全称】
## {Path(input_word_path).stem} - 投标文件
{outline}
@ -287,41 +297,57 @@ def main():
- 类似业绩证明材料
- 偏离表
"""
final_md_path = "output/最终投标文件.md"
Path(final_md_path).write_text(final_md, encoding="utf-8")
print(f"\n最终 Markdown 生成成功!总计约 {len(final_md) // 2}")
final_md_path = "output/最终投标文件.md"
Path(final_md_path).write_text(final_md, encoding="utf-8")
print(f"\n最终 Markdown 生成成功!总计约 {len(final_md) // 2}")
# 5. 转 Word三保险
print("正在转换为 Word 文档...")
success = False
pandoc_cmd = which("pandoc") or which("pandoc.exe")
if pandoc_cmd and os.path.exists(pandoc_cmd):
cmd = [pandoc_cmd, final_md_path, "-o", OUTPUT_WORD, "--reference-doc=template.docx"] if os.path.exists(
"template.docx") else [pandoc_cmd, final_md_path, "-o", OUTPUT_WORD]
if subprocess.run(cmd, capture_output=True).returncode == 0:
success = True
# 5. 转 Word三保险
print("正在转换为 Word 文档...")
success = False
pandoc_cmd = which("pandoc") or which("pandoc.exe")
if pandoc_cmd and os.path.exists(pandoc_cmd):
cmd = [pandoc_cmd, final_md_path, "-o", output_word_path,
"--reference-doc=template.docx"] if os.path.exists(
"template.docx") else [pandoc_cmd, final_md_path, "-o", output_word_path]
if subprocess.run(cmd, capture_output=True).returncode == 0:
success = True
if not success:
print("Pandoc 失败,使用 python-docx 强制生成...")
doc = Document()
for line in final_md.split('\n'):
l = line.strip()
if l.startswith("# "):
doc.add_heading(l[2:], 0)
elif l.startswith("## "):
doc.add_heading(l[3:], 1)
elif l.startswith("### "):
doc.add_heading(l[4:], 2)
elif l.startswith("#### "):
doc.add_heading(l[5:], 3)
elif l:
doc.add_paragraph(l)
doc.save(OUTPUT_WORD)
if not success:
print("Pandoc 失败,使用 python-docx 强制生成...")
doc = Document()
for line in final_md.split('\n'):
l = line.strip()
if l.startswith("# "):
doc.add_heading(l[2:], 0)
elif l.startswith("## "):
doc.add_heading(l[3:], 1)
elif l.startswith("### "):
doc.add_heading(l[4:], 2)
elif l.startswith("#### "):
doc.add_heading(l[5:], 3)
elif l:
doc.add_paragraph(l)
doc.save(output_word_path)
update_word_toc(OUTPUT_WORD)
print(f"\n大功告成!投标文件已生成:")
print(f" {OUTPUT_WORD}")
print(f" 总字数约:{len(final_md) // 2}")
update_word_toc(output_word_path)
print(f"\n大功告成!投标文件已生成:")
print(f" {output_word_path}")
print(f" 总字数约:{len(final_md) // 2}")
# 清理临时生成的md文件可选保留也可以
if os.path.exists(tender_md):
os.remove(tender_md)
return True
except Exception as e:
print(f"投标文件生成失败:{str(e)}")
return False
# ==================== 原有主流程(保持不变,方便单独运行)===================
def main():
generate_tender_from_input(INPUT_WORD, OUTPUT_WORD)
os.startfile(OUTPUT_WORD)