refine ui further

This commit is contained in:
Developers Digest
2025-09-05 15:56:14 -04:00
parent 836b085f75
commit 9d71ae77e7
8 changed files with 285 additions and 232 deletions
+52 -19
View File
@@ -1294,26 +1294,59 @@ It's better to have 3 complete files than 10 incomplete files.`
}
let result;
try {
result = await streamText(streamOptions);
} catch (streamError) {
console.error('[generate-ai-code-stream] Error calling streamText:', streamError);
// Send specific error for debugging
await sendProgress({
type: 'error',
message: `Failed to initialize ${isGoogle ? 'Gemini' : isAnthropic ? 'Claude' : isOpenAI ? 'GPT-5' : 'Groq'} streaming: ${(streamError as Error).message}`
});
// If this is a Google model error, provide helpful info
if (isGoogle) {
await sendProgress({
type: 'info',
message: 'Tip: Make sure your GEMINI_API_KEY is set correctly and has proper permissions.'
});
let retryCount = 0;
const maxRetries = 2;
while (retryCount <= maxRetries) {
try {
result = await streamText(streamOptions);
break; // Success, exit retry loop
} catch (streamError: any) {
console.error(`[generate-ai-code-stream] Error calling streamText (attempt ${retryCount + 1}/${maxRetries + 1}):`, streamError);
// Check if this is a Groq service unavailable error
const isGroqServiceError = isKimiGroq && streamError.message?.includes('Service unavailable');
const isRetryableError = streamError.message?.includes('Service unavailable') ||
streamError.message?.includes('rate limit') ||
streamError.message?.includes('timeout');
if (retryCount < maxRetries && isRetryableError) {
retryCount++;
console.log(`[generate-ai-code-stream] Retrying in ${retryCount * 2} seconds...`);
// Send progress update about retry
await sendProgress({
type: 'info',
message: `Service temporarily unavailable, retrying (attempt ${retryCount + 1}/${maxRetries + 1})...`
});
// Wait before retry with exponential backoff
await new Promise(resolve => setTimeout(resolve, retryCount * 2000));
// If Groq fails, try switching to a fallback model
if (isGroqServiceError && retryCount === maxRetries) {
console.log('[generate-ai-code-stream] Groq service unavailable, falling back to GPT-4');
streamOptions.model = openai('gpt-4-turbo');
actualModel = 'gpt-4-turbo';
}
} else {
// Final error, send to user
await sendProgress({
type: 'error',
message: `Failed to initialize ${isGoogle ? 'Gemini' : isAnthropic ? 'Claude' : isOpenAI ? 'GPT-5' : isKimiGroq ? 'Kimi (Groq)' : 'Groq'} streaming: ${streamError.message}`
});
// If this is a Google model error, provide helpful info
if (isGoogle) {
await sendProgress({
type: 'info',
message: 'Tip: Make sure your GEMINI_API_KEY is set correctly and has proper permissions.'
});
}
throw streamError;
}
}
throw streamError;
}
// Stream the response and parse in real-time
+25 -4
View File
@@ -21,8 +21,11 @@ export async function POST(req: NextRequest) {
const app = new FirecrawlApp({ apiKey });
// Use Firecrawl SDK to capture screenshot with the latest API
const scrapeResult = await app.scrapeUrl(url, {
console.log('[scrape-screenshot] Attempting to capture screenshot for:', url);
console.log('[scrape-screenshot] Using Firecrawl API key:', apiKey ? 'Present' : 'Missing');
// Use the new v4 scrape method (not scrapeUrl)
const scrapeResult = await app.scrape(url, {
formats: ['screenshot'], // Request screenshot format
waitFor: 3000, // Wait for page to fully load
timeout: 30000,
@@ -35,7 +38,12 @@ export async function POST(req: NextRequest) {
]
});
console.log('[scrape-screenshot] Scrape result success:', scrapeResult.success);
console.log('[scrape-screenshot] Scrape result data:', scrapeResult.data ? Object.keys(scrapeResult.data) : 'No data');
if (!scrapeResult.success) {
console.error('[scrape-screenshot] Firecrawl API error:', scrapeResult.error);
console.error('[scrape-screenshot] Full scrapeResult:', JSON.stringify(scrapeResult, null, 2));
throw new Error(scrapeResult.error || 'Failed to capture screenshot');
}
@@ -50,9 +58,22 @@ export async function POST(req: NextRequest) {
});
} catch (error: any) {
console.error('Screenshot capture error:', error);
console.error('[scrape-screenshot] Screenshot capture error:', error);
console.error('[scrape-screenshot] Error stack:', error.stack);
// Provide fallback response for development
if (process.env.NODE_ENV === 'development') {
console.warn('[scrape-screenshot] Returning placeholder screenshot for development');
return NextResponse.json({
success: true,
screenshot: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
metadata: { error: 'Screenshot capture failed, using placeholder' }
});
}
return NextResponse.json({
error: error.message || 'Failed to capture screenshot'
error: error.message || 'Failed to capture screenshot',
details: process.env.NODE_ENV === 'development' ? error.stack : undefined
}, { status: 500 });
}
}
+12 -3
View File
@@ -43,7 +43,7 @@ export async function POST(request: NextRequest) {
},
body: JSON.stringify({
url,
formats: ['markdown', 'html'],
formats: ['markdown', 'html', 'screenshot'],
waitFor: 3000,
timeout: 30000,
blockAds: true,
@@ -52,6 +52,10 @@ export async function POST(request: NextRequest) {
{
type: 'wait',
milliseconds: 2000
},
{
type: 'screenshot',
fullPage: false // Just visible viewport for performance
}
]
})
@@ -68,7 +72,10 @@ export async function POST(request: NextRequest) {
throw new Error('Failed to scrape content');
}
const { markdown, html, metadata } = data.data;
const { markdown, html, metadata, screenshot, actions } = data.data;
// Get screenshot from either direct field or actions result
const screenshotUrl = screenshot || actions?.screenshots?.[0] || null;
// Sanitize the markdown content
const sanitizedMarkdown = sanitizeQuotes(markdown || '');
@@ -91,11 +98,13 @@ ${sanitizedMarkdown}
success: true,
url,
content: formattedContent,
screenshot: screenshotUrl,
structured: {
title: sanitizeQuotes(title),
description: sanitizeQuotes(description),
content: sanitizedMarkdown,
url
url,
screenshot: screenshotUrl
},
metadata: {
scraper: 'firecrawl-enhanced',
+1 -1
View File
@@ -40,7 +40,7 @@ export async function POST(request: NextRequest) {
// Scrape the website using the latest SDK patterns
// Include screenshot if requested in formats
const scrapeResult = await app.scrapeUrl(url, {
const scrapeResult = await app.scrape(url, {
formats: formats,
onlyMainContent: options.onlyMainContent !== false, // Default to true for cleaner content
waitFor: options.waitFor || 2000, // Wait for dynamic content