|
|
import { useState, useEffect } from 'react' |
|
|
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card' |
|
|
import { Button } from '@/components/ui/button' |
|
|
import { Badge } from '@/components/ui/badge' |
|
|
import { |
|
|
Bot, |
|
|
MessageSquare, |
|
|
Trash2, |
|
|
Share, |
|
|
Plus, |
|
|
Sparkles |
|
|
} from 'lucide-react' |
|
|
|
|
|
export function Assistants() { |
|
|
const [savedAssistants, setSavedAssistants] = useState<any[]>([]) |
|
|
|
|
|
useEffect(() => { |
|
|
loadSavedAssistants() |
|
|
}, []) |
|
|
|
|
|
const loadSavedAssistants = () => { |
|
|
try { |
|
|
const assistants = JSON.parse(localStorage.getItem('savedAssistants') || '[]') |
|
|
setSavedAssistants(assistants) |
|
|
} catch (error) { |
|
|
console.error('Failed to load assistants:', error) |
|
|
} |
|
|
} |
|
|
|
|
|
const loadAssistant = (assistant: any) => { |
|
|
localStorage.setItem('loadAssistantConfig', JSON.stringify(assistant)) |
|
|
window.location.href = '/playground' |
|
|
} |
|
|
|
|
|
const deleteAssistant = (assistantId: string) => { |
|
|
const updatedAssistants = savedAssistants.filter(a => a.id !== assistantId) |
|
|
setSavedAssistants(updatedAssistants) |
|
|
localStorage.setItem('savedAssistants', JSON.stringify(updatedAssistants)) |
|
|
} |
|
|
|
|
|
const shareMyAssistant = (assistant: any) => { |
|
|
alert(`"${assistant.name}" has been shared to the community! (This is a demo - in production, it would be submitted for review.)`) |
|
|
} |
|
|
|
|
|
const createNewAssistant = () => { |
|
|
window.location.href = '/playground' |
|
|
} |
|
|
|
|
|
return ( |
|
|
<div className="min-h-screen bg-background"> |
|
|
{/* Header */} |
|
|
<div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60"> |
|
|
<div className="max-w-6xl mx-auto p-6"> |
|
|
<div className="flex items-center justify-between"> |
|
|
<div className="flex items-center gap-3"> |
|
|
<div className="w-8 h-8 bg-purple-600 rounded-lg flex items-center justify-center"> |
|
|
<Bot className="h-5 w-5 text-white" /> |
|
|
</div> |
|
|
<div> |
|
|
<h1 className="text-2xl font-bold">My Assistants</h1> |
|
|
<p className="text-sm text-muted-foreground"> |
|
|
Manage your custom AI assistants and configurations |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
<Button onClick={createNewAssistant} className="flex items-center gap-2"> |
|
|
<Plus className="h-4 w-4" /> |
|
|
Create New Assistant |
|
|
</Button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div className="flex-1 p-6"> |
|
|
<div className="max-w-6xl mx-auto space-y-6"> |
|
|
|
|
|
{/* Info Card */} |
|
|
<Card className="bg-purple-50 border-purple-200"> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-start gap-3"> |
|
|
<Sparkles className="h-5 w-5 text-purple-600 mt-0.5" /> |
|
|
<div> |
|
|
<h3 className="font-medium text-purple-900">Custom AI Assistants</h3> |
|
|
<p className="text-sm text-purple-700 mt-1"> |
|
|
Create specialized AI assistants by configuring models, prompts, and parameters in the Playground. |
|
|
Save different configurations for various tasks and workflows. |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
|
|
|
{/* Assistants Grid */} |
|
|
{savedAssistants.length > 0 ? ( |
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
|
|
{savedAssistants.map((assistant) => ( |
|
|
<AssistantCard |
|
|
key={assistant.id} |
|
|
assistant={assistant} |
|
|
onUse={() => loadAssistant(assistant)} |
|
|
onDelete={() => deleteAssistant(assistant.id)} |
|
|
onShare={() => shareMyAssistant(assistant)} |
|
|
/> |
|
|
))} |
|
|
</div> |
|
|
) : ( |
|
|
<Card className="text-center py-16"> |
|
|
<Bot className="h-16 w-16 mx-auto text-muted-foreground mb-6" /> |
|
|
<h3 className="text-xl font-medium mb-3">No assistants yet</h3> |
|
|
<p className="text-muted-foreground mb-6 max-w-md mx-auto"> |
|
|
Create your first AI assistant by configuring parameters and prompts in the Playground, |
|
|
then saving your configuration for future use. |
|
|
</p> |
|
|
<Button onClick={createNewAssistant} size="lg" className="flex items-center gap-2 mx-auto"> |
|
|
<Plus className="h-5 w-5" /> |
|
|
Create Your First Assistant |
|
|
</Button> |
|
|
</Card> |
|
|
)} |
|
|
|
|
|
{/* Stats Cards */} |
|
|
{savedAssistants.length > 0 && ( |
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> |
|
|
<Card> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-center justify-between"> |
|
|
<div> |
|
|
<div className="text-2xl font-bold text-purple-600"> |
|
|
{savedAssistants.length} |
|
|
</div> |
|
|
<div className="text-sm text-muted-foreground">Total Assistants</div> |
|
|
</div> |
|
|
<Bot className="h-8 w-8 text-purple-600" /> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
|
|
|
<Card> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-center justify-between"> |
|
|
<div> |
|
|
<div className="text-2xl font-bold text-blue-600"> |
|
|
{new Set(savedAssistants.map(a => a.model)).size} |
|
|
</div> |
|
|
<div className="text-sm text-muted-foreground">Models Used</div> |
|
|
</div> |
|
|
<MessageSquare className="h-8 w-8 text-blue-600" /> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
|
|
|
<Card> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-center justify-between"> |
|
|
<div> |
|
|
<div className="text-2xl font-bold text-green-600"> |
|
|
{savedAssistants.filter(a => a.createdAt && |
|
|
new Date(a.createdAt) > new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) |
|
|
).length} |
|
|
</div> |
|
|
<div className="text-sm text-muted-foreground">Created This Week</div> |
|
|
</div> |
|
|
<Sparkles className="h-8 w-8 text-green-600" /> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
</div> |
|
|
)} |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
) |
|
|
} |
|
|
|
|
|
|
|
|
function AssistantCard({ |
|
|
assistant, |
|
|
onUse, |
|
|
onDelete, |
|
|
onShare |
|
|
}: { |
|
|
assistant: any |
|
|
onUse: () => void |
|
|
onDelete: () => void |
|
|
onShare: () => void |
|
|
}) { |
|
|
return ( |
|
|
<Card className="hover:shadow-lg transition-all duration-200 hover:-translate-y-1"> |
|
|
<CardHeader className="pb-3"> |
|
|
<div className="flex items-start justify-between"> |
|
|
<div className="flex-1"> |
|
|
<CardTitle className="text-base flex items-center gap-2"> |
|
|
<Bot className="h-4 w-4 text-purple-600" /> |
|
|
{assistant.name} |
|
|
</CardTitle> |
|
|
<p className="text-sm text-muted-foreground mt-1"> |
|
|
{assistant.description || 'No description provided'} |
|
|
</p> |
|
|
</div> |
|
|
<div className="flex gap-1"> |
|
|
<Button |
|
|
variant="ghost" |
|
|
size="sm" |
|
|
onClick={onShare} |
|
|
className="text-blue-600 hover:text-blue-700 hover:bg-blue-50" |
|
|
title="Share to community" |
|
|
> |
|
|
<Share className="h-4 w-4" /> |
|
|
</Button> |
|
|
<Button |
|
|
variant="ghost" |
|
|
size="sm" |
|
|
onClick={onDelete} |
|
|
className="text-red-500 hover:text-red-600 hover:bg-red-50" |
|
|
title="Delete assistant" |
|
|
> |
|
|
<Trash2 className="h-4 w-4" /> |
|
|
</Button> |
|
|
</div> |
|
|
</div> |
|
|
</CardHeader> |
|
|
<CardContent className="space-y-4"> |
|
|
{/* Configuration Details */} |
|
|
<div className="grid grid-cols-2 gap-3 text-xs"> |
|
|
<div className="bg-gray-50 rounded p-2"> |
|
|
<span className="font-medium text-gray-600">Model:</span> |
|
|
<p className="text-gray-800 truncate">{assistant.model}</p> |
|
|
</div> |
|
|
<div className="bg-gray-50 rounded p-2"> |
|
|
<span className="font-medium text-gray-600">Temperature:</span> |
|
|
<p className="text-gray-800">{assistant.temperature}</p> |
|
|
</div> |
|
|
<div className="bg-gray-50 rounded p-2"> |
|
|
<span className="font-medium text-gray-600">Max Tokens:</span> |
|
|
<p className="text-gray-800">{assistant.maxTokens}</p> |
|
|
</div> |
|
|
<div className="bg-gray-50 rounded p-2"> |
|
|
<span className="font-medium text-gray-600">Created:</span> |
|
|
<p className="text-gray-800">{new Date(assistant.createdAt).toLocaleDateString()}</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
{/* System Prompt Preview */} |
|
|
{assistant.systemPrompt && ( |
|
|
<div className="bg-blue-50 rounded p-2"> |
|
|
<span className="text-xs font-medium text-blue-700">System Prompt:</span> |
|
|
<p className="text-xs text-blue-600 mt-1 line-clamp-2"> |
|
|
{assistant.systemPrompt} |
|
|
</p> |
|
|
</div> |
|
|
)} |
|
|
|
|
|
{/* Action Button */} |
|
|
<Button onClick={onUse} className="w-full flex items-center gap-2"> |
|
|
<MessageSquare className="h-4 w-4" /> |
|
|
Use Assistant |
|
|
</Button> |
|
|
</CardContent> |
|
|
</Card> |
|
|
) |
|
|
} |
|
|
|