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

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

parent 48d71c1e
......@@ -11,6 +11,7 @@ use think\helper\Time;
use addons\shopro\service\goods\GoodsService;
use addons\shopro\service\user\User;
use addons\shopro\service\user\Ai;
use think\Log;
class AiTryon extends Common
......@@ -134,7 +135,7 @@ class AiTryon extends Common
// 'goods_title' => $params['goods_title'],
// 'goods_subtitle' => $params['goods_subtitle'],
// 'goods_image' => $params['jewelry_image'],
// 'ai_task_id' => 0,
// 'ai_task_id' => '',
// 'ai_type' => 0,
// ];
//
......@@ -171,65 +172,92 @@ class AiTryon extends Common
*/
public function genVideo()
{
// if (!$this->request->isPost()) {
// $this->error('');
// }
//
// $params = $this->request->only([
// 'person_image', 'jewelry_image','goods_id','goods_title','goods_subtitle'
// ]);
// $this->svalidate($params, ".aiadd");
//
// $user = auth_user();
// $userService = new User();
// $res = $userService->isTry($user->id);
//
// if ($res === 0) {
// $this->success('今日免费试戴次数已用完', 0);
// } else {
// // 合成AI图
// $ai = new Ai();
// $res = $ai->generateVideo($params, $user->id);
//
// // 我的试戴
// $tryonModel = new AiTryOnModel();
// $tryonData = [
// 'user_id' => $user->id,
// 'goods_id' => $params['goods_id'],
// 'goods_title' => $params['goods_title'],
// 'goods_subtitle' => $params['goods_subtitle'],
// 'goods_image' => $params['jewelry_image'],
// 'ai_task_id' => 0,
// 'ai_type' => 0,
// ];
//
// if ($res['code'] === 0) {
//
// $tryonData['ai_status'] = 2;
// $tryonData['ai_err_msg'] = $res['msg'];
// $tryonModel->save($tryonData);
//
// $this->error($res['msg']);
// } else {
// // 保存图片到本地
// $upload = new Upload();
// $attachment = $upload->uploadBase64($res['data']);
//
// if($attachment['code'] == 0){
// $tryonData['ai_status'] = 2;
// $tryonData['ai_err_msg'] = '图片上传失败';
// $tryonModel->save($tryonData);
// $this->error('图片上传失败');
// }
//
// $tryonData['ai_status'] = 1;
// $tryonData['ai_url'] = config('shopro.api_host') . $attachment['data'];
// $tryonModel->save($tryonData);
//
// $this->success($res['msg'], config('shopro.api_host') . $attachment['data']);
// }
// }
if (!$this->request->isPost()) {
$this->error('');
}
$params = $this->request->only([
'person_image', 'jewelry_image','goods_id','goods_title','goods_subtitle'
]);
$this->svalidate($params, ".aiadd");
$user = auth_user();
\think\Queue::push('\addons\shopro\job\AiVideoGen@save', ['taskid' => 'cgt-20260430190444-vmb4q', 'user' => $user], 'shopro-high');
exit;
$userService = new User();
$res = $userService->isTry($user->id);
if ($res === 0) {
$this->success('今日免费试戴次数已用完', 0);
} else {
// 合成AI视频
$ai = new Ai();
$res = $ai->generateVideo($params, $user->id);
// 我的试戴
$tryonModel = new AiTryOnModel();
$tryonData = [
'user_id' => $user->id,
'goods_id' => $params['goods_id'],
'goods_title' => $params['goods_title'],
'goods_subtitle' => $params['goods_subtitle'],
'goods_image' => $params['jewelry_image'],
'ai_type' => 1,
];
if ($res['code'] === 0) {
$tryonData['ai_status'] = 2;
$tryonData['ai_err_msg'] = $res['msg'];
$tryonModel->save($tryonData);
$this->error($res['msg']);
} else {
// 保存一条 我的试戴
$tryonData['ai_status'] = 0;
$tryonData['ai_task_id'] = isset($res['data']) ? $res['data'] : '';
$tryonModel->save($tryonData);
// 推送队列
\think\Queue::push('\addons\shopro\job\AiVideoGen@save', ['taskid' => $res['data'], 'user' => $user], 'shopro-high');
$this->success($res['msg']);
}
}
}
/**
* 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
* AI 生成图片
* @param string $param 入参
* @param string $userId 入参
* @param string $response_format 入参
* @return object|array
*/
public function generateImage($param = [], $userId = 0)
public function generateImage($param = [], $userId = 0, $response_format = 'b64_json')
{
try {
$url = $this->ark_host . '/api/v3/images/generations';
......@@ -38,7 +39,7 @@ class Ai
"prompt" => $prompt,
"image" => [$param['person_image'], $param['jewelry_image']],
"sequential_image_generation" => "disabled",
"response_format" => "b64_json",
"response_format" => $response_format,
"size" => "2K",
"stream" => false,
"watermark" => true
......@@ -57,15 +58,27 @@ class Ai
$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'])) {
return [
'code' => 0 ,
'msg' => 'AI图片解析失败,无返回图片'
];
if ($response_format == 'url'){
if (!$result || !isset($result['data'][0]['url'])) {
return [
'code' => 0 ,
'msg' => 'AI图片解析失败,无返回图片'
];
}
}
if (isset($result['error']) && $result['error'] !== 0) {
return [
'code' => 0 ,
......@@ -76,7 +89,7 @@ class Ai
return [
'code' => 1 ,
'msg' => '图片生成成功' ,
'data' => $result['data'][0]['b64_json'] ?? ''
'data' => $response_format == 'b64_json' ? $result['data'][0]['b64_json'] : $result['data'][0]['url']
];
} catch (\Exception $e) {
......@@ -90,48 +103,70 @@ class Ai
/**
* AI 生成视频
* @param string $image_url 图片地址
* @return array
* @param array $params 入参
* @param string $userId 入参
* @return object|array
*/
public function generateVideo($image_url = '')
public function generateVideo($params = [] , $userId = 0)
{
try {
$url = $this->ark_host . '/api/v3/contents/generations';
$params = [
'image_url' => $image_url,
'motion' => 'medium',
'duration' => 5
];
$header = [
'Authorization: Bearer ' . $this->api_key,
'Content-Type: application/json'
];
// 合成AI图片
$resGenImg = $this->generateImage($params, $userId, $response_format = 'url');
if ($resGenImg['code'] == 0) {
return $resGenImg;
}
$response = Http::header($header)
->postJson($url, $params);
// 调试的时候用,一张AI佩戴饰品的照片
// $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);
Log::info('AI生成视频返回:', $result);
$url = $this->ark_host . '/api/v3/contents/generations/tasks';
$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) {
return [
'code' => 0,
'msg' => $result['message'] ?? '生成失败'
];
}
$content = $response->getBody()->getContents();
$content = trim($content);
$content = preg_replace('/[^\x20-\x7E]/', '', $content);
$result = json_decode($content, true);
// 记录日志
Log::info('用户ID:'. $userId .' AI生成视频接口返回:'.json_encode($result));
return [
'code' => 1,
'msg' => '生成成功',
'data' => $result['data']['video_url'] ?? ''
'code' => 1 ,
'msg' => '视频生成中' ,
'data' => $result['id'] ?? ''
];
} catch (\Exception $e) {
Log::error('AI生成视频异常:' . $e->getMessage());
Log::error('用户ID:'. $userId .' AI生成视频异常:' . $e->getMessage());
return [
'code' => 0,
'code' => 0 ,
'msg' => '请求异常:' . $e->getMessage()
];
}
......
......@@ -16,6 +16,7 @@ class AiTryon extends Validate
'goods_sku_image' => 'require|length:0,255',
'person_image' => 'require',
'jewelry_image' => 'require',
'goods_id' => 'require',
];
/**
* 提示消息
......@@ -35,6 +36,7 @@ class AiTryon extends Validate
'person_image.require' => '人物图片缺失',
'jewelry_image.require' => '饰品图片缺失',
'goods_id.require' => '商品ID缺失',
];
/**
* 验证场景
......@@ -42,7 +44,7 @@ class AiTryon extends Validate
protected $scene = [
'add' => ['url', 'goods_id', 'goods_title', 'goods_sku_id', 'goods_sku_name', 'goods_sku_image'],
'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