mirror of
https://github.com/johndoe6345789/snippet-pastebin.git
synced 2026-04-24 13:34:55 +00:00
Add OpenAI API integration for error analysis with settings UI
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
2
.github/workflows/deploy-pages.yml
vendored
2
.github/workflows/deploy-pages.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
run: npm ci
|
||||
|
||||
- name: Build Next.js
|
||||
run: npm run build -- --webpack
|
||||
run: npm run build
|
||||
env:
|
||||
BUILD_STATIC: 'true'
|
||||
NEXT_PUBLIC_FLASK_BACKEND_URL: ${{ vars.NEXT_PUBLIC_FLASK_BACKEND_URL || '' }}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { StorageBackendCard } from '@/components/settings/StorageBackendCard';
|
||||
import { DatabaseStatsCard } from '@/components/settings/DatabaseStatsCard';
|
||||
import { StorageInfoCard } from '@/components/settings/StorageInfoCard';
|
||||
import { DatabaseActionsCard } from '@/components/settings/DatabaseActionsCard';
|
||||
import { OpenAISettingsCard } from '@/components/settings/OpenAISettingsCard';
|
||||
import { useSettingsState } from '@/hooks/useSettingsState';
|
||||
import { PageLayout } from '../PageLayout';
|
||||
|
||||
@@ -50,6 +51,8 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 max-w-3xl">
|
||||
<OpenAISettingsCard />
|
||||
|
||||
<PersistenceSettings />
|
||||
|
||||
<SchemaHealthCard
|
||||
|
||||
@@ -3,23 +3,89 @@ export async function analyzeErrorWithAI(
|
||||
errorStack?: string,
|
||||
context?: string
|
||||
): Promise<string> {
|
||||
// Simple error analysis without AI - just return helpful debugging info
|
||||
const lines = ['## Error Analysis\n'];
|
||||
// Check if OpenAI API key is configured
|
||||
const apiKey = localStorage.getItem('openai_api_key');
|
||||
|
||||
lines.push('**Error Message:**');
|
||||
lines.push(`\`${errorMessage}\`\n`);
|
||||
|
||||
if (context) {
|
||||
lines.push('**Context:**');
|
||||
lines.push(`${context}\n`);
|
||||
}
|
||||
|
||||
if (errorStack) {
|
||||
lines.push('**Possible Solutions:**');
|
||||
if (!apiKey) {
|
||||
// Fallback to simple error analysis if no API key
|
||||
const lines = ['## Error Analysis\n'];
|
||||
|
||||
lines.push('**Error Message:**');
|
||||
lines.push(`\`${errorMessage}\`\n`);
|
||||
|
||||
if (context) {
|
||||
lines.push('**Context:**');
|
||||
lines.push(`${context}\n`);
|
||||
}
|
||||
|
||||
lines.push('**Note:** Configure your OpenAI API key in Settings to enable AI-powered error analysis.\n');
|
||||
|
||||
lines.push('**Basic Troubleshooting:**');
|
||||
lines.push('1. Check the browser console for more details');
|
||||
lines.push('2. Try refreshing the page');
|
||||
lines.push('3. Clear your browser cache and local storage\n');
|
||||
lines.push('3. Clear your browser cache and local storage');
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
// Use OpenAI API for advanced error analysis
|
||||
try {
|
||||
const contextInfo = context ? `\n\nContext: ${context}` : '';
|
||||
const stackInfo = errorStack ? `\n\nStack trace: ${errorStack}` : '';
|
||||
|
||||
const prompt = `You are a helpful debugging assistant for a code snippet manager app. Analyze this error and provide:
|
||||
|
||||
1. A clear explanation of what went wrong (in plain language)
|
||||
2. Why this error likely occurred
|
||||
3. 2-3 specific actionable steps to fix it
|
||||
|
||||
Error message: ${errorMessage}${contextInfo}${stackInfo}
|
||||
|
||||
Keep your response concise, friendly, and focused on practical solutions. Format your response with clear sections using markdown.`;
|
||||
|
||||
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'gpt-4o-mini',
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a helpful debugging assistant for a code snippet manager app.',
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: prompt,
|
||||
},
|
||||
],
|
||||
temperature: 0.7,
|
||||
max_tokens: 500,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`OpenAI API error: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.choices[0]?.message?.content || 'Unable to analyze error.';
|
||||
} catch (err) {
|
||||
console.error('Error calling OpenAI API:', err);
|
||||
|
||||
// Fallback to simple analysis if API call fails
|
||||
return `## Error Analysis
|
||||
|
||||
**Error Message:**
|
||||
\`${errorMessage}\`
|
||||
|
||||
**Note:** Failed to get AI analysis. ${err instanceof Error ? err.message : 'Unknown error'}
|
||||
|
||||
**Basic Troubleshooting:**
|
||||
1. Check the browser console for more details
|
||||
2. Try refreshing the page
|
||||
3. Verify your OpenAI API key in Settings`;
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
107
src/components/settings/OpenAISettingsCard.tsx
Normal file
107
src/components/settings/OpenAISettingsCard.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Eye, EyeClosed, Key } from '@phosphor-icons/react';
|
||||
|
||||
export function OpenAISettingsCard() {
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [showKey, setShowKey] = useState(false);
|
||||
const [saved, setSaved] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Load the API key from localStorage on mount
|
||||
const storedKey = localStorage.getItem('openai_api_key');
|
||||
if (storedKey) {
|
||||
setApiKey(storedKey);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleSave = () => {
|
||||
if (apiKey.trim()) {
|
||||
localStorage.setItem('openai_api_key', apiKey.trim());
|
||||
setSaved(true);
|
||||
setTimeout(() => setSaved(false), 2000);
|
||||
} else {
|
||||
localStorage.removeItem('openai_api_key');
|
||||
setSaved(true);
|
||||
setTimeout(() => setSaved(false), 2000);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClear = () => {
|
||||
setApiKey('');
|
||||
localStorage.removeItem('openai_api_key');
|
||||
setSaved(true);
|
||||
setTimeout(() => setSaved(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<Key className="h-5 w-5 text-primary" weight="duotone" />
|
||||
<CardTitle>OpenAI API Settings</CardTitle>
|
||||
</div>
|
||||
<CardDescription>
|
||||
Configure your OpenAI API key for AI-powered error analysis. Your key is stored locally in your browser.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="openai-key">OpenAI API Key</Label>
|
||||
<div className="flex gap-2">
|
||||
<div className="relative flex-1">
|
||||
<Input
|
||||
id="openai-key"
|
||||
type={showKey ? 'text' : 'password'}
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
placeholder="sk-..."
|
||||
className="pr-10"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowKey(!showKey)}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{showKey ? <EyeClosed size={18} /> : <Eye size={18} />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Get your API key from{' '}
|
||||
<a
|
||||
href="https://platform.openai.com/api-keys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
OpenAI Platform
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={handleSave} disabled={!apiKey.trim()}>
|
||||
{saved ? 'Saved!' : 'Save API Key'}
|
||||
</Button>
|
||||
{apiKey && (
|
||||
<Button onClick={handleClear} variant="outline">
|
||||
Clear
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{apiKey && (
|
||||
<div className="text-sm text-muted-foreground bg-muted/50 p-3 rounded-md">
|
||||
✓ API key is configured. Error analysis will use OpenAI GPT-4.
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user