delete sampleArticles seed; serve all sections from bb.wp_imported_posts (DB)
Eliminates 72 hardcoded rocket.new image refs in one shot. Section pages (/gear, /technology, /show-coverage, /news) now render from bb.wp_imported_posts via getLegacyArticlesBySection(section), which maps each non-news section to a curated tag set (e.g. gear -> Audio, Cameras, lighting, Blackmagic Design, monitoring; technology -> AI, Streaming, OTT, IP, Cloud, AV; show-coverage -> NAB, IBC, BroadcastAsia). Also: - src/lib/articles/types.ts: Article interface lifted out of the deleted seed file. Type-only consumers (NewsArticleDetailClient, ArticleDetailClient, legacy-source) re-imported from here. - /news (client component) now wrapped: server fetches articles from DB and passes to NewsPageClient. Filter UI unchanged. - generateStaticParams on /news/[slug] and /articles/[slug] no longer references seed slugs; pre-renders 50 most-recent imported slugs and relies on dynamicParams + revalidate=3600 for the rest. - sitemap.ts now sources article URLs from getLegacyRecentSitemapEntries() (up to 5000 most-recent imported posts). Default BASE_URL fallback updated from the rocket.new placeholder to bb-staging.onsethost.com. - src/app/api/ai/article-suggestions/route.ts now pulls candidates from the DB (top 100 recent news) and resolves AI-returned slugs via DB lookup if not in the candidate window. Inline rocket.new image refs in homepage components (ArticleFeed, FeaturedBento) are unchanged in this commit; those are inline seed arrays in the components, not imports of sampleArticles.
This commit is contained in:
@@ -1,22 +1,26 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { hybridAI } from '@/lib/ai/hybridRouter';
|
||||
import { sampleArticles } from '@/lib/articles/sampleArticles';
|
||||
import {
|
||||
getLegacyArticlesBySection,
|
||||
getLegacyArticleBySlug,
|
||||
} from '@/lib/articles/legacy-source';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { interests, readingHistory } = await request.json();
|
||||
|
||||
// Build a compact article index for the AI to reason over
|
||||
const articleIndex = sampleArticles
|
||||
.filter((a) => a.section === 'news')
|
||||
.map((a) => ({
|
||||
slug: a.slug,
|
||||
title: a.title,
|
||||
excerpt: a.excerpt,
|
||||
tags: a.tags,
|
||||
category: a.category,
|
||||
date: a.date,
|
||||
}));
|
||||
// Pull a recent slice of news for the AI to choose from. Cap at 100 so the
|
||||
// prompt stays bounded.
|
||||
const news = await getLegacyArticlesBySection('news', 100);
|
||||
|
||||
const articleIndex = news.map((a) => ({
|
||||
slug: a.slug,
|
||||
title: a.title,
|
||||
excerpt: a.excerpt,
|
||||
tags: a.tags,
|
||||
category: a.category,
|
||||
date: a.date,
|
||||
}));
|
||||
|
||||
const systemPrompt = `You are a personalized content recommendation engine for BroadcastBeat, a broadcast engineering news platform.
|
||||
Given a reader's topic interests and reading history, select the 4 most relevant articles from the provided article list.
|
||||
@@ -36,45 +40,38 @@ Return the 4 most relevant article slugs as a JSON array.`;
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userPrompt },
|
||||
],
|
||||
{
|
||||
maxTokens: 200,
|
||||
temperature: 0.3,
|
||||
priority: 4,
|
||||
}
|
||||
{ maxTokens: 200, temperature: 0.3, priority: 4 }
|
||||
);
|
||||
|
||||
const content = result.text;
|
||||
|
||||
let slugs: string[] = [];
|
||||
try {
|
||||
// Extract JSON array from response (model may wrap it in text)
|
||||
const match = content.match(/\[[\s\S]*?\]/);
|
||||
slugs = match ? JSON.parse(match[0]) : JSON.parse(content.trim());
|
||||
} catch {
|
||||
// Fallback: extract slugs with regex
|
||||
const matches = content.match(/"([^"]+)"/g);
|
||||
slugs = matches ? matches.map((m: string) => m.replace(/"/g, '')).slice(0, 4) : [];
|
||||
}
|
||||
|
||||
// Resolve full article objects
|
||||
const suggested = slugs
|
||||
.map((slug: string) => sampleArticles.find((a) => a.slug === slug))
|
||||
.filter(Boolean)
|
||||
.slice(0, 4);
|
||||
// Resolve from the candidate set first; if a slug wasn't in the recent
|
||||
// window, look it up via DB so AI hallucinations or older slugs still resolve.
|
||||
const suggested = (
|
||||
await Promise.all(
|
||||
slugs.slice(0, 4).map(async (slug: string) =>
|
||||
news.find((a) => a.slug === slug) || (await getLegacyArticleBySlug(slug))
|
||||
)
|
||||
)
|
||||
).filter(Boolean);
|
||||
|
||||
// Fallback: return latest news if AI returned nothing useful
|
||||
if (suggested.length === 0) {
|
||||
const fallback = sampleArticles
|
||||
.filter((a) => a.section === 'news')
|
||||
.slice(0, 4);
|
||||
return NextResponse.json({ suggestions: fallback });
|
||||
return NextResponse.json({ suggestions: news.slice(0, 4) });
|
||||
}
|
||||
|
||||
return NextResponse.json({ suggestions: suggested });
|
||||
} catch (error) {
|
||||
console.error('Article suggestions error:', error);
|
||||
// Graceful fallback
|
||||
const fallback = sampleArticles.filter((a) => a.section === 'news').slice(0, 4);
|
||||
const fallback = await getLegacyArticlesBySection('news', 4);
|
||||
return NextResponse.json({ suggestions: fallback });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user