308 lines
11 KiB
Python
308 lines
11 KiB
Python
"""
|
|
模特管理 CLI 命令
|
|
"""
|
|
|
|
from pathlib import Path
|
|
from typing import Optional, List
|
|
from dataclasses import asdict
|
|
from datetime import datetime
|
|
import typer
|
|
from python_core.utils.jsonrpc_enhanced import create_response_handler, create_progress_reporter
|
|
from python_core.database.model_postgres import model_table
|
|
from python_core.utils.logger import logger
|
|
from uuid import uuid4
|
|
|
|
# 创建模特应用
|
|
model_app = typer.Typer(help="模特管理命令")
|
|
|
|
|
|
@model_app.command("create")
|
|
def create_model(
|
|
model_number: str = typer.Argument(..., help="模特编号"),
|
|
model_image: str = typer.Argument(..., help="模特图片路径"),
|
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
|
is_cloud: bool = typer.Option(False, "--cloud", help="是否为云端模特"),
|
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
|
):
|
|
"""创建模特"""
|
|
response = create_response_handler()
|
|
try:
|
|
# 创建模特
|
|
model = model_table.create_model(
|
|
model_number=model_number,
|
|
model_image=model_image,
|
|
user_id=user_id or "default",
|
|
is_cloud=is_cloud
|
|
)
|
|
|
|
if model:
|
|
response.success({
|
|
'model': asdict(model),
|
|
'message': f'模特创建成功: {model.model_number}'
|
|
})
|
|
else:
|
|
response.error(-32603, "创建模特失败")
|
|
|
|
except ValueError as e:
|
|
response.error(-32602, str(e))
|
|
except Exception as e:
|
|
logger.error(f"创建模特失败: {e}")
|
|
response.error(-32603, f"创建模特失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("list")
|
|
def list_models(
|
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
|
include_cloud: bool = typer.Option(True, "--include-cloud", help="包含云端模特"),
|
|
include_inactive: bool = typer.Option(False, "--include-inactive", help="包含已禁用模特"),
|
|
limit: int = typer.Option(100, "--limit", "-l", help="显示数量限制"),
|
|
offset: int = typer.Option(0, "--offset", help="偏移量"),
|
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
|
):
|
|
"""获取模特列表"""
|
|
response = create_response_handler()
|
|
try:
|
|
# 获取模特列表
|
|
models = model_table.get_all_models(
|
|
user_id=user_id or "default",
|
|
include_cloud=include_cloud,
|
|
include_inactive=include_inactive,
|
|
limit=limit,
|
|
offset=offset
|
|
)
|
|
|
|
# 获取总数
|
|
total_count = model_table.get_model_count(
|
|
user_id=user_id or "default",
|
|
include_cloud=include_cloud,
|
|
include_inactive=include_inactive
|
|
)
|
|
|
|
response.success({
|
|
'models': [asdict(model) for model in models],
|
|
'total_count': total_count,
|
|
'limit': limit,
|
|
'offset': offset,
|
|
'message': f'获取到 {len(models)} 个模特'
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"获取模特列表失败: {e}")
|
|
response.error(-32603, f"获取模特列表失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("get")
|
|
def get_model(
|
|
model_id: str = typer.Argument(..., help="模特ID"),
|
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
|
):
|
|
"""获取模特详情"""
|
|
response = create_response_handler()
|
|
try:
|
|
model = model_table.get_model_by_id(model_id)
|
|
|
|
if model:
|
|
response.success({
|
|
'model': asdict(model),
|
|
'message': f'获取模特成功: {model.model_number}'
|
|
})
|
|
else:
|
|
response.error(-32604, f"模特不存在: {model_id}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"获取模特失败: {e}")
|
|
response.error(-32603, f"获取模特失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("get-by-number")
|
|
def get_model_by_number(
|
|
model_number: str = typer.Argument(..., help="模特编号"),
|
|
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()
|
|
try:
|
|
model = model_table.get_model_by_number(
|
|
model_number=model_number,
|
|
user_id=user_id or "default"
|
|
)
|
|
|
|
if model:
|
|
response.success({
|
|
'model': asdict(model),
|
|
'message': f'获取模特成功: {model.model_number}'
|
|
})
|
|
else:
|
|
response.error(-32604, f"模特不存在: {model_number}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"获取模特失败: {e}")
|
|
response.error(-32603, f"获取模特失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("update")
|
|
def update_model(
|
|
model_id: str = typer.Argument(..., help="模特ID"),
|
|
model_number: Optional[str] = typer.Option(None, "--model-number", help="模特编号"),
|
|
model_image: Optional[str] = typer.Option(None, "--model-image", help="模特图片路径"),
|
|
is_active: Optional[bool] = typer.Option(None, "--active", help="是否激活"),
|
|
is_cloud: Optional[bool] = typer.Option(None, "--cloud", help="是否为云端模特"),
|
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
|
):
|
|
"""更新模特"""
|
|
response = create_response_handler()
|
|
try:
|
|
# 构建更新数据
|
|
updates = {}
|
|
if model_number is not None:
|
|
updates['model_number'] = model_number
|
|
if model_image is not None:
|
|
updates['model_image'] = model_image
|
|
if is_active is not None:
|
|
updates['is_active'] = is_active
|
|
if is_cloud is not None:
|
|
updates['is_cloud'] = is_cloud
|
|
|
|
if not updates:
|
|
response.error(-32602, "没有提供更新字段")
|
|
return
|
|
|
|
success = model_table.update_model(model_id, updates)
|
|
|
|
if success:
|
|
response.success({
|
|
'model_id': model_id,
|
|
'updates': updates,
|
|
'message': '模特更新成功'
|
|
})
|
|
else:
|
|
response.error(-32604, f"模特不存在: {model_id}")
|
|
|
|
except ValueError as e:
|
|
response.error(-32602, str(e))
|
|
except Exception as e:
|
|
logger.error(f"更新模特失败: {e}")
|
|
response.error(-32603, f"更新模特失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("delete")
|
|
def delete_model(
|
|
model_id: str = typer.Argument(..., help="模特ID"),
|
|
hard_delete: bool = typer.Option(False, "--hard", help="硬删除(永久删除)"),
|
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
|
):
|
|
"""删除模特"""
|
|
response = create_response_handler()
|
|
try:
|
|
success = model_table.delete_model(model_id, hard_delete=hard_delete)
|
|
|
|
if success:
|
|
action = "删除" if hard_delete else "禁用"
|
|
response.success({
|
|
'model_id': model_id,
|
|
'hard_delete': hard_delete,
|
|
'message': f'模特{action}成功'
|
|
})
|
|
else:
|
|
response.error(-32604, f"模特不存在: {model_id}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"删除模特失败: {e}")
|
|
response.error(-32603, f"删除模特失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("search")
|
|
def search_models(
|
|
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()
|
|
try:
|
|
models = model_table.search_models(
|
|
query=query,
|
|
user_id=user_id or "default",
|
|
include_cloud=include_cloud,
|
|
limit=limit
|
|
)
|
|
|
|
response.success({
|
|
'models': [asdict(model) for model in models],
|
|
'query': query,
|
|
'count': len(models),
|
|
'message': f'搜索到 {len(models)} 个模特'
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"搜索模特失败: {e}")
|
|
response.error(-32603, f"搜索模特失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("toggle")
|
|
def toggle_model_status(
|
|
model_id: str = typer.Argument(..., help="模特ID"),
|
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
|
):
|
|
"""切换模特状态"""
|
|
response = create_response_handler()
|
|
try:
|
|
success = model_table.toggle_model_status(model_id)
|
|
|
|
if success:
|
|
response.success({
|
|
'model_id': model_id,
|
|
'message': '模特状态切换成功'
|
|
})
|
|
else:
|
|
response.error(-32604, f"模特不存在: {model_id}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"切换模特状态失败: {e}")
|
|
response.error(-32603, f"切换模特状态失败: {str(e)}")
|
|
|
|
|
|
@model_app.command("count")
|
|
def get_model_count(
|
|
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
|
|
include_cloud: bool = typer.Option(True, "--include-cloud", help="包含云端模特"),
|
|
include_inactive: bool = typer.Option(False, "--include-inactive", help="包含已禁用模特"),
|
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
|
|
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
|
|
):
|
|
"""获取模特数量"""
|
|
response = create_response_handler()
|
|
try:
|
|
count = model_table.get_model_count(
|
|
user_id=user_id or "default",
|
|
include_cloud=include_cloud,
|
|
include_inactive=include_inactive
|
|
)
|
|
|
|
response.success({
|
|
'count': count,
|
|
'user_id': user_id or "default",
|
|
'include_cloud': include_cloud,
|
|
'include_inactive': include_inactive,
|
|
'message': f'共有 {count} 个模特'
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"获取模特数量失败: {e}")
|
|
response.error(-32603, f"获取模特数量失败: {str(e)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
model_app()
|