initial commit: rocket.new export of broadcastbeat
This commit is contained in:
80
src/app/api/ai/article-suggestions/route.ts
Normal file
80
src/app/api/ai/article-suggestions/route.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { hybridAI } from '@/lib/ai/hybridRouter';
|
||||
import { sampleArticles } from '@/lib/articles/sampleArticles';
|
||||
|
||||
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,
|
||||
}));
|
||||
|
||||
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.
|
||||
Return ONLY a valid JSON array of slugs in order of relevance. Example: ["slug-1","slug-2","slug-3","slug-4"]
|
||||
Do not include any explanation or markdown — only the raw JSON array.`;
|
||||
|
||||
const userPrompt = `Reader interests: ${interests?.length ? interests.join(', ') : 'general broadcast engineering'}
|
||||
Reading history (recently read slugs): ${readingHistory?.length ? readingHistory.join(', ') : 'none'}
|
||||
|
||||
Available articles:
|
||||
${JSON.stringify(articleIndex, null, 2)}
|
||||
|
||||
Return the 4 most relevant article slugs as a JSON array.`;
|
||||
|
||||
const result = await hybridAI(
|
||||
[
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userPrompt },
|
||||
],
|
||||
{
|
||||
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);
|
||||
|
||||
// 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: suggested });
|
||||
} catch (error) {
|
||||
console.error('Article suggestions error:', error);
|
||||
// Graceful fallback
|
||||
const fallback = sampleArticles.filter((a) => a.section === 'news').slice(0, 4);
|
||||
return NextResponse.json({ suggestions: fallback });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user