diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js index d3ba72f..fa8a2ca 100644 --- a/web/storyforge-web-v4/assets/app.js +++ b/web/storyforge-web-v4/assets/app.js @@ -578,15 +578,24 @@ async function loadKnowledgeDocuments(knowledgeBases) { async function loadDouyinAccount(accountId) { if (!accountId) return; appState.selectedAccountId = accountId; + const supportsAccountVideos = backendSupports("/v2/douyin/accounts/{account_id}/videos"); const [workspace, videos] = await Promise.all([ storyforgeFetch(`/v2/douyin/accounts/${encodeURIComponent(accountId)}/workspace`), - storyforgeFetch(`/v2/douyin/accounts/${encodeURIComponent(accountId)}/videos?limit=80`).catch(() => ({ - items: [], - meta: {}, - top_scored_video_ids: [], - latest_video_ids: [], - high_score_threshold: 60 - })) + supportsAccountVideos + ? storyforgeFetch(`/v2/douyin/accounts/${encodeURIComponent(accountId)}/videos?limit=80`).catch(() => ({ + items: [], + meta: {}, + top_scored_video_ids: [], + latest_video_ids: [], + high_score_threshold: 60 + })) + : Promise.resolve({ + items: [], + meta: {}, + top_scored_video_ids: [], + latest_video_ids: [], + high_score_threshold: 60 + }) ]); appState.selectedWorkspace = workspace; appState.selectedVideos = videos; @@ -849,7 +858,9 @@ function getSelectedAccount() { function getHighScoreVideos(limit = 3) { const items = safeArray(appState.selectedVideos?.items); - return items + const fallback = safeArray(getSelectedAccount()?.video_summary?.videos); + const pool = items.length ? items : fallback; + return pool .slice() .sort((a, b) => Number(b.score?.performance_score || 0) - Number(a.score?.performance_score || 0)) .slice(0, limit); @@ -857,7 +868,9 @@ function getHighScoreVideos(limit = 3) { function getLatestVideos(limit = 3) { const items = safeArray(appState.selectedVideos?.items); - return items + const fallback = safeArray(getSelectedAccount()?.video_summary?.videos); + const pool = items.length ? items : fallback; + return pool .slice() .sort((a, b) => new Date(b.published_at || 0).getTime() - new Date(a.published_at || 0).getTime()) .slice(0, limit); @@ -1511,6 +1524,8 @@ function renderDiscoveryScreen() { const reports = safeArray(appState.selectedWorkspace?.recent_reports); const linkedAccounts = safeArray(appState.selectedWorkspace?.linked_accounts); const videos = safeArray(appState.selectedVideos?.items); + const fallbackVideos = safeArray(selected?.video_summary?.videos); + const effectiveVideos = videos.length ? videos : fallbackVideos; const topVideos = getHighScoreVideos(3); const latestVideos = getLatestVideos(2); const similarCandidates = safeArray(appState.lastSimilaritySearch?.candidates).slice(0, 5); @@ -1533,7 +1548,7 @@ function renderDiscoveryScreen() {
平台:抖音
账号数:${escapeHtml(formatNumber(accounts.length))}
报告:${escapeHtml(formatNumber(reports.length))}
-
作品:${escapeHtml(formatNumber(videos.length))}
+
作品:${escapeHtml(formatNumber(effectiveVideos.length))}
@@ -1671,7 +1686,7 @@ function renderDiscoveryScreen() {
-

最新作品

优先看近期更新与窗口期题材
${escapeHtml(formatNumber(videos.length))} 条
+

最新作品

优先看近期更新与窗口期题材
${escapeHtml(formatNumber(effectiveVideos.length))} 条
${latestVideos.map((video) => `
@@ -2755,6 +2770,11 @@ function openAnalyzeSelectedAccountAction() { function openAnalyzeTopVideosAction() { const account = requireSelectedAccountRow(); + if (!backendSupports("/v2/douyin/accounts/{account_id}/videos/analyze-top")) { + rememberAction("当前后端暂不支持", "这套 live collector 还没有接入高分作品批量分析。", "orange"); + renderAll(); + return; + } openActionModal({ title: "分析高分作品", description: "对当前对标账号的高分作品批量补分析。",