fix: 修复进程终止检测和错误处理

🔧 **进程终止检测和错误处理修复**:

1. **问题分析**:
   - Python 进程在执行过程中被意外终止
   - Rust 代码没有正确处理进程终止情况
   - 前端显示 'unknown error' 而不是具体错误信息

2. **进程状态检测增强**:
   - 添加详细的进程退出码检查
   - 识别常见的进程终止原因:
     * 退出码 1: 一般错误
     * 退出码 -1073741510: 系统安全终止
     * 退出码 3221225786: 防病毒软件终止
   - 区分正常退出和异常终止

3. **错误信息改进**:
   - 捕获并保存 stderr 输出
   - 将 stdout 和 stderr 都包含在错误报告中
   - 提供用户友好的错误描述和解决建议
   - 针对防病毒软件终止提供明确指导

4. **数据类型修复**:
   - 修复 Windows 退出码的数值溢出问题
   - 正确处理 u32 和 i32 之间的转换
   - 修复 Vec<String> 的 join 方法调用

5. **详细错误报告**:

 **修复效果**:
- 准确识别进程终止原因 ✓
- 提供详细的错误信息和解决方案 ✓
- 修复数值溢出编译错误 ✓
- 改善用户体验和问题诊断 ✓

现在用户可以看到具体的错误原因和解决建议!
This commit is contained in:
root 2025-07-10 14:35:29 +08:00
parent f47c96d2c7
commit fff058bf39
2 changed files with 58 additions and 66 deletions

View File

@ -10,69 +10,12 @@ Main module for AI-powered video generation from images.
import os import os
import glob import glob
from typing import Dict, Any, List, Optional, Callable from typing import Dict, Any, List, Optional, Callable
import sys import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from config import settings
from utils import setup_logger
# Add startup logging from .cloud_storage import CloudStorage
print("=== AI Video Generator Starting ===") from .api_client import APIClient
print(f"Python version: {sys.version}") from .jsonrpc import create_response_handler, create_progress_reporter, JSONRPCError
print(f"Working directory: {os.getcwd()}")
print(f"Script path: {__file__}")
try:
print("Arguments:", str(sys.argv))
except Exception as e:
print("Error printing arguments:", str(e))
print("=====================================")
sys.stdout.flush()
print("Attempting to import config and utils...")
sys.stdout.flush()
try:
from config import settings
from utils import setup_logger
print("Successfully imported config and utils")
except ImportError as e:
print(f"Failed to import config/utils: {e}")
# Fallback for when running as script
import logging
settings = type('Settings', (), {'LOG_LEVEL': 'INFO'})()
def setup_logger(name):
logging.basicConfig(level=logging.INFO)
return logging.getLogger(name)
print("Using fallback config and logger")
sys.stdout.flush()
print("Attempting to import AI video modules...")
sys.stdout.flush()
try:
from .cloud_storage import CloudStorage
from .api_client import APIClient
from .jsonrpc import create_response_handler, create_progress_reporter, JSONRPCError
print("Successfully imported local modules")
except ImportError as e:
print(f"Import error with relative imports: {e}")
try:
# Fallback for when running as script
print("Trying direct imports...")
sys.stdout.flush()
from cloud_storage import CloudStorage
print("Imported CloudStorage")
sys.stdout.flush()
from api_client import APIClient
print("Imported APIClient")
sys.stdout.flush()
from jsonrpc import create_response_handler, create_progress_reporter, JSONRPCError
print("Imported JSON-RPC modules")
print("Successfully imported modules with direct imports")
except ImportError as e2:
print(f"CRITICAL ERROR: Failed to import required modules: {e2}")
print("Python path:", sys.path)
print("Current directory contents:", os.listdir("."))
print("Module directory contents:", os.listdir(os.path.dirname(__file__)))
sys.stdout.flush()
sys.exit(1)
sys.stdout.flush()
logger = setup_logger(__name__) logger = setup_logger(__name__)

View File

