AIDeveloper-PC/requirements_generator/handlers/module_handler.py

997 lines
38 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.

# 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
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
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]"
)