fix: search visual cards show localized language first (JA before EN)

- Bilingual format: 【JA】... then 【English】...
- Summary uses localized language (vlm_description_lang) as primary
- Load More function now also supports bilingual format
- Fallback: only vlm_description shows single language without labels
This commit is contained in:
2026-10-23 04:41:15 +08:00
parent 342d4e33b8
commit 1ffceaba26

View File

@@ -1178,18 +1178,22 @@ async function sendMessage() {
const frameNumber = s.frame_number ?? Math.round(ts * fps)
const windowSec = 5
// Build bilingual description
// Build bilingual description: localized language first, then English
let vlmDesc = s.vlm_description || ''
let textContent = vlmDesc
if (bilingual && s.vlm_description_en && s.vlm_description_lang) {
// Show both English and preferred language
textContent = `【English】\n${s.vlm_description_en}\n\n【${outputLang.toUpperCase()}】\n${s.vlm_description_lang}`
vlmDesc = textContent
// Show localized language first, then English
textContent = `【${outputLang.toUpperCase()}】\n${s.vlm_description_lang}\n\n【English】\n${s.vlm_description_en}`
vlmDesc = s.vlm_description_lang
} else if (bilingual && s.vlm_description_lang) {
// Only localized language available
textContent = `【${outputLang.toUpperCase()}】\n${s.vlm_description_lang}`
vlmDesc = s.vlm_description_lang
} else if (bilingual && s.vlm_description_en) {
// Only English available
textContent = `【English】\n${s.vlm_description_en}`
vlmDesc = textContent
vlmDesc = s.vlm_description_en
}
return {
@@ -1217,16 +1221,22 @@ async function sendMessage() {
const ts = t.start_time ?? t.timestamp_sec ?? (frame / fps)
const windowSec = 5
// Build bilingual description
// Build bilingual description: localized language first, then English
let vlmDesc = t.vlm_description || ''
let textContent = vlmDesc
if (bilingual && t.vlm_description_en && t.vlm_description_lang) {
textContent = `【English】\n${t.vlm_description_en}\n\n【${outputLang.toUpperCase()}】\n${t.vlm_description_lang}`
vlmDesc = textContent
// Show localized language first, then English
textContent = `【${outputLang.toUpperCase()}】\n${t.vlm_description_lang}\n\n【English】\n${t.vlm_description_en}`
vlmDesc = t.vlm_description_lang
} else if (bilingual && t.vlm_description_lang) {
// Only localized language available
textContent = `【${outputLang.toUpperCase()}】\n${t.vlm_description_lang}`
vlmDesc = t.vlm_description_lang
} else if (bilingual && t.vlm_description_en) {
// Only English available
textContent = `【English】\n${t.vlm_description_en}`
vlmDesc = textContent
vlmDesc = t.vlm_description_en
}
return {
@@ -1323,6 +1333,7 @@ async function loadMore() {
const base = getApiBase()
const maxResults = 10
const outputLang = searchConfig.value.vlm_output_language || 'en'
const bilingual = outputLang !== 'en'
// Use offset-based pagination instead of page
const offset = nextOffset.value
@@ -1339,33 +1350,72 @@ async function loadMore() {
}).then(r => r.json()).catch(() => ({}))
])
const sceneResults = (scenesRes.scenes || []).map((s: any) => ({
file_uuid: s.file_uuid,
file_name: s.file_name || '',
summary: `[SCENE] ${s.vlm_description || ''}`,
similarity: s.score ?? null,
start_frame: s.frame_number ?? Math.round((s.timestamp_sec || 0) * 30),
end_frame: (s.frame_number ?? Math.round((s.timestamp_sec || 0) * 30)) + 30,
start_time: s.timestamp_sec,
end_time: (s.timestamp_sec || 0) + 1,
source_type: 'scene',
thumbnail_url: s.thumbnail_url,
vlm_tags: s.vlm_tags || [],
search_query: q
}))
const sceneResults = (scenesRes.scenes || []).map((s: any) => {
let vlmDesc = s.vlm_description || ''
let textContent = vlmDesc
if (bilingual && s.vlm_description_en && s.vlm_description_lang) {
textContent = `【${outputLang.toUpperCase()}】\n${s.vlm_description_lang}\n\n【English】\n${s.vlm_description_en}`
vlmDesc = s.vlm_description_lang
} else if (bilingual && s.vlm_description_lang) {
textContent = `【${outputLang.toUpperCase()}】\n${s.vlm_description_lang}`
vlmDesc = s.vlm_description_lang
} else if (bilingual && s.vlm_description_en) {
textContent = `【English】\n${s.vlm_description_en}`
vlmDesc = s.vlm_description_en
}
return {
file_uuid: s.file_uuid,
file_name: s.file_name || '',
summary: vlmDesc ? `[SCENE] ${vlmDesc}` : `[SCENE] ${s.vlm_description || ''}`,
text_content: textContent,
similarity: s.score ?? null,
start_frame: s.frame_number ?? Math.round((s.timestamp_sec || 0) * 30),
end_frame: (s.frame_number ?? Math.round((s.timestamp_sec || 0) * 30)) + 30,
start_time: s.timestamp_sec,
end_time: (s.timestamp_sec || 0) + 1,
source_type: 'scene',
thumbnail_url: s.thumbnail_url,
vlm_tags: s.vlm_tags || [],
bilingual,
vlm_description_en: s.vlm_description_en,
vlm_description_lang: s.vlm_description_lang,
search_query: q
}
})
const traceResults = (tracesRes.traces || []).map((t: any) => ({
file_uuid: t.file_uuid,
file_name: t.file_name || '',
summary: `[TRACE] ${t.vlm_description || ''}`,
similarity: t.score ?? null,
start_frame: t.start_frame,
end_frame: t.end_frame,
source_type: 'trace',
trace_id: t.trace_id,
vlm_description: t.vlm_description,
search_query: q
}))
const traceResults = (tracesRes.traces || []).map((t: any) => {
let vlmDesc = t.vlm_description || ''
let textContent = vlmDesc
if (bilingual && t.vlm_description_en && t.vlm_description_lang) {
textContent = `【${outputLang.toUpperCase()}】\n${t.vlm_description_lang}\n\n【English】\n${t.vlm_description_en}`
vlmDesc = t.vlm_description_lang
} else if (bilingual && t.vlm_description_lang) {
textContent = `【${outputLang.toUpperCase()}】\n${t.vlm_description_lang}`
vlmDesc = t.vlm_description_lang
} else if (bilingual && t.vlm_description_en) {
textContent = `【English】\n${t.vlm_description_en}`
vlmDesc = t.vlm_description_en
}
return {
file_uuid: t.file_uuid,
file_name: t.file_name || '',
summary: vlmDesc || t.text_content || t.vlm_description || 'Person appearance',
text_content: textContent,
similarity: t.score ?? null,
start_frame: t.start_frame,
end_frame: t.end_frame,
source_type: 'trace',
trace_id: t.trace_id,
bilingual,
vlm_description_en: t.vlm_description_en,
vlm_description_lang: t.vlm_description_lang,
search_query: q
}
})
newResults = [...sceneResults, ...traceResults].slice(0, maxResults)
} else if (currentMode === 'people') {