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:
parent
f47c96d2c7
commit
fff058bf39
|
|
@ -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__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue