This commit is contained in:
root 2025-07-12 23:11:40 +08:00
parent 26cf5ad37b
commit 4994734ca1
7 changed files with 1207 additions and 499 deletions

View File

@ -0,0 +1,337 @@
# Resource Category 统一入口改造
## 概述
`resource_category.rs` 改造成统一入口模式,参考 `template.rs` 的实现,使用 `execute_python_cli_command` 统一执行 Python CLI 命令。
## 改造内容
### 1. Rust 端改造
#### 新增数据结构
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct ResourceCategoryResponse {
pub success: bool,
pub message: String,
pub data: Option<serde_json::Value>,
pub output: Option<String>,
pub error: Option<String>,
}
// 各种请求结构体
pub struct CategoryListRequest { ... }
pub struct CategoryGetRequest { ... }
pub struct CategoryCreateRequest { ... }
pub struct CategoryUpdateRequest { ... }
pub struct CategoryDeleteRequest { ... }
pub struct CategorySearchRequest { ... }
pub struct CategoryColorRequest { ... }
pub struct CategoryBatchCreateRequest { ... }
```
#### 统一执行函数
```rust
async fn execute_python_cli_command(
app: AppHandle,
command_args: Vec<String>,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["-m".to_string(), "python_core.cli".to_string()];
args.extend(command_args);
match execute_python_command(app, &args, None).await {
Ok(output) => {
// 解析JSON响应或返回文本输出
}
Err(error) => {
// 返回错误响应
}
}
}
```
#### 新增 CLI 命令
- `get_all_resource_categories_cli()` - 获取所有分类
- `get_resource_category_by_id_cli()` - 根据ID获取分类
- `create_resource_category_cli()` - 创建分类
- `update_resource_category_cli()` - 更新分类
- `delete_resource_category_cli()` - 删除分类
- `search_resource_categories_cli()` - 搜索分类
- `get_resource_categories_by_color_cli()` - 按颜色获取分类
- `get_cloud_resource_categories_cli()` - 获取云端分类
- `batch_create_resource_categories_cli()` - 批量创建分类
- `get_resource_category_count_cli()` - 获取分类数量
- `activate_resource_category_cli()` - 激活分类
- `deactivate_resource_category_cli()` - 停用分类
#### 向后兼容
保留原有的命令函数,确保现有前端代码不受影响:
```rust
#[command]
pub async fn get_all_resource_categories(app: AppHandle) -> Result<String, String> {
// 原有实现保持不变
}
```
### 2. Python CLI 端实现
#### 新增命令文件
创建 `python_core/cli/commands/resource_category.py`
```python
resource_category_app = typer.Typer(help="素材分类管理命令")
@resource_category_app.command("list")
def list_categories(...):
"""获取所有素材分类"""
@resource_category_app.command("get")
def get_category(...):
"""根据ID获取素材分类"""
@resource_category_app.command("create")
def create_category(...):
"""创建新的素材分类"""
# ... 其他命令
```
#### 注册到主 CLI
`python_core/cli/cli.py` 中注册:
```python
from python_core.cli.commands.resource_category import resource_category_app
app.add_typer(resource_category_app, name="resource-category")
```
### 3. 支持的 CLI 命令
#### 基本操作
```bash
# 获取所有分类
python -m python_core.cli resource-category list --user-id USER_ID
# 根据ID获取分类
python -m python_core.cli resource-category get CATEGORY_ID --user-id USER_ID
# 创建分类
python -m python_core.cli resource-category create "分类名称" \
--ai-prompt "AI提示词" --color "#FF0000" --user-id USER_ID
# 更新分类
python -m python_core.cli resource-category update CATEGORY_ID \
--title "新标题" --color "#00FF00" --user-id USER_ID
# 删除分类
python -m python_core.cli resource-category delete CATEGORY_ID \
--hard-delete --user-id USER_ID
```
#### 高级查询
```bash
# 搜索分类
python -m python_core.cli resource-category search "关键词" --user-id USER_ID
# 按颜色获取分类
python -m python_core.cli resource-category by-color "#FF0000" --user-id USER_ID
# 获取云端分类
python -m python_core.cli resource-category cloud --limit 50
# 获取分类数量
python -m python_core.cli resource-category count --user-id USER_ID
```
#### 状态管理
```bash
# 激活分类
python -m python_core.cli resource-category activate CATEGORY_ID --user-id USER_ID
# 停用分类
python -m python_core.cli resource-category deactivate CATEGORY_ID --user-id USER_ID
```
#### 批量操作
```bash
# 批量创建分类
python -m python_core.cli resource-category batch-create \
--data '[{"title":"分类1","color":"#FF0000"},{"title":"分类2","color":"#00FF00"}]' \
--user-id USER_ID
```
## 主要特点
### 🔄 **统一模式**
- 所有新命令都使用 `execute_python_cli_command` 模式
- 统一的错误处理和响应格式
- 与 `template.rs` 保持一致的架构
### 🔗 **向后兼容**
- 保留所有原有的命令函数
- 现有前端代码无需修改
- 渐进式迁移到新的 CLI 模式
### 🚀 **功能增强**
- 支持更多的查询和过滤选项
- 批量操作支持
- 状态管理功能
- 云端分类管理
### 📊 **统一响应格式**
```rust
pub struct ResourceCategoryResponse {
pub success: bool, // 操作是否成功
pub message: String, // 操作消息
pub data: Option<Value>, // 返回数据
pub output: Option<String>, // 原始输出
pub error: Option<String>, // 错误信息
}
```
### 🎯 **丰富的参数支持**
每个命令都支持:
- `--user-id`: 用户ID
- `--verbose`: 详细输出
- `--json`: JSON格式输出
- 特定的业务参数
## 使用示例
### 前端调用新的 CLI 命令
```typescript
// 获取所有分类
const response = await invoke<ResourceCategoryResponse>('get_all_resource_categories_cli', {
request: {
user_id: "user_123",
include_cloud: true,
limit: 50,
verbose: false,
json_output: true
}
});
// 创建分类
const createResponse = await invoke<ResourceCategoryResponse>('create_resource_category_cli', {
request: {
title: "新分类",
ai_prompt: "AI提示词",
color: "#FF0000",
is_cloud: false,
user_id: "user_123",
verbose: false,
json_output: true
}
});
```
### 直接使用 CLI
```bash
# 完整的工作流示例
python -m python_core.cli resource-category create "视频素材" \
--ai-prompt "用于识别视频文件" \
--color "#FF6B6B" \
--user-id "demo_user"
python -m python_core.cli resource-category list --user-id "demo_user"
python -m python_core.cli resource-category search "视频" --user-id "demo_user"
```
## 注册的 Tauri 命令
`lib.rs` 中注册了以下新命令:
```rust
commands::get_all_resource_categories_cli,
commands::get_resource_category_by_id_cli,
commands::create_resource_category_cli,
commands::update_resource_category_cli,
commands::delete_resource_category_cli,
commands::search_resource_categories_cli,
commands::get_resource_categories_by_color_cli,
commands::get_cloud_resource_categories_cli,
commands::batch_create_resource_categories_cli,
commands::get_resource_category_count_cli,
commands::activate_resource_category_cli,
commands::deactivate_resource_category_cli,
```
## 迁移建议
### 1. 渐进式迁移
```typescript
// 阶段1继续使用原有命令
const categories = await invoke<string>('get_all_resource_categories');
// 阶段2迁移到新的 CLI 命令
const response = await invoke<ResourceCategoryResponse>('get_all_resource_categories_cli', {
request: { user_id: "user_123" }
});
```
### 2. 错误处理改进
```typescript
// 新的错误处理模式
if (response.success) {
const categories = response.data;
// 处理成功结果
} else {
console.error('操作失败:', response.error);
// 处理错误
}
```
### 3. 利用新功能
```typescript
// 利用新的查询功能
const colorCategories = await invoke<ResourceCategoryResponse>('get_resource_categories_by_color_cli', {
request: {
color: "#FF0000",
user_id: "user_123",
include_cloud: true
}
});
// 利用批量操作
const batchResult = await invoke<ResourceCategoryResponse>('batch_create_resource_categories_cli', {
request: {
categories: [
{ title: "分类1", color: "#FF0000" },
{ title: "分类2", color: "#00FF00" }
],
user_id: "user_123"
}
});
```
## 总结
通过这次改造,`resource_category.rs` 现在:
- ✅ 使用统一的 CLI 执行模式
- ✅ 保持向后兼容性
- ✅ 提供丰富的功能和参数选项
- ✅ 支持批量操作和高级查询
- ✅ 统一的错误处理和响应格式
- ✅ 与 `template.rs` 架构保持一致
这为后续的功能扩展和维护提供了良好的基础。

View File

@ -10,7 +10,7 @@ import typer
# 导入命令模块
from python_core.cli.commands import scene_detect
from python_core.cli.commands.template import template_app
from python_core.cli.commands.category import category_app
from python_core.cli.commands.resource_category import resource_category_app
from python_core.cli.commands.auth import auth_app
app = typer.Typer(
@ -33,7 +33,7 @@ app = typer.Typer(
# 添加命令组到主应用
app.add_typer(scene_detect, name="scene")
app.add_typer(template_app, name="template")
app.add_typer(category_app, name="category")
app.add_typer(resource_category_app, name="resource-category")
app.add_typer(auth_app, name="auth")
@app.command()

View File

@ -1,491 +0,0 @@
"""
资源分类管理CLI命令
"""
from typing import Optional
import typer
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
import json
import re
from python_core.services.resource_category_manager_v2 import resource_category_manager_v2, ResourceCategory
from python_core.utils.logger import logger
console = Console()
category_app = typer.Typer(name="category", help="资源分类管理命令")
def validate_color(color: str) -> bool:
"""验证颜色格式hex格式"""
pattern = r'^#[0-9A-Fa-f]{6}$'
return bool(re.match(pattern, color))
@category_app.command("list")
def list_categories(
include_inactive: bool = typer.Option(False, "--include-inactive", "-i", help="包含已禁用的分类"),
limit: int = typer.Option(20, "--limit", "-l", help="显示数量限制"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
format_output: str = typer.Option("table", "--format", "-f", help="输出格式: table, json")
):
"""列出所有资源分类"""
try:
console.print(f"📋 [bold blue]资源分类列表[/bold blue]")
# 创建分类管理器
manager = resource_category_manager_v2
# 获取分类列表
categories = manager.get_all_categories()
# 过滤非活跃分类
if not include_inactive:
categories = [cat for cat in categories if cat.get('is_active', True)]
if not categories:
console.print("📭 没有分类")
return
# 限制显示数量
total_count = len(categories)
if len(categories) > limit:
categories = categories[:limit]
console.print(f"📊 显示前 {limit} 个分类(共 {total_count} 个)")
else:
console.print(f"📊 共 {total_count} 个分类")
if format_output == "json":
# JSON格式输出
console.print(json.dumps(categories, 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("AI提示词", style="yellow")
table.add_column("颜色", style="magenta")
table.add_column("状态", style="blue")
table.add_column("创建时间", style="dim")
if verbose:
table.add_column("更新时间", style="dim")
for category in categories:
# 状态
status = "✅ 启用" if category.get('is_active', True) else "❌ 禁用"
# 格式化创建时间
created_at = category.get('created_at', '')
if 'T' in created_at:
created_at = created_at.split('T')[0] + ' ' + created_at.split('T')[1][:8]
# 颜色显示
color = category.get('color', '')
color_display = f"[{color}]●[/{color}] {color}" if color else color
row = [
category.get('id', '')[:12],
category.get('title', ''),
category.get('ai_prompt', '')[:30] + ('...' if len(category.get('ai_prompt', '')) > 30 else ''),
color_display,
status,
created_at
]
if verbose:
updated_at = category.get('updated_at', '')
if 'T' in updated_at:
updated_at = updated_at.split('T')[0] + ' ' + updated_at.split('T')[1][:8]
row.append(updated_at)
table.add_row(*row)
console.print(table)
except Exception as e:
console.print(f"[red]❌ 获取分类列表失败: {str(e)}[/red]")
raise typer.Exit(1)
@category_app.command("create")
def create_category(
title: str = typer.Argument(..., help="分类标题"),
ai_prompt: str = typer.Argument(..., help="AI识别提示词"),
color: str = typer.Argument(..., help="展示颜色hex格式如 #FF5733"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出")
):
"""创建新的资源分类"""
try:
console.print(f"🆕 [bold blue]创建资源分类[/bold blue]")
console.print(f"标题: {title}")
console.print(f"AI提示词: {ai_prompt}")
console.print(f"颜色: {color}")
# 验证颜色格式
if not validate_color(color):
console.print(f"[red]❌ 颜色格式无效: {color}[/red]")
console.print("颜色必须是hex格式如: #FF5733")
raise typer.Exit(1)
# 创建分类管理器
manager = resource_category_manager_v2
# 创建分类
result = manager.create_category(title, ai_prompt, color)
console.print(f"\n✅ [bold green]分类创建成功![/bold green]")
console.print(f"分类ID: {result['id']}")
console.print(f"创建时间: {result['created_at']}")
if verbose:
# 显示分类详细信息
category_info = f"""
🆔 分类ID: {result['id']}
📝 标题: {result['title']}
🤖 AI提示词: {result['ai_prompt']}
🎨 颜色: {result['color']}
📅 创建时间: {result['created_at']}
🔄 更新时间: {result['updated_at']}
状态: {'启用' if result['is_active'] else '禁用'}
"""
panel = Panel(category_info.strip(), title="分类详情", border_style="green")
console.print(panel)
except Exception as e:
console.print(f"[red]❌ 创建分类失败: {str(e)}[/red]")
raise typer.Exit(1)
@category_app.command("get")
def get_category(
category_id: str = typer.Argument(..., help="分类ID"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
format_output: str = typer.Option("panel", "--format", "-f", help="输出格式: panel, json")
):
"""获取分类详情"""
try:
console.print(f"🔍 [bold blue]获取分类详情[/bold blue]")
console.print(f"分类ID: {category_id}")
# 创建分类管理器
manager = resource_category_manager_v2
# 获取分类
category = manager.get_category_by_id(category_id)
if not category:
console.print(f"[red]❌ 未找到分类: {category_id}[/red]")
raise typer.Exit(1)
if format_output == "json":
# JSON格式输出
console.print(json.dumps(category, ensure_ascii=False, indent=2))
return
# 面板格式输出
console.print(f"\n✅ [bold green]分类详情[/bold green]")
# 基本信息
basic_info = f"""
🆔 分类ID: {category.get('id', '')}
📝 标题: {category.get('title', '')}
🤖 AI提示词: {category.get('ai_prompt', '')}
🎨 颜色: {category.get('color', '')}
📅 创建时间: {category.get('created_at', '')}
🔄 更新时间: {category.get('updated_at', '')}
状态: {'启用' if category.get('is_active', True) else '禁用'}
"""
panel = Panel(basic_info.strip(), title="分类基本信息", border_style="green")
console.print(panel)
if verbose:
# 显示颜色预览
color = category.get('color', '')
if color:
color_info = f"""
🎨 颜色预览: [{color}][/{color}] {color}
"""
color_panel = Panel(color_info.strip(), title="颜色预览", border_style="blue")
console.print(color_panel)
except Exception as e:
console.print(f"[red]❌ 获取分类详情失败: {str(e)}[/red]")
raise typer.Exit(1)
@category_app.command("update")
def update_category(
category_id: str = typer.Argument(..., help="分类ID"),
title: Optional[str] = typer.Option(None, "--title", "-t", help="新的标题"),
ai_prompt: Optional[str] = typer.Option(None, "--ai-prompt", "-p", help="新的AI提示词"),
color: Optional[str] = typer.Option(None, "--color", "-c", help="新的颜色hex格式"),
active: Optional[bool] = typer.Option(None, "--active", "-a", help="是否启用"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出")
):
"""更新分类信息"""
try:
console.print(f"🔄 [bold blue]更新分类[/bold blue]")
console.print(f"分类ID: {category_id}")
# 验证至少有一个更新参数
if not any([title, ai_prompt, color, active is not None]):
console.print(f"[red]❌ 请至少提供一个要更新的参数[/red]")
raise typer.Exit(1)
# 验证颜色格式(如果提供)
if color and not validate_color(color):
console.print(f"[red]❌ 颜色格式无效: {color}[/red]")
console.print("颜色必须是hex格式如: #FF5733")
raise typer.Exit(1)
# 创建分类管理器
manager = resource_category_manager_v2
# 更新分类
result = manager.update_category(
category_id=category_id,
title=title,
ai_prompt=ai_prompt,
color=color,
is_active=active
)
if not result:
console.print(f"[red]❌ 未找到分类或更新失败: {category_id}[/red]")
raise typer.Exit(1)
console.print(f"\n✅ [bold green]分类更新成功![/bold green]")
console.print(f"更新时间: {result['updated_at']}")
if verbose:
# 显示更新后的分类信息
category_info = f"""
🆔 分类ID: {result['id']}
📝 标题: {result['title']}
🤖 AI提示词: {result['ai_prompt']}
🎨 颜色: {result['color']}
📅 创建时间: {result['created_at']}
🔄 更新时间: {result['updated_at']}
状态: {'启用' if result['is_active'] else '禁用'}
"""
panel = Panel(category_info.strip(), title="更新后的分类信息", border_style="green")
console.print(panel)
except Exception as e:
console.print(f"[red]❌ 更新分类失败: {str(e)}[/red]")
raise typer.Exit(1)
@category_app.command("delete")
def delete_category(
category_id: str = typer.Argument(..., help="分类ID"),
force: bool = typer.Option(False, "--force", "-f", help="强制删除,不询问确认")
):
"""删除分类"""
try:
console.print(f"🗑️ [bold red]删除分类[/bold red]")
console.print(f"分类ID: {category_id}")
# 创建分类管理器
manager = resource_category_manager_v2
# 获取分类信息
category = manager.get_category_by_id(category_id)
if not category:
console.print(f"[red]❌ 未找到分类: {category_id}[/red]")
raise typer.Exit(1)
console.print(f"分类标题: {category.get('title', 'Unknown')}")
console.print(f"AI提示词: {category.get('ai_prompt', 'Unknown')}")
# 确认删除
if not force:
confirm = typer.confirm("确定要删除这个分类吗?此操作不可恢复。")
if not confirm:
console.print("❌ 操作已取消")
return
# 删除分类
success = manager.delete_category(category_id)
if success:
console.print(f"✅ [bold green]分类删除成功[/bold green]")
else:
console.print(f"[red]❌ 分类删除失败[/red]")
raise typer.Exit(1)
except Exception as e:
console.print(f"[red]❌ 删除分类失败: {str(e)}[/red]")
raise typer.Exit(1)
@category_app.command("search")
def search_categories(
keyword: str = typer.Argument(..., help="搜索关键词"),
limit: int = typer.Option(10, "--limit", "-l", help="显示数量限制"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出")
):
"""搜索分类"""
try:
console.print(f"🔍 [bold blue]搜索分类[/bold blue]")
console.print(f"关键词: {keyword}")
# 创建分类管理器
manager = resource_category_manager_v2
# 搜索分类
categories = manager.search_categories(keyword)
if not categories:
console.print(f"📭 没有找到匹配 '{keyword}' 的分类")
return
console.print(f"✅ 找到 {len(categories)} 个匹配的分类")
# 限制显示数量
if len(categories) > limit:
categories = categories[:limit]
console.print(f"📊 显示前 {limit} 个结果")
# 创建表格
table = Table(title=f"搜索结果: {keyword}")
table.add_column("ID", style="cyan", width=12)
table.add_column("标题", style="green")
table.add_column("AI提示词", style="yellow")
table.add_column("颜色", style="magenta")
table.add_column("状态", style="blue")
if verbose:
table.add_column("创建时间", style="dim")
for category in categories:
status = "✅ 启用" if category.get('is_active', True) else "❌ 禁用"
# 颜色显示
color = category.get('color', '')
color_display = f"[{color}]●[/{color}] {color}" if color else color
row = [
category.get('id', '')[:12],
category.get('title', ''),
category.get('ai_prompt', '')[:30] + ('...' if len(category.get('ai_prompt', '')) > 30 else ''),
color_display,
status
]
if verbose:
created_at = category.get('created_at', '')
if 'T' in created_at:
created_at = created_at.split('T')[0] + ' ' + created_at.split('T')[1][:8]
row.append(created_at)
table.add_row(*row)
console.print(table)
except Exception as e:
console.print(f"[red]❌ 搜索分类失败: {str(e)}[/red]")
raise typer.Exit(1)
@category_app.command("stats")
def show_stats():
"""显示分类统计信息"""
try:
console.print(f"📊 [bold blue]分类统计信息[/bold blue]")
# 创建分类管理器
manager = resource_category_manager_v2
# 获取所有分类
categories = manager.get_all_categories()
if not categories:
console.print("📭 没有分类")
return
# 计算统计信息
total_categories = len(categories)
active_categories = len([cat for cat in categories if cat.get('is_active', True)])
inactive_categories = total_categories - active_categories
# 颜色统计
colors = {}
for category in categories:
color = category.get('color', '')
if color:
colors[color] = colors.get(color, 0) + 1
# 创建统计面板
stats_content = f"""
📈 [bold green]总体统计[/bold green]
分类总数: {total_categories}
启用分类: {active_categories}
禁用分类: {inactive_categories}
使用的颜色: {len(colors)}
"""
stats_panel = Panel(stats_content.strip(), title="分类统计", border_style="green")
console.print(stats_panel)
# 显示最近的分类
recent_categories = sorted(categories, key=lambda x: x.get('created_at', ''), reverse=True)[:5]
if recent_categories:
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 category in recent_categories:
color = category.get('color', '')
color_display = f"[{color}]●[/{color}] {color}" if color else color
created_at = category.get('created_at', '')
if 'T' in created_at:
created_at = created_at.split('T')[0] + ' ' + created_at.split('T')[1][:8]
recent_table.add_row(
category.get('title', 'Unknown'),
color_display,
created_at
)
console.print(recent_table)
# 显示颜色使用统计
if colors:
console.print(f"\n🎨 [bold green]颜色使用统计[/bold green]")
color_table = Table()
color_table.add_column("颜色", style="magenta")
color_table.add_column("使用次数", style="cyan")
for color, count in sorted(colors.items(), key=lambda x: x[1], reverse=True):
color_display = f"[{color}]●[/{color}] {color}"
color_table.add_row(color_display, str(count))
console.print(color_table)
except Exception as e:
console.print(f"[red]❌ 获取统计信息失败: {str(e)}[/red]")
raise typer.Exit(1)
if __name__ == "__main__":
category_app()

View File

@ -0,0 +1,328 @@
"""
素材分类管理 CLI 命令
"""
import typer
import json
from typing import Optional, List, Dict, Any
from dataclasses import asdict
from python_core.utils.logger import logger
from python_core.utils.jsonrpc import create_response_handler
from python_core.services.resource_category_manager_v2 import ResourceCategoryManagerV2
# 创建子应用
resource_category_app = typer.Typer(help="素材分类管理命令")
@resource_category_app.command("list")
def list_categories(
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
include_cloud: bool = typer.Option(True, "--include-cloud/--no-include-cloud", help="是否包含云端分类"),
limit: int = typer.Option(100, "--limit", help="最大返回数量"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""获取所有素材分类"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
categories = manager.get_all_categories(include_cloud=include_cloud)
# 限制返回数量
if limit > 0:
categories = categories[:limit]
response.success(categories)
except Exception as e:
logger.error(f"获取分类列表失败: {e}")
response.error(-32603, f"获取分类列表失败: {str(e)}")
@resource_category_app.command("get")
def get_category(
category_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="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""根据ID获取素材分类"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
category = manager.get_category_by_id(category_id)
if category:
response.success(category)
else:
response.error(-32603, f"分类不存在: {category_id}")
except Exception as e:
logger.error(f"获取分类失败: {e}")
response.error(-32603, f"获取分类失败: {str(e)}")
@resource_category_app.command("create")
def create_category(
title: str = typer.Argument(..., help="分类标题"),
ai_prompt: Optional[str] = typer.Option("", "--ai-prompt", help="AI识别提示词"),
color: Optional[str] = typer.Option("#FF5733", "--color", help="展示颜色"),
is_cloud: bool = typer.Option(False, "--is-cloud", 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:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
category = manager.create_category(
title=title,
ai_prompt=ai_prompt,
color=color,
is_cloud=is_cloud
)
response.success(category)
except Exception as e:
logger.error(f"创建分类失败: {e}")
response.error(-32603, f"创建分类失败: {str(e)}")
@resource_category_app.command("update")
def update_category(
category_id: str = typer.Argument(..., help="分类ID"),
title: Optional[str] = typer.Option(None, "--title", help="新标题"),
ai_prompt: Optional[str] = typer.Option(None, "--ai-prompt", help="新AI提示词"),
color: Optional[str] = typer.Option(None, "--color", help="新颜色"),
activate: bool = typer.Option(False, "--activate", help="激活分类"),
deactivate: bool = typer.Option(False, "--deactivate", 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:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
# 处理激活/停用状态
is_active = None
if activate and deactivate:
response.error(-32602, "不能同时指定激活和停用")
return
elif activate:
is_active = True
elif deactivate:
is_active = False
category = manager.update_category(
category_id=category_id,
title=title,
ai_prompt=ai_prompt,
color=color,
is_active=is_active
)
if category:
response.success(category)
else:
response.error(-32603, f"更新分类失败: {category_id}")
except Exception as e:
logger.error(f"更新分类失败: {e}")
response.error(-32603, f"更新分类失败: {str(e)}")
@resource_category_app.command("delete")
def delete_category(
category_id: str = typer.Argument(..., help="分类ID"),
hard_delete: bool = typer.Option(True, "--hard-delete/--soft-delete", 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:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
success = manager.delete_category(category_id, hard_delete=hard_delete)
if success:
delete_type = "硬删除" if hard_delete else "软删除"
response.success({"message": f"分类{delete_type}成功", "category_id": category_id})
else:
response.error(-32603, f"删除分类失败: {category_id}")
except Exception as e:
logger.error(f"删除分类失败: {e}")
response.error(-32603, f"删除分类失败: {str(e)}")
@resource_category_app.command("search")
def search_categories(
query: str = typer.Argument(..., help="搜索关键词"),
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
include_cloud: bool = typer.Option(True, "--include-cloud/--no-include-cloud", help="是否包含云端分类"),
limit: int = typer.Option(50, "--limit", help="最大返回数量"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""搜索素材分类"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
categories = manager.search_categories(query, include_cloud=include_cloud)
# 限制返回数量
if limit > 0:
categories = categories[:limit]
response.success(categories)
except Exception as e:
logger.error(f"搜索分类失败: {e}")
response.error(-32603, f"搜索分类失败: {str(e)}")
@resource_category_app.command("by-color")
def get_categories_by_color(
color: str = typer.Argument(..., help="颜色值hex格式"),
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
include_cloud: bool = typer.Option(True, "--include-cloud/--no-include-cloud", help="是否包含云端分类"),
limit: int = typer.Option(50, "--limit", help="最大返回数量"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""根据颜色获取素材分类"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
categories = manager.get_categories_by_color(color, include_cloud=include_cloud)
# 限制返回数量
if limit > 0:
categories = categories[:limit]
response.success(categories)
except Exception as e:
logger.error(f"按颜色获取分类失败: {e}")
response.error(-32603, f"按颜色获取分类失败: {str(e)}")
@resource_category_app.command("cloud")
def get_cloud_categories(
limit: int = typer.Option(100, "--limit", help="最大返回数量"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""获取云端素材分类"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2()
categories = manager.get_cloud_categories()
# 限制返回数量
if limit > 0:
categories = categories[:limit]
response.success(categories)
except Exception as e:
logger.error(f"获取云端分类失败: {e}")
response.error(-32603, f"获取云端分类失败: {str(e)}")
@resource_category_app.command("count")
def get_category_count(
user_id: Optional[str] = typer.Option(None, "--user-id", help="用户ID"),
include_cloud: bool = typer.Option(True, "--include-cloud/--no-include-cloud", help="是否包含云端分类"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""获取素材分类数量"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
count = manager.get_category_count(include_cloud=include_cloud)
response.success({"count": count})
except Exception as e:
logger.error(f"获取分类数量失败: {e}")
response.error(-32603, f"获取分类数量失败: {str(e)}")
@resource_category_app.command("activate")
def activate_category(
category_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="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""激活素材分类"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
success = manager.activate_category(category_id)
if success:
response.success({"message": "分类激活成功", "category_id": category_id})
else:
response.error(-32603, f"激活分类失败: {category_id}")
except Exception as e:
logger.error(f"激活分类失败: {e}")
response.error(-32603, f"激活分类失败: {str(e)}")
@resource_category_app.command("deactivate")
def deactivate_category(
category_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="详细输出"),
json_output: bool = typer.Option(True, "--json", help="JSON格式输出")
):
"""停用素材分类"""
response = create_response_handler()
try:
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
success = manager.deactivate_category(category_id)
if success:
response.success({"message": "分类停用成功", "category_id": category_id})
else:
response.error(-32603, f"停用分类失败: {category_id}")
except Exception as e:
logger.error(f"停用分类失败: {e}")
response.error(-32603, f"停用分类失败: {str(e)}")
@resource_category_app.command("batch-create")
def batch_create_categories(
data: str = typer.Option(..., "--data", help="批量创建数据JSON格式"),
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:
# 解析批量数据
categories_data = json.loads(data)
manager = ResourceCategoryManagerV2(user_id=user_id or "default")
result = manager.batch_create_categories(categories_data)
response.success(result)
except json.JSONDecodeError as e:
logger.error(f"解析批量数据失败: {e}")
response.error(-32602, f"解析批量数据失败: {str(e)}")
except Exception as e:
logger.error(f"批量创建分类失败: {e}")
response.error(-32603, f"批量创建分类失败: {str(e)}")

9
rust.md Normal file
View File

@ -0,0 +1,9 @@
# ffmpeg
1. ffmpeg-next
- 专业级媒体处理
# orm
1. Diesel

View File

@ -1,7 +1,107 @@
/**
* ResourceCategory
* 使 execute_python_cli_command
*/
use serde::{Deserialize, Serialize};
use tauri::{command, AppHandle};
use crate::python_executor::execute_python_command;
#[derive(Debug, Serialize, Deserialize)]
pub struct ResourceCategoryResponse {
pub success: bool,
pub message: String,
pub data: Option<serde_json::Value>,
pub output: Option<String>,
pub error: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct CategoryListRequest {
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 CategoryGetRequest {
pub category_id: String,
pub user_id: Option<String>,
pub verbose: Option<bool>,
pub json_output: Option<bool>,
}
#[derive(Debug, Deserialize)]
pub struct CategoryCreateRequest {
pub title: String,
pub ai_prompt: Option<String>,
pub color: Option<String>,
pub is_cloud: Option<bool>,
pub user_id: Option<String>,
pub verbose: Option<bool>,
pub json_output: Option<bool>,
}
#[derive(Debug, Deserialize)]
pub struct CategoryUpdateRequest {
pub category_id: String,
pub title: Option<String>,
pub ai_prompt: Option<String>,
pub color: Option<String>,
pub is_active: Option<bool>,
pub user_id: Option<String>,
pub verbose: Option<bool>,
pub json_output: Option<bool>,
}
#[derive(Debug, Deserialize)]
pub struct CategoryDeleteRequest {
pub category_id: String,
pub hard_delete: Option<bool>,
pub user_id: Option<String>,
pub verbose: Option<bool>,
pub json_output: Option<bool>,
}
#[derive(Debug, Deserialize)]
pub struct CategorySearchRequest {
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>,
}
#[derive(Debug, Deserialize)]
pub struct CategoryColorRequest {
pub color: String,
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 CategoryBatchCreateRequest {
pub categories: Vec<CategoryBatchItem>,
pub user_id: Option<String>,
pub verbose: Option<bool>,
pub json_output: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CategoryBatchItem {
pub title: String,
pub ai_prompt: Option<String>,
pub color: Option<String>,
pub is_cloud: Option<bool>,
}
// 保持向后兼容的旧结构体
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateCategoryRequest {
pub title: String,
@ -17,7 +117,85 @@ pub struct UpdateCategoryRequest {
pub is_active: Option<bool>,
}
/// 获取所有资源分类
/// 执行Python CLI命令的通用函数统一模式
async fn execute_python_cli_command(
app: AppHandle,
command_args: Vec<String>,
) -> Result<ResourceCategoryResponse, String> {
// 构建完整的命令参数
let mut args = vec!["-m".to_string(), "python_core.cli".to_string()];
args.extend(command_args);
println!("Executing ResourceCategory 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(ResourceCategoryResponse {
success: true,
message: "素材分类命令执行成功".to_string(),
data: Some(json_value),
output: Some(output),
error: None,
})
} else {
// 如果不是JSON直接返回文本输出
Ok(ResourceCategoryResponse {
success: true,
message: "素材分类命令执行成功".to_string(),
data: None,
output: Some(output),
error: None,
})
}
}
Err(error) => {
Ok(ResourceCategoryResponse {
success: false,
message: "素材分类命令执行失败".to_string(),
data: None,
output: None,
error: Some(error),
})
}
}
}
/// 获取所有资源分类新版本使用CLI模式
#[command]
pub async fn get_all_resource_categories_cli(
app: AppHandle,
request: CategoryListRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".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) = request.limit {
args.push("--limit".to_string());
args.push(limit.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
}
/// 获取所有资源分类(保持向后兼容)
#[command]
pub async fn get_all_resource_categories(app: AppHandle) -> Result<String, String> {
let args = vec![
@ -29,7 +207,31 @@ pub async fn get_all_resource_categories(app: AppHandle) -> Result<String, Strin
execute_python_command(app, &args, None).await
}
/// 根据ID获取资源分类
/// 根据ID获取资源分类新版本使用CLI模式
#[command]
pub async fn get_resource_category_by_id_cli(
app: AppHandle,
request: CategoryGetRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "get".to_string(), request.category_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
}
/// 根据ID获取资源分类保持向后兼容
#[command]
pub async fn get_resource_category_by_id(app: AppHandle, category_id: String) -> Result<String, String> {
let args = vec![
@ -42,7 +244,45 @@ pub async fn get_resource_category_by_id(app: AppHandle, category_id: String) ->
execute_python_command(app, &args, None).await
}
/// 创建新的资源分类
/// 创建新的资源分类新版本使用CLI模式
#[command]
pub async fn create_resource_category_cli(
app: AppHandle,
request: CategoryCreateRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "create".to_string(), request.title];
if let Some(ai_prompt) = request.ai_prompt {
args.push("--ai-prompt".to_string());
args.push(ai_prompt);
}
if let Some(color) = request.color {
args.push("--color".to_string());
args.push(color);
}
if request.is_cloud.unwrap_or(false) {
args.push("--is-cloud".to_string());
}
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
}
/// 创建新的资源分类(保持向后兼容)
#[command]
pub async fn create_resource_category(app: AppHandle, request: CreateCategoryRequest) -> Result<String, String> {
let args = vec![
@ -57,7 +297,54 @@ pub async fn create_resource_category(app: AppHandle, request: CreateCategoryReq
execute_python_command(app, &args, None).await
}
/// 更新资源分类
/// 更新资源分类新版本使用CLI模式
#[command]
pub async fn update_resource_category_cli(
app: AppHandle,
request: CategoryUpdateRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "update".to_string(), request.category_id];
if let Some(title) = request.title {
args.push("--title".to_string());
args.push(title);
}
if let Some(ai_prompt) = request.ai_prompt {
args.push("--ai-prompt".to_string());
args.push(ai_prompt);
}
if let Some(color) = request.color {
args.push("--color".to_string());
args.push(color);
}
if let Some(is_active) = request.is_active {
if is_active {
args.push("--activate".to_string());
} else {
args.push("--deactivate".to_string());
}
}
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
}
/// 更新资源分类(保持向后兼容)
#[command]
pub async fn update_resource_category(
app: AppHandle,
@ -78,7 +365,35 @@ pub async fn update_resource_category(
execute_python_command(app, &args, None).await
}
/// 删除资源分类
/// 删除资源分类新版本使用CLI模式
#[command]
pub async fn delete_resource_category_cli(
app: AppHandle,
request: CategoryDeleteRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "delete".to_string(), request.category_id];
if request.hard_delete.unwrap_or(true) {
args.push("--hard-delete".to_string());
}
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
}
/// 删除资源分类(保持向后兼容)
#[command]
pub async fn delete_resource_category(app: AppHandle, category_id: String) -> Result<String, String> {
let args = vec![
@ -91,7 +406,40 @@ pub async fn delete_resource_category(app: AppHandle, category_id: String) -> Re
execute_python_command(app, &args, None).await
}
/// 搜索资源分类
/// 搜索资源分类新版本使用CLI模式
#[command]
pub async fn search_resource_categories_cli(
app: AppHandle,
request: CategorySearchRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".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) = request.limit {
args.push("--limit".to_string());
args.push(limit.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
}
/// 搜索资源分类(保持向后兼容)
#[command]
pub async fn search_resource_categories(app: AppHandle, keyword: String) -> Result<String, String> {
let args = vec![
@ -103,3 +451,168 @@ pub async fn search_resource_categories(app: AppHandle, keyword: String) -> Resu
execute_python_command(app, &args, None).await
}
/// 按颜色获取资源分类新版本使用CLI模式
#[command]
pub async fn get_resource_categories_by_color_cli(
app: AppHandle,
request: CategoryColorRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "by-color".to_string(), request.color];
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) = request.limit {
args.push("--limit".to_string());
args.push(limit.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
}
/// 获取云端资源分类新版本使用CLI模式
#[command]
pub async fn get_cloud_resource_categories_cli(
app: AppHandle,
request: CategoryListRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "cloud".to_string()];
if let Some(limit) = request.limit {
args.push("--limit".to_string());
args.push(limit.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
}
/// 批量创建资源分类新版本使用CLI模式
#[command]
pub async fn batch_create_resource_categories_cli(
app: AppHandle,
request: CategoryBatchCreateRequest,
) -> Result<ResourceCategoryResponse, String> {
// 将批量数据序列化为JSON
let categories_json = serde_json::to_string(&request.categories)
.map_err(|e| format!("Failed to serialize categories: {}", e))?;
let mut args = vec!["resource-category".to_string(), "batch-create".to_string()];
// 通过临时文件传递批量数据
args.push("--data".to_string());
args.push(categories_json);
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
}
/// 获取资源分类数量新版本使用CLI模式
#[command]
pub async fn get_resource_category_count_cli(
app: AppHandle,
request: CategoryListRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "count".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 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
}
/// 激活资源分类新版本使用CLI模式
#[command]
pub async fn activate_resource_category_cli(
app: AppHandle,
request: CategoryGetRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "activate".to_string(), request.category_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
}
/// 停用资源分类新版本使用CLI模式
#[command]
pub async fn deactivate_resource_category_cli(
app: AppHandle,
request: CategoryGetRequest,
) -> Result<ResourceCategoryResponse, String> {
let mut args = vec!["resource-category".to_string(), "deactivate".to_string(), request.category_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
}

View File

@ -46,11 +46,23 @@ pub fn run() {
commands::get_template_detail_cli,
commands::delete_template,
commands::get_all_resource_categories,
commands::get_all_resource_categories_cli,
commands::get_resource_category_by_id,
commands::get_resource_category_by_id_cli,
commands::create_resource_category,
commands::create_resource_category_cli,
commands::update_resource_category,
commands::update_resource_category_cli,
commands::delete_resource_category,
commands::delete_resource_category_cli,
commands::search_resource_categories,
commands::search_resource_categories_cli,
commands::get_resource_categories_by_color_cli,
commands::get_cloud_resource_categories_cli,
commands::batch_create_resource_categories_cli,
commands::get_resource_category_count_cli,
commands::activate_resource_category_cli,
commands::deactivate_resource_category_cli,
commands::get_all_projects,
commands::get_project_by_id,
commands::create_project,