Commit c4c76bf1 authored by 刘小敏's avatar 刘小敏

AI试戴生成视频接口和队列

parent 48d71c1e
...@@ -11,6 +11,7 @@ use think\helper\Time; ...@@ -11,6 +11,7 @@ use think\helper\Time;
use addons\shopro\service\goods\GoodsService; use addons\shopro\service\goods\GoodsService;
use addons\shopro\service\user\User; use addons\shopro\service\user\User;
use addons\shopro\service\user\Ai; use addons\shopro\service\user\Ai;
use think\Log;
class AiTryon extends Common class AiTryon extends Common
...@@ -134,7 +135,7 @@ class AiTryon extends Common ...@@ -134,7 +135,7 @@ class AiTryon extends Common
// 'goods_title' => $params['goods_title'], // 'goods_title' => $params['goods_title'],
// 'goods_subtitle' => $params['goods_subtitle'], // 'goods_subtitle' => $params['goods_subtitle'],
// 'goods_image' => $params['jewelry_image'], // 'goods_image' => $params['jewelry_image'],
// 'ai_task_id' => 0, // 'ai_task_id' => '',
// 'ai_type' => 0, // 'ai_type' => 0,
// ]; // ];
// //
...@@ -171,65 +172,92 @@ class AiTryon extends Common ...@@ -171,65 +172,92 @@ class AiTryon extends Common
*/ */
public function genVideo() public function genVideo()
{ {
// if (!$this->request->isPost()) {
// $this->error(''); if (!$this->request->isPost()) {
// } $this->error('');
// }
// $params = $this->request->only([
// 'person_image', 'jewelry_image','goods_id','goods_title','goods_subtitle' $params = $this->request->only([
// ]); 'person_image', 'jewelry_image','goods_id','goods_title','goods_subtitle'
// $this->svalidate($params, ".aiadd"); ]);
// $this->svalidate($params, ".aiadd");
// $user = auth_user();
// $userService = new User(); $user = auth_user();
// $res = $userService->isTry($user->id);
// \think\Queue::push('\addons\shopro\job\AiVideoGen@save', ['taskid' => 'cgt-20260430190444-vmb4q', 'user' => $user], 'shopro-high');
// if ($res === 0) { exit;
// $this->success('今日免费试戴次数已用完', 0);
// } else { $userService = new User();
// // 合成AI图 $res = $userService->isTry($user->id);
// $ai = new Ai();
// $res = $ai->generateVideo($params, $user->id); if ($res === 0) {
// $this->success('今日免费试戴次数已用完', 0);
// // 我的试戴 } else {
// $tryonModel = new AiTryOnModel(); // 合成AI视频
// $tryonData = [ $ai = new Ai();
// 'user_id' => $user->id, $res = $ai->generateVideo($params, $user->id);
// 'goods_id' => $params['goods_id'],
// 'goods_title' => $params['goods_title'], // 我的试戴
// 'goods_subtitle' => $params['goods_subtitle'], $tryonModel = new AiTryOnModel();
// 'goods_image' => $params['jewelry_image'], $tryonData = [
// 'ai_task_id' => 0, 'user_id' => $user->id,
// 'ai_type' => 0, 'goods_id' => $params['goods_id'],
// ]; 'goods_title' => $params['goods_title'],
// 'goods_subtitle' => $params['goods_subtitle'],
// if ($res['code'] === 0) { 'goods_image' => $params['jewelry_image'],
// 'ai_type' => 1,
// $tryonData['ai_status'] = 2; ];
// $tryonData['ai_err_msg'] = $res['msg'];
// $tryonModel->save($tryonData); if ($res['code'] === 0) {
//
// $this->error($res['msg']); $tryonData['ai_status'] = 2;
// } else { $tryonData['ai_err_msg'] = $res['msg'];
// // 保存图片到本地 $tryonModel->save($tryonData);
// $upload = new Upload();
// $attachment = $upload->uploadBase64($res['data']); $this->error($res['msg']);
//
// if($attachment['code'] == 0){ } else {
// $tryonData['ai_status'] = 2;
// $tryonData['ai_err_msg'] = '图片上传失败'; // 保存一条 我的试戴
// $tryonModel->save($tryonData); $tryonData['ai_status'] = 0;
// $this->error('图片上传失败'); $tryonData['ai_task_id'] = isset($res['data']) ? $res['data'] : '';
// } $tryonModel->save($tryonData);
//
// $tryonData['ai_status'] = 1; // 推送队列
// $tryonData['ai_url'] = config('shopro.api_host') . $attachment['data']; \think\Queue::push('\addons\shopro\job\AiVideoGen@save', ['taskid' => $res['data'], 'user' => $user], 'shopro-high');
// $tryonModel->save($tryonData);
// $this->success($res['msg']);
// $this->success($res['msg'], config('shopro.api_host') . $attachment['data']);
// } }
// } }
} }
/**
* AI试戴 查询视频生成状态
*/
public function getGenVideoTask()
{
// curl -X GET https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks/{id} \
// -H "Content-Type: application/json" \
// -H "Authorization: Bearer $ARK_API_KEY"
}
/**
* AI试戴视频回调函数
* 更新 AI试戴视频结果状态
*/
public function updateAiTryonStatus()
{
// 记录日志
// Log::info('TASKS ID:'. $taskId .' AI生成视频回调函数接口返回:'.json_encode($result));
// // 更新表状态
// $aiTryonModel = new AiTryOnModel();
// $aiTryonModel::where('ai_task_id' , $taskId)->update(['ai_status' => 1]);
}
} }
...@@ -21,9 +21,10 @@ class Ai ...@@ -21,9 +21,10 @@ class Ai
* AI 生成图片 * AI 生成图片
* @param string $param 入参 * @param string $param 入参
* @param string $userId 入参 * @param string $userId 入参
* @param string $response_format 入参
* @return object|array * @return object|array
*/ */
public function generateImage($param = [], $userId = 0) public function generateImage($param = [], $userId = 0, $response_format = 'b64_json')
{ {
try { try {
$url = $this->ark_host . '/api/v3/images/generations'; $url = $this->ark_host . '/api/v3/images/generations';
...@@ -38,7 +39,7 @@ class Ai ...@@ -38,7 +39,7 @@ class Ai
"prompt" => $prompt, "prompt" => $prompt,
"image" => [$param['person_image'], $param['jewelry_image']], "image" => [$param['person_image'], $param['jewelry_image']],
"sequential_image_generation" => "disabled", "sequential_image_generation" => "disabled",
"response_format" => "b64_json", "response_format" => $response_format,
"size" => "2K", "size" => "2K",
"stream" => false, "stream" => false,
"watermark" => true "watermark" => true
...@@ -57,15 +58,27 @@ class Ai ...@@ -57,15 +58,27 @@ class Ai
$result = json_decode($content, true); $result = json_decode($content, true);
// 记录日志 // 记录日志
Log::info('用户ID:'. $userId .' AI生成图片接口返回result:'.json_encode($result)); Log::info('用户ID:'. $userId .' AI生成图片接口返回:'.json_encode($result));
if ($response_format == 'b64_json'){
if (!$result || !isset($result['data'][0]['b64_json'])) {
return [
'code' => 0 ,
'msg' => 'AI图片解析失败,无返回图片'
];
}
}
if (!$result || !isset($result['data'][0]['b64_json'])) { if ($response_format == 'url'){
return [ if (!$result || !isset($result['data'][0]['url'])) {
'code' => 0 , return [
'msg' => 'AI图片解析失败,无返回图片' 'code' => 0 ,
]; 'msg' => 'AI图片解析失败,无返回图片'
];
}
} }
if (isset($result['error']) && $result['error'] !== 0) { if (isset($result['error']) && $result['error'] !== 0) {
return [ return [
'code' => 0 , 'code' => 0 ,
...@@ -76,7 +89,7 @@ class Ai ...@@ -76,7 +89,7 @@ class Ai
return [ return [
'code' => 1 , 'code' => 1 ,
'msg' => '图片生成成功' , 'msg' => '图片生成成功' ,
'data' => $result['data'][0]['b64_json'] ?? '' 'data' => $response_format == 'b64_json' ? $result['data'][0]['b64_json'] : $result['data'][0]['url']
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
...@@ -90,48 +103,70 @@ class Ai ...@@ -90,48 +103,70 @@ class Ai
/** /**
* AI 生成视频 * AI 生成视频
* @param string $image_url 图片地址 * @param array $params 入参
* @return array * @param string $userId 入参
* @return object|array
*/ */
public function generateVideo($image_url = '') public function generateVideo($params = [] , $userId = 0)
{ {
try { try {
$url = $this->ark_host . '/api/v3/contents/generations';
$params = [
'image_url' => $image_url,
'motion' => 'medium',
'duration' => 5
];
$header = [ // 合成AI图片
'Authorization: Bearer ' . $this->api_key, $resGenImg = $this->generateImage($params, $userId, $response_format = 'url');
'Content-Type: application/json' if ($resGenImg['code'] == 0) {
]; return $resGenImg;
}
$response = Http::header($header) // 调试的时候用,一张AI佩戴饰品的照片
->postJson($url, $params); // $resGenImg['data'] = 'https://ark-acg-cn-beijing.tos-cn-beijing.volces.com/doubao-seedream-5-0/02177752801269334e1fb186d00f6ff5c484dce264092c4da58e2_0.jpeg?X-Tos-Algorithm=TOS4-HMAC-SHA256&X-Tos-Credential=AKLTYWJkZTExNjA1ZDUyNDc3YzhjNTM5OGIyNjBhNDcyOTQ%2F20260430%2Fcn-beijing%2Ftos%2Frequest&X-Tos-Date=20260430T054730Z&X-Tos-Expires=86400&X-Tos-Signature=2d109489c534c8bd9e2f9f1820edff8956916da5ee5a477022f6ab8d3024af19&X-Tos-SignedHeaders=host';
$result = json_decode($response, true); $url = $this->ark_host . '/api/v3/contents/generations/tasks';
Log::info('AI生成视频返回:', $result); $prompt = '人物自然微动,轻微转头,微笑,眨眼,动作柔和流畅,画面稳定不闪烁、不抖动、不扭曲,真实人像质感,高清清晰,饰品完美展示,整体自然优雅,无变形、无穿模、无悬浮';
$params = [
'headers' => [
'Authorization' => 'Bearer ' . $this->api_key,
'Content-Type' => 'application/json'
],
'json' => [
"model" => "doubao-seedance-1-5-pro-251215",
"content" => [
[
"type" => "text",
"text" => $prompt
],
[
"type" => "image_url",
"image_url" => [ "url" => $resGenImg['data'] ]
]
],
"generate_audio" => false, // 不要声音
"safety_identifier" => md5($userId)
],
'timeout' => 300,
'verify' => false, // 关闭 SSL 证书验证
'allow_redirects' => true
];
// 发送请求
$client = new Http();
$response = $client->post($url, $params);
if (isset($result['code']) && $result['code'] != 0) { $content = $response->getBody()->getContents();
return [ $content = trim($content);
'code' => 0, $content = preg_replace('/[^\x20-\x7E]/', '', $content);
'msg' => $result['message'] ?? '生成失败' $result = json_decode($content, true);
];
}
// 记录日志
Log::info('用户ID:'. $userId .' AI生成视频接口返回:'.json_encode($result));
return [ return [
'code' => 1, 'code' => 1 ,
'msg' => '生成成功', 'msg' => '视频生成中' ,
'data' => $result['data']['video_url'] ?? '' 'data' => $result['id'] ?? ''
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('AI生成视频异常:' . $e->getMessage()); Log::error('用户ID:'. $userId .' AI生成视频异常:' . $e->getMessage());
return [ return [
'code' => 0, 'code' => 0 ,
'msg' => '请求异常:' . $e->getMessage() 'msg' => '请求异常:' . $e->getMessage()
]; ];
} }
......
...@@ -16,6 +16,7 @@ class AiTryon extends Validate ...@@ -16,6 +16,7 @@ class AiTryon extends Validate
'goods_sku_image' => 'require|length:0,255', 'goods_sku_image' => 'require|length:0,255',
'person_image' => 'require', 'person_image' => 'require',
'jewelry_image' => 'require', 'jewelry_image' => 'require',
'goods_id' => 'require',
]; ];
/** /**
* 提示消息 * 提示消息
...@@ -35,6 +36,7 @@ class AiTryon extends Validate ...@@ -35,6 +36,7 @@ class AiTryon extends Validate
'person_image.require' => '人物图片缺失', 'person_image.require' => '人物图片缺失',
'jewelry_image.require' => '饰品图片缺失', 'jewelry_image.require' => '饰品图片缺失',
'goods_id.require' => '商品ID缺失',
]; ];
/** /**
* 验证场景 * 验证场景
...@@ -42,7 +44,7 @@ class AiTryon extends Validate ...@@ -42,7 +44,7 @@ class AiTryon extends Validate
protected $scene = [ protected $scene = [
'add' => ['url', 'goods_id', 'goods_title', 'goods_sku_id', 'goods_sku_name', 'goods_sku_image'], 'add' => ['url', 'goods_id', 'goods_title', 'goods_sku_id', 'goods_sku_name', 'goods_sku_image'],
'edit' => [], 'edit' => [],
'aiadd' => ['person_image', 'jewelry_image'] 'aiadd' => ['person_image', 'jewelry_image', 'goods_id', 'goods_title']
]; ];
} }
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