Commit 285b276b authored by 刘小敏's avatar 刘小敏

AI视频队列程序日志优化;

parent ab7732df
...@@ -226,6 +226,7 @@ class AiTryon extends Common ...@@ -226,6 +226,7 @@ class AiTryon extends Common
$user = auth_user(); $user = auth_user();
// \think\Queue::push('\addons\shopro\job\AiVideoGen@save', ['taskid' => 'cgt-20260506113558-x6wtq', 'user' => $user], 'shopro-high'); // \think\Queue::push('\addons\shopro\job\AiVideoGen@save', ['taskid' => 'cgt-20260506113558-x6wtq', 'user' => $user], 'shopro-high');
// $this->success('推送队列成功'); // $this->success('推送队列成功');
// exit; // exit;
......
...@@ -926,9 +926,8 @@ if (!function_exists('operate_disabled')) { ...@@ -926,9 +926,8 @@ if (!function_exists('operate_disabled')) {
// 调试输出 // 调试输出
if (!function_exists('debug_echo')) { if (!function_exists('debug_echo')) {
function debug_echo($text='') function debug_echo($text='', $name='gen_ai')
{ {
echo PHP_EOL . '------' . $text . '------' . PHP_EOL ; echo PHP_EOL . '------' . $text . '------' . PHP_EOL ;
\think\Log::info($text);
} }
} }
...@@ -7,6 +7,9 @@ use addons\shopro\library\HttpClient as Http; ...@@ -7,6 +7,9 @@ use addons\shopro\library\HttpClient as Http;
use app\admin\model\shopro\AiTryon as AiTryOnModel; use app\admin\model\shopro\AiTryon as AiTryOnModel;
use think\Log; use think\Log;
use think\queue\Job; use think\queue\Job;
use app\admin\model\shopro\user\User;
use think\facade\Notification as NotificationFacade;
use addons\shopro\notification\ai\AiVideoSuccess;
/** /**
* AI生成的视频保存到本地并更新数据表 * AI生成的视频保存到本地并更新数据表
...@@ -18,12 +21,27 @@ class AiVideoGen extends BaseJob ...@@ -18,12 +21,27 @@ class AiVideoGen extends BaseJob
private $ark_host = 'https://ark.cn-beijing.volces.com'; private $ark_host = 'https://ark.cn-beijing.volces.com';
private $public_dir = ROOT_PATH . 'public'; private $public_dir = ROOT_PATH . 'public';
// 是否输出调试日志
private $is_debug = true;
// 是否记录日志
private $is_log = true;
// 调试日志 && 自定义日志
private function debug_log($text=''){
if ($this->is_debug){
debug_echo($text);
}
if ($this->is_log){
custom_log($text, 'gen_ai_video');
}
}
/** /**
* 保存远端视频文件到本地 * 保存远端视频文件到本地
*/ */
private function saveVideoLoc ($videoUrl){ private function saveVideoLoc ($videoUrl){
debug_echo('videoUrl: '.$videoUrl); $this->debug_log('videoUrl: '.$videoUrl);
// 1 生成存储目录(fastadmin标准uploads目录) // 1 生成存储目录(fastadmin标准uploads目录)
$upload_dir = '/uploads/ai_video/' . date('Ymd') . '/'; $upload_dir = '/uploads/ai_video/' . date('Ymd') . '/';
...@@ -60,7 +78,7 @@ class AiVideoGen extends BaseJob ...@@ -60,7 +78,7 @@ class AiVideoGen extends BaseJob
if (file_exists($full_path)) { if (file_exists($full_path)) {
unlink($full_path); unlink($full_path);
} }
debug_echo('视频下载失败:' . $error . "HTTP状态码:{$http_code},文件为空"); $this->debug_log('视频下载失败:' . $error . "HTTP状态码:{$http_code},文件为空");
return 0; // 统一失败返回值 return 0; // 统一失败返回值
} }
...@@ -102,30 +120,28 @@ class AiVideoGen extends BaseJob ...@@ -102,30 +120,28 @@ class AiVideoGen extends BaseJob
} }
/** /**
* AI视频结果 * AI视频结果处理
*/ */
public function save(Job $job, $data) public function save(Job $job, $data)
{ {
try { try {
$taskid = $data['taskid']; $taskid = $data['taskid'];
// $taskid = 'cgt-20260430190444-vmb4q';
$user = $data['user']; $user = $data['user'];
$user_id = isset($user['id']) ? $user['id'] : 0; $user_id = isset($user['id']) ? $user['id'] : 0;
$this->debug_log('***************************** 保存AI视频脚本开始 userid '.$user_id.' taskid:'.$taskid.' ***********************************'.PHP_EOL);
if (!isset($taskid) || empty($taskid) || !isset($user_id) || empty($user_id)) { if (!isset($taskid) || empty($taskid) || !isset($user_id) || empty($user_id)) {
debug_echo('[AI视频]入参有空值 taskid:'.$taskid .' user_id:'.$user_id);
$this->debug_log('[AI视频]入参有空值 taskid:'.$taskid .' user_id:'.$user_id);
// 删除队列job // 删除队列job
debug_echo('[AI视频]删除Job'); $this->debug_log('[AI视频]删除Job');
$job->delete(); $job->delete();
return false; return false;
} }
$url = $this->ark_host . '/api/v3/contents/generations/tasks/' . $taskid; $url = $this->ark_host . '/api/v3/contents/generations/tasks/' . $taskid;
debug_echo('[AI视频]脚本开始执行 AI接口url:'.$url);
$params = [ $params = [
'headers' => [ 'headers' => [
'Authorization' => 'Bearer ' . config('shopro.ai_api_key'), 'Authorization' => 'Bearer ' . config('shopro.ai_api_key'),
...@@ -135,6 +151,8 @@ class AiVideoGen extends BaseJob ...@@ -135,6 +151,8 @@ class AiVideoGen extends BaseJob
'allow_redirects' => true 'allow_redirects' => true
]; ];
$this->debug_log('[AI视频]请求AI接口入参 user_id:'.$user_id.' AI接口url:'.$url.' params:'.json_encode($params));
// 向AI接口 发送请求 // 向AI接口 发送请求
$client = new Http(); $client = new Http();
$response = $client->get($url, $params); $response = $client->get($url, $params);
...@@ -143,77 +161,77 @@ class AiVideoGen extends BaseJob ...@@ -143,77 +161,77 @@ class AiVideoGen extends BaseJob
$content = preg_replace('/[^\x20-\x7E]/', '', $content); $content = preg_replace('/[^\x20-\x7E]/', '', $content);
$result = json_decode($content, true); $result = json_decode($content, true);
$this->debug_log('[AI视频]请求AI接口出参 response:'.json_encode($result));
// AI接口 返回失败 // AI接口 返回失败
if (isset($result['error'])){ if (isset($result['error'])){
$code = $result['error']['code'] ?? '';
$message = $result['error']['message'] ?? '未知错误'; $message = $result['error']['message'] ?? '未知错误';
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => $message]); AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => $message]);
// 记录错误日志
Log::error('AI生成视频队列返回:taskId: ' . $taskid . 'code '.$code . 'message: ' . $message . ' result:' . $content . PHP_EOL);
// 删除队列job // 删除队列job
debug_echo('[AI视频]删除Job'); $this->debug_log('[AI视频]删除Job');
$job->delete(); $job->delete();
return false; return false;
} }
// AI接口 返回成功 // AI接口 返回成功
if (isset($result['status'])){ if (isset($result['status'])){
debug_echo('[AI视频]AI接口 返回成功 status有值:'.$result['status']);
switch ($result['status']) { switch ($result['status']) {
// 成功返回视频链接 // 成功返回视频链接
case 'succeeded': case 'succeeded':
// 保存远程视频到本地 // 保存远程视频到本地
$video_url = $this->saveVideoLoc(isset($result['content']['video_url']) ? $result['content']['video_url'] : ''); $video_url = $this->saveVideoLoc(isset($result['content']['video_url']) ? $result['content']['video_url'] : '');
debug_echo('[AI视频]保存本地接口返回值 video_url:'.$video_url); $this->debug_log('[AI视频]保存本地接口返回值 video_url:'.$video_url);
if ($video_url === 0){ if ($video_url === 0){
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频保存到本地失败']); AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频保存到本地失败']);
debug_echo('[AI视频]保存本地视频失败sql:'.db()->getLastSql()); $this->debug_log('[AI视频]保存本地视频失败 sql: '.db()->getLastSql());
break;
} }
// 更新我的试戴 // 更新我的试戴
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 1,'ai_url' => config('shopro.api_host').$video_url, 'ai_err_msg' => '视频生成成功']); AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 1,'ai_url' => config('shopro.api_host').$video_url, 'ai_err_msg' => '视频生成成功']);
debug_echo('[AI视频]保存本地视频成功sql:'.db()->getLastSql()); $this->debug_log('[AI视频]保存本地视频成功 sql: '.db()->getLastSql());
// ========== 新增:发送消息通知 ==========
// $this->sendNotification($user_id, config('shopro.api_host').$video_url);
// 删除队列job // 删除队列job
debug_echo('[AI视频]删除Job'); $this->debug_log('[AI视频]删除Job');
$job->delete(); $job->delete();
break; break;
case 'cancelled': case 'cancelled':
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '任务已取消']); AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '任务已取消']);
debug_echo('[AI视频]AI生成视频任务 取消: taskId: ' . $taskid . 'userId '. $user_id ); $this->debug_log('[AI视频]AI生成视频任务 取消: taskId: ' . $taskid . 'userId '. $user_id );
debug_echo('[AI视频]AI生成视频任务 取消: result:'.json_encode($result)); $this->debug_log('[AI视频]AI生成视频任务 取消: result:'.json_encode($result));
debug_echo('[AI视频]AI生成视频任务 取消: sql:' .db()->getLastSql()); $this->debug_log('[AI视频]AI生成视频任务 取消: sql:' .db()->getLastSql());
// 删除队列job // 删除队列job
debug_echo('[AI视频]删除Job'); $this->debug_log('[AI视频]删除Job');
$job->delete(); $job->delete();
break; break;
case 'failed': case 'failed':
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成失败']); AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成失败']);
debug_echo('[AI视频]AI生成视频任务 失败: taskId: ' . $taskid . 'userId '. $user_id ); $this->debug_log('[AI视频]AI生成视频任务 失败: taskId: ' . $taskid . 'userId '. $user_id );
debug_echo('[AI视频]AI生成视频任务 失败: result:'.json_encode($result)); $this->debug_log('[AI视频]AI生成视频任务 失败: result:'.json_encode($result));
debug_echo('[AI视频]AI生成视频任务 失败: sql:' .db()->getLastSql()); $this->debug_log('[AI视频]AI生成视频任务 失败: sql:' .db()->getLastSql());
// 删除队列job // 删除队列job
debug_echo('[AI视频]删除Job'); $this->debug_log('[AI视频]删除Job');
$job->delete(); $job->delete();
break; break;
case 'expired': case 'expired':
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '任务已过期']); AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '任务已过期']);
debug_echo('[AI视频]AI生成视频任务 过期: taskId: ' . $taskid . 'userId '. $user_id ); $this->debug_log('[AI视频]AI生成视频任务 过期: taskId: ' . $taskid . 'userId '. $user_id );
debug_echo('[AI视频]AI生成视频任务 过期: result:'.json_encode($result)); $this->debug_log('[AI视频]AI生成视频任务 过期: result:'.json_encode($result));
debug_echo('[AI视频]AI生成视频任务 过期: sql:' .db()->getLastSql()); $this->debug_log('[AI视频]AI生成视频任务 过期: sql:' .db()->getLastSql());
// 删除队列job // 删除队列job
debug_echo('[AI视频]删除Job'); $this->debug_log('[AI视频]删除Job');
$job->delete(); $job->delete();
break; break;
...@@ -228,11 +246,56 @@ class AiVideoGen extends BaseJob ...@@ -228,11 +246,56 @@ class AiVideoGen extends BaseJob
} catch (\Exception $e) { } catch (\Exception $e) {
// 队列执行失败 // 队列执行失败
debug_echo('[AI视频]异常:' . $e->getMessage()); $logInfo = [
format_log_error($e, 'AiVideoGen.save.' . isset($user['id']) ?? 'user_id' . isset($video_url) ?? 'video_url'); " [AI视频] Exception LOG INFO BEGIN ",
'[ Message ] ' . var_export('[' . $e->getCode() . ']' . $e->getMessage() . ' ' . 'AiVideoGen.save.' . $user['id'] ?? 'user_id' . $video_url??'video_url', true),
'[ File ] ' . var_export($e->getFile() . ':' . $e->getLine(), true),
'[ Trace ] ' . var_export($e->getTraceAsString(), true),
"[AI视频] Exception LOG INFO ENDED ",
];
$logInfo = implode(PHP_EOL, $logInfo) . PHP_EOL;
$this->debug_log($logInfo);
// $this->deleteLocalVideo($video_url); // 删除保存到本地的视频,如果已经保存了的话,暂时不处理保存到视频,获取不到video_url
// 删除队列job
$this->debug_log('[AI视频]删除Job');
$job->delete();
}
}
debug_echo('[AI视频]异常删除视频:'. $video_url); /**
$this->deleteLocalVideo($video_url); // 删除保存到本地的视频,如果已经保存了的话 * 发送AI视频生成成功通知
*/
private function sendNotification($user_id, $video_url)
{
try {
// 获取用户信息
$user = User::find($user_id);
if (!$user) {
// Log::error('[AI视频通知]用户不存在: ' . $user_id);
$this->debug_log('[AI视频通知]用户不存在: ' . $user_id, 'gen_ai');
return false;
}
// 获取AI试戴记录
$aiTryon = AiTryOnModel::where('user_id', $user_id)
->where('ai_url', $video_url)
->find();
// 发送通知
NotificationFacade::send($user, new AiVideoSuccess([
'ai_tryon' => $aiTryon ? $aiTryon->toArray() : [],
'user' => $user->toArray()
]));
// Log::info('[AI视频通知]通知发送成功: user_id=' . $user_id);
$this->debug_log('[AI视频通知]通知发送成功: user_id=' . $user_id, 'gen_ai');
return true;
} catch (\Exception $e) {
// Log::error('[AI视频通知]发送失败: ' . $e->getMessage());
$this->debug_log('[AI视频通知]发送失败: user_id=' . $user_id . ' ' . $e->getMessage(), 'gen_ai');
return false;
} }
} }
......
...@@ -507,3 +507,23 @@ EOT; ...@@ -507,3 +507,23 @@ EOT;
return $icon; return $icon;
} }
} }
if (!function_exists('custom_log')) {
/**
* 自定义日志文件名
* @param string $content 日志内容
* @param string $name 文件名(不需要 .log)
* @param string $level 级别 info/error/debug
*/
function custom_log($content, $name = 'custom', $level = 'info')
{
\think\Log::init([
'type' => 'File',
'path' => RUNTIME_PATH . 'log/'.date('Ym').'/',
'single' => $name.'_'.date('Ymd').'_',
'max_files' => 0,
]);
\think\Log::record($content, $level);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment