bug fix
This commit is contained in:
parent
0da31ea6c7
commit
4855388b7c
|
|
@ -12,7 +12,6 @@ from rich.table import Table
|
|||
from rich.panel import Panel
|
||||
from rich.prompt import Prompt, Confirm
|
||||
from rich.rule import Rule
|
||||
from rich.text import Text
|
||||
|
||||
import config
|
||||
from database.db_manager import DBManager
|
||||
|
|
@ -51,7 +50,7 @@ def print_main_menu():
|
|||
console.print(Rule("[bold cyan]主菜单[/bold cyan]"))
|
||||
menu_items = [
|
||||
("1", "📁 新建项目", "输入需求 → 分解 → 生成代码"),
|
||||
("2", "🔄 变更项目需求", "变更已有需求 / 新增需求"),
|
||||
("2", "🔄 变更项目需求", "变更已有需求 / 变更模块需求 / 新增需求"),
|
||||
("3", "📋 查看所有项目", "列表展示全部项目"),
|
||||
("4", "🔍 查看项目详情", "需求列表 / 模块分组 / 变更历史"),
|
||||
("5", "🗑 删除指定项目", "删除项目及其所有数据"),
|
||||
|
|
@ -59,8 +58,8 @@ def print_main_menu():
|
|||
]
|
||||
table = Table(show_header=False, box=None, padding=(0, 2))
|
||||
table.add_column("选项", style="bold yellow", width=4)
|
||||
table.add_column("功能", style="bold", width=20)
|
||||
table.add_column("说明", style="dim", width=35)
|
||||
table.add_column("功能", style="bold", width=22)
|
||||
table.add_column("说明", style="dim", width=38)
|
||||
for key, name, desc in menu_items:
|
||||
table.add_row(f"[{key}]", name, desc)
|
||||
console.print(table)
|
||||
|
|
@ -68,7 +67,6 @@ def print_main_menu():
|
|||
|
||||
|
||||
def print_projects_table(projects: List[Project]):
|
||||
"""以表格形式展示所有项目"""
|
||||
if not projects:
|
||||
console.print("[yellow] 暂无项目记录。[/yellow]")
|
||||
return
|
||||
|
|
@ -79,18 +77,18 @@ def print_projects_table(projects: List[Project]):
|
|||
table.add_column("描述", width=35)
|
||||
table.add_column("输出目录", style="dim", width=30)
|
||||
for p in projects:
|
||||
desc = p.description or ""
|
||||
table.add_row(
|
||||
str(p.id),
|
||||
p.name,
|
||||
p.language or "-",
|
||||
(p.description or "")[:40] + ("..." if len(p.description or "") > 40 else ""),
|
||||
desc[:40] + ("..." if len(desc) > 40 else ""),
|
||||
p.output_dir or "-",
|
||||
)
|
||||
console.print(table)
|
||||
|
||||
|
||||
def print_functional_requirements(reqs: List[FunctionalRequirement]):
|
||||
"""以表格形式展示功能需求列表"""
|
||||
if not reqs:
|
||||
console.print("[yellow] 暂无功能需求。[/yellow]")
|
||||
return
|
||||
|
|
@ -103,12 +101,12 @@ def print_functional_requirements(reqs: List[FunctionalRequirement]):
|
|||
table.add_column("优先级", width=8)
|
||||
table.add_column("状态", width=10)
|
||||
table.add_column("描述", width=35)
|
||||
|
||||
priority_color = {"high": "red", "medium": "yellow", "low": "green"}
|
||||
status_color = {"pending": "yellow", "generated": "green", "failed": "red"}
|
||||
for req in reqs:
|
||||
pc = priority_color.get(req.priority, "white")
|
||||
sc = status_color.get(req.status, "white")
|
||||
desc = req.description
|
||||
table.add_row(
|
||||
str(req.index_no),
|
||||
str(req.id) if req.id else "-",
|
||||
|
|
@ -117,13 +115,12 @@ def print_functional_requirements(reqs: List[FunctionalRequirement]):
|
|||
f"[code]{req.function_name}[/code]",
|
||||
f"[{pc}]{req.priority}[/{pc}]",
|
||||
f"[{sc}]{req.status}[/{sc}]",
|
||||
req.description[:40] + "..." if len(req.description) > 40 else req.description,
|
||||
desc[:40] + "..." if len(desc) > 40 else desc,
|
||||
)
|
||||
console.print(table)
|
||||
|
||||
|
||||
def print_module_summary(reqs: List[FunctionalRequirement]):
|
||||
"""打印模块分组摘要"""
|
||||
module_map: Dict[str, List[str]] = {}
|
||||
for req in reqs:
|
||||
m = req.module or config.DEFAULT_MODULE
|
||||
|
|
@ -137,8 +134,28 @@ def print_module_summary(reqs: List[FunctionalRequirement]):
|
|||
console.print(table)
|
||||
|
||||
|
||||
def print_module_list(reqs: List[FunctionalRequirement]) -> List[str]:
|
||||
"""打印带序号的模块列表,返回有序模块名列表。"""
|
||||
module_map: Dict[str, List[FunctionalRequirement]] = {}
|
||||
for req in reqs:
|
||||
m = req.module or config.DEFAULT_MODULE
|
||||
module_map.setdefault(m, []).append(req)
|
||||
|
||||
table = Table(title="📦 模块列表", show_lines=True)
|
||||
table.add_column("序号", style="cyan", width=6)
|
||||
table.add_column("模块名", style="magenta bold", width=22)
|
||||
table.add_column("需求数量", style="yellow", width=8)
|
||||
table.add_column("包含函数", width=45)
|
||||
|
||||
modules = sorted(module_map.keys())
|
||||
for i, module in enumerate(modules, 1):
|
||||
funcs = [r.function_name for r in module_map[module]]
|
||||
table.add_row(str(i), module, str(len(funcs)), ", ".join(funcs))
|
||||
console.print(table)
|
||||
return modules
|
||||
|
||||
|
||||
def print_signatures_preview(signatures: List[dict]):
|
||||
"""以表格形式预览函数签名列表"""
|
||||
table = Table(title="📄 函数签名预览", show_lines=True)
|
||||
table.add_column("需求编号", style="cyan", width=8)
|
||||
table.add_column("模块", style="magenta", width=15)
|
||||
|
|
@ -162,7 +179,6 @@ def print_signatures_preview(signatures: List[dict]):
|
|||
|
||||
|
||||
def print_change_history(histories: List[ChangeHistory]):
|
||||
"""展示变更历史"""
|
||||
if not histories:
|
||||
console.print("[dim] 暂无变更历史。[/dim]")
|
||||
return
|
||||
|
|
@ -180,7 +196,6 @@ def print_change_history(histories: List[ChangeHistory]):
|
|||
|
||||
|
||||
def select_project(prompt_text: str = "请选择项目 ID") -> Optional[Project]:
|
||||
"""列出所有项目并让用户选择,返回 Project 对象;取消返回 None"""
|
||||
projects = db.list_projects()
|
||||
if not projects:
|
||||
console.print("[yellow]当前暂无项目,请先新建项目。[/yellow]")
|
||||
|
|
@ -245,12 +260,7 @@ def menu_create_project():
|
|||
console.print(f"[green]✓ 项目已创建: {project_name} (ID={project.id})[/green]")
|
||||
|
||||
# ── 2. 知识库(可选)────────────────────────────
|
||||
knowledge_text = ""
|
||||
if Confirm.ask("是否加载知识库文件?", default=False):
|
||||
kb_path = Prompt.ask("知识库文件路径(多个用逗号分隔)")
|
||||
paths = [p.strip() for p in kb_path.split(",") if p.strip()]
|
||||
knowledge_text = merge_knowledge_files(paths)
|
||||
console.print(f"[dim]已加载 {len(paths)} 个知识库文件[/dim]")
|
||||
knowledge_text = _load_knowledge_optional()
|
||||
|
||||
# ── 3. 原始需求输入 ──────────────────────────────
|
||||
console.print("\n[bold]请选择需求来源:[/bold]")
|
||||
|
|
@ -300,7 +310,6 @@ def menu_create_project():
|
|||
console.print(f"[green]✓ 分解完成,共 {len(func_reqs)} 条功能需求[/green]")
|
||||
print_functional_requirements(func_reqs)
|
||||
|
||||
# 交互式编辑分解结果
|
||||
while True:
|
||||
action = Prompt.ask(
|
||||
"操作",
|
||||
|
|
@ -316,7 +325,6 @@ def menu_create_project():
|
|||
elif action == "add":
|
||||
func_reqs = _interactive_add_req(func_reqs, project, raw_req_id)
|
||||
|
||||
# 持久化功能需求
|
||||
for req in func_reqs:
|
||||
req.id = db.create_functional_requirement(req)
|
||||
console.print(f"[green]✓ 功能需求已持久化,共 {len(func_reqs)} 条[/green]")
|
||||
|
|
@ -334,16 +342,12 @@ def menu_create_project():
|
|||
if Confirm.ask("是否手动调整模块归属?", default=False):
|
||||
func_reqs = _interactive_adjust_modules(func_reqs)
|
||||
|
||||
# ── 6. 确保输出目录 ──────────────────────────────
|
||||
# ── 6. 输出目录 ──────────────────────────────────
|
||||
output_dir = ensure_project_dir(project.name)
|
||||
|
||||
# ── 7. 生成函数签名 ──────────────────────────────
|
||||
console.print("\n[bold]Step · 生成函数签名[/bold]", style="blue")
|
||||
signatures = _generate_signatures(
|
||||
analyzer = analyzer,
|
||||
func_reqs = func_reqs,
|
||||
knowledge_text = knowledge_text,
|
||||
)
|
||||
signatures = _generate_signatures(analyzer, func_reqs, knowledge_text)
|
||||
json_path = write_function_signatures_json(
|
||||
output_dir=output_dir,
|
||||
signatures=signatures,
|
||||
|
|
@ -414,21 +418,35 @@ def menu_change_requirements():
|
|||
return
|
||||
|
||||
output_dir = ensure_project_dir(project.name)
|
||||
|
||||
# 知识库(可选复用)
|
||||
knowledge_text = _load_knowledge_optional()
|
||||
|
||||
change_menu = [
|
||||
("A", "🔧 变更指定功能需求", "按需求 ID 修改单条需求"),
|
||||
("B", "📦 变更指定模块需求", "按模块批量操作模块内所有需求"),
|
||||
("C", "➕ 新增需求", "输入新需求文本,LLM 分解后生成代码"),
|
||||
]
|
||||
|
||||
while True:
|
||||
console.print()
|
||||
print_functional_requirements(func_reqs)
|
||||
console.print(Rule())
|
||||
console.print(Rule("[bold]变更操作[/bold]"))
|
||||
|
||||
table = Table(show_header=False, box=None, padding=(0, 2))
|
||||
table.add_column("选项", style="bold yellow", width=5)
|
||||
table.add_column("功能", style="bold", width=22)
|
||||
table.add_column("说明", style="dim", width=38)
|
||||
for key, name, desc in change_menu:
|
||||
table.add_row(f"[{key}]", name, desc)
|
||||
table.add_row("[back]", "↩ 返回主菜单", "")
|
||||
console.print(table)
|
||||
|
||||
action = Prompt.ask(
|
||||
"请选择操作",
|
||||
choices=["A-变更已有需求", "B-新增需求", "back"],
|
||||
choices=["A", "B", "C", "back"],
|
||||
default="back",
|
||||
)
|
||||
|
||||
if action == "A-变更已有需求":
|
||||
if action == "A":
|
||||
_change_existing_requirement(
|
||||
project=project,
|
||||
func_reqs=func_reqs,
|
||||
|
|
@ -437,7 +455,16 @@ def menu_change_requirements():
|
|||
)
|
||||
func_reqs = db.list_functional_requirements(project.id)
|
||||
|
||||
elif action == "B-新增需求":
|
||||
elif action == "B":
|
||||
_change_module_requirements(
|
||||
project=project,
|
||||
func_reqs=func_reqs,
|
||||
output_dir=output_dir,
|
||||
knowledge_text=knowledge_text,
|
||||
)
|
||||
func_reqs = db.list_functional_requirements(project.id)
|
||||
|
||||
elif action == "C":
|
||||
_add_new_requirements(
|
||||
project=project,
|
||||
func_reqs=func_reqs,
|
||||
|
|
@ -474,7 +501,6 @@ def menu_project_detail():
|
|||
if not project:
|
||||
return
|
||||
|
||||
# 项目基本信息
|
||||
console.print(Panel(
|
||||
f"[bold]项目名称:[/bold]{project.name}\n"
|
||||
f"[bold]语言: [/bold]{project.language}\n"
|
||||
|
|
@ -484,21 +510,17 @@ def menu_project_detail():
|
|||
border_style="cyan",
|
||||
))
|
||||
|
||||
# 功能需求列表
|
||||
func_reqs = db.list_functional_requirements(project.id)
|
||||
print_functional_requirements(func_reqs)
|
||||
|
||||
# 模块分组
|
||||
if func_reqs:
|
||||
print_module_summary(func_reqs)
|
||||
|
||||
# 变更历史
|
||||
llm = LLMClient()
|
||||
analyzer = RequirementAnalyzer(llm)
|
||||
histories = analyzer.get_change_history(project.id)
|
||||
print_change_history(histories)
|
||||
|
||||
# 签名 JSON 预览
|
||||
if project.output_dir:
|
||||
sig_path = os.path.join(project.output_dir, "function_signatures.json")
|
||||
if os.path.exists(sig_path):
|
||||
|
|
@ -539,7 +561,6 @@ def menu_delete_project():
|
|||
_pause()
|
||||
return
|
||||
|
||||
# 二次确认
|
||||
confirm_name = Prompt.ask("请再次输入项目名称以确认")
|
||||
if confirm_name != project.name:
|
||||
console.print("[red]项目名称不匹配,删除已取消。[/red]")
|
||||
|
|
@ -552,7 +573,7 @@ def menu_delete_project():
|
|||
|
||||
|
||||
# ══════════════════════════════════════════════════════
|
||||
# 变更已有需求(内部)
|
||||
# 变更操作 A:变更指定功能需求
|
||||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def _change_existing_requirement(
|
||||
|
|
@ -561,6 +582,7 @@ def _change_existing_requirement(
|
|||
output_dir: str,
|
||||
knowledge_text: str = "",
|
||||
) -> None:
|
||||
"""按需求 ID 修改单条功能需求,确认后重新生成签名与代码。"""
|
||||
req_id_str = Prompt.ask("请输入要变更的功能需求 ID")
|
||||
try:
|
||||
req_id = int(req_id_str)
|
||||
|
|
@ -613,12 +635,10 @@ def _change_existing_requirement(
|
|||
db.update_functional_requirement(req)
|
||||
console.print(f"[green]✓ 需求 ID={req.id} 已更新[/green]")
|
||||
|
||||
# 重新生成签名与代码
|
||||
console.print("\n[cyan]正在重新生成签名与代码...[/cyan]")
|
||||
change_sig_file = f"change_{req.id}_signatures.json"
|
||||
|
||||
signatures = _generate_signatures(analyzer, [req], knowledge_text)
|
||||
json_path = write_function_signatures_json(
|
||||
write_function_signatures_json(
|
||||
output_dir=output_dir,
|
||||
signatures=signatures,
|
||||
project_name=project.name,
|
||||
|
|
@ -648,13 +668,341 @@ def _change_existing_requirement(
|
|||
output_dir=output_dir,
|
||||
file_name=change_sig_file,
|
||||
)
|
||||
# 合并到主签名 JSON
|
||||
_merge_signatures_to_main(project, signatures, output_dir)
|
||||
console.print(f"[green]✓ 变更完成,代码已重新生成[/green]")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════
|
||||
# 新增需求(内部)
|
||||
# 变更操作 B:变更指定模块需求
|
||||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def _change_module_requirements(
|
||||
project: Project,
|
||||
func_reqs: List[FunctionalRequirement],
|
||||
output_dir: str,
|
||||
knowledge_text: str = "",
|
||||
) -> None:
|
||||
"""
|
||||
选择目标模块,进入模块级变更子菜单:
|
||||
B1 · 重命名模块
|
||||
B2 · 逐条修改模块内需求
|
||||
B3 · 批量重新生成模块代码
|
||||
"""
|
||||
console.print(Rule("[bold magenta]变更指定模块需求[/bold magenta]"))
|
||||
|
||||
# ── 选择模块 ─────────────────────────────────────
|
||||
modules = print_module_list(func_reqs)
|
||||
if not modules:
|
||||
console.print("[yellow]当前项目暂无模块信息。[/yellow]")
|
||||
return
|
||||
|
||||
mod_idx_str = Prompt.ask("请输入模块序号(输入 0 返回)", default="0")
|
||||
if mod_idx_str == "0":
|
||||
return
|
||||
try:
|
||||
mod_idx = int(mod_idx_str) - 1
|
||||
if mod_idx < 0 or mod_idx >= len(modules):
|
||||
raise ValueError
|
||||
target_module = modules[mod_idx]
|
||||
except ValueError:
|
||||
console.print("[red]序号无效[/red]")
|
||||
return
|
||||
|
||||
# 该模块下的所有需求
|
||||
module_reqs = [
|
||||
r for r in func_reqs
|
||||
if (r.module or config.DEFAULT_MODULE) == target_module
|
||||
]
|
||||
console.print(
|
||||
f"\n[bold magenta]模块:{target_module}[/bold magenta]"
|
||||
f" 共 {len(module_reqs)} 条需求"
|
||||
)
|
||||
print_functional_requirements(module_reqs)
|
||||
|
||||
# ── 模块级操作子菜单 ─────────────────────────────
|
||||
sub_menu = [
|
||||
("B1", "✏️ 重命名模块", "修改模块名,批量更新该模块所有需求"),
|
||||
("B2", "🔧 逐条修改模块内需求", "对模块内每条需求单独修改并重新生成"),
|
||||
("B3", "⚡ 批量重新生成模块代码", "保持需求内容不变,整体重新生成签名+代码"),
|
||||
]
|
||||
|
||||
while True:
|
||||
console.print(Rule())
|
||||
table = Table(show_header=False, box=None, padding=(0, 2))
|
||||
table.add_column("选项", style="bold yellow", width=5)
|
||||
table.add_column("功能", style="bold", width=24)
|
||||
table.add_column("说明", style="dim", width=38)
|
||||
for key, name, desc in sub_menu:
|
||||
table.add_row(f"[{key}]", name, desc)
|
||||
table.add_row("[back]", "↩ 返回", "")
|
||||
console.print(table)
|
||||
|
||||
sub_action = Prompt.ask(
|
||||
"请选择操作",
|
||||
choices=["B1", "B2", "B3", "back"],
|
||||
default="back",
|
||||
)
|
||||
|
||||
if sub_action == "B1":
|
||||
_module_rename(
|
||||
project=project,
|
||||
module_reqs=module_reqs,
|
||||
old_module=target_module,
|
||||
)
|
||||
# 模块名已变,退出子菜单
|
||||
break
|
||||
|
||||
elif sub_action == "B2":
|
||||
_module_edit_each(
|
||||
project=project,
|
||||
module_reqs=module_reqs,
|
||||
output_dir=output_dir,
|
||||
knowledge_text=knowledge_text,
|
||||
)
|
||||
# 刷新 module_reqs
|
||||
module_reqs = [
|
||||
db.get_functional_requirement(r.id)
|
||||
for r in module_reqs
|
||||
]
|
||||
|
||||
elif sub_action == "B3":
|
||||
_module_regen_code(
|
||||
project=project,
|
||||
module_reqs=module_reqs,
|
||||
output_dir=output_dir,
|
||||
knowledge_text=knowledge_text,
|
||||
)
|
||||
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
# ── B1:重命名模块 ────────────────────────────────────
|
||||
|
||||
def _module_rename(
|
||||
project: Project,
|
||||
module_reqs: List[FunctionalRequirement],
|
||||
old_module: str,
|
||||
) -> None:
|
||||
"""将指定模块重命名,批量更新该模块下所有需求的 module 字段。"""
|
||||
new_module = Prompt.ask(f"请输入新模块名(当前:{old_module})")
|
||||
if not new_module.strip():
|
||||
console.print("[red]模块名不能为空[/red]")
|
||||
return
|
||||
if new_module == old_module:
|
||||
console.print("[dim]模块名未变更,跳过。[/dim]")
|
||||
return
|
||||
|
||||
change_summary = (
|
||||
f"模块重命名:'{old_module}' → '{new_module}'\n"
|
||||
f" 影响需求数:{len(module_reqs)} 条\n"
|
||||
+ "\n".join(f" · [{r.id}] {r.title}" for r in module_reqs)
|
||||
)
|
||||
console.print(Panel(change_summary, title="📝 模块重命名预览", border_style="yellow"))
|
||||
|
||||
if not Confirm.ask("确认执行模块重命名?", default=True):
|
||||
console.print("[yellow]已取消。[/yellow]")
|
||||
return
|
||||
|
||||
llm = LLMClient()
|
||||
analyzer = RequirementAnalyzer(llm)
|
||||
analyzer.log_change(project.id, change_summary)
|
||||
|
||||
for req in module_reqs:
|
||||
req.module = new_module
|
||||
db.update_functional_requirement(req)
|
||||
|
||||
console.print(
|
||||
f"[green]✓ 模块已重命名:'{old_module}' → '{new_module}',"
|
||||
f"共更新 {len(module_reqs)} 条需求[/green]"
|
||||
)
|
||||
|
||||
|
||||
# ── B2:逐条修改模块内需求 ────────────────────────────
|
||||
|
||||
def _module_edit_each(
|
||||
project: Project,
|
||||
module_reqs: List[FunctionalRequirement],
|
||||
output_dir: str,
|
||||
knowledge_text: str = "",
|
||||
) -> None:
|
||||
"""
|
||||
对模块内需求逐条展示并允许修改,
|
||||
每条修改确认后立即重新生成签名与代码。
|
||||
"""
|
||||
llm = LLMClient()
|
||||
analyzer = RequirementAnalyzer(llm)
|
||||
generator = CodeGenerator(llm)
|
||||
|
||||
for req in module_reqs:
|
||||
console.print(Rule(f"[cyan]需求 ID={req.id} · {req.title}[/cyan]"))
|
||||
console.print(
|
||||
f" 描述: {req.description}\n"
|
||||
f" 优先级: {req.priority}\n"
|
||||
f" 模块: {req.module}"
|
||||
)
|
||||
|
||||
if not Confirm.ask("是否修改此需求?", default=False):
|
||||
continue
|
||||
|
||||
new_description = Prompt.ask(" 新描述", default=req.description)
|
||||
new_priority = Prompt.ask(
|
||||
" 新优先级", default=req.priority,
|
||||
choices=["high", "medium", "low"],
|
||||
)
|
||||
new_module = Prompt.ask(" 新模块名", default=req.module)
|
||||
|
||||
changed = (
|
||||
new_description != req.description
|
||||
or new_priority != req.priority
|
||||
or new_module != req.module
|
||||
)
|
||||
if not changed:
|
||||
console.print("[dim] 未检测到变更,跳过。[/dim]")
|
||||
continue
|
||||
|
||||
change_summary = (
|
||||
f"需求 '{req.title}'(ID={req.id})变更:\n"
|
||||
f" 描述: '{req.description}' → '{new_description}'\n"
|
||||
f" 优先级: '{req.priority}' → '{new_priority}'\n"
|
||||
f" 模块: '{req.module}' → '{new_module}'"
|
||||
)
|
||||
console.print(Panel(change_summary, title="📝 变更预览", border_style="yellow"))
|
||||
|
||||
if not Confirm.ask("确认此条变更?", default=True):
|
||||
console.print("[yellow] 已跳过。[/yellow]")
|
||||
continue
|
||||
|
||||
analyzer.log_change(project.id, change_summary)
|
||||
req.description = new_description
|
||||
req.priority = new_priority
|
||||
req.module = new_module
|
||||
req.status = "pending"
|
||||
db.update_functional_requirement(req)
|
||||
|
||||
console.print(f" [cyan]正在重新生成 {req.function_name} 的签名与代码...[/cyan]")
|
||||
change_sig_file = f"change_{req.id}_signatures.json"
|
||||
signatures = _generate_signatures(analyzer, [req], knowledge_text)
|
||||
write_function_signatures_json(
|
||||
output_dir=output_dir,
|
||||
signatures=signatures,
|
||||
project_name=project.name,
|
||||
project_description=project.description or "",
|
||||
file_name=change_sig_file,
|
||||
)
|
||||
code_files = _generate_code(
|
||||
generator=generator,
|
||||
project=project,
|
||||
func_reqs=[req],
|
||||
output_dir=output_dir,
|
||||
knowledge_text=knowledge_text,
|
||||
signatures=signatures,
|
||||
)
|
||||
for cf in code_files:
|
||||
db.upsert_code_file(cf)
|
||||
req.status = "generated"
|
||||
db.update_functional_requirement(req)
|
||||
_patch_and_save_signatures(
|
||||
project=project,
|
||||
signatures=signatures,
|
||||
code_files=code_files,
|
||||
output_dir=output_dir,
|
||||
file_name=change_sig_file,
|
||||
)
|
||||
_merge_signatures_to_main(project, signatures, output_dir)
|
||||
console.print(f" [green]✓ 需求 ID={req.id} 变更完成[/green]")
|
||||
|
||||
console.print("[green]✓ 模块内需求逐条修改完成[/green]")
|
||||
|
||||
|
||||
# ── B3:批量重新生成模块代码 ──────────────────────────
|
||||
|
||||
def _module_regen_code(
|
||||
project: Project,
|
||||
module_reqs: List[FunctionalRequirement],
|
||||
output_dir: str,
|
||||
knowledge_text: str = "",
|
||||
) -> None:
|
||||
"""
|
||||
保持需求内容不变,对整个模块的所有需求
|
||||
批量重新生成函数签名与代码文件,并更新主签名 JSON。
|
||||
"""
|
||||
module_name = module_reqs[0].module if module_reqs else "未知模块"
|
||||
console.print(Panel(
|
||||
f"模块:[bold magenta]{module_name}[/bold magenta]\n"
|
||||
f"需求数量:{len(module_reqs)} 条\n"
|
||||
+ "\n".join(
|
||||
f" · [{r.id}] {r.title} ({r.function_name})"
|
||||
for r in module_reqs
|
||||
),
|
||||
title="⚡ 批量重新生成预览",
|
||||
border_style="cyan",
|
||||
))
|
||||
|
||||
if not Confirm.ask(
|
||||
f"确认对模块 '{module_name}' 的 {len(module_reqs)} 条需求批量重新生成代码?",
|
||||
default=True,
|
||||
):
|
||||
console.print("[yellow]已取消。[/yellow]")
|
||||
return
|
||||
|
||||
llm = LLMClient()
|
||||
analyzer = RequirementAnalyzer(llm)
|
||||
generator = CodeGenerator(llm)
|
||||
|
||||
for req in module_reqs:
|
||||
req.status = "pending"
|
||||
db.update_functional_requirement(req)
|
||||
|
||||
console.print(f"\n[cyan]正在为模块 '{module_name}' 生成函数签名...[/cyan]")
|
||||
signatures = _generate_signatures(analyzer, module_reqs, knowledge_text)
|
||||
mod_sig_file = f"module_{module_name}_signatures.json"
|
||||
write_function_signatures_json(
|
||||
output_dir=output_dir,
|
||||
signatures=signatures,
|
||||
project_name=project.name,
|
||||
project_description=project.description or "",
|
||||
file_name=mod_sig_file,
|
||||
)
|
||||
print_signatures_preview(signatures)
|
||||
|
||||
console.print(f"\n[cyan]正在为模块 '{module_name}' 生成代码文件...[/cyan]")
|
||||
code_files = _generate_code(
|
||||
generator=generator,
|
||||
project=project,
|
||||
func_reqs=module_reqs,
|
||||
output_dir=output_dir,
|
||||
knowledge_text=knowledge_text,
|
||||
signatures=signatures,
|
||||
)
|
||||
for cf in code_files:
|
||||
db.upsert_code_file(cf)
|
||||
for req in module_reqs:
|
||||
req.status = "generated"
|
||||
db.update_functional_requirement(req)
|
||||
|
||||
_patch_and_save_signatures(
|
||||
project=project,
|
||||
signatures=signatures,
|
||||
code_files=code_files,
|
||||
output_dir=output_dir,
|
||||
file_name=mod_sig_file,
|
||||
)
|
||||
_merge_signatures_to_main(project, signatures, output_dir)
|
||||
|
||||
change_summary = (
|
||||
f"模块 '{module_name}' 批量重新生成代码,共 {len(module_reqs)} 条需求"
|
||||
)
|
||||
analyzer.log_change(project.id, change_summary)
|
||||
|
||||
console.print(
|
||||
f"[bold green]✅ 模块 '{module_name}' 批量重新生成完成!"
|
||||
f"共 {len(code_files)} 个文件[/bold green]"
|
||||
)
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════
|
||||
# 变更操作 C:新增需求
|
||||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def _add_new_requirements(
|
||||
|
|
@ -709,7 +1057,6 @@ def _add_new_requirements(
|
|||
console.print("[yellow]已取消新增。[/yellow]")
|
||||
return
|
||||
|
||||
# 模块分类
|
||||
with console.status("[cyan]LLM 正在进行模块分类...[/cyan]"):
|
||||
module_map = analyzer.classify_modules(new_reqs, knowledge_text)
|
||||
name_to_module = {item["function_name"]: item["module"] for item in module_map}
|
||||
|
|
@ -718,15 +1065,11 @@ def _add_new_requirements(
|
|||
req.module = name_to_module[req.function_name]
|
||||
print_module_summary(new_reqs)
|
||||
|
||||
# 持久化
|
||||
for req in new_reqs:
|
||||
req.id = db.create_functional_requirement(req)
|
||||
console.print(f"[green]✓ 新增功能需求已持久化[/green]")
|
||||
|
||||
# 记录变更历史
|
||||
analyzer.log_change(project.id, change_summary)
|
||||
|
||||
# 生成签名
|
||||
signatures = _generate_signatures(analyzer, new_reqs, knowledge_text)
|
||||
write_function_signatures_json(
|
||||
output_dir=output_dir,
|
||||
|
|
@ -737,7 +1080,6 @@ def _add_new_requirements(
|
|||
)
|
||||
print_signatures_preview(signatures)
|
||||
|
||||
# 生成代码
|
||||
generator = CodeGenerator(llm)
|
||||
code_files = _generate_code(
|
||||
generator=generator,
|
||||
|
|
@ -753,11 +1095,9 @@ def _add_new_requirements(
|
|||
req.status = "generated"
|
||||
db.update_functional_requirement(req)
|
||||
|
||||
# 更新 README
|
||||
all_reqs = db.list_functional_requirements(project.id)
|
||||
_write_readme(project, all_reqs, output_dir)
|
||||
|
||||
# 回填 URL & 合并主签名
|
||||
_patch_and_save_signatures(
|
||||
project=project,
|
||||
signatures=signatures,
|
||||
|
|
@ -777,7 +1117,6 @@ def _add_new_requirements(
|
|||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def _load_knowledge_optional() -> str:
|
||||
"""可选加载知识库文件,返回合并后的文本"""
|
||||
if Confirm.ask("是否加载知识库文件?", default=False):
|
||||
kb_path = Prompt.ask("知识库文件路径(多个用逗号分隔)")
|
||||
paths = [p.strip() for p in kb_path.split(",") if p.strip()]
|
||||
|
|
@ -792,9 +1131,6 @@ def _generate_signatures(
|
|||
func_reqs: List[FunctionalRequirement],
|
||||
knowledge_text: str = "",
|
||||
) -> List[dict]:
|
||||
"""批量生成函数签名,带进度输出"""
|
||||
total = len(func_reqs)
|
||||
|
||||
def on_progress(i, t, req, sig, err):
|
||||
status = "[red]✗ 降级[/red]" if err else "[green]✓[/green]"
|
||||
console.print(
|
||||
|
|
@ -818,7 +1154,6 @@ def _generate_code(
|
|||
knowledge_text: str = "",
|
||||
signatures: List[dict] = None,
|
||||
) -> list:
|
||||
"""批量生成代码文件,带进度输出"""
|
||||
def on_progress(i, t, req, code_file, err):
|
||||
if err:
|
||||
console.print(
|
||||
|
|
@ -890,7 +1225,6 @@ def _merge_signatures_to_main(
|
|||
output_dir: str,
|
||||
main_file: str = "function_signatures.json",
|
||||
) -> None:
|
||||
"""将新签名合并追加到主签名 JSON(以 name 去重,新覆盖旧)"""
|
||||
main_path = os.path.join(output_dir, main_file)
|
||||
if os.path.exists(main_path):
|
||||
with open(main_path, "r", encoding="utf-8") as f:
|
||||
|
|
@ -903,12 +1237,10 @@ def _merge_signatures_to_main(
|
|||
"description": project.description or "",
|
||||
"functions": [],
|
||||
}
|
||||
|
||||
sig_map = {s["name"]: s for s in existing_sigs}
|
||||
for sig in new_sigs:
|
||||
sig_map[sig["name"]] = sig
|
||||
main_doc["functions"] = list(sig_map.values())
|
||||
|
||||
with open(main_path, "w", encoding="utf-8") as f:
|
||||
json.dump(main_doc, f, ensure_ascii=False, indent=2)
|
||||
console.print(
|
||||
|
|
@ -1003,7 +1335,6 @@ def _interactive_adjust_modules(
|
|||
|
||||
|
||||
def _pause():
|
||||
"""等待用户按 Enter 键继续"""
|
||||
console.print()
|
||||
input(" 按 Enter 键返回主菜单...")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue