Skip to content

Commit ad176ca

Browse files
committed
Add Nebius fallback for presentation outline when Gemini fails
1 parent f568602 commit ad176ca

File tree

1 file changed

+74
-7
lines changed
  • app/api/generate/presentation-outline

1 file changed

+74
-7
lines changed

app/api/generate/presentation-outline/route.ts

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,67 @@ import {
77
generatePresentationText,
88
generateChartData
99
} from '@/lib/mistral';
10+
import OpenAI from 'openai';
11+
12+
// Fallback to Nebius/Qwen when Gemini fails
13+
const nebiusClient = new OpenAI({
14+
baseURL: 'https://api.tokenfactory.nebius.com/v1/',
15+
apiKey: process.env.NEBIUS_API_KEY,
16+
});
17+
18+
async function generateWithNebius(prompt: string, pageCount: number) {
19+
console.log('🔄 Using Nebius/Qwen as fallback...');
20+
21+
const completion = await nebiusClient.chat.completions.create({
22+
model: 'Qwen/Qwen3-235B-A22B-Instruct-2507',
23+
messages: [
24+
{
25+
role: 'system',
26+
content: `You are a professional presentation designer. Generate exactly ${pageCount} slides for a presentation.
27+
Return a JSON array of slides with this structure:
28+
[
29+
{
30+
"slideNumber": 1,
31+
"type": "title",
32+
"title": "Main Title",
33+
"subtitle": "Subtitle text",
34+
"content": "Brief description",
35+
"bulletPoints": ["Point 1", "Point 2", "Point 3"]
36+
}
37+
]
38+
Slide types: title, content, bullets, stats, comparison, timeline, conclusion
39+
Make content professional, engaging, and visually focused.`
40+
},
41+
{
42+
role: 'user',
43+
content: `Create a ${pageCount}-slide presentation about: ${prompt}`
44+
}
45+
],
46+
max_tokens: 4000,
47+
temperature: 0.7,
48+
});
49+
50+
const content = completion.choices[0]?.message?.content || '[]';
51+
52+
// Extract JSON from response
53+
const jsonMatch = content.match(/\[[\s\S]*\]/);
54+
if (jsonMatch) {
55+
try {
56+
return JSON.parse(jsonMatch[0]);
57+
} catch (e) {
58+
console.error('Failed to parse Nebius response:', e);
59+
}
60+
}
61+
62+
// Fallback: create basic slides
63+
return Array.from({ length: pageCount }, (_, i) => ({
64+
slideNumber: i + 1,
65+
type: i === 0 ? 'title' : i === pageCount - 1 ? 'conclusion' : 'content',
66+
title: i === 0 ? prompt : `Slide ${i + 1}`,
67+
content: 'Content for this slide',
68+
bulletPoints: ['Key point 1', 'Key point 2', 'Key point 3']
69+
}));
70+
}
1071

1172

1273
export async function POST(request: Request) {
@@ -23,14 +84,20 @@ export async function POST(request: Request) {
2384

2485
console.log('📝 Step 1: Generating slide text content...');
2586

26-
// Step 1: Generate text content (choice between Gemini or Mistral)
87+
// Step 1: Generate text content with fallback
2788
let outlines;
28-
if (useGemini) {
29-
console.log('Using Gemini 2.0 Flash for text generation');
30-
outlines = await generatePresentationOutline({ prompt, pageCount });
31-
} else {
32-
console.log('Using Mistral Large for text generation');
33-
outlines = await generatePresentationText(prompt, pageCount);
89+
try {
90+
if (useGemini) {
91+
console.log('Using Gemini 2.0 Flash for text generation');
92+
outlines = await generatePresentationOutline({ prompt, pageCount });
93+
} else {
94+
console.log('Using Mistral Large for text generation');
95+
outlines = await generatePresentationText(prompt, pageCount);
96+
}
97+
} catch (geminiError: any) {
98+
console.error('⚠️ Gemini failed:', geminiError.message);
99+
console.log('🔄 Falling back to Nebius/Qwen...');
100+
outlines = await generateWithNebius(prompt, pageCount);
34101
}
35102

36103
console.log(`✅ Generated ${outlines.length} slides`);

0 commit comments

Comments
 (0)