feat(content): comprehensive extraction hardening, code mode UI, overnight plan
- Relax isBookLikeResponse threshold (>=2 to >=1) - Widen book patterns: inline prose, verb-preceded, numbered bold, em-dash - Remove overly aggressive film/song gating on book extraction - Allow songs to coexist with film/book tags (explicit tags always returned) - Strengthen TV patterns: seasons, created by, standalone "tv" query match - Fix TV_EXT_RE to handle both Title|Year|Creator and Title|Creator|Year - Widen place patterns: type word search in descriptions, bold fallback - Add "pizza" to isPlaceQuery and preferredFirstTab - Add Code tab: isCodeQuery, isCodeLikeResponse, extractCodeBlocks, wiring - Fix image threshold: single image with meaningful alt text shown - Refactor filterTabsByContext: specialized paths now append remaining content - Add code mode UI: orange input styling, design system selection, file selection - DesignSystemGrid: selection toggle only on checkmark, card click opens detail - Add 64-test extraction quality test suite - Update overnight plan.md and prompt.md for hardening run Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
75e9274582
commit
f0eb4383bd
@@ -11,13 +11,14 @@ import {
|
||||
extractMagazineSections, extractMagazineHeroImage,
|
||||
extractMarkdownLinks, extractBoldDomainLinks, extractBareDomainLinks, mergeNewsResults,
|
||||
extractFilmIds, extractSongIds, extractPodcastIds,
|
||||
extractApps,
|
||||
extractApps, extractCodeBlocks,
|
||||
stripFilmTags, stripSongTags, stripPodcastTags, stripContentTags, stripMarkdownLinks,
|
||||
} from './contentExtraction'
|
||||
import type { AppEntry } from './contentExtraction'
|
||||
import type { AppEntry, CodeBlock } from './contentExtraction'
|
||||
import {
|
||||
isNewsQuery, isNewsLikeResponse, isTVQuery,
|
||||
isNostrQuery, isNostrLikeResponse,
|
||||
isCodeQuery, isCodeLikeResponse,
|
||||
filterTabsByContext, extractQueryContext,
|
||||
} from './contentFiltering'
|
||||
export type { ContentTab, MagazineSection } from './contentFiltering'
|
||||
@@ -37,6 +38,7 @@ const panelPodcasts = ref<Podcast[]>([])
|
||||
const panelImages = ref<ImageItem[]>([])
|
||||
const panelPlaces = ref<Place[]>([])
|
||||
const panelApps = ref<AppEntry[]>([])
|
||||
const panelCodeBlocks = ref<CodeBlock[]>([])
|
||||
const selectedFilm = ref<Film | null>(null)
|
||||
const selectedBook = ref<Book | null>(null)
|
||||
const selectedTVSeries = ref<TVSeries | null>(null)
|
||||
@@ -95,6 +97,10 @@ export function useContentPanel() {
|
||||
const apps = extractApps(text, userQuery)
|
||||
const hasApps = apps.length > 0
|
||||
|
||||
// Code block extraction
|
||||
const codeBlocks = extractCodeBlocks(text)
|
||||
const hasCode = codeBlocks.length > 0 && (isCodeQuery(userQuery) || isCodeLikeResponse(text))
|
||||
|
||||
// Nostr detection
|
||||
const hasNostr = isNostrQuery(userQuery) || isNostrLikeResponse(text)
|
||||
|
||||
@@ -132,7 +138,7 @@ export function useContentPanel() {
|
||||
})
|
||||
}
|
||||
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, places.length > 0, hasNews, hasWebsites, hasMagazine, hasNostr, hasApps)
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, places.length > 0, hasNews, hasWebsites, hasMagazine, hasNostr, hasApps, hasCode)
|
||||
availableTabs.value = tabs.length > 0 ? tabs : ['film']
|
||||
activeTab.value = tabs[0] ?? 'film'
|
||||
|
||||
@@ -147,6 +153,7 @@ export function useContentPanel() {
|
||||
const showWebsitesTab = tabs.includes('websites')
|
||||
const showMagazine = tabs.includes('magazine')
|
||||
const showApps = tabs.includes('app')
|
||||
const showCode = tabs.includes('code')
|
||||
|
||||
const visibleFilms = showFilms ? films : []
|
||||
const visibleBooks = showBooks ? books : []
|
||||
@@ -159,6 +166,7 @@ export function useContentPanel() {
|
||||
const visibleWebsites = showWebsitesTab ? mergedWebsites : []
|
||||
const visibleMagazineSections = showMagazine ? magazineSections : []
|
||||
const visibleApps = showApps ? apps : []
|
||||
const visibleCodeBlocks = showCode ? codeBlocks : []
|
||||
|
||||
panelFilms.value = visibleFilms
|
||||
panelBooks.value = visibleBooks
|
||||
@@ -170,6 +178,7 @@ export function useContentPanel() {
|
||||
panelWebResults.value = visibleNews
|
||||
panelWebsites.value = visibleWebsites
|
||||
panelApps.value = visibleApps
|
||||
panelCodeBlocks.value = visibleCodeBlocks
|
||||
panelMagazineSections.value = visibleMagazineSections
|
||||
panelMagazineHeroImage.value = showMagazine
|
||||
? (extractMagazineHeroImage(text) ?? webResults[0]?.imgSrc ?? null)
|
||||
@@ -224,6 +233,7 @@ export function useContentPanel() {
|
||||
const ctx = extractQueryContext(userQuery)
|
||||
panelTitle.value = ctx ? `${ctx} — Brief` : 'AI Brief'
|
||||
}
|
||||
else if (visibleCodeBlocks.length > 0) panelTitle.value = `${visibleCodeBlocks.length} Code Blocks`
|
||||
else if (visibleApps.length > 0) panelTitle.value = `${visibleApps.length} Apps`
|
||||
else if (visibleWebsites.length > 0) panelTitle.value = `${visibleWebsites.length} Websites`
|
||||
else if (hasNostr) panelTitle.value = 'Nostr'
|
||||
@@ -258,6 +268,8 @@ export function useContentPanel() {
|
||||
const hasWebsites = websitesLinks.length > 0
|
||||
const apps = extractApps(text, userQuery)
|
||||
const hasApps = apps.length > 0
|
||||
const codeBlocks = extractCodeBlocks(text)
|
||||
const hasCode = codeBlocks.length > 0 && (isCodeQuery(userQuery) || isCodeLikeResponse(text))
|
||||
const hasNostr = isNostrQuery(userQuery) || isNostrLikeResponse(text)
|
||||
const images = extractAllImages(text, userQuery)
|
||||
const places = extractAllPlaces(text, userQuery)
|
||||
@@ -268,7 +280,7 @@ export function useContentPanel() {
|
||||
/sentiment|bearish|bull case|macro|%|BTC|bitcoin|BIP|protocol|debate|what'?s happening|ETF|inflow|trading at|key developments|price recovery|institutional|analyst watch|market cap/i.test(text) ||
|
||||
(!hasAnyOtherInline && !hasWebsites && magazineSections.length >= 2)
|
||||
)
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, places.length > 0, hasNews, hasWebsites, hasMagazine, hasNostr, hasApps)
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, places.length > 0, hasNews, hasWebsites, hasMagazine, hasNostr, hasApps, hasCode)
|
||||
return {
|
||||
films: tabs.includes('film') ? films : [],
|
||||
books: tabs.includes('book') ? books : [],
|
||||
@@ -281,6 +293,7 @@ export function useContentPanel() {
|
||||
websitesLinks: tabs.includes('websites') ? websitesLinks : [],
|
||||
magazineSections: tabs.includes('magazine') ? magazineSections : [],
|
||||
apps: tabs.includes('app') ? apps : [],
|
||||
codeBlocks: tabs.includes('code') ? codeBlocks : [],
|
||||
hasNostr,
|
||||
}
|
||||
}
|
||||
@@ -422,6 +435,7 @@ export function useContentPanel() {
|
||||
panelWebResults,
|
||||
panelWebsites,
|
||||
panelApps,
|
||||
panelCodeBlocks,
|
||||
panelMagazineSections,
|
||||
panelMagazineHeroImage,
|
||||
selectedFilm,
|
||||
@@ -450,6 +464,7 @@ export function useContentPanel() {
|
||||
extractAllSongs,
|
||||
extractPodcastIds,
|
||||
extractAllPodcasts,
|
||||
extractCodeBlocks,
|
||||
getContextualInlineContent,
|
||||
updatePanelFromText,
|
||||
stripFilmTags,
|
||||
|
||||
Reference in New Issue
Block a user