Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
loveisland
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
刘小敏
loveisland
Commits
c4c76bf1
Commit
c4c76bf1
authored
Apr 30, 2026
by
刘小敏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
AI试戴生成视频接口和队列
parent
48d71c1e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
163 additions
and
98 deletions
+163
-98
AiTryon.php
addons/shopro/controller/user/AiTryon.php
+87
-59
Ai.php
addons/shopro/service/user/Ai.php
+73
-38
AiTryon.php
addons/shopro/validate/user/AiTryon.php
+3
-1
No files found.
addons/shopro/controller/user/AiTryon.php
View file @
c4c76bf1
...
@@ -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 U
ser();
$user
=
auth_u
ser
();
// $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]);
}
}
}
addons/shopro/service/user/Ai.php
View file @
c4c76bf1
...
@@ -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'
=>
$res
ult
[
'data'
][
0
][
'b64_json'
]
??
''
'data'
=>
$res
ponse_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
()
];
];
}
}
...
...
addons/shopro/validate/user/AiTryon.php
View file @
c4c76bf1
...
@@ -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'
]
];
];
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment