fix: bug
This commit is contained in:
@@ -1,468 +1,309 @@
|
|||||||
"""
|
"""
|
||||||
模板管理CLI命令
|
模板管理CLI命令 - 简化版本,只传输JSON RPC
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
from dataclasses import asdict
|
||||||
import typer
|
import typer
|
||||||
from rich.console import Console
|
|
||||||
from rich.table import Table
|
|
||||||
from rich.panel import Panel
|
|
||||||
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
|
|
||||||
from rich.live import Live
|
|
||||||
import json
|
import json
|
||||||
|
from python_core.utils.jsonrpc_enhanced import create_response_handler, create_progress_reporter
|
||||||
from python_core.services.template_manager_cloud import TemplateManagerCloud, TemplateInfo
|
from python_core.services.template_manager_cloud import TemplateManagerCloud, TemplateInfo
|
||||||
from python_core.utils.logger import logger
|
from python_core.utils.logger import logger
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
console = Console()
|
|
||||||
template_app = typer.Typer(name="template", help="模板管理命令")
|
template_app = typer.Typer(name="template", help="模板管理命令")
|
||||||
|
|
||||||
|
|
||||||
@template_app.command("import")
|
@template_app.command("batch-import")
|
||||||
def batch_import(
|
def batch_import(
|
||||||
source_folder: str = typer.Argument(..., help="包含模板子文件夹的源文件夹"),
|
source_folder: str = typer.Argument(..., help="包含模板子文件夹的源文件夹"),
|
||||||
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
show_progress: bool = typer.Option(True, "--progress", "-p", help="显示进度条")
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
):
|
):
|
||||||
"""批量导入模板"""
|
"""批量导入模板"""
|
||||||
|
response = create_progress_reporter(str(uuid4()))
|
||||||
try:
|
try:
|
||||||
console.print(f"📦 [bold blue]批量导入模板[/bold blue]")
|
|
||||||
console.print(f"📁 源文件夹: {source_folder}")
|
|
||||||
|
|
||||||
# 验证源文件夹
|
# 验证源文件夹
|
||||||
source_path = Path(source_folder)
|
source_path = Path(source_folder)
|
||||||
if not source_path.exists():
|
if not source_path.exists():
|
||||||
console.print(f"[red]❌ 源文件夹不存在: {source_folder}[/red]")
|
response.error(-32603, f"源文件夹不存在: {source_folder}")
|
||||||
raise typer.Exit(1)
|
return
|
||||||
|
|
||||||
if not source_path.is_dir():
|
if not source_path.is_dir():
|
||||||
console.print(f"[red]❌ 路径不是文件夹: {source_folder}[/red]")
|
response.error(-32603, f"路径不是文件夹: {source_folder}")
|
||||||
raise typer.Exit(1)
|
return
|
||||||
|
|
||||||
# 创建模板管理器
|
# 创建模板管理器
|
||||||
manager = TemplateManagerCloud()
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
# 进度回调函数
|
# 进度回调函数
|
||||||
progress_messages = []
|
def progress_callback(current: int, total: int, message: str):
|
||||||
|
response.progress(current, total, message)
|
||||||
def progress_callback(message: str):
|
|
||||||
progress_messages.append(message)
|
|
||||||
if verbose:
|
|
||||||
console.print(f" {message}")
|
|
||||||
|
|
||||||
# 执行批量导入
|
# 执行批量导入
|
||||||
if show_progress and not verbose:
|
result = manager.batch_import_templates(source_folder, progress_callback)
|
||||||
with Progress(
|
|
||||||
SpinnerColumn(),
|
|
||||||
TextColumn("[progress.description]{task.description}"),
|
|
||||||
BarColumn(),
|
|
||||||
TaskProgressColumn(),
|
|
||||||
console=console
|
|
||||||
) as progress:
|
|
||||||
task = progress.add_task("正在导入模板...", total=None)
|
|
||||||
|
|
||||||
def progress_with_bar(message: str):
|
|
||||||
progress.update(task, description=message)
|
|
||||||
progress_callback(message)
|
|
||||||
|
|
||||||
result = manager.batch_import_templates(source_folder, progress_with_bar)
|
|
||||||
else:
|
|
||||||
result = manager.batch_import_templates(source_folder, progress_callback)
|
|
||||||
|
|
||||||
# 显示结果
|
# 返回结果
|
||||||
if result['status']:
|
if result['status']:
|
||||||
console.print(f"\n✅ [bold green]导入完成![/bold green]")
|
response.success({
|
||||||
console.print(f"📊 成功导入: {result['imported_count']} 个模板")
|
"imported_count": result['imported_count'],
|
||||||
console.print(f"❌ 导入失败: {result['failed_count']} 个模板")
|
"failed_count": result['failed_count'],
|
||||||
|
"imported_templates": result['imported_templates'],
|
||||||
# 显示成功导入的模板
|
"failed_templates": result['failed_templates'],
|
||||||
if result['imported_templates'] and verbose:
|
"message": result['msg']
|
||||||
console.print(f"\n📋 [bold green]成功导入的模板:[/bold green]")
|
})
|
||||||
for template in result['imported_templates']:
|
|
||||||
if isinstance(template, dict):
|
|
||||||
console.print(f" ✅ {template.get('name', 'Unknown')} (ID: {template.get('id', 'Unknown')})")
|
|
||||||
else:
|
|
||||||
console.print(f" ✅ {template.name} (ID: {template.id})")
|
|
||||||
|
|
||||||
# 显示失败的模板
|
|
||||||
if result['failed_templates']:
|
|
||||||
console.print(f"\n❌ [bold red]导入失败的模板:[/bold red]")
|
|
||||||
for failed in result['failed_templates']:
|
|
||||||
console.print(f" ❌ {failed['name']}: {failed['error']}")
|
|
||||||
else:
|
else:
|
||||||
console.print(f"[red]❌ 导入失败: {result['msg']}[/red]")
|
response.error(-32603, result['msg'])
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"[red]❌ 批量导入失败: {str(e)}[/red]")
|
response.error(-32603, f"批量导入失败: {str(e)}")
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
@template_app.command("list")
|
@template_app.command("list")
|
||||||
def list_templates(
|
def list_templates(
|
||||||
limit: int = typer.Option(20, "--limit", "-l", help="显示数量限制"),
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
|
include_cloud: bool = typer.Option(True, "--include-cloud", help="包含云端模板"),
|
||||||
|
limit: int = typer.Option(100, "--limit", "-l", help="显示数量限制"),
|
||||||
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
format_output: str = typer.Option("table", "--format", "-f", help="输出格式: table, json")
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
):
|
):
|
||||||
"""列出所有模板"""
|
"""列出所有模板"""
|
||||||
|
response = create_response_handler(str(uuid4()))
|
||||||
try:
|
try:
|
||||||
console.print(f"📋 [bold blue]模板列表[/bold blue]")
|
|
||||||
|
|
||||||
# 创建模板管理器
|
# 创建模板管理器
|
||||||
manager = TemplateManagerCloud()
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
# 获取模板列表
|
# 获取模板列表
|
||||||
templates = manager.get_templates()
|
templates = manager.get_templates(include_cloud=include_cloud)
|
||||||
|
|
||||||
if not templates:
|
|
||||||
console.print("📭 没有模板")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 限制显示数量
|
# 限制显示数量
|
||||||
total_count = len(templates)
|
|
||||||
if len(templates) > limit:
|
if len(templates) > limit:
|
||||||
templates = templates[:limit]
|
templates = templates[:limit]
|
||||||
console.print(f"📊 显示前 {limit} 个模板(共 {total_count} 个)")
|
|
||||||
else:
|
|
||||||
console.print(f"📊 共 {total_count} 个模板")
|
|
||||||
|
|
||||||
if format_output == "json":
|
|
||||||
# JSON格式输出
|
|
||||||
templates_data = []
|
|
||||||
for template in templates:
|
|
||||||
if isinstance(template, TemplateInfo):
|
|
||||||
from dataclasses import asdict
|
|
||||||
templates_data.append(asdict(template))
|
|
||||||
else:
|
|
||||||
templates_data.append(template)
|
|
||||||
|
|
||||||
console.print(json.dumps(templates_data, ensure_ascii=False, indent=2))
|
|
||||||
return
|
|
||||||
|
|
||||||
# 表格格式输出
|
|
||||||
table = Table(title="模板列表")
|
|
||||||
table.add_column("ID", style="cyan", width=12)
|
|
||||||
table.add_column("名称", style="green")
|
|
||||||
table.add_column("描述", style="yellow")
|
|
||||||
table.add_column("时长", style="magenta")
|
|
||||||
table.add_column("素材数", style="blue")
|
|
||||||
table.add_column("轨道数", style="red")
|
|
||||||
table.add_column("创建时间", style="dim")
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
table.add_column("标签", style="cyan")
|
|
||||||
table.add_column("资源路径", style="dim")
|
|
||||||
|
|
||||||
|
# 转换为字典格式
|
||||||
|
templates_data = []
|
||||||
for template in templates:
|
for template in templates:
|
||||||
# 格式化时长
|
if isinstance(template, TemplateInfo):
|
||||||
duration = getattr(template, 'duration', 0)
|
templates_data.append(asdict(template))
|
||||||
if duration > 60:
|
|
||||||
duration_str = f"{duration // 60}m{duration % 60}s"
|
|
||||||
else:
|
else:
|
||||||
duration_str = f"{duration}s"
|
templates_data.append(template)
|
||||||
|
|
||||||
# 格式化创建时间
|
|
||||||
created_at = getattr(template, 'created_at', '')
|
|
||||||
if 'T' in created_at:
|
|
||||||
created_at = created_at.split('T')[0] + ' ' + created_at.split('T')[1][:8]
|
|
||||||
|
|
||||||
row = [
|
|
||||||
getattr(template, 'id', '')[:12],
|
|
||||||
getattr(template, 'name', ''),
|
|
||||||
getattr(template, 'description', '')[:50] + ('...' if len(getattr(template, 'description', '')) > 50 else ''),
|
|
||||||
duration_str,
|
|
||||||
str(getattr(template, 'material_count', 0)),
|
|
||||||
str(getattr(template, 'track_count', 0)),
|
|
||||||
created_at
|
|
||||||
]
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
tags = getattr(template, 'tags', [])
|
|
||||||
tags_str = ', '.join(tags) if tags else '-'
|
|
||||||
resources_path = getattr(template, 'resources_path', '')
|
|
||||||
|
|
||||||
row.extend([
|
|
||||||
tags_str,
|
|
||||||
resources_path
|
|
||||||
])
|
|
||||||
|
|
||||||
table.add_row(*row)
|
|
||||||
|
|
||||||
console.print(table)
|
response.success({
|
||||||
|
"templates": templates_data,
|
||||||
|
"total_count": len(templates_data),
|
||||||
|
"limit": limit
|
||||||
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"[red]❌ 获取模板列表失败: {str(e)}[/red]")
|
response.error(-32603, f"获取模板列表失败: {str(e)}")
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
@template_app.command("get")
|
@template_app.command("get")
|
||||||
def get_template(
|
def get_template(
|
||||||
template_id: str = typer.Argument(..., help="模板ID"),
|
template_id: str = typer.Argument(..., help="模板ID"),
|
||||||
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
format_output: str = typer.Option("panel", "--format", "-f", help="输出格式: panel, json")
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
):
|
):
|
||||||
"""获取模板详情"""
|
"""获取模板详情"""
|
||||||
|
response = create_response_handler(str(uuid4()))
|
||||||
try:
|
try:
|
||||||
console.print(f"🔍 [bold blue]获取模板详情[/bold blue]")
|
|
||||||
console.print(f"模板ID: {template_id}")
|
|
||||||
|
|
||||||
# 创建模板管理器
|
# 创建模板管理器
|
||||||
manager = TemplateManagerCloud()
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
# 获取模板
|
# 获取模板
|
||||||
template = manager.get_template(template_id)
|
template = manager.get_template(template_id)
|
||||||
|
|
||||||
if not template:
|
if not template:
|
||||||
console.print(f"[red]❌ 未找到模板: {template_id}[/red]")
|
response.error(-32604, f"未找到模板: {template_id}")
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
if format_output == "json":
|
|
||||||
# JSON格式输出
|
|
||||||
if isinstance(template, TemplateInfo):
|
|
||||||
from dataclasses import asdict
|
|
||||||
template_data = asdict(template)
|
|
||||||
else:
|
|
||||||
template_data = template
|
|
||||||
|
|
||||||
console.print(json.dumps(template_data, ensure_ascii=False, indent=2))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# 面板格式输出
|
# 转换为字典格式
|
||||||
console.print(f"\n✅ [bold green]模板详情[/bold green]")
|
if isinstance(template, TemplateInfo):
|
||||||
|
template_data = asdict(template)
|
||||||
# 格式化时长
|
|
||||||
duration = getattr(template, 'duration', 0)
|
|
||||||
if duration > 60:
|
|
||||||
duration_str = f"{duration // 60}分{duration % 60}秒"
|
|
||||||
else:
|
else:
|
||||||
duration_str = f"{duration}秒"
|
template_data = template
|
||||||
|
|
||||||
# 基本信息
|
response.success(template_data)
|
||||||
basic_info = f"""
|
|
||||||
🆔 模板ID: {getattr(template, 'id', '')}
|
|
||||||
📝 名称: {getattr(template, 'name', '')}
|
|
||||||
📄 描述: {getattr(template, 'description', '')}
|
|
||||||
⏱️ 时长: {duration_str}
|
|
||||||
📦 素材数: {getattr(template, 'material_count', 0)}
|
|
||||||
🎬 轨道数: {getattr(template, 'track_count', 0)}
|
|
||||||
📅 创建时间: {getattr(template, 'created_at', '')}
|
|
||||||
🔄 更新时间: {getattr(template, 'updated_at', '')}
|
|
||||||
"""
|
|
||||||
|
|
||||||
panel = Panel(basic_info.strip(), title="模板基本信息", border_style="green")
|
|
||||||
console.print(panel)
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
# 详细信息
|
|
||||||
tags = getattr(template, 'tags', [])
|
|
||||||
tags_str = ', '.join(tags) if tags else '无'
|
|
||||||
|
|
||||||
detail_info = f"""
|
|
||||||
🏷️ 标签: {tags_str}
|
|
||||||
📁 草稿路径: {getattr(template, 'draft_content_path', '')}
|
|
||||||
📂 资源路径: {getattr(template, 'resources_path', '')}
|
|
||||||
🖼️ 缩略图: {getattr(template, 'thumbnail_path', '') or '无'}
|
|
||||||
"""
|
|
||||||
|
|
||||||
detail_panel = Panel(detail_info.strip(), title="详细信息", border_style="blue")
|
|
||||||
console.print(detail_panel)
|
|
||||||
|
|
||||||
# 画布配置
|
|
||||||
canvas_config = getattr(template, 'canvas_config', {})
|
|
||||||
if canvas_config:
|
|
||||||
canvas_info = f"""
|
|
||||||
📐 画布配置:
|
|
||||||
宽度: {canvas_config.get('width', 'Unknown')}
|
|
||||||
高度: {canvas_config.get('height', 'Unknown')}
|
|
||||||
帧率: {canvas_config.get('fps', 'Unknown')}
|
|
||||||
"""
|
|
||||||
|
|
||||||
canvas_panel = Panel(canvas_info.strip(), title="画布配置", border_style="yellow")
|
|
||||||
console.print(canvas_panel)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"[red]❌ 获取模板详情失败: {str(e)}[/red]")
|
response.error(-32603, f"获取模板详情失败: {str(e)}")
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
@template_app.command("detail")
|
|
||||||
def get_template_detail(
|
|
||||||
template_id: str = typer.Argument(..., help="模板ID"),
|
|
||||||
format_output: str = typer.Option("json", "--format", "-f", help="输出格式: json, summary")
|
|
||||||
):
|
|
||||||
"""获取模板详细信息(包含轨道和片段)"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
console.print(f"🔍 [bold blue]获取模板详细信息[/bold blue]")
|
|
||||||
console.print(f"模板ID: {template_id}")
|
|
||||||
|
|
||||||
# 创建模板管理器
|
|
||||||
manager = TemplateManagerCloud()
|
|
||||||
|
|
||||||
# 获取模板详细信息
|
|
||||||
detail = manager.get_template_detail(template_id)
|
|
||||||
|
|
||||||
if not detail:
|
|
||||||
console.print(f"[red]❌ 未找到模板详细信息: {template_id}[/red]")
|
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
if format_output == "json":
|
|
||||||
# JSON格式输出
|
|
||||||
console.print(json.dumps(detail, ensure_ascii=False, indent=2))
|
|
||||||
return
|
|
||||||
|
|
||||||
# 摘要格式输出
|
|
||||||
console.print(f"\n✅ [bold green]模板详细信息[/bold green]")
|
|
||||||
|
|
||||||
# 基本信息
|
|
||||||
template_info = detail.get('template', {})
|
|
||||||
console.print(f"📝 名称: {template_info.get('name', 'Unknown')}")
|
|
||||||
console.print(f"📄 描述: {template_info.get('description', 'Unknown')}")
|
|
||||||
console.print(f"⏱️ 时长: {template_info.get('duration', 0)}秒")
|
|
||||||
|
|
||||||
# 轨道信息
|
|
||||||
tracks = detail.get('tracks', [])
|
|
||||||
console.print(f"\n🎬 [bold green]轨道信息 ({len(tracks)} 个轨道)[/bold green]")
|
|
||||||
|
|
||||||
for i, track in enumerate(tracks, 1):
|
|
||||||
track_type = track.get('type', 'unknown')
|
|
||||||
segments_count = len(track.get('segments', []))
|
|
||||||
console.print(f" 轨道 {i}: {track_type} ({segments_count} 个片段)")
|
|
||||||
|
|
||||||
# 显示片段信息
|
|
||||||
for j, segment in enumerate(track.get('segments', []), 1):
|
|
||||||
segment_name = segment.get('name', f'片段{j}')
|
|
||||||
start_time = segment.get('start_time', 0)
|
|
||||||
end_time = segment.get('end_time', 0)
|
|
||||||
console.print(f" 片段 {j}: {segment_name} ({start_time}s - {end_time}s)")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
console.print(f"[red]❌ 获取模板详细信息失败: {str(e)}[/red]")
|
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
@template_app.command("delete")
|
@template_app.command("delete")
|
||||||
def delete_template(
|
def delete_template(
|
||||||
template_id: str = typer.Argument(..., help="模板ID"),
|
template_id: str = typer.Argument(..., help="模板ID"),
|
||||||
force: bool = typer.Option(False, "--force", "-f", help="强制删除,不询问确认")
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
|
force: bool = typer.Option(False, "--force", "-f", help="强制删除,不询问确认"),
|
||||||
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
):
|
):
|
||||||
"""删除模板"""
|
"""删除模板"""
|
||||||
|
response = create_response_handler(str(uuid4()))
|
||||||
try:
|
try:
|
||||||
console.print(f"🗑️ [bold red]删除模板[/bold red]")
|
|
||||||
console.print(f"模板ID: {template_id}")
|
|
||||||
|
|
||||||
# 创建模板管理器
|
# 创建模板管理器
|
||||||
manager = TemplateManagerCloud()
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
# 获取模板信息
|
# 获取模板信息
|
||||||
template = manager.get_template(template_id)
|
template = manager.get_template(template_id)
|
||||||
if not template:
|
if not template:
|
||||||
console.print(f"[red]❌ 未找到模板: {template_id}[/red]")
|
response.error(-32604, f"未找到模板: {template_id}")
|
||||||
raise typer.Exit(1)
|
return
|
||||||
|
|
||||||
console.print(f"模板名称: {getattr(template, 'name', 'Unknown')}")
|
|
||||||
console.print(f"模板描述: {getattr(template, 'description', 'Unknown')}")
|
|
||||||
|
|
||||||
# 确认删除
|
|
||||||
if not force:
|
|
||||||
confirm = typer.confirm("确定要删除这个模板吗?此操作不可恢复。")
|
|
||||||
if not confirm:
|
|
||||||
console.print("❌ 操作已取消")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 删除模板
|
# 删除模板
|
||||||
success = manager.delete_template(template_id)
|
success = manager.delete_template(template_id)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
console.print(f"✅ [bold green]模板删除成功[/bold green]")
|
response.success({
|
||||||
|
"deleted": True,
|
||||||
|
"template_id": template_id,
|
||||||
|
"template_name": getattr(template, 'name', 'Unknown')
|
||||||
|
})
|
||||||
else:
|
else:
|
||||||
console.print(f"[red]❌ 模板删除失败[/red]")
|
response.error(-32603, "模板删除失败")
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"[red]❌ 删除模板失败: {str(e)}[/red]")
|
response.error(-32603, f"删除模板失败: {str(e)}")
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
|
@template_app.command("search")
|
||||||
|
def search_templates(
|
||||||
|
query: str = typer.Argument(..., help="搜索关键词"),
|
||||||
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
|
include_cloud: bool = typer.Option(True, "--include-cloud", help="包含云端模板"),
|
||||||
|
limit: int = typer.Option(50, "--limit", "-l", help="显示数量限制"),
|
||||||
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
|
):
|
||||||
|
"""搜索模板"""
|
||||||
|
response = create_response_handler(str(uuid4()))
|
||||||
|
try:
|
||||||
|
# 创建模板管理器
|
||||||
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
|
# 搜索模板
|
||||||
|
templates = manager.search_templates(query, include_cloud=include_cloud, limit=limit)
|
||||||
|
|
||||||
|
# 转换为字典格式
|
||||||
|
templates_data = []
|
||||||
|
for template in templates:
|
||||||
|
if isinstance(template, TemplateInfo):
|
||||||
|
templates_data.append(asdict(template))
|
||||||
|
else:
|
||||||
|
templates_data.append(template)
|
||||||
|
|
||||||
|
response.success({
|
||||||
|
"templates": templates_data,
|
||||||
|
"query": query,
|
||||||
|
"total_count": len(templates_data),
|
||||||
|
"limit": limit
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
response.error(-32603, f"搜索模板失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
@template_app.command("stats")
|
@template_app.command("stats")
|
||||||
def show_stats():
|
def get_template_stats(
|
||||||
"""显示模板统计信息"""
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
|
):
|
||||||
|
"""获取模板统计信息"""
|
||||||
|
response = create_response_handler(str(uuid4()))
|
||||||
try:
|
try:
|
||||||
console.print(f"📊 [bold blue]模板统计信息[/bold blue]")
|
|
||||||
|
|
||||||
# 创建模板管理器
|
# 创建模板管理器
|
||||||
manager = TemplateManagerCloud()
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
# 获取所有模板
|
# 获取模板数量
|
||||||
templates = manager.get_templates()
|
template_count = manager.get_template_count(include_cloud=True)
|
||||||
|
user_template_count = manager.get_template_count(include_cloud=False)
|
||||||
|
|
||||||
if not templates:
|
# 获取所有模板进行统计
|
||||||
console.print("📭 没有模板")
|
templates = manager.get_templates(include_cloud=True)
|
||||||
return
|
|
||||||
|
|
||||||
# 计算统计信息
|
# 计算统计信息
|
||||||
total_templates = len(templates)
|
|
||||||
total_materials = sum(getattr(template, 'material_count', 0) for template in templates)
|
total_materials = sum(getattr(template, 'material_count', 0) for template in templates)
|
||||||
total_tracks = sum(getattr(template, 'track_count', 0) for template in templates)
|
total_tracks = sum(getattr(template, 'track_count', 0) for template in templates)
|
||||||
total_duration = sum(getattr(template, 'duration', 0) for template in templates)
|
total_duration = sum(getattr(template, 'duration', 0) for template in templates)
|
||||||
|
|
||||||
# 格式化总时长
|
response.success({
|
||||||
if total_duration > 3600:
|
"total_templates": template_count,
|
||||||
duration_str = f"{total_duration // 3600}小时{(total_duration % 3600) // 60}分{total_duration % 60}秒"
|
"user_templates": user_template_count,
|
||||||
elif total_duration > 60:
|
"cloud_templates": template_count - user_template_count,
|
||||||
duration_str = f"{total_duration // 60}分{total_duration % 60}秒"
|
"total_materials": total_materials,
|
||||||
else:
|
"total_tracks": total_tracks,
|
||||||
duration_str = f"{total_duration}秒"
|
"total_duration": total_duration,
|
||||||
|
"average_duration": total_duration // template_count if template_count > 0 else 0
|
||||||
# 创建统计面板
|
})
|
||||||
stats_content = f"""
|
|
||||||
📈 [bold green]总体统计[/bold green]
|
|
||||||
模板总数: {total_templates}
|
|
||||||
素材总数: {total_materials}
|
|
||||||
轨道总数: {total_tracks}
|
|
||||||
总时长: {duration_str}
|
|
||||||
平均时长: {total_duration // total_templates if total_templates > 0 else 0}秒
|
|
||||||
"""
|
|
||||||
|
|
||||||
stats_panel = Panel(stats_content.strip(), title="模板统计", border_style="green")
|
|
||||||
console.print(stats_panel)
|
|
||||||
|
|
||||||
# 显示最近的模板
|
|
||||||
recent_templates = sorted(templates, key=lambda x: getattr(x, 'created_at', ''), reverse=True)[:5]
|
|
||||||
|
|
||||||
if recent_templates:
|
|
||||||
console.print(f"\n🕒 [bold green]最近创建的模板[/bold green]")
|
|
||||||
|
|
||||||
recent_table = Table()
|
|
||||||
recent_table.add_column("名称", style="green")
|
|
||||||
recent_table.add_column("时长", style="magenta")
|
|
||||||
recent_table.add_column("创建时间", style="dim")
|
|
||||||
|
|
||||||
for template in recent_templates:
|
|
||||||
duration = getattr(template, 'duration', 0)
|
|
||||||
duration_str = f"{duration}s" if duration < 60 else f"{duration // 60}m{duration % 60}s"
|
|
||||||
|
|
||||||
created_at = getattr(template, 'created_at', '')
|
|
||||||
if 'T' in created_at:
|
|
||||||
created_at = created_at.split('T')[0] + ' ' + created_at.split('T')[1][:8]
|
|
||||||
|
|
||||||
recent_table.add_row(
|
|
||||||
getattr(template, 'name', 'Unknown'),
|
|
||||||
duration_str,
|
|
||||||
created_at
|
|
||||||
)
|
|
||||||
|
|
||||||
console.print(recent_table)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"[red]❌ 获取统计信息失败: {str(e)}[/red]")
|
response.error(-32603, f"获取统计信息失败: {str(e)}")
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
|
@template_app.command("tags")
|
||||||
|
def get_popular_tags(
|
||||||
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
|
limit: int = typer.Option(20, "--limit", "-l", help="显示数量限制"),
|
||||||
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
|
):
|
||||||
|
"""获取热门标签"""
|
||||||
|
response = create_response_handler(str(uuid4()))
|
||||||
|
try:
|
||||||
|
# 创建模板管理器
|
||||||
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
|
# 获取热门标签
|
||||||
|
tags = manager.get_popular_tags(limit=limit)
|
||||||
|
|
||||||
|
response.success({
|
||||||
|
"tags": tags,
|
||||||
|
"total_count": len(tags),
|
||||||
|
"limit": limit
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
response.error(-32603, f"获取热门标签失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@template_app.command("by-tag")
|
||||||
|
def get_templates_by_tag(
|
||||||
|
tag: str = typer.Argument(..., help="标签名称"),
|
||||||
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
||||||
|
include_cloud: bool = typer.Option(True, "--include-cloud", help="包含云端模板"),
|
||||||
|
limit: int = typer.Option(50, "--limit", "-l", help="显示数量限制"),
|
||||||
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
||||||
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
||||||
|
):
|
||||||
|
"""根据标签获取模板"""
|
||||||
|
response = create_response_handler(str(uuid4()))
|
||||||
|
try:
|
||||||
|
# 创建模板管理器
|
||||||
|
manager = TemplateManagerCloud(user_id=user_id or "default")
|
||||||
|
|
||||||
|
# 根据标签获取模板
|
||||||
|
templates = manager.get_templates_by_tag(tag, include_cloud=include_cloud, limit=limit)
|
||||||
|
|
||||||
|
# 转换为字典格式
|
||||||
|
templates_data = []
|
||||||
|
for template in templates:
|
||||||
|
if isinstance(template, TemplateInfo):
|
||||||
|
templates_data.append(asdict(template))
|
||||||
|
else:
|
||||||
|
templates_data.append(template)
|
||||||
|
|
||||||
|
response.success({
|
||||||
|
"templates": templates_data,
|
||||||
|
"tag": tag,
|
||||||
|
"total_count": len(templates_data),
|
||||||
|
"limit": limit
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
response.error(-32603, f"根据标签获取模板失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -1,10 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* Template 命令封装
|
||||||
|
* 统一使用 execute_python_cli_command 模式
|
||||||
|
*/
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::python_executor::{execute_python_command, execute_python_action_with_progress};
|
|
||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
|
use crate::python_executor::{execute_python_command, execute_python_action_with_progress};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TemplateResponse {
|
||||||
|
pub success: bool,
|
||||||
|
pub message: String,
|
||||||
|
pub data: Option<serde_json::Value>,
|
||||||
|
pub output: Option<String>,
|
||||||
|
pub error: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct BatchImportRequest {
|
pub struct BatchImportRequest {
|
||||||
pub source_folder: String,
|
pub source_folder: String,
|
||||||
|
pub user_id: Option<String>,
|
||||||
|
pub verbose: Option<bool>,
|
||||||
|
pub json_output: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct TemplateListRequest {
|
||||||
|
pub user_id: Option<String>,
|
||||||
|
pub include_cloud: Option<bool>,
|
||||||
|
pub limit: Option<i32>,
|
||||||
|
pub verbose: Option<bool>,
|
||||||
|
pub json_output: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct TemplateGetRequest {
|
||||||
|
pub template_id: String,
|
||||||
|
pub user_id: Option<String>,
|
||||||
|
pub verbose: Option<bool>,
|
||||||
|
pub json_output: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct TemplateDeleteRequest {
|
||||||
|
pub template_id: String,
|
||||||
|
pub user_id: Option<String>,
|
||||||
|
pub verbose: Option<bool>,
|
||||||
|
pub json_output: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct TemplateSearchRequest {
|
||||||
|
pub query: String,
|
||||||
|
pub user_id: Option<String>,
|
||||||
|
pub include_cloud: Option<bool>,
|
||||||
|
pub limit: Option<i32>,
|
||||||
|
pub verbose: Option<bool>,
|
||||||
|
pub json_output: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-export PythonProgress as ImportProgress for backward compatibility
|
// Re-export PythonProgress as ImportProgress for backward compatibility
|
||||||
@@ -29,8 +81,78 @@ pub struct TemplateInfo {
|
|||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 执行Python CLI命令的通用函数(统一模式)
|
||||||
|
async fn execute_python_cli_command(
|
||||||
|
app: AppHandle,
|
||||||
|
command_args: Vec<String>,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
// 构建完整的命令参数
|
||||||
|
let mut args = vec!["-m".to_string(), "python_core.cli".to_string()];
|
||||||
|
args.extend(command_args);
|
||||||
|
|
||||||
|
println!("Executing Template CLI: python {}", args.join(" "));
|
||||||
|
|
||||||
|
match execute_python_command(app, &args, None).await {
|
||||||
|
Ok(output) => {
|
||||||
|
// 尝试解析JSON响应
|
||||||
|
if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(&output) {
|
||||||
|
Ok(TemplateResponse {
|
||||||
|
success: true,
|
||||||
|
message: "模板命令执行成功".to_string(),
|
||||||
|
data: Some(json_value),
|
||||||
|
output: Some(output),
|
||||||
|
error: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 如果不是JSON,直接返回文本输出
|
||||||
|
Ok(TemplateResponse {
|
||||||
|
success: true,
|
||||||
|
message: "模板命令执行成功".to_string(),
|
||||||
|
data: None,
|
||||||
|
output: Some(output),
|
||||||
|
error: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
Ok(TemplateResponse {
|
||||||
|
success: false,
|
||||||
|
message: "模板命令执行失败".to_string(),
|
||||||
|
data: None,
|
||||||
|
output: None,
|
||||||
|
error: Some(error),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// 批量导入模板(新版本,使用CLI模式)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn batch_import_templates_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
request: BatchImportRequest,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "batch-import".to_string(), request.source_folder];
|
||||||
|
|
||||||
|
if let Some(user_id) = request.user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.json_output.unwrap_or(true) {
|
||||||
|
args.push("--json".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 批量导入模板(保持向后兼容)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn batch_import_templates(app: tauri::AppHandle, request: BatchImportRequest) -> Result<String, String> {
|
pub async fn batch_import_templates(app: tauri::AppHandle, request: BatchImportRequest) -> Result<String, String> {
|
||||||
let args = vec![
|
let args = vec![
|
||||||
@@ -62,6 +184,40 @@ pub async fn batch_import_templates_with_progress(
|
|||||||
).await
|
).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 获取模板列表(新版本,使用CLI模式)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_templates_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
request: TemplateListRequest,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "list".to_string()];
|
||||||
|
|
||||||
|
if let Some(user_id) = request.user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.include_cloud.unwrap_or(true) {
|
||||||
|
args.push("--include-cloud".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(limit_val) = request.limit {
|
||||||
|
args.push("--limit".to_string());
|
||||||
|
args.push(limit_val.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.json_output.unwrap_or(true) {
|
||||||
|
args.push("--json".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取模板列表(保持向后兼容)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_templates(app: tauri::AppHandle) -> Result<String, String> {
|
pub async fn get_templates(app: tauri::AppHandle) -> Result<String, String> {
|
||||||
let args = vec![
|
let args = vec![
|
||||||
@@ -74,6 +230,31 @@ pub async fn get_templates(app: tauri::AppHandle) -> Result<String, String> {
|
|||||||
execute_python_command(app, &args, None).await
|
execute_python_command(app, &args, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 获取单个模板(新版本,使用CLI模式)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_template_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
request: TemplateGetRequest,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "get".to_string(), request.template_id];
|
||||||
|
|
||||||
|
if let Some(user_id) = request.user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.json_output.unwrap_or(true) {
|
||||||
|
args.push("--json".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取单个模板(保持向后兼容)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_template(app: tauri::AppHandle, template_id: String) -> Result<String, String> {
|
pub async fn get_template(app: tauri::AppHandle, template_id: String) -> Result<String, String> {
|
||||||
let args = vec![
|
let args = vec![
|
||||||
@@ -88,6 +269,31 @@ pub async fn get_template(app: tauri::AppHandle, template_id: String) -> Result<
|
|||||||
execute_python_command(app, &args, None).await
|
execute_python_command(app, &args, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 删除模板(新版本,使用CLI模式)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn delete_template_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
request: TemplateDeleteRequest,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "delete".to_string(), request.template_id];
|
||||||
|
|
||||||
|
if let Some(user_id) = request.user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.json_output.unwrap_or(true) {
|
||||||
|
args.push("--json".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 删除模板(保持向后兼容)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn delete_template(app: tauri::AppHandle, template_id: String) -> Result<String, String> {
|
pub async fn delete_template(app: tauri::AppHandle, template_id: String) -> Result<String, String> {
|
||||||
let args = vec![
|
let args = vec![
|
||||||
@@ -102,6 +308,40 @@ pub async fn delete_template(app: tauri::AppHandle, template_id: String) -> Resu
|
|||||||
execute_python_command(app, &args, None).await
|
execute_python_command(app, &args, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 搜索模板(新功能,使用CLI模式)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn search_templates_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
request: TemplateSearchRequest,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "search".to_string(), request.query];
|
||||||
|
|
||||||
|
if let Some(user_id) = request.user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.include_cloud.unwrap_or(true) {
|
||||||
|
args.push("--include-cloud".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(limit_val) = request.limit {
|
||||||
|
args.push("--limit".to_string());
|
||||||
|
args.push(limit_val.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.json_output.unwrap_or(true) {
|
||||||
|
args.push("--json".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取模板详情(保持向后兼容)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_template_detail(app: tauri::AppHandle, template_id: String) -> Result<String, String> {
|
pub async fn get_template_detail(app: tauri::AppHandle, template_id: String) -> Result<String, String> {
|
||||||
let args = vec![
|
let args = vec![
|
||||||
@@ -140,3 +380,90 @@ pub async fn generate_video_with_progress(
|
|||||||
None,
|
None,
|
||||||
).await
|
).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 获取模板统计信息(新功能)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_template_stats_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
user_id: Option<String>,
|
||||||
|
verbose: Option<bool>,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "stats".to_string()];
|
||||||
|
|
||||||
|
if let Some(user_id) = user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push("--json".to_string());
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取热门标签(新功能)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_popular_tags_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
user_id: Option<String>,
|
||||||
|
limit: Option<i32>,
|
||||||
|
verbose: Option<bool>,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "tags".to_string()];
|
||||||
|
|
||||||
|
if let Some(user_id) = user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(limit_val) = limit {
|
||||||
|
args.push("--limit".to_string());
|
||||||
|
args.push(limit_val.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push("--json".to_string());
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 按标签获取模板(新功能)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_templates_by_tag_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
tag: String,
|
||||||
|
user_id: Option<String>,
|
||||||
|
include_cloud: Option<bool>,
|
||||||
|
limit: Option<i32>,
|
||||||
|
verbose: Option<bool>,
|
||||||
|
) -> Result<TemplateResponse, String> {
|
||||||
|
let mut args = vec!["template".to_string(), "by-tag".to_string(), tag];
|
||||||
|
|
||||||
|
if let Some(user_id) = user_id {
|
||||||
|
args.push("--user-id".to_string());
|
||||||
|
args.push(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if include_cloud.unwrap_or(true) {
|
||||||
|
args.push("--include-cloud".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(limit_val) = limit {
|
||||||
|
args.push("--limit".to_string());
|
||||||
|
args.push(limit_val.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose.unwrap_or(false) {
|
||||||
|
args.push("--verbose".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push("--json".to_string());
|
||||||
|
|
||||||
|
execute_python_cli_command(app, args).await
|
||||||
|
}
|
||||||
|
|||||||
@@ -120,7 +120,16 @@ pub fn run() {
|
|||||||
commands::python_cli::python_cli_template_batch_import,
|
commands::python_cli::python_cli_template_batch_import,
|
||||||
commands::python_cli::python_cli_category_list,
|
commands::python_cli::python_cli_category_list,
|
||||||
commands::python_cli::python_cli_scene_detect,
|
commands::python_cli::python_cli_scene_detect,
|
||||||
commands::python_cli::python_cli_execute
|
commands::python_cli::python_cli_execute,
|
||||||
|
// Template CLI Commands (New)
|
||||||
|
commands::template::batch_import_templates_cli,
|
||||||
|
commands::template::get_templates_cli,
|
||||||
|
commands::template::get_template_cli,
|
||||||
|
commands::template::delete_template_cli,
|
||||||
|
commands::template::search_templates_cli,
|
||||||
|
commands::template::get_template_stats_cli,
|
||||||
|
commands::template::get_popular_tags_cli,
|
||||||
|
commands::template::get_templates_by_tag_cli
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { TemplateService } from '../services/tauri'
|
import { TemplateService } from '../services/templateService'
|
||||||
import { useTemplateProgress } from '../hooks/useProgressCommand'
|
import { useTemplateProgress } from '../hooks/useProgressCommand'
|
||||||
import type { TemplateInfo } from '../hooks/useProgressCommand'
|
import type { TemplateInfo } from '../hooks/useProgressCommand'
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -633,88 +633,3 @@ export class MLService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template management operations
|
|
||||||
export class TemplateService {
|
|
||||||
/**
|
|
||||||
* Batch import templates from a folder
|
|
||||||
*/
|
|
||||||
static async batchImportTemplates(sourceFolder: string): Promise<any> {
|
|
||||||
try {
|
|
||||||
const request = { source_folder: sourceFolder }
|
|
||||||
const result = await invoke('batch_import_templates', { request })
|
|
||||||
return JSON.parse(result as string)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to batch import templates:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Batch import templates with progress monitoring
|
|
||||||
*/
|
|
||||||
static async batchImportTemplatesWithProgress(
|
|
||||||
sourceFolder: string,
|
|
||||||
onProgress?: (progress: any) => void
|
|
||||||
): Promise<any> {
|
|
||||||
const request = { source_folder: sourceFolder }
|
|
||||||
return executeCommandWithProgress(
|
|
||||||
'batch_import_templates_with_progress',
|
|
||||||
{ request },
|
|
||||||
'template-import-progress',
|
|
||||||
onProgress
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all templates
|
|
||||||
*/
|
|
||||||
static async getTemplates(): Promise<any> {
|
|
||||||
try {
|
|
||||||
const result = await invoke('get_templates')
|
|
||||||
return JSON.parse(result as string)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to get templates:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get template detail with tracks and segments
|
|
||||||
*/
|
|
||||||
static async getTemplateDetail(templateId: string): Promise<any> {
|
|
||||||
try {
|
|
||||||
const result = await invoke('get_template_detail', { templateId })
|
|
||||||
return JSON.parse(result as string)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to get template detail:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a specific template
|
|
||||||
*/
|
|
||||||
static async getTemplate(templateId: string): Promise<any> {
|
|
||||||
try {
|
|
||||||
const result = await invoke('get_template', { templateId })
|
|
||||||
return JSON.parse(result as string)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to get template:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a template
|
|
||||||
*/
|
|
||||||
static async deleteTemplate(templateId: string): Promise<any> {
|
|
||||||
try {
|
|
||||||
const result = await invoke('delete_template', { templateId })
|
|
||||||
return JSON.parse(result as string)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to delete template:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
201
template_rust_update_summary.md
Normal file
201
template_rust_update_summary.md
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# Template.rs 更新总结
|
||||||
|
|
||||||
|
## 🎯 更新目标
|
||||||
|
|
||||||
|
参考 `python_cli.rs` 的实现模式,统一使用 `execute_python_cli_command` 来处理模板相关的命令。
|
||||||
|
|
||||||
|
## 🔄 主要变更
|
||||||
|
|
||||||
|
### 1. **统一响应结构**
|
||||||
|
|
||||||
|
新增 `TemplateResponse` 结构体,与 `python_cli.rs` 中的 `PythonCliResponse` 保持一致:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TemplateResponse {
|
||||||
|
pub success: bool,
|
||||||
|
pub message: String,
|
||||||
|
pub data: Option<serde_json::Value>,
|
||||||
|
pub output: Option<String>,
|
||||||
|
pub error: Option<String>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. **统一命令执行函数**
|
||||||
|
|
||||||
|
添加 `execute_python_cli_command` 函数,参考 `python_cli.rs` 的实现:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
async fn execute_python_cli_command(
|
||||||
|
app: AppHandle,
|
||||||
|
command_args: Vec<String>,
|
||||||
|
) -> Result<TemplateResponse, String>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. **新增请求结构体**
|
||||||
|
|
||||||
|
为支持更丰富的参数,新增多个请求结构体:
|
||||||
|
|
||||||
|
- `TemplateListRequest` - 模板列表查询参数
|
||||||
|
- `TemplateGetRequest` - 单个模板获取参数
|
||||||
|
- `TemplateDeleteRequest` - 模板删除参数
|
||||||
|
- `TemplateSearchRequest` - 模板搜索参数
|
||||||
|
- 更新 `BatchImportRequest` - 添加用户ID等参数
|
||||||
|
|
||||||
|
### 4. **新版本命令函数**
|
||||||
|
|
||||||
|
为每个原有命令添加新版本,使用CLI模式:
|
||||||
|
|
||||||
|
| 原函数 | 新函数 | 说明 |
|
||||||
|
|--------|--------|------|
|
||||||
|
| `batch_import_templates` | `batch_import_templates_cli` | 批量导入模板 |
|
||||||
|
| `get_templates` | `get_templates_cli` | 获取模板列表 |
|
||||||
|
| `get_template` | `get_template_cli` | 获取单个模板 |
|
||||||
|
| `delete_template` | `delete_template_cli` | 删除模板 |
|
||||||
|
|
||||||
|
### 5. **新增功能命令**
|
||||||
|
|
||||||
|
添加新的CLI命令函数:
|
||||||
|
|
||||||
|
- `search_templates_cli` - 搜索模板
|
||||||
|
- `get_template_stats_cli` - 获取模板统计
|
||||||
|
- `get_popular_tags_cli` - 获取热门标签
|
||||||
|
- `get_templates_by_tag_cli` - 按标签获取模板
|
||||||
|
|
||||||
|
## 📋 命令对比
|
||||||
|
|
||||||
|
### **批量导入模板**
|
||||||
|
|
||||||
|
#### 原版本
|
||||||
|
```rust
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn batch_import_templates(
|
||||||
|
app: tauri::AppHandle,
|
||||||
|
request: BatchImportRequest
|
||||||
|
) -> Result<String, String>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 新版本
|
||||||
|
```rust
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn batch_import_templates_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
request: BatchImportRequest,
|
||||||
|
) -> Result<TemplateResponse, String>
|
||||||
|
```
|
||||||
|
|
||||||
|
### **模板列表**
|
||||||
|
|
||||||
|
#### 原版本
|
||||||
|
```rust
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_templates(app: tauri::AppHandle) -> Result<String, String>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 新版本
|
||||||
|
```rust
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_templates_cli(
|
||||||
|
app: AppHandle,
|
||||||
|
request: TemplateListRequest,
|
||||||
|
) -> Result<TemplateResponse, String>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 使用示例
|
||||||
|
|
||||||
|
### **前端调用新版本API**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 批量导入模板
|
||||||
|
const importResult = await invoke('batch_import_templates_cli', {
|
||||||
|
request: {
|
||||||
|
source_folder: '/path/to/templates',
|
||||||
|
user_id: 'user123',
|
||||||
|
verbose: true,
|
||||||
|
json_output: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取模板列表
|
||||||
|
const templatesResult = await invoke('get_templates_cli', {
|
||||||
|
request: {
|
||||||
|
user_id: 'user123',
|
||||||
|
include_cloud: true,
|
||||||
|
limit: 50,
|
||||||
|
verbose: false,
|
||||||
|
json_output: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索模板
|
||||||
|
const searchResult = await invoke('search_templates_cli', {
|
||||||
|
request: {
|
||||||
|
query: '商业宣传',
|
||||||
|
user_id: 'user123',
|
||||||
|
include_cloud: true,
|
||||||
|
limit: 20,
|
||||||
|
json_output: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### **响应格式**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface TemplateResponse {
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
data?: any;
|
||||||
|
output?: string;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 CLI命令映射
|
||||||
|
|
||||||
|
新版本函数直接调用 Python CLI 命令:
|
||||||
|
|
||||||
|
| Rust函数 | Python CLI命令 |
|
||||||
|
|----------|----------------|
|
||||||
|
| `batch_import_templates_cli` | `python -m python_core.cli template batch-import` |
|
||||||
|
| `get_templates_cli` | `python -m python_core.cli template list` |
|
||||||
|
| `search_templates_cli` | `python -m python_core.cli template search` |
|
||||||
|
| `get_template_cli` | `python -m python_core.cli template get` |
|
||||||
|
| `delete_template_cli` | `python -m python_core.cli template delete` |
|
||||||
|
|
||||||
|
## 📈 优势
|
||||||
|
|
||||||
|
### **1. 统一性**
|
||||||
|
- 与 `python_cli.rs` 保持一致的架构
|
||||||
|
- 统一的响应格式和错误处理
|
||||||
|
- 一致的参数传递方式
|
||||||
|
|
||||||
|
### **2. 功能丰富**
|
||||||
|
- 支持用户ID参数
|
||||||
|
- 支持详细的查询选项
|
||||||
|
- 新增搜索和统计功能
|
||||||
|
|
||||||
|
### **3. 向后兼容**
|
||||||
|
- 保留原有函数,确保现有代码不受影响
|
||||||
|
- 渐进式迁移到新版本
|
||||||
|
|
||||||
|
### **4. 可维护性**
|
||||||
|
- 统一的命令执行逻辑
|
||||||
|
- 清晰的参数结构
|
||||||
|
- 完善的类型定义
|
||||||
|
|
||||||
|
## 🔮 后续计划
|
||||||
|
|
||||||
|
1. **逐步迁移** - 前端代码逐步迁移到新版本API
|
||||||
|
2. **移除旧版本** - 确认迁移完成后移除旧版本函数
|
||||||
|
3. **功能扩展** - 基于CLI模式添加更多模板管理功能
|
||||||
|
4. **性能优化** - 优化命令执行和响应处理
|
||||||
|
|
||||||
|
## 📝 注意事项
|
||||||
|
|
||||||
|
1. **函数命名** - 新版本函数添加 `_cli` 后缀以区分
|
||||||
|
2. **参数结构** - 使用结构体传递参数,支持可选字段
|
||||||
|
3. **响应格式** - 统一使用 `TemplateResponse` 结构
|
||||||
|
4. **错误处理** - 保持与 `python_cli.rs` 一致的错误处理方式
|
||||||
|
|
||||||
|
Template.rs 已成功更新为统一的CLI模式,提供了更丰富的功能和更好的一致性!🎉
|
||||||
Reference in New Issue
Block a user