feat: 添加 --advice 参数,支持快速获取执行建议
- 新增 scripts/core/advice_generator.py 建议生成器模块 - 在 config.py 中添加 DEPENDENCIES 依赖配置 - 在 lyxy_document_reader.py 中添加 -a/--advice 参数 - 复用 Reader 实例的 supports 方法检测文件类型 - 支持平台检测,对 macOS x86_64 PDF 返回特殊命令 - 添加单元测试和集成测试 - 更新 SKILL.md,引导优先使用 --advice 参数 - 更新 README.md,添加项目结构说明 - 添加 openspec/specs/cli-advice/spec.md 规范文档
This commit is contained in:
@@ -16,6 +16,7 @@ from .markdown import (
|
||||
search_markdown,
|
||||
)
|
||||
from .parser import parse_input, process_content, output_result
|
||||
from .advice_generator import generate_advice
|
||||
|
||||
__all__ = [
|
||||
"LyxyDocumentError",
|
||||
@@ -32,4 +33,5 @@ __all__ = [
|
||||
"parse_input",
|
||||
"process_content",
|
||||
"output_result",
|
||||
"generate_advice",
|
||||
]
|
||||
|
||||
251
scripts/core/advice_generator.py
Normal file
251
scripts/core/advice_generator.py
Normal file
@@ -0,0 +1,251 @@
|
||||
"""建议生成器模块,根据文件类型和平台返回执行建议。"""
|
||||
|
||||
import platform
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, Tuple, List, Type
|
||||
|
||||
from config import DEPENDENCIES
|
||||
from readers import BaseReader
|
||||
from readers import (
|
||||
PdfReader,
|
||||
DocxReader,
|
||||
XlsxReader,
|
||||
PptxReader,
|
||||
HtmlReader,
|
||||
)
|
||||
|
||||
|
||||
# Reader 类到配置 key 的映射
|
||||
_READER_KEY_MAP: Dict[Type[BaseReader], str] = {
|
||||
PdfReader: "pdf",
|
||||
DocxReader: "docx",
|
||||
XlsxReader: "xlsx",
|
||||
PptxReader: "pptx",
|
||||
HtmlReader: "html",
|
||||
}
|
||||
|
||||
|
||||
def detect_file_type_light(input_path: str, readers: List[BaseReader]) -> Optional[Type[BaseReader]]:
|
||||
"""
|
||||
轻量文件类型检测,复用 Reader 的 supports 方法。
|
||||
|
||||
Args:
|
||||
input_path: 文件路径或 URL
|
||||
readers: 已实例化的 reader 列表
|
||||
|
||||
Returns:
|
||||
支持该输入的 Reader 类,无法识别返回 None
|
||||
"""
|
||||
for reader in readers:
|
||||
if reader.supports(input_path):
|
||||
return reader.__class__
|
||||
return None
|
||||
|
||||
|
||||
def get_platform() -> str:
|
||||
"""
|
||||
获取当前平台标识,格式为 {system}-{machine}。
|
||||
|
||||
Returns:
|
||||
平台标识,例如 "Darwin-arm64"、"Linux-x86_64"、"Windows-AMD64"
|
||||
"""
|
||||
system = platform.system()
|
||||
machine = platform.machine()
|
||||
return f"{system}-{machine}"
|
||||
|
||||
|
||||
def get_dependencies(reader_cls: Type[BaseReader], platform_id: str) -> Tuple[Optional[str], list]:
|
||||
"""
|
||||
获取指定 Reader 类和平台的依赖配置。
|
||||
|
||||
Args:
|
||||
reader_cls: Reader 类
|
||||
platform_id: 平台标识(如 "Darwin-arm64")
|
||||
|
||||
Returns:
|
||||
(python_version, dependencies) 元组
|
||||
- python_version: 需要的 python 版本,None 表示使用默认
|
||||
- dependencies: 依赖包列表
|
||||
"""
|
||||
key = _READER_KEY_MAP.get(reader_cls)
|
||||
if not key or key not in DEPENDENCIES:
|
||||
return None, []
|
||||
|
||||
type_config = DEPENDENCIES[key]
|
||||
|
||||
# 先尝试匹配特定平台
|
||||
if platform_id in type_config:
|
||||
config = type_config[platform_id]
|
||||
return config.get("python"), config.get("dependencies", [])
|
||||
|
||||
# 使用 default 配置
|
||||
if "default" in type_config:
|
||||
config = type_config["default"]
|
||||
return config.get("python"), config.get("dependencies", [])
|
||||
|
||||
return None, []
|
||||
|
||||
|
||||
def generate_uv_command(
|
||||
dependencies: list,
|
||||
input_path: str,
|
||||
python_version: Optional[str] = None,
|
||||
script_path: str = "scripts/lyxy_document_reader.py"
|
||||
) -> str:
|
||||
"""
|
||||
生成 uv run 命令。
|
||||
|
||||
Args:
|
||||
dependencies: 依赖包列表
|
||||
input_path: 输入文件路径或 URL
|
||||
python_version: 需要的 python 版本,None 表示不指定
|
||||
script_path: 脚本路径
|
||||
|
||||
Returns:
|
||||
uv run 命令字符串
|
||||
"""
|
||||
parts = ["uv run"]
|
||||
|
||||
if python_version:
|
||||
parts.append(f"--python {python_version}")
|
||||
|
||||
for dep in dependencies:
|
||||
# 处理包含空格的依赖(如 unstructured[pdf]),需要加引号
|
||||
if "[" in dep or " " in dep:
|
||||
parts.append(f'--with "{dep}"')
|
||||
else:
|
||||
parts.append(f"--with {dep}")
|
||||
|
||||
parts.append(f"{script_path} {input_path}")
|
||||
|
||||
return " ".join(parts)
|
||||
|
||||
|
||||
def generate_python_command(
|
||||
dependencies: list,
|
||||
input_path: str,
|
||||
script_path: str = "scripts/lyxy_document_reader.py"
|
||||
) -> Tuple[str, str]:
|
||||
"""
|
||||
生成 python 命令和 pip 安装命令。
|
||||
|
||||
Args:
|
||||
dependencies: 依赖包列表
|
||||
input_path: 输入文件路径或 URL
|
||||
script_path: 脚本路径
|
||||
|
||||
Returns:
|
||||
(python_command, pip_command) 元组
|
||||
"""
|
||||
python_cmd = f"python {script_path} {input_path}"
|
||||
|
||||
# 构建 pip install 命令,处理带引号的依赖
|
||||
pip_parts = ["pip install"]
|
||||
for dep in dependencies:
|
||||
pip_parts.append(dep)
|
||||
pip_cmd = " ".join(pip_parts)
|
||||
|
||||
return python_cmd, pip_cmd
|
||||
|
||||
|
||||
def format_advice(
|
||||
file_type: str,
|
||||
input_path: str,
|
||||
platform_id: str,
|
||||
uv_command: str,
|
||||
python_command: str,
|
||||
pip_command: str,
|
||||
has_platform_specific: bool = False
|
||||
) -> str:
|
||||
"""
|
||||
格式化建议输出。
|
||||
|
||||
Args:
|
||||
file_type: 文件类型
|
||||
input_path: 输入路径
|
||||
platform_id: 平台标识
|
||||
uv_command: uv 命令
|
||||
python_command: python 命令
|
||||
pip_command: pip 安装命令
|
||||
has_platform_specific: 是否使用了平台特殊配置
|
||||
|
||||
Returns:
|
||||
格式化后的建议文本
|
||||
"""
|
||||
lines = []
|
||||
|
||||
# 文件类型和输入路径
|
||||
lines.append(f"文件类型: {file_type.upper()}")
|
||||
lines.append(f"输入路径: {input_path}")
|
||||
|
||||
# 平台信息(仅当使用了特殊配置时显示)
|
||||
if has_platform_specific:
|
||||
lines.append(f"平台: {platform_id}")
|
||||
|
||||
lines.append("")
|
||||
|
||||
# uv 命令
|
||||
lines.append("[uv 命令]")
|
||||
lines.append(uv_command)
|
||||
lines.append("")
|
||||
|
||||
# python 命令
|
||||
lines.append("[python 命令]")
|
||||
lines.append(python_command)
|
||||
lines.append(pip_command)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def generate_advice(
|
||||
input_path: str,
|
||||
readers: List[BaseReader],
|
||||
script_path: str = "scripts/lyxy_document_reader.py"
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
生成完整的执行建议。
|
||||
|
||||
Args:
|
||||
input_path: 输入文件路径或 URL
|
||||
readers: 已实例化的 reader 列表
|
||||
script_path: 脚本路径
|
||||
|
||||
Returns:
|
||||
格式化的建议文本,无法识别文件类型返回 None
|
||||
"""
|
||||
# 检测文件类型,获取 Reader 类
|
||||
reader_cls = detect_file_type_light(input_path, readers)
|
||||
if not reader_cls:
|
||||
return None
|
||||
|
||||
# 获取配置 key 和显示名称
|
||||
key = _READER_KEY_MAP.get(reader_cls, "unknown")
|
||||
file_type = key
|
||||
|
||||
# 获取平台
|
||||
platform_id = get_platform()
|
||||
|
||||
# 获取依赖配置
|
||||
python_version, dependencies = get_dependencies(reader_cls, platform_id)
|
||||
|
||||
# 判断是否使用了平台特殊配置
|
||||
has_platform_specific = False
|
||||
if key in DEPENDENCIES:
|
||||
type_config = DEPENDENCIES[key]
|
||||
if platform_id in type_config and "default" in type_config:
|
||||
has_platform_specific = True
|
||||
|
||||
# 生成命令
|
||||
uv_command = generate_uv_command(dependencies, input_path, python_version, script_path)
|
||||
python_command, pip_command = generate_python_command(dependencies, input_path, script_path)
|
||||
|
||||
# 格式化输出
|
||||
return format_advice(
|
||||
file_type,
|
||||
input_path,
|
||||
platform_id,
|
||||
uv_command,
|
||||
python_command,
|
||||
pip_command,
|
||||
has_platform_specific
|
||||
)
|
||||
Reference in New Issue
Block a user