Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yaoai-video
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
姚珂
yaoai-video
Commits
232de8ef
Commit
232de8ef
authored
Jun 03, 2026
by
yaoke.yk
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
客户端设定-道具修改
parent
347882ac
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
137 additions
and
3 deletions
+137
-3
PropsGeneration.tsx
doc/html/src/app/pages/PropsGeneration.tsx
+0
-0
useAssets.ts
doc/html/src/hooks/useAssets.ts
+25
-0
assets.ts
doc/html/src/lib/api/assets.ts
+15
-0
GlobalAssetsController.java
...java/com/yaoai/api/controller/GlobalAssetsController.java
+87
-1
ImageGenPipelineService.java
...a/com/yaoai/pipeline/service/ImageGenPipelineService.java
+2
-0
ImageGenPipelineServiceImpl.java
...ai/pipeline/service/impl/ImageGenPipelineServiceImpl.java
+8
-2
No files found.
doc/html/src/app/pages/PropsGeneration.tsx
View file @
232de8ef
This diff is collapsed.
Click to expand it.
doc/html/src/hooks/useAssets.ts
View file @
232de8ef
...
...
@@ -27,6 +27,31 @@ export function useToggleFavorite(type: string, library: string) {
});
}
export
function
useUpdateAsset
(
type
:
string
,
library
:
string
)
{
const
qc
=
useQueryClient
();
return
useMutation
({
mutationFn
:
({
id
,
patch
}:
{
id
:
string
;
patch
:
Partial
<
CreateAssetPayload
>
})
=>
assetsApi
.
update
(
id
,
patch
),
onSuccess
:
()
=>
qc
.
invalidateQueries
({
queryKey
:
assetsKey
(
type
,
library
)
}),
});
}
export
function
useUploadAssetImage
(
type
:
string
,
library
:
string
)
{
const
qc
=
useQueryClient
();
return
useMutation
({
mutationFn
:
({
id
,
file
}:
{
id
:
string
;
file
:
File
})
=>
assetsApi
.
uploadImage
(
id
,
file
),
onSuccess
:
()
=>
qc
.
invalidateQueries
({
queryKey
:
assetsKey
(
type
,
library
)
}),
});
}
export
function
useGenerateAssetImage
(
type
:
string
,
library
:
string
)
{
const
qc
=
useQueryClient
();
return
useMutation
({
mutationFn
:
(
id
:
string
)
=>
assetsApi
.
generateImage
(
id
),
onSuccess
:
()
=>
qc
.
invalidateQueries
({
queryKey
:
assetsKey
(
type
,
library
)
}),
});
}
export
function
useDeleteAsset
(
type
:
string
,
library
:
string
)
{
const
qc
=
useQueryClient
();
return
useMutation
({
...
...
doc/html/src/lib/api/assets.ts
View file @
232de8ef
...
...
@@ -42,6 +42,21 @@ export const assetsApi = {
const
r
=
await
apiClient
.
put
(
`/assets/
${
id
}
`
,
patch
);
return
r
.
data
.
data
;
},
uploadImage
:
async
(
id
:
string
,
file
:
File
):
Promise
<
GlobalAsset
>
=>
{
const
form
=
new
FormData
();
form
.
append
(
"file"
,
file
);
const
r
=
await
apiClient
.
post
(
`/assets/
${
id
}
/upload-image`
,
form
,
{
headers
:
{
"Content-Type"
:
"multipart/form-data"
},
timeout
:
600
_000
,
});
return
r
.
data
.
data
;
},
generateImage
:
async
(
id
:
string
):
Promise
<
GlobalAsset
>
=>
{
const
r
=
await
apiClient
.
post
(
`/assets/
${
id
}
/generate-image`
,
undefined
,
{
timeout
:
180
_000
,
});
return
r
.
data
.
data
;
},
delete
:
async
(
id
:
string
):
Promise
<
void
>
=>
{
await
apiClient
.
delete
(
`/assets/
${
id
}
`
);
},
...
...
yaoai-comic-studio/yaoai-api/src/main/java/com/yaoai/api/controller/GlobalAssetsController.java
View file @
232de8ef
...
...
@@ -7,12 +7,17 @@ import com.yaoai.common.exception.ErrorCode;
import
com.yaoai.common.response.ApiResponse
;
import
com.yaoai.domain.entity.GlobalAsset
;
import
com.yaoai.domain.mapper.GlobalAssetMapper
;
import
com.yaoai.pipeline.service.ImageGenPipelineService
;
import
com.yaoai.security.context.TenantContext
;
import
com.yaoai.storage.service.TosService
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -23,6 +28,8 @@ import java.util.Map;
public
class
GlobalAssetsController
{
private
final
GlobalAssetMapper
globalAssetMapper
;
private
final
TosService
tosService
;
private
final
ImageGenPipelineService
imageGenPipelineService
;
@Operation
(
summary
=
"获取资产列表"
)
@GetMapping
...
...
@@ -54,7 +61,11 @@ public class GlobalAssetsController {
asset
.
setDescription
((
String
)
body
.
get
(
"description"
));
asset
.
setIsFavorite
(
0
);
Object
srcProject
=
body
.
get
(
"sourceProjectId"
);
if
(
srcProject
instanceof
Number
)
asset
.
setSourceProjectId
(((
Number
)
srcProject
).
longValue
());
if
(
srcProject
instanceof
Number
)
{
asset
.
setSourceProjectId
(((
Number
)
srcProject
).
longValue
());
}
else
if
(
srcProject
instanceof
String
srcProjectText
&&
!
srcProjectText
.
isBlank
())
{
asset
.
setSourceProjectId
(
Long
.
valueOf
(
srcProjectText
));
}
globalAssetMapper
.
insert
(
asset
);
return
ApiResponse
.
success
(
GlobalAssetDTO
.
from
(
asset
));
...
...
@@ -90,6 +101,65 @@ public class GlobalAssetsController {
return
ApiResponse
.
success
(
GlobalAssetDTO
.
from
(
asset
));
}
@Operation
(
summary
=
"AI 生成资产图片"
)
@PostMapping
(
"/{id}/generate-image"
)
public
ApiResponse
<
GlobalAssetDTO
>
generateImage
(
@PathVariable
Long
id
)
{
Long
tenantId
=
TenantContext
.
get
();
Long
userId
=
StpUtil
.
getLoginIdAsLong
();
GlobalAsset
asset
=
globalAssetMapper
.
selectById
(
id
);
if
(
asset
==
null
||
!
tenantId
.
equals
(
asset
.
getTenantId
()))
{
throw
new
BizException
(
ErrorCode
.
NOT_FOUND
,
"资产不存在"
);
}
if
(!
"prop"
.
equals
(
asset
.
getAssetType
()))
{
throw
new
BizException
(
ErrorCode
.
INVALID_PARAM
,
"当前仅支持生成道具图片"
);
}
Long
projectKeyId
=
asset
.
getSourceProjectId
()
!=
null
?
asset
.
getSourceProjectId
()
:
0L
;
String
key
=
imageGenPipelineService
.
generateAndStore
(
tenantId
,
userId
,
projectKeyId
,
"global-assets/"
+
asset
.
getAssetType
(),
buildPropImagePrompt
(
asset
)
);
asset
.
setImageTosKey
(
key
);
asset
.
setImageUrl
(
tosService
.
publicUrl
(
key
));
globalAssetMapper
.
updateById
(
asset
);
return
ApiResponse
.
success
(
GlobalAssetDTO
.
from
(
asset
));
}
@Operation
(
summary
=
"上传资产图片"
)
@PostMapping
(
value
=
"/{id}/upload-image"
,
consumes
=
MediaType
.
MULTIPART_FORM_DATA_VALUE
)
public
ApiResponse
<
GlobalAssetDTO
>
uploadImage
(
@PathVariable
Long
id
,
@RequestPart
(
"file"
)
MultipartFile
file
)
throws
IOException
{
Long
tenantId
=
TenantContext
.
get
();
GlobalAsset
asset
=
globalAssetMapper
.
selectById
(
id
);
if
(
asset
==
null
||
!
tenantId
.
equals
(
asset
.
getTenantId
()))
{
throw
new
BizException
(
ErrorCode
.
NOT_FOUND
,
"资产不存在"
);
}
if
(
file
==
null
||
file
.
isEmpty
())
{
throw
new
BizException
(
ErrorCode
.
INVALID_PARAM
,
"图片文件不能为空"
);
}
String
contentType
=
file
.
getContentType
()
!=
null
?
file
.
getContentType
()
:
"application/octet-stream"
;
if
(!
contentType
.
startsWith
(
"image/"
))
{
throw
new
BizException
(
ErrorCode
.
INVALID_PARAM
,
"请上传图片文件"
);
}
Long
projectKeyId
=
asset
.
getSourceProjectId
()
!=
null
?
asset
.
getSourceProjectId
()
:
0L
;
String
key
=
TosService
.
buildKey
(
tenantId
,
projectKeyId
,
"global-assets/"
+
asset
.
getAssetType
(),
file
.
getOriginalFilename
()
);
tosService
.
upload
(
key
,
file
.
getInputStream
(),
file
.
getSize
(),
contentType
);
asset
.
setImageTosKey
(
key
);
asset
.
setImageUrl
(
tosService
.
publicUrl
(
key
));
globalAssetMapper
.
updateById
(
asset
);
return
ApiResponse
.
success
(
GlobalAssetDTO
.
from
(
asset
));
}
@Operation
(
summary
=
"删除资产"
)
@DeleteMapping
(
"/{id}"
)
public
ApiResponse
<
Void
>
delete
(
@PathVariable
Long
id
)
{
...
...
@@ -101,4 +171,20 @@ public class GlobalAssetsController {
globalAssetMapper
.
deleteById
(
id
);
return
ApiResponse
.
success
();
}
private
String
buildPropImagePrompt
(
GlobalAsset
asset
)
{
String
category
=
asset
.
getTags
()
!=
null
&&
!
asset
.
getTags
().
isBlank
()
?
asset
.
getTags
()
:
"道具"
;
String
description
=
asset
.
getDescription
()
!=
null
&&
!
asset
.
getDescription
().
isBlank
()
?
asset
.
getDescription
()
:
"根据名称和分类设计清晰可识别的影视道具"
;
return
"""
Cinematic AI short-drama prop reference image, single object only.
Create one clear hero reference image for a prop used in video generation.
Neutral clean studio background, three-quarter view, accurate material, scale cues, sharp silhouette, realistic lighting.
No people, no hands, no environment clutter, no text, no labels, no watermark, no logo, no duplicated objects.
Prop name: %s
Prop category: %s
Prop description: %s
"""
.
formatted
(
asset
.
getName
(),
category
,
description
);
}
}
yaoai-comic-studio/yaoai-pipeline/src/main/java/com/yaoai/pipeline/service/ImageGenPipelineService.java
View file @
232de8ef
...
...
@@ -13,4 +13,6 @@ public interface ImageGenPipelineService {
String
generateAndStore
(
Long
tenantId
,
Long
projectId
,
String
prompt
);
String
generateAndStore
(
Long
tenantId
,
Long
userId
,
Long
projectId
,
String
prompt
);
String
generateAndStore
(
Long
tenantId
,
Long
userId
,
Long
projectId
,
String
assetType
,
String
prompt
);
}
yaoai-comic-studio/yaoai-pipeline/src/main/java/com/yaoai/pipeline/service/impl/ImageGenPipelineServiceImpl.java
View file @
232de8ef
...
...
@@ -39,6 +39,11 @@ public class ImageGenPipelineServiceImpl implements ImageGenPipelineService {
@Override
public
String
generateAndStore
(
Long
tenantId
,
Long
userId
,
Long
projectId
,
String
prompt
)
{
return
generateAndStore
(
tenantId
,
userId
,
projectId
,
"scene"
,
prompt
);
}
@Override
public
String
generateAndStore
(
Long
tenantId
,
Long
userId
,
Long
projectId
,
String
assetType
,
String
prompt
)
{
billingService
.
checkBalance
(
BillingChargeRequest
.
builder
()
.
tenantId
(
tenantId
)
.
userId
(
userId
)
...
...
@@ -60,9 +65,10 @@ public class ImageGenPipelineServiceImpl implements ImageGenPipelineService {
byte
[]
imageBytes
=
downloadImage
(
imageUrl
);
// 3. 上传到 TOS
String
key
=
TosService
.
buildKey
(
tenantId
,
projectId
,
"scene"
,
"scene.jpg"
);
String
normalizedAssetType
=
assetType
!=
null
&&
!
assetType
.
isBlank
()
?
assetType
:
"image"
;
String
key
=
TosService
.
buildKey
(
tenantId
,
projectId
,
normalizedAssetType
,
normalizedAssetType
+
".jpg"
);
tosService
.
upload
(
key
,
new
ByteArrayInputStream
(
imageBytes
),
imageBytes
.
length
,
"image/jpeg"
);
log
.
info
(
"
Scene
image stored: key={}"
,
key
);
log
.
info
(
"
Generated
image stored: key={}"
,
key
);
billingService
.
charge
(
BillingChargeRequest
.
builder
()
.
tenantId
(
tenantId
)
.
userId
(
userId
)
...
...
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