llmcodegen/src/llm_codegen/design_manager.py

137 lines
5.2 KiB
Python
Raw Permalink 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.

from pathlib import Path
from typing import Optional
import hashlib
import json
from .models import DesignModel
from .utils import read_file, write_file
class DesignManager:
"""设计管理类,用于处理 design.json 文件的加载、保存、README 哈希计算、校验和同步功能。"""
def __init__(self, design_file_path: Optional[Path] = None):
"""初始化 DesignManager。
参数:
design_file_path: design.json 文件的可选路径,如果提供,则可在后续方法中省略路径参数。
"""
self.design_file_path = design_file_path
def load_design(self, file_path: Optional[Path] = None) -> DesignModel:
"""加载 design.json 文件并解析为 DesignModel 对象。
参数:
file_path: design.json 文件路径,如果为 None则使用初始化时设置的路径。
返回:
DesignModel: 解析后的设计模型。
异常:
FileNotFoundError: 如果文件不存在。
ValueError: 如果 JSON 解析或模型验证失败。
"""
if file_path is None:
if self.design_file_path is None:
raise ValueError("未提供 design.json 文件路径")
file_path = self.design_file_path
file_path = Path(file_path)
if not file_path.exists():
raise FileNotFoundError(f"design.json 文件不存在: {file_path}")
content = read_file(str(file_path))
try:
design_dict = json.loads(content)
design = DesignModel.parse_obj(design_dict)
return design
except json.JSONDecodeError as e:
raise ValueError(f"JSON 解析失败: {e}")
except Exception as e:
raise ValueError(f"模型验证失败: {e}")
def save_design(self, design: DesignModel, file_path: Optional[Path] = None) -> None:
"""将 DesignModel 对象保存为 design.json 文件。
参数:
design: 要保存的设计模型。
file_path: 保存的文件路径,如果为 None则使用初始化时设置的路径。
异常:
ValueError: 如果未提供文件路径且初始化时未设置。
"""
if file_path is None:
if self.design_file_path is None:
raise ValueError("未提供 design.json 文件路径")
file_path = self.design_file_path
file_path = Path(file_path)
design_dict = design.dict(exclude_none=True)
content = json.dumps(design_dict, indent=2, ensure_ascii=False)
write_file(str(file_path), content)
@staticmethod
def compute_readme_hash(readme_path: Path) -> str:
"""计算 README 文件的 SHA256 哈希值。
参数:
readme_path: README 文件路径(例如 README.md
返回:
str: 十六进制字符串表示的 SHA256 哈希值。
异常:
FileNotFoundError: 如果文件不存在。
"""
readme_path = Path(readme_path)
if not readme_path.exists():
raise FileNotFoundError(f"README 文件不存在: {readme_path}")
with open(readme_path, 'rb') as f:
content = f.read()
hash_obj = hashlib.sha256(content)
return hash_obj.hexdigest()
def validate_readme_hash(self, design: DesignModel, readme_path: Optional[Path] = None) -> bool:
"""校验 README 文件的哈希值与 design.json 中存储的哈希值是否一致。
参数:
design: 设计模型,包含存储的 readme_hash。
readme_path: README 文件路径,如果为 None则使用 design.readme_path。
返回:
bool: 如果哈希一致或 readme_hash 为 None视为无效返回 True否则返回 False。
"""
if readme_path is None:
if design.readme_path is None:
return False # 没有存储的路径,无法校验
readme_path = Path(design.readme_path)
else:
readme_path = Path(readme_path)
if design.readme_hash is None:
return False # 没有存储的哈希,视为无效
try:
computed_hash = self.compute_readme_hash(readme_path)
return computed_hash == design.readme_hash
except FileNotFoundError:
return False # 文件不存在,校验失败
def sync_with_readme(self, design: DesignModel, readme_path: Path) -> DesignModel:
"""同步 design.json 与 README 文件,更新 readme_path 和 readme_hash。
参数:
design: 要更新的设计模型。
readme_path: README 文件路径。
返回:
DesignModel: 更新后的设计模型(原地修改并返回同一个对象)。
"""
readme_path = Path(readme_path)
if not readme_path.exists():
raise FileNotFoundError(f"README 文件不存在: {readme_path}")
new_hash = self.compute_readme_hash(readme_path)
design.readme_path = str(readme_path)
design.readme_hash = new_hash
return design