fix: 优化点1,2,3,6
This commit is contained in:
parent
c78fc762f4
commit
0d5d58a86e
|
|
@ -162,8 +162,8 @@ import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
|||
import { Message } from '@arco-design/web-vue'
|
||||
import { uploadFile, extractUploadUrlFromResponse, PORTAL_TENCENT_COS_UPLOAD_URL } from '@/utils/file'
|
||||
|
||||
/** 图生参考:不同参考图最多 4 张(图1–图4),同一 URL 可多次 @ */
|
||||
const MAX_REFERENCE_UNIQUE = 4
|
||||
/** 富文本内「不同素材」种类上限(图/视频/音频合计);同一 URL 可多次 @,提交时 reference_* 去重后最多 9 条 */
|
||||
const MAX_REFERENCE_CONTENT_SLOTS = 9
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
|
@ -603,7 +603,7 @@ const getUniqueRefUrlsInDoc = () => {
|
|||
return s
|
||||
}
|
||||
|
||||
/** 按文档顺序为不同 URL 分配 [图n]/[视频n]/[音频n],并同步 data-token / 展示 */
|
||||
/** 按文档顺序为不同 URL 分配 [图n]/[视频n]/[音频n];不同素材合计最多 MAX_REFERENCE_CONTENT_SLOTS,同 URL 复用同一序号 */
|
||||
const renumberAllReferenceMentions = () => {
|
||||
if (!editorRef.value || !isReference.value) return
|
||||
const refs = Array.from(editorRef.value.querySelectorAll('.vg-inline-ref[data-mention-reference="1"]'))
|
||||
|
|
@ -613,6 +613,7 @@ const renumberAllReferenceMentions = () => {
|
|||
let imgNext = 1
|
||||
let vidNext = 1
|
||||
let audNext = 1
|
||||
let globalDistinct = 0
|
||||
let droppedExtra = false
|
||||
for (const el of refs) {
|
||||
const u = el.getAttribute('data-reference-url') || ''
|
||||
|
|
@ -624,31 +625,34 @@ const renumberAllReferenceMentions = () => {
|
|||
let token = ''
|
||||
if (kind === 'video') {
|
||||
if (!vidMap.has(u)) {
|
||||
if (vidNext > MAX_REFERENCE_UNIQUE) {
|
||||
if (globalDistinct >= MAX_REFERENCE_CONTENT_SLOTS) {
|
||||
el.remove()
|
||||
droppedExtra = true
|
||||
continue
|
||||
}
|
||||
globalDistinct++
|
||||
vidMap.set(u, vidNext++)
|
||||
}
|
||||
token = `[视频${vidMap.get(u)}]`
|
||||
} else if (kind === 'audio') {
|
||||
if (!audMap.has(u)) {
|
||||
if (audNext > MAX_REFERENCE_UNIQUE) {
|
||||
if (globalDistinct >= MAX_REFERENCE_CONTENT_SLOTS) {
|
||||
el.remove()
|
||||
droppedExtra = true
|
||||
continue
|
||||
}
|
||||
globalDistinct++
|
||||
audMap.set(u, audNext++)
|
||||
}
|
||||
token = `[音频${audMap.get(u)}]`
|
||||
} else {
|
||||
if (!imgMap.has(u)) {
|
||||
if (imgNext > MAX_REFERENCE_UNIQUE) {
|
||||
if (globalDistinct >= MAX_REFERENCE_CONTENT_SLOTS) {
|
||||
el.remove()
|
||||
droppedExtra = true
|
||||
continue
|
||||
}
|
||||
globalDistinct++
|
||||
imgMap.set(u, imgNext++)
|
||||
}
|
||||
token = `[图${imgMap.get(u)}]`
|
||||
|
|
@ -658,7 +662,7 @@ const renumberAllReferenceMentions = () => {
|
|||
if (imgEl) imgEl.setAttribute('alt', token)
|
||||
}
|
||||
if (droppedExtra) {
|
||||
Message.warning(`每类参考最多 ${MAX_REFERENCE_UNIQUE} 个不同素材,已移除多余引用`)
|
||||
Message.warning(`富文本内不同素材最多 ${MAX_REFERENCE_CONTENT_SLOTS} 个(图/视频/音频合计),已移除多余引用`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -697,21 +701,30 @@ const collectReferenceMentionsInDocOrder = () => {
|
|||
}
|
||||
|
||||
/**
|
||||
* 参考图模式提交用:首条 text;其后按文中 [图n]/[视频n]/[音频n] 顺序对应各 reference_*。
|
||||
* 参考图模式提交用:首条 text;其后为 reference_*。
|
||||
* 文中多次出现同一 [图n]/[视频n]/[音频n](同一 URL)时,只输出一条记录(按文中首次出现顺序),最多 9 条。
|
||||
*/
|
||||
const getImageReferenceContentItems = () => {
|
||||
const text = getEditorPlainText()
|
||||
const first = { type: 'text', text: text || '' }
|
||||
const mentions = collectReferenceMentionsInDocOrder()
|
||||
const rest = mentions.map(({ url, kind }) => {
|
||||
const seen = new Set()
|
||||
const rest = []
|
||||
for (const { url, kind } of mentions) {
|
||||
const u = String(url || '').trim()
|
||||
if (!u) continue
|
||||
const key = `${kind}::${u}`
|
||||
if (seen.has(key)) continue
|
||||
seen.add(key)
|
||||
if (rest.length >= MAX_REFERENCE_CONTENT_SLOTS) break
|
||||
if (kind === 'video') {
|
||||
return { type: 'video_url', video_url: { url }, role: 'reference_video' }
|
||||
rest.push({ type: 'video_url', video_url: { url: u }, role: 'reference_video' })
|
||||
} else if (kind === 'audio') {
|
||||
rest.push({ type: 'audio_url', audio_url: { url: u }, role: 'reference_audio' })
|
||||
} else {
|
||||
rest.push({ type: 'image_url', image_url: { url: u }, role: 'reference_image' })
|
||||
}
|
||||
if (kind === 'audio') {
|
||||
return { type: 'audio_url', audio_url: { url }, role: 'reference_audio' }
|
||||
}
|
||||
return { type: 'image_url', image_url: { url }, role: 'reference_image' }
|
||||
})
|
||||
}
|
||||
return [first, ...rest]
|
||||
}
|
||||
|
||||
|
|
@ -1001,15 +1014,17 @@ const applyReferenceFromHistory = ({ text, contentItems }) => {
|
|||
const selectMentionItem = (item) => {
|
||||
if (!item?.url || !editorRef.value) return
|
||||
const kind = item.mediaType === 'video' ? 'video' : item.mediaType === 'audio' ? 'audio' : 'image'
|
||||
const uniqueByKind = { image: new Set(), video: new Set(), audio: new Set() }
|
||||
const refSlotKey = `${kind}::${item.url}`
|
||||
const keysInDoc = new Set()
|
||||
editorRef.value.querySelectorAll('.vg-inline-ref[data-mention-reference="1"]').forEach((el) => {
|
||||
const u = el.getAttribute('data-reference-url')
|
||||
const k = el.getAttribute('data-reference-kind') || 'image'
|
||||
if (u) uniqueByKind[k]?.add(u)
|
||||
if (u) keysInDoc.add(`${k}::${u}`)
|
||||
})
|
||||
const keySet = uniqueByKind[kind] || uniqueByKind.image
|
||||
if (!keySet.has(item.url) && keySet.size >= MAX_REFERENCE_UNIQUE) {
|
||||
Message.warning(`该类型最多 ${MAX_REFERENCE_UNIQUE} 个不同素材`)
|
||||
if (!keysInDoc.has(refSlotKey) && keysInDoc.size >= MAX_REFERENCE_CONTENT_SLOTS) {
|
||||
Message.warning(
|
||||
`富文本内不同素材最多 ${MAX_REFERENCE_CONTENT_SLOTS} 个(图/视频/音频合计),同一素材可重复插入`
|
||||
)
|
||||
mentionVisible.value = false
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ export default {
|
|||
maxMediaCount() {
|
||||
if (this.videoMode === 'image-first-frame') return 1
|
||||
if (this.videoMode === 'image-first-last-frame') return 2
|
||||
if (this.videoMode === 'image-reference') return 9
|
||||
if (this.videoMode === 'image-reference') return 12
|
||||
return 12
|
||||
},
|
||||
allowedMediaTypes() {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import org.springframework.web.bind.annotation.*;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
|
@ -305,7 +306,8 @@ public class PortalVideoController extends BaseController {
|
|||
filtered.add(it);
|
||||
}
|
||||
}
|
||||
contentList = filtered;
|
||||
// 文中多次出现同一 [图n]/[视频n]/[音频n](同一 URL)时,只保留一条 reference_* 记录
|
||||
contentList = dedupeReferenceContentAfterText(filtered);
|
||||
|
||||
String firstRef = contentList.stream()
|
||||
.skip(1)
|
||||
|
|
@ -343,6 +345,42 @@ public class PortalVideoController extends BaseController {
|
|||
return submitOrderAndCreate(request, "image-reference", body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文中多次出现同一素材(同一 role + URL)时,只保留一条 reference_*,顺序为首次出现顺序。
|
||||
*/
|
||||
private static List<ContentItem> dedupeReferenceContentAfterText(List<ContentItem> filtered) {
|
||||
if (filtered == null || filtered.isEmpty()) {
|
||||
return filtered;
|
||||
}
|
||||
List<ContentItem> out = new ArrayList<>();
|
||||
out.add(filtered.get(0));
|
||||
Set<String> seen = new LinkedHashSet<>();
|
||||
for (int i = 1; i < filtered.size(); i++) {
|
||||
ContentItem it = filtered.get(i);
|
||||
String key = referenceItemDedupeKey(it);
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
continue;
|
||||
}
|
||||
if (seen.add(key)) {
|
||||
out.add(it);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static String referenceItemDedupeKey(ContentItem item) {
|
||||
if (isReferenceImageContentItem(item) && item.getImageUrl() != null) {
|
||||
return "reference_image::" + StringUtils.trim(item.getImageUrl().getUrl());
|
||||
}
|
||||
if (isReferenceVideoContentItem(item) && item.getVideoUrl() != null) {
|
||||
return "reference_video::" + StringUtils.trim(item.getVideoUrl().getUrl());
|
||||
}
|
||||
if (isReferenceAudioContentItem(item) && item.getAudioUrl() != null) {
|
||||
return "reference_audio::" + StringUtils.trim(item.getAudioUrl().getUrl());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String firstReferenceUrlFromItem(ContentItem item) {
|
||||
if (isReferenceImageContentItem(item)) {
|
||||
return item.getImageUrl().getUrl();
|
||||
|
|
|
|||
Loading…
Reference in New Issue