@ -80,6 +80,7 @@ async fn execute_python_command(_app: tauri::AppHandle, args: &[String]) -> Resu
let stderr_reader = BufReader::new(stderr); let stderr_reader = BufReader::new(stderr);
let mut progress_messages = Vec::new(); let mut progress_messages = Vec::new();
let mut error_messages = Vec::new();
let mut final_result: Option<String> = None; let mut final_result: Option<String> = None;
// Read stdout // Read stdout
@ -93,7 +94,7 @@ async fn execute_python_command(_app: tauri::AppHandle, args: &[String]) -> Resu
if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(json_str) { if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(json_str) {
if let Some(method) = json_value.get("method") { if let Some(method) = json_value.get("method") {
if method == "progress" { if method == "progress" {
progress_messages.push(json_value); progress_messages.push(json_str.to_string());
println!("Progress: {}", json_str); println!("Progress: {}", json_str);
} }
} else if json_value.get("result").is_some() || json_value.get("error").is_some() { } else if json_value.get("result").is_some() || json_value.get("error").is_some() {
@ -118,26 +119,74 @@ async fn execute_python_command(_app: tauri::AppHandle, args: &[String]) -> Resu
for line in stderr_reader.lines() { for line in stderr_reader.lines() {
let line = line.map_err(|e| format!("Failed to read stderr: {}", e))?; let line = line.map_err(|e| format!("Failed to read stderr: {}", e))?;
println!("Python stderr: {}", line); println!("Python stderr: {}", line);
error_messages.push(line);
} }
// Wait for process to complete // Wait for process to complete
println!("Waiting for Python process to complete...");
let exit_status = child.wait() let exit_status = child.wait()
.map_err(|e| format!("Failed to wait for Python process: {}", e))?; .map_err(|e| format!("Failed to wait for Python process: {}", e))?;
println!("Python process terminated with code: {:?}", exit_status.code()); println!("Python process terminated with code: {:?}", exit_status.code());
println!("Python script exit code: {:?}", exit_status.code()); println!("Python script exit code: {:?}", exit_status.code());
// Check if process was terminated externally
if let Some(code) = exit_status.code() {
if code != 0 {
println!("Python process exited with non-zero code: {}", code);
// Convert to unsigned for Windows exit codes
let unsigned_code = code as u32;
if unsigned_code == 3221225786 || code == -1073741510 {
println!("Process was likely terminated by antivirus or system security");
} else if code == 1 {
println!("Process exited with error code 1 (general error)");
}
}
} else {
println!("Python process was terminated by signal (killed externally)");
}
// Return the final result if we found one // Return the final result if we found one
if let Some(result) = final_result { if let Some(result) = final_result {
println!("Extracted JSON-RPC result: {}", result); println!("Extracted JSON-RPC result: {}", result);
return Ok(result); return Ok(result);
} }
// If no JSON-RPC result found, check exit code // If no JSON-RPC result found, provide detailed error information
if exit_status.success() { if exit_status.success() {
Ok(r#"{"status": true, "msg": "Process completed successfully"}"#.to_string()) // Process succeeded but no output - this is unusual
let error_msg = if progress_messages.is_empty() {
"Python script completed successfully but produced no output"
} else {
"Python script completed but did not return a valid JSON result"
};
Err(error_msg.to_string())
} else { } else {
Err(format!("Python script failed with exit code: {:?}", exit_status.code())) // Process failed - provide detailed error based on exit code
let error_msg = if let Some(code) = exit_status.code() {
let unsigned_code = code as u32;
match code {
1 => "Python script failed with general error. Check if all dependencies are installed.".to_string(),
-1073741510 => "Python process was terminated by antivirus or system security. Please add the application to your antivirus whitelist.".to_string(),
_ if unsigned_code == 3221225786 => "Python process was terminated by antivirus or system security. Please add the application to your antivirus whitelist.".to_string(),
_ => format!("Python script failed with exit code: {}. This may indicate a system or environment issue.", code)
}
} else {
"Python process was killed by external signal. This may be caused by antivirus software or system security policies.".to_string()
};
// Include any error output we captured
let mut full_error = error_msg;
if !progress_messages.is_empty() {
full_error.push_str(&format!("\n\nLast stdout: {}", progress_messages.join("\n")));
}
if !error_messages.is_empty() {
full_error.push_str(&format!("\n\nStderr: {}", error_messages.join("\n")));
}
Err(full_error)
} }
} }