bug fix
This commit is contained in:
parent
d2b1a0b657
commit
d48ec86026
|
|
@ -226,14 +226,514 @@ def module_redescribe(
|
|||
with console.status(
|
||||
f"[cyan]LLM 正在重新分解模块 '{target_module}' 需求...[/cyan]"
|
||||
):
|
||||
# ✅ 修复:移除不存在的 module_hint 参数
|
||||
# 分解后统一通过 req.module = target_module 强制设置模块归属
|
||||
new_reqs = analyzer.decompose(
|
||||
raw_requirement = new_desc_text,
|
||||
project_id = project.id,
|
||||
raw_req_id = raw_req_id,
|
||||
knowledge = knowledge_text,
|
||||
module_hint = target_module,
|
||||
)
|
||||
|
||||
# 强制将所有新需求归属到当前模块
|
||||
for req in new_reqs:
|
||||
req.module = target_module
|
||||
|
||||
console.print(f"[green]✓ 重新分解完成,共 {len(new_reqs)} 条新功能需求[/green]")
|
||||
|
||||
print_req_diff(old_reqs=module_reqs, new_reqs=new_reqs)
|
||||
|
||||
if not Confirm.ask(
|
||||
f"确认用以上 {len(new_reqs)} 条新需求替换模块 '{target_module}' 的旧需求?",
|
||||
default=True,
|
||||
):
|
||||
console.print("[yellow]已取消重新描述。[/yellow]")
|
||||
return
|
||||
|
||||
# ── 软删除旧需求 ──────────────────────────────────
|
||||
deleted_ids = []
|
||||
for req in module_reqs:
|
||||
req.status = "deleted"
|
||||
db.update_functional_requirement(req)
|
||||
deleted_ids.append(req.id)
|
||||
console.print(
|
||||
f"[dim]✓ 已软删除旧需求 {len(deleted_ids)} 条(ID: {deleted_ids})[/dim]"
|
||||
)
|
||||
|
||||
# ── 持久化新需求 ──────────────────────────────────
|
||||
all_reqs = db.list_functional_requirements(project.id)
|
||||
max_idx = max((r.index_no for r in all_reqs), default=0)
|
||||
for i, req in enumerate(new_reqs):
|
||||
req.index_no = max_idx + i + 1
|
||||
req.id = db.create_functional_requirement(req)
|
||||
console.print(f"[green]✓ 新功能需求已持久化,共 {len(new_reqs)} 条[/green]")
|
||||
|
||||
# ── 记录变更历史 ──────────────────────────────────
|
||||
change_summary = (
|
||||
f"模块 '{target_module}' 需求重新描述:\n"
|
||||
f" 旧需求 {len(module_reqs)} 条(已软删除):\n"
|
||||
+ "\n".join(f" - [{r.id}] {r.title}" for r in module_reqs)
|
||||
+ f"\n 新需求 {len(new_reqs)} 条:\n"
|
||||
+ "\n".join(f" + [{r.id}] {r.title}" for r in new_reqs)
|
||||
)
|
||||
log_change(
|
||||
project_id = project.id,
|
||||
change_type = CHG_REDESCRIBE,
|
||||
summary = change_summary,
|
||||
module = target_module,
|
||||
)
|
||||
|
||||
# ── 重新生成签名与代码 ────────────────────────────
|
||||
console.print(
|
||||
f"\n[cyan]正在为模块 '{target_module}' 重新生成签名与代码...[/cyan]"
|
||||
)
|
||||
generator = CodeGenerator(llm)
|
||||
signatures = generate_signatures(analyzer, new_reqs, knowledge_text)
|
||||
mod_sig_file = f"module_{target_module}_redescribe_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)
|
||||
|
||||
code_files = generate_code(
|
||||
generator=generator, project=project, func_reqs=new_reqs,
|
||||
output_dir=output_dir, knowledge_text=knowledge_text, signatures=signatures,
|
||||
)
|
||||
for cf in code_files:
|
||||
db.upsert_code_file(cf)
|
||||
for req in new_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)
|
||||
|
||||
all_active = active_reqs(db.list_functional_requirements(project.id))
|
||||
write_readme(project, all_active, output_dir)
|
||||
|
||||
console.print(Panel.fit(
|
||||
f"[bold green]✅ 模块 '{target_module}' 需求重新描述完成![/bold green]\n"
|
||||
f"新需求 {len(new_reqs)} 条,生成代码 {len(code_files)} 个文件",
|
||||
border_style="green",
|
||||
))
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════
|
||||
# B3:逐条修改模块内需求
|
||||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def module_edit_each(
|
||||
project: Project,
|
||||
module_reqs: list,
|
||||
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
|
||||
|
||||
req.description = new_description
|
||||
req.priority = new_priority
|
||||
req.module = new_module
|
||||
req.status = "pending"
|
||||
db.update_functional_requirement(req)
|
||||
|
||||
log_change(
|
||||
project_id = project.id,
|
||||
change_type = CHG_EDIT,
|
||||
summary = change_summary,
|
||||
module = new_module,
|
||||
req_id = req.id,
|
||||
)
|
||||
|
||||
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]")
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════
|
||||
# B4:批量重新生成模块代码
|
||||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def module_regen_code(
|
||||
project: Project,
|
||||
module_reqs: list,
|
||||
output_dir: str,
|
||||
knowledge_text: str = "",
|
||||
) -> None:
|
||||
"""保持需求内容不变,对整个模块批量重新生成签名与代码,记录变更历史。"""
|
||||
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)} 条需求:\n"
|
||||
+ "\n".join(f" · [{r.id}] {r.title}" for r in module_reqs)
|
||||
)
|
||||
log_change(
|
||||
project_id = project.id,
|
||||
change_type = CHG_REGEN,
|
||||
summary = change_summary,
|
||||
module = module_name,
|
||||
)
|
||||
console.print(
|
||||
f"[bold green]✅ 模块 '{module_name}' 批量重新生成完成!"
|
||||
f"共 {len(code_files)} 个文件[/bold green]"
|
||||
)# handlers/module_handler.py - 模块级变更处理
|
||||
# B1 重命名 / B2 重新描述 / B3 逐条修改 / B4 批量重新生成
|
||||
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
from rich.prompt import Confirm, Prompt
|
||||
from rich.rule import Rule
|
||||
from rich.table import Table
|
||||
|
||||
import config
|
||||
from constants import CHG_EDIT, CHG_REGEN, CHG_RENAME, CHG_REDESCRIBE
|
||||
from core_utils import (
|
||||
active_reqs, generate_code, generate_signatures,
|
||||
log_change, merge_signatures_to_main,
|
||||
patch_and_save_signatures, write_readme,
|
||||
)
|
||||
from core.code_generator import CodeGenerator
|
||||
from core.llm_client import LLMClient
|
||||
from core.requirement_analyzer import RequirementAnalyzer
|
||||
from database.db_manager import DBManager
|
||||
from database.models import FunctionalRequirement, Project
|
||||
from ui.display import (
|
||||
print_functional_requirements, print_module_list,
|
||||
print_req_diff, print_signatures_preview,
|
||||
)
|
||||
from utils.output_writer import write_function_signatures_json
|
||||
|
||||
console = Console()
|
||||
db = DBManager()
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════
|
||||
# 模块变更入口(子菜单)
|
||||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def change_module_requirements(
|
||||
project: Project,
|
||||
func_reqs: list,
|
||||
output_dir: str,
|
||||
knowledge_text: str = "",
|
||||
) -> None:
|
||||
"""
|
||||
选择目标模块,进入模块级变更子菜单:
|
||||
B1 · 重命名模块
|
||||
B2 · 重新描述模块需求
|
||||
B3 · 逐条修改模块内需求
|
||||
B4 · 批量重新生成模块代码
|
||||
"""
|
||||
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
|
||||
and r.status != "deleted"
|
||||
]
|
||||
console.print(
|
||||
f"\n[bold magenta]模块:{target_module}[/bold magenta]"
|
||||
f" 共 {len(module_reqs)} 条需求"
|
||||
)
|
||||
print_functional_requirements(module_reqs)
|
||||
|
||||
sub_menu = [
|
||||
("B1", "✏️ 重命名模块", "修改模块名,批量更新该模块所有需求"),
|
||||
("B2", "📝 重新描述模块需求", "重新输入模块需求描述,LLM 重新分解并生成代码"),
|
||||
("B3", "🔧 逐条修改模块内需求", "对模块内每条需求单独修改并重新生成"),
|
||||
("B4", "⚡ 批量重新生成模块代码", "保持需求内容不变,整体重新生成签名+代码"),
|
||||
]
|
||||
|
||||
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=26)
|
||||
table.add_column("说明", style="dim", width=42)
|
||||
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", "B4", "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_redescribe(
|
||||
project=project, module_reqs=module_reqs,
|
||||
target_module=target_module, output_dir=output_dir,
|
||||
knowledge_text=knowledge_text,
|
||||
)
|
||||
break
|
||||
|
||||
elif sub_action == "B3":
|
||||
module_edit_each(
|
||||
project=project, module_reqs=module_reqs,
|
||||
output_dir=output_dir, knowledge_text=knowledge_text,
|
||||
)
|
||||
module_reqs = [
|
||||
db.get_functional_requirement(r.id)
|
||||
for r in module_reqs
|
||||
if db.get_functional_requirement(r.id)
|
||||
]
|
||||
|
||||
elif sub_action == "B4":
|
||||
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,
|
||||
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
|
||||
|
||||
for req in module_reqs:
|
||||
req.module = new_module
|
||||
db.update_functional_requirement(req)
|
||||
|
||||
log_change(
|
||||
project_id = project.id,
|
||||
change_type = CHG_RENAME,
|
||||
summary = change_summary,
|
||||
module = old_module,
|
||||
)
|
||||
console.print(
|
||||
f"[green]✓ 模块已重命名:'{old_module}' → '{new_module}',"
|
||||
f"共更新 {len(module_reqs)} 条需求[/green]"
|
||||
)
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════
|
||||
# B2:重新描述模块需求
|
||||
# ══════════════════════════════════════════════════════
|
||||
|
||||
def module_redescribe(
|
||||
project: Project,
|
||||
module_reqs: list,
|
||||
target_module: str,
|
||||
output_dir: str,
|
||||
knowledge_text: str = "",
|
||||
) -> None:
|
||||
"""
|
||||
用户重新输入该模块的需求描述文本,
|
||||
LLM 重新分解为功能需求,展示新旧对比后确认,
|
||||
软删除旧需求,持久化新需求,重新生成签名+代码,记录变更历史。
|
||||
"""
|
||||
console.print(Rule(
|
||||
f"[bold magenta]重新描述模块 '{target_module}' 需求[/bold magenta]"
|
||||
))
|
||||
|
||||
console.print("[bold]当前模块需求:[/bold]")
|
||||
print_functional_requirements(module_reqs)
|
||||
|
||||
console.print(
|
||||
f"\n[bold]请重新输入模块 '[magenta]{target_module}[/magenta]'"
|
||||
" 的需求描述[/bold](输入空行结束):"
|
||||
)
|
||||
lines = []
|
||||
while True:
|
||||
line = input()
|
||||
if line == "":
|
||||
break
|
||||
lines.append(line)
|
||||
new_desc_text = "\n".join(lines).strip()
|
||||
if not new_desc_text:
|
||||
console.print("[yellow]输入为空,已取消。[/yellow]")
|
||||
return
|
||||
|
||||
llm = LLMClient()
|
||||
analyzer = RequirementAnalyzer(llm)
|
||||
raw_req_id = module_reqs[0].raw_req_id if module_reqs else None
|
||||
|
||||
with console.status(
|
||||
f"[cyan]LLM 正在重新分解模块 '{target_module}' 需求...[/cyan]"
|
||||
):
|
||||
# ✅ 修复:移除不存在的 module_hint 参数
|
||||
# 分解后统一通过 req.module = target_module 强制设置模块归属
|
||||
new_reqs = analyzer.decompose(
|
||||
raw_requirement = new_desc_text,
|
||||
project_id = project.id,
|
||||
raw_req_id = raw_req_id,
|
||||
knowledge = knowledge_text,
|
||||
)
|
||||
|
||||
# 强制将所有新需求归属到当前模块
|
||||
for req in new_reqs:
|
||||
req.module = target_module
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue