mxivideo/docs/python_executor_progress.md

243 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Python Executor with Progress Support
通用的Python执行器支持实时进度回调和JSON-RPC通信。
## 功能特性
- ✅ 支持多种Python命令 (python, python3, py)
- ✅ UTF-8编码处理
- ✅ 并发stdout/stderr读取
- ✅ JSON-RPC消息解析
- ✅ 实时进度回调
- ✅ Tauri事件发射
- ✅ 超时处理
- ✅ 错误处理
## 使用方法
### 1. 基本用法(无进度)
```rust
use crate::python_executor::execute_python_command;
#[tauri::command]
pub async fn my_command(app: AppHandle) -> Result<String, String> {
let args = vec![
"-m".to_string(),
"my_python_module".to_string(),
"--action".to_string(),
"do_something".to_string(),
];
execute_python_command(app, &args, None).await
}
```
### 2. 使用Tauri事件进度回调
```rust
use crate::python_executor::execute_python_with_events;
#[tauri::command]
pub async fn my_command_with_progress(app: AppHandle) -> Result<String, String> {
let args = vec![
"-m".to_string(),
"my_python_module".to_string(),
"--action".to_string(),
"long_running_task".to_string(),
];
// 进度将通过 "my-task-progress" 事件发送到前端
execute_python_with_events(app, &args, None, "my-task-progress").await
}
```
### 3. 使用函数回调
```rust
use crate::python_executor::{execute_python_with_callback, PythonProgress};
#[tauri::command]
pub async fn my_command_with_callback(app: AppHandle) -> Result<String, String> {
let args = vec![
"-m".to_string(),
"my_python_module".to_string(),
"--action".to_string(),
"process_data".to_string(),
];
// 自定义进度处理
let progress_callback = |progress: PythonProgress| {
println!("Progress: {}% - {}", progress.progress, progress.message);
// 可以在这里添加自定义逻辑,如数据库记录、日志等
};
execute_python_with_callback(app, &args, None, progress_callback).await
}
```
### 4. 高级用法(自定义回调)
```rust
use crate::python_executor::{execute_python_command_with_progress, ProgressCallback, PythonProgress};
struct CustomProgressHandler {
task_id: String,
}
impl ProgressCallback for CustomProgressHandler {
fn on_progress(&self, progress: PythonProgress) {
// 自定义进度处理逻辑
println!("Task {}: {}% - {}", self.task_id, progress.progress, progress.message);
// 可以发送到数据库、文件、其他服务等
if progress.step == "complete" {
println!("Task {} completed!", self.task_id);
}
}
}
#[tauri::command]
pub async fn my_advanced_command(app: AppHandle, task_id: String) -> Result<String, String> {
let args = vec![
"-m".to_string(),
"my_python_module".to_string(),
"--task-id".to_string(),
task_id.clone(),
];
let progress_handler = CustomProgressHandler { task_id };
execute_python_command_with_progress(app, &args, None, Some(progress_handler)).await
}
```
## Python端实现
Python脚本需要使用JSON-RPC协议发送进度信息
```python
from python_core.utils.jsonrpc import create_response_handler, create_progress_reporter
def my_long_running_task():
rpc = create_response_handler("task_id")
progress = create_progress_reporter()
try:
# 报告开始
progress.step("start", "开始处理任务...")
# 处理步骤1
progress.report("step1", 25.0, "正在处理步骤1...")
# ... 实际处理逻辑 ...
# 处理步骤2
progress.report("step2", 50.0, "正在处理步骤2...")
# ... 实际处理逻辑 ...
# 处理步骤3
progress.report("step3", 75.0, "正在处理步骤3...")
# ... 实际处理逻辑 ...
# 完成
progress.complete("任务完成!")
# 发送最终结果
result = {
"status": True,
"message": "任务成功完成",
"data": {...}
}
rpc.success(result)
except Exception as e:
progress.error(f"任务失败: {str(e)}")
rpc.error(-32603, "任务执行失败", str(e))
if __name__ == "__main__":
my_long_running_task()
```
## 前端使用
```typescript
import { listen } from '@tauri-apps/api/event'
// 监听进度事件
const unlisten = await listen('my-task-progress', (event) => {
const progress = event.payload as {
step: string
progress: number
message: string
details?: any
timestamp: number
}
console.log(`Progress: ${progress.progress}% - ${progress.message}`)
// 更新UI
updateProgressBar(progress.progress)
updateStatusMessage(progress.message)
})
// 执行命令
try {
const result = await invoke('my_command_with_progress')
console.log('Task completed:', result)
} finally {
unlisten() // 清理监听器
}
```
## 进度数据结构
```rust
pub struct PythonProgress {
pub step: String, // 当前步骤名称
pub progress: f64, // 进度百分比 (0-100, -1表示不确定)
pub message: String, // 进度消息
pub details: Option<serde_json::Value>, // 额外详情
pub timestamp: f64, // 时间戳
}
```
## 配置选项
```rust
pub struct PythonExecutorConfig {
pub timeout_seconds: u64, // 超时时间(秒)
pub working_directory: Option<PathBuf>, // 工作目录
}
// 默认配置10分钟超时当前目录
let config = PythonExecutorConfig::default();
// 自定义配置
let config = PythonExecutorConfig {
timeout_seconds: 1800, // 30分钟
working_directory: Some("/path/to/workdir".into()),
};
```
## 最佳实践
1. **选择合适的回调方式**
- 简单任务:使用 `execute_python_command`
- 需要前端进度显示:使用 `execute_python_with_events`
- 需要自定义处理:使用 `execute_python_with_callback`
2. **Python端进度报告**
- 使用有意义的步骤名称
- 提供清晰的进度消息
- 合理设置进度百分比
- 在关键节点报告进度
3. **错误处理**
- Python端使用try-catch包装
- 通过JSON-RPC发送错误信息
- Rust端处理超时和进程错误
4. **性能考虑**
- 不要过于频繁地报告进度
- 避免在进度回调中执行耗时操作
- 合理设置超时时间