fix: 对接素材管理
This commit is contained in:
parent
b13e51a6ca
commit
2a91a33825
|
|
@ -58,7 +58,15 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="vg-asset-controls">
|
||||
<input v-model.trim="assetGroupId" class="vg-asset-group-input" placeholder="请输入 GroupId" />
|
||||
<select v-model="assetGroupId" class="vg-asset-group-input">
|
||||
<option value="">请选择素材组</option>
|
||||
<option v-for="g in assetGroups" :key="g.Id || g.id" :value="g.Id || g.id">
|
||||
{{ g.Name || g.name || g.Id || g.id }}
|
||||
</option>
|
||||
</select>
|
||||
<mf-button class="vg-compose-left-upload" size="small" @click="loadAssetGroups" :loading="groupLoading">
|
||||
刷新分组
|
||||
</mf-button>
|
||||
<mf-button class="vg-compose-left-upload" size="small" @click="loadAssetsByGroup" :loading="assetLoading">
|
||||
查询资产
|
||||
</mf-button>
|
||||
|
|
@ -66,6 +74,12 @@
|
|||
上传资产
|
||||
</mf-button>
|
||||
</div>
|
||||
<div class="vg-asset-controls">
|
||||
<input v-model.trim="newGroupName" class="vg-asset-group-input" placeholder="输入新素材组名称" />
|
||||
<mf-button class="vg-compose-left-upload" size="small" type="primary" @click="createAssetGroup" :loading="groupLoading">
|
||||
新建素材组
|
||||
</mf-button>
|
||||
</div>
|
||||
|
||||
<div v-if="mediaList.length === 0" class="vg-compose-empty" @click="openFilePicker">
|
||||
<div class="vg-compose-empty-icon" aria-hidden="true">+</div>
|
||||
|
|
@ -207,6 +221,9 @@ const mentionVisible = ref(false)
|
|||
const mentionActiveIndex = ref(-1)
|
||||
const assetGroupId = ref('')
|
||||
const assetLoading = ref(false)
|
||||
const groupLoading = ref(false)
|
||||
const assetGroups = ref([])
|
||||
const newGroupName = ref('')
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
|
|
@ -244,6 +261,9 @@ onMounted(() => {
|
|||
if (editorRef.value && localPrompt.value) {
|
||||
editorRef.value.innerText = localPrompt.value
|
||||
}
|
||||
if (isReference.value) {
|
||||
loadAssetGroups()
|
||||
}
|
||||
})
|
||||
|
||||
const mediaList = computed(() => internalMediaList.value)
|
||||
|
|
@ -368,6 +388,62 @@ const mergeAssetsToMediaList = (assets) => {
|
|||
setMediaList(next.slice(0, props.maxMediaCount))
|
||||
}
|
||||
|
||||
const loadAssetGroups = async () => {
|
||||
if (!proxy?.$axios) return
|
||||
groupLoading.value = true
|
||||
try {
|
||||
const res = await proxy.$axios({
|
||||
url: 'api/byteAssetGroup/listAssetGroups',
|
||||
method: 'POST',
|
||||
data: {
|
||||
Filter: { GroupType: 'AIGC' },
|
||||
PageNumber: 1,
|
||||
PageSize: 100,
|
||||
SortBy: 'CreateTime',
|
||||
SortOrder: 'Desc'
|
||||
}
|
||||
})
|
||||
const rows = Array.isArray(res?.data?.Items) ? res.data.Items : []
|
||||
assetGroups.value = rows
|
||||
if (!assetGroupId.value && rows.length) {
|
||||
assetGroupId.value = rows[0]?.Id || rows[0]?.id || ''
|
||||
}
|
||||
} catch (err) {
|
||||
Message.error(err?.message || '加载素材组失败')
|
||||
} finally {
|
||||
groupLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createAssetGroup = async () => {
|
||||
const name = String(newGroupName.value || '').trim()
|
||||
if (!name) {
|
||||
Message.warning('请输入素材组名称')
|
||||
return
|
||||
}
|
||||
if (!proxy?.$axios) return
|
||||
groupLoading.value = true
|
||||
try {
|
||||
const res = await proxy.$axios({
|
||||
url: 'api/byteAssetGroup/createAssetGroup',
|
||||
method: 'POST',
|
||||
data: {
|
||||
Name: name,
|
||||
ProjectName: 'default'
|
||||
}
|
||||
})
|
||||
const gid = res?.data?.Id || res?.data?.id || ''
|
||||
newGroupName.value = ''
|
||||
await loadAssetGroups()
|
||||
if (gid) assetGroupId.value = gid
|
||||
Message.success('素材组创建成功')
|
||||
} catch (err) {
|
||||
Message.error(err?.message || '创建素材组失败')
|
||||
} finally {
|
||||
groupLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const loadAssetsByGroup = async () => {
|
||||
const gid = String(assetGroupId.value || '').trim()
|
||||
if (!gid) {
|
||||
|
|
@ -381,7 +457,7 @@ const loadAssetsByGroup = async () => {
|
|||
assetLoading.value = true
|
||||
try {
|
||||
const res = await proxy.$axios({
|
||||
url: 'api/portal/asset/listAssets',
|
||||
url: 'api/byteAsset/listAssets',
|
||||
method: 'POST',
|
||||
data: {
|
||||
Filter: {
|
||||
|
|
@ -509,15 +585,15 @@ const loadAssetsByGroup = async () => {
|
|||
const mt = entry.mediaType || 'image'
|
||||
const assetType =
|
||||
mt === 'video' ? 'Video' : mt === 'audio' ? 'Audio' : 'Image'
|
||||
const fd = new FormData()
|
||||
fd.append('file', entry._fileRef)
|
||||
fd.append('groupId', gid)
|
||||
fd.append('assetType', assetType)
|
||||
fd.append('name', entry?.name || '')
|
||||
const createRes = await proxy.$axios({
|
||||
url: 'api/portal/asset/createAsset',
|
||||
url: 'api/byteAsset/createAsset',
|
||||
method: 'POST',
|
||||
data: {
|
||||
GroupId: gid,
|
||||
URL: url,
|
||||
Name: entry?.name || '',
|
||||
AssetType: assetType
|
||||
}
|
||||
data: fd
|
||||
})
|
||||
assetId = createRes?.data?.Id || createRes?.data?.id || ''
|
||||
if (!assetId) throw new Error(createRes?.msg || '创建素材失败:未返回资产ID')
|
||||
|
|
|
|||
|
|
@ -176,12 +176,13 @@ export default {
|
|||
this.createLoading = true
|
||||
try {
|
||||
const res = await this.$axios({
|
||||
url: 'api/portal/asset/post',
|
||||
url: 'api/byteAssetGroup/createAssetGroup',
|
||||
method: 'POST',
|
||||
data: {
|
||||
Name: name,
|
||||
Description: String(this.createForm.description || '').trim(),
|
||||
GroupType: 'AIGC'
|
||||
GroupType: 'AIGC',
|
||||
ProjectName: 'default'
|
||||
}
|
||||
})
|
||||
if (res.code === 200) {
|
||||
|
|
@ -217,7 +218,7 @@ export default {
|
|||
if (ids.length) payload.Filter.GroupIds = ids
|
||||
|
||||
const res = await this.$axios({
|
||||
url: 'api/portal/asset/list',
|
||||
url: 'api/byteAssetGroup/listAssetGroups',
|
||||
method: 'POST',
|
||||
data: payload
|
||||
})
|
||||
|
|
@ -255,7 +256,7 @@ export default {
|
|||
this.detailLoadingId = id
|
||||
try {
|
||||
const res = await this.$axios({
|
||||
url: 'api/portal/asset/get',
|
||||
url: 'api/byteAssetGroup/getAssetGroup',
|
||||
method: 'POST',
|
||||
data: { Id: id }
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,6 +3,16 @@
|
|||
<section class="asset-left">
|
||||
<div class="panel-title">素材组树</div>
|
||||
<a-button size="mini" type="outline" :loading="groupLoading" @click="loadGroups">刷新分组</a-button>
|
||||
<div class="form-grid mtop">
|
||||
<div class="field">
|
||||
<label>素材组名称</label>
|
||||
<a-input v-model="groupForm.name" placeholder="输入分组名称" />
|
||||
</div>
|
||||
<div class="field actions">
|
||||
<a-button type="primary" size="mini" @click="createGroup">新建分组</a-button>
|
||||
<a-button size="mini" @click="updateGroup" :disabled="!groupForm.id">更新分组</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group-tree">
|
||||
<div
|
||||
v-for="g in groups"
|
||||
|
|
@ -27,8 +37,9 @@
|
|||
<a-input v-model="createForm.groupId" placeholder="请选择左侧分组或手动输入" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>URL</label>
|
||||
<a-input v-model="createForm.url" placeholder="素材公网 URL(http/https)" />
|
||||
<label>文件</label>
|
||||
<input type="file" @change="onFileChange" />
|
||||
<div class="group-id">{{ createForm.fileName || '未选择文件' }}</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Name</label>
|
||||
|
|
@ -143,11 +154,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
const GROUP_LIST_API = 'api/portal/asset/list'
|
||||
const ASSET_CREATE_API = 'api/portal/asset/createAsset'
|
||||
const ASSET_LIST_API = 'api/portal/asset/listAssets'
|
||||
const ASSET_GET_API = 'api/portal/asset/getAsset'
|
||||
const ASSET_DELETE_API = 'api/portal/asset/deleteAsset'
|
||||
const GROUP_LIST_API = 'api/byteAssetGroup/listAssetGroups'
|
||||
const GROUP_CREATE_API = 'api/byteAssetGroup/createAssetGroup'
|
||||
const GROUP_GET_API = 'api/byteAssetGroup/getAssetGroup'
|
||||
const GROUP_UPDATE_API = 'api/byteAssetGroup/updateAssetGroup'
|
||||
const ASSET_CREATE_API = 'api/byteAsset/createAsset'
|
||||
const ASSET_LIST_API = 'api/byteAsset/listAssets'
|
||||
const ASSET_GET_API = 'api/byteAsset/getAsset'
|
||||
const ASSET_DELETE_API = 'api/byteAsset/deleteAsset'
|
||||
|
||||
export default {
|
||||
name: 'AssetManage',
|
||||
|
|
@ -160,10 +174,15 @@ export default {
|
|||
selectedGroupId: '',
|
||||
createForm: {
|
||||
groupId: '',
|
||||
url: '',
|
||||
file: null,
|
||||
fileName: '',
|
||||
name: '',
|
||||
assetType: 'Image'
|
||||
},
|
||||
groupForm: {
|
||||
name: '',
|
||||
id: ''
|
||||
},
|
||||
filters: {
|
||||
groupId: '',
|
||||
name: '',
|
||||
|
|
@ -206,6 +225,8 @@ export default {
|
|||
if (!this.selectedGroupId && this.groups.length) {
|
||||
const gid = this.groups[0].Id || this.groups[0].id
|
||||
this.selectedGroupId = gid
|
||||
this.groupForm.id = gid
|
||||
this.groupForm.name = this.groups[0].Name || this.groups[0].name || ''
|
||||
this.createForm.groupId = gid
|
||||
this.filters.groupId = gid
|
||||
this.searchAssets(1)
|
||||
|
|
@ -219,30 +240,89 @@ export default {
|
|||
selectGroup(g) {
|
||||
const gid = g?.Id || g?.id
|
||||
this.selectedGroupId = gid
|
||||
this.groupForm.id = gid
|
||||
this.groupForm.name = g?.Name || g?.name || ''
|
||||
this.createForm.groupId = gid
|
||||
this.filters.groupId = gid
|
||||
this.searchAssets(1)
|
||||
},
|
||||
async createGroup() {
|
||||
const name = String(this.groupForm.name || '').trim()
|
||||
if (!name) return this.$message.error('请输入素材组名称')
|
||||
try {
|
||||
const res = await this.$axios({
|
||||
url: GROUP_CREATE_API,
|
||||
method: 'POST',
|
||||
data: { Name: name, ProjectName: 'default' }
|
||||
})
|
||||
if (res.code === 200) {
|
||||
this.$message.success('创建素材组成功')
|
||||
await this.loadGroups()
|
||||
} else {
|
||||
this.$message.error(res.msg || '创建素材组失败')
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message.error(e?.message || '创建素材组失败')
|
||||
}
|
||||
},
|
||||
async updateGroup() {
|
||||
const id = String(this.groupForm.id || '').trim()
|
||||
const name = String(this.groupForm.name || '').trim()
|
||||
if (!id) return this.$message.error('请先选择素材组')
|
||||
if (!name) return this.$message.error('请输入素材组名称')
|
||||
try {
|
||||
const detailRes = await this.$axios({
|
||||
url: GROUP_GET_API,
|
||||
method: 'POST',
|
||||
data: { Id: id }
|
||||
})
|
||||
const detail = detailRes?.data || {}
|
||||
const payload = {
|
||||
Id: id,
|
||||
Name: name,
|
||||
GroupType: detail.GroupType || detail.groupType || 'AIGC',
|
||||
ProjectName: detail.ProjectName || detail.projectName || 'default'
|
||||
}
|
||||
const res = await this.$axios({
|
||||
url: GROUP_UPDATE_API,
|
||||
method: 'POST',
|
||||
data: payload
|
||||
})
|
||||
if (res.code === 200) {
|
||||
this.$message.success('更新素材组成功')
|
||||
await this.loadGroups()
|
||||
} else {
|
||||
this.$message.error(res.msg || '更新素材组失败')
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message.error(e?.message || '更新素材组失败')
|
||||
}
|
||||
},
|
||||
onFileChange(e) {
|
||||
const file = e?.target?.files?.[0]
|
||||
this.createForm.file = file || null
|
||||
this.createForm.fileName = file?.name || ''
|
||||
},
|
||||
async createAsset() {
|
||||
const groupId = String(this.createForm.groupId || '').trim()
|
||||
const url = String(this.createForm.url || '').trim()
|
||||
if (!groupId) return this.$message.error('请填写 GroupId')
|
||||
if (!/^https?:\/\//i.test(url)) return this.$message.error('URL 必须是 http(s) 地址')
|
||||
if (!this.createForm.file) return this.$message.error('请选择上传文件')
|
||||
this.createLoading = true
|
||||
try {
|
||||
const fd = new FormData()
|
||||
fd.append('file', this.createForm.file)
|
||||
fd.append('groupId', groupId)
|
||||
fd.append('assetType', this.createForm.assetType)
|
||||
fd.append('name', String(this.createForm.name || '').trim())
|
||||
const res = await this.$axios({
|
||||
url: ASSET_CREATE_API,
|
||||
method: 'POST',
|
||||
data: {
|
||||
GroupId: groupId,
|
||||
URL: url,
|
||||
Name: String(this.createForm.name || '').trim(),
|
||||
AssetType: this.createForm.assetType
|
||||
}
|
||||
data: fd
|
||||
})
|
||||
if (res.code === 200) {
|
||||
this.$message.success('新增素材成功')
|
||||
this.createForm.url = ''
|
||||
this.createForm.file = null
|
||||
this.createForm.fileName = ''
|
||||
this.createForm.name = ''
|
||||
this.searchAssets(1)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -44,8 +44,6 @@ public class ByteApiController extends BaseController {
|
|||
private String url;
|
||||
|
||||
// 火山引擎配置
|
||||
@Value("${volcengine.ark.apiKey}")
|
||||
private String volcApiKey;
|
||||
@Value("${volcengine.ark.baseUrl}")
|
||||
private String volcBaseUrl;
|
||||
@Value("${volcengine.ark.callbackUrl}")
|
||||
|
|
|
|||
|
|
@ -224,16 +224,16 @@ tencentCos:
|
|||
# domain: https://images.iqyjsnwv.com/
|
||||
|
||||
byteapi:
|
||||
url: https://ark.ap-southeast.bytepluses.com/api/v3
|
||||
apiKey: 3e33e034-7e25-4228-8864-b51b2a7a8f97
|
||||
callBackUrl: https://undressing.top
|
||||
url:
|
||||
apiKey:
|
||||
callBackUrl:
|
||||
|
||||
# 火山引擎 Ark API (Seedance 2.0)
|
||||
volcengine:
|
||||
ark:
|
||||
baseUrl: https://ark.cn-beijing.volces.com
|
||||
apiKey: 3e33e034-7e25-4228-8864-b51b2a7a8f97
|
||||
callbackUrl: https://undressing.top/api/ai/volcCallback
|
||||
baseUrl:
|
||||
apiKey:
|
||||
callbackUrl:
|
||||
|
||||
# 门户视频生成页:模型 / 比例 / 时长 / 分辨率均由此处维护,前后端不写死业务枚举
|
||||
portal:
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.ai.domain.ByteBodyReq;
|
||||
import com.ruoyi.ai.domain.ByteBodyRes;
|
||||
import com.ruoyi.ai.service.IByteDeptApiKeyService;
|
||||
import com.ruoyi.ai.service.IByteService;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.http.OkHttpUtils;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
|
@ -29,15 +32,12 @@ public class ByteService implements IByteService {
|
|||
@Value("${byteapi.url}")
|
||||
private String API_URL;
|
||||
|
||||
@Value("${byteapi.apiKey}")
|
||||
private String apiKey;
|
||||
|
||||
// 火山引擎配置
|
||||
@Value("${volcengine.ark.baseUrl:https://ark.cn-beijing.volces.com}")
|
||||
private String volcBaseUrl;
|
||||
|
||||
@Value("${volcengine.ark.apiKey}")
|
||||
private String volcApiKey;
|
||||
@Autowired
|
||||
private IByteDeptApiKeyService byteDeptApiKeyService;
|
||||
|
||||
@Override
|
||||
public ByteBodyRes promptToImg(ByteBodyReq req) throws Exception {
|
||||
|
|
@ -59,7 +59,7 @@ public class ByteService implements IByteService {
|
|||
Request request = new Request.Builder()
|
||||
.url(API_URL + "/images/generations")
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Authorization", "Bearer " + apiKey)
|
||||
.header("Authorization", "Bearer " + resolveCurrentAiUserApiKey())
|
||||
// .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("192.168.1.1", 8080)))
|
||||
.post(RequestBody.create(
|
||||
MediaType.parse("application/json"),
|
||||
|
|
@ -84,7 +84,7 @@ public class ByteService implements IByteService {
|
|||
|
||||
@Override
|
||||
public ByteBodyRes imgToVideo(ByteBodyReq req) throws Exception {
|
||||
return imgToVideo(req, volcApiKey);
|
||||
return imgToVideo(req, resolveCurrentAiUserApiKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -125,7 +125,7 @@ public class ByteService implements IByteService {
|
|||
|
||||
@Override
|
||||
public ByteBodyRes uploadVideo(String id) throws Exception {
|
||||
return uploadVideo(id, volcApiKey);
|
||||
return uploadVideo(id, resolveCurrentAiUserApiKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -161,7 +161,7 @@ public class ByteService implements IByteService {
|
|||
|
||||
@Override
|
||||
public AjaxResult cancelVideoTask(String id) throws Exception {
|
||||
return cancelVideoTask(id, volcApiKey);
|
||||
return cancelVideoTask(id, resolveCurrentAiUserApiKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -228,4 +228,8 @@ public class ByteService implements IByteService {
|
|||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
private String resolveCurrentAiUserApiKey() {
|
||||
return byteDeptApiKeyService.resolveVolcApiKey(SecurityUtils.getAiUserId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue