|
|
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 { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' |
|
|
import { |
|
|
Users, |
|
|
Star, |
|
|
Heart, |
|
|
Download, |
|
|
Copy, |
|
|
Sparkles, |
|
|
TrendingUp, |
|
|
Award |
|
|
} from 'lucide-react' |
|
|
|
|
|
|
|
|
interface CommunityTemplate { |
|
|
id: string |
|
|
name: string |
|
|
description: string |
|
|
author: string |
|
|
category: string |
|
|
tags: string[] |
|
|
model: string |
|
|
systemPrompt: string |
|
|
temperature: number |
|
|
maxTokens: number |
|
|
likes: number |
|
|
downloads: number |
|
|
isOfficial: boolean |
|
|
createdAt: string |
|
|
} |
|
|
|
|
|
|
|
|
function getCommunityTemplates(): CommunityTemplate[] { |
|
|
return [ |
|
|
{ |
|
|
id: 'code-reviewer', |
|
|
name: 'Code Review Expert', |
|
|
description: 'Professional code reviewer that provides detailed analysis, suggests improvements, and identifies potential issues.', |
|
|
author: 'EdgeLLM Team', |
|
|
category: 'coding', |
|
|
tags: ['code review', 'programming', 'best practices'], |
|
|
model: 'Qwen/Qwen3-30B-A3B', |
|
|
systemPrompt: 'You are a senior software engineer specializing in code review. Analyze the provided code for:\n\n1. **Code Quality**: Structure, readability, maintainability\n2. **Best Practices**: Following language conventions and patterns\n3. **Performance**: Potential optimizations and bottlenecks\n4. **Security**: Common vulnerabilities and security issues\n5. **Testing**: Testability and edge cases\n\nProvide constructive feedback with specific examples and actionable suggestions.', |
|
|
temperature: 0.3, |
|
|
maxTokens: 1500, |
|
|
likes: 245, |
|
|
downloads: 1200, |
|
|
isOfficial: true, |
|
|
createdAt: '2024-01-15' |
|
|
}, |
|
|
{ |
|
|
id: 'writing-tutor', |
|
|
name: 'Academic Writing Tutor', |
|
|
description: 'Helps improve academic writing with structure suggestions, grammar corrections, and clarity enhancements.', |
|
|
author: 'Academic Guild', |
|
|
category: 'writing', |
|
|
tags: ['academic writing', 'essay', 'research'], |
|
|
model: 'Qwen/Qwen3-30B-A3B', |
|
|
systemPrompt: 'You are an experienced academic writing tutor. Help users improve their writing by:\n\n1. **Structure & Organization**: Clear thesis, logical flow, proper transitions\n2. **Clarity & Precision**: Eliminate ambiguity, improve word choice\n3. **Academic Style**: Formal tone, appropriate citations, scholarly voice\n4. **Grammar & Mechanics**: Correct errors, improve sentence variety\n5. **Argument Development**: Strengthen evidence, address counterarguments\n\nProvide specific feedback with examples and rewrite suggestions where helpful.', |
|
|
temperature: 0.4, |
|
|
maxTokens: 1200, |
|
|
likes: 189, |
|
|
downloads: 856, |
|
|
isOfficial: false, |
|
|
createdAt: '2024-01-20' |
|
|
}, |
|
|
{ |
|
|
id: 'data-analyst', |
|
|
name: 'Data Analysis Assistant', |
|
|
description: 'Helps analyze data, create visualizations, and explain statistical concepts in simple terms.', |
|
|
author: 'DataPro', |
|
|
category: 'analysis', |
|
|
tags: ['data science', 'statistics', 'visualization'], |
|
|
model: 'Qwen/Qwen3-30B-A3B', |
|
|
systemPrompt: 'You are a data analysis expert. Help users understand and analyze data by:\n\n1. **Data Exploration**: Identify patterns, outliers, relationships\n2. **Statistical Analysis**: Apply appropriate tests, interpret results\n3. **Visualization**: Suggest effective charts and graphs\n4. **Insights**: Draw meaningful conclusions from data\n5. **Communication**: Explain complex concepts simply\n\nProvide step-by-step analysis and practical recommendations.', |
|
|
temperature: 0.2, |
|
|
maxTokens: 1000, |
|
|
likes: 156, |
|
|
downloads: 643, |
|
|
isOfficial: false, |
|
|
createdAt: '2024-01-25' |
|
|
}, |
|
|
{ |
|
|
id: 'creative-writer', |
|
|
name: 'Creative Writing Coach', |
|
|
description: 'Inspires creativity and helps develop compelling stories, characters, and narrative techniques.', |
|
|
author: 'StoryMaster', |
|
|
category: 'creative', |
|
|
tags: ['creative writing', 'storytelling', 'fiction'], |
|
|
model: 'Qwen/Qwen3-30B-A3B', |
|
|
systemPrompt: 'You are a creative writing coach with expertise in storytelling. Help writers by:\n\n1. **Story Development**: Plot structure, pacing, conflict resolution\n2. **Character Creation**: Compelling personalities, realistic dialogue, character arcs\n3. **World Building**: Consistent settings, atmosphere, details\n4. **Writing Techniques**: Show vs tell, point of view, voice\n5. **Inspiration**: Creative prompts, overcoming writer\'s block\n\nProvide encouraging feedback and concrete suggestions to enhance creativity.', |
|
|
temperature: 0.8, |
|
|
maxTokens: 1200, |
|
|
likes: 312, |
|
|
downloads: 987, |
|
|
isOfficial: false, |
|
|
createdAt: '2024-01-30' |
|
|
}, |
|
|
{ |
|
|
id: 'interview-prep', |
|
|
name: 'Interview Preparation Coach', |
|
|
description: 'Helps prepare for job interviews with practice questions, answer strategies, and confidence building.', |
|
|
author: 'CareerBoost', |
|
|
category: 'career', |
|
|
tags: ['interview', 'job search', 'career'], |
|
|
model: 'Qwen/Qwen3-30B-A3B', |
|
|
systemPrompt: 'You are a professional career coach specializing in interview preparation. Help candidates by:\n\n1. **Question Practice**: Common and behavioral interview questions\n2. **Answer Framework**: STAR method, structured responses\n3. **Company Research**: Industry insights, company-specific preparation\n4. **Confidence Building**: Reducing anxiety, improving presentation\n5. **Follow-up**: Thank you notes, next steps\n\nProvide personalized advice and realistic practice scenarios.', |
|
|
temperature: 0.5, |
|
|
maxTokens: 1000, |
|
|
likes: 278, |
|
|
downloads: 1456, |
|
|
isOfficial: true, |
|
|
createdAt: '2024-02-05' |
|
|
} |
|
|
] |
|
|
} |
|
|
|
|
|
export function Community() { |
|
|
const [communityTemplates] = useState<CommunityTemplate[]>(getCommunityTemplates()) |
|
|
const [likedTemplates, setLikedTemplates] = useState<string[]>([]) |
|
|
|
|
|
useEffect(() => { |
|
|
loadLikedTemplates() |
|
|
}, []) |
|
|
|
|
|
const loadLikedTemplates = () => { |
|
|
try { |
|
|
const liked = JSON.parse(localStorage.getItem('likedTemplates') || '[]') |
|
|
setLikedTemplates(liked) |
|
|
} catch (error) { |
|
|
console.error('Failed to load liked templates:', error) |
|
|
} |
|
|
} |
|
|
|
|
|
const toggleLikeTemplate = (templateId: string) => { |
|
|
const updatedLiked = likedTemplates.includes(templateId) |
|
|
? likedTemplates.filter(id => id !== templateId) |
|
|
: [...likedTemplates, templateId] |
|
|
|
|
|
setLikedTemplates(updatedLiked) |
|
|
localStorage.setItem('likedTemplates', JSON.stringify(updatedLiked)) |
|
|
} |
|
|
|
|
|
const useTemplate = (template: CommunityTemplate) => { |
|
|
const assistantConfig = { |
|
|
name: template.name, |
|
|
description: template.description, |
|
|
model: template.model, |
|
|
systemPrompt: template.systemPrompt, |
|
|
temperature: template.temperature, |
|
|
maxTokens: template.maxTokens |
|
|
} |
|
|
|
|
|
localStorage.setItem('loadAssistantConfig', JSON.stringify(assistantConfig)) |
|
|
window.location.href = '/playground' |
|
|
} |
|
|
|
|
|
const featuredTemplates = communityTemplates.filter(t => t.isOfficial || t.likes > 200) |
|
|
const totalLikes = communityTemplates.reduce((sum, t) => sum + t.likes, 0) |
|
|
const totalDownloads = communityTemplates.reduce((sum, t) => sum + t.downloads, 0) |
|
|
|
|
|
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-blue-600 rounded-lg flex items-center justify-center"> |
|
|
<Users className="h-5 w-5 text-white" /> |
|
|
</div> |
|
|
<div> |
|
|
<h1 className="text-2xl font-bold">Community Templates</h1> |
|
|
<p className="text-sm text-muted-foreground"> |
|
|
Discover and share AI assistant templates created by the community |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
<div className="flex items-center gap-4 text-sm text-muted-foreground"> |
|
|
<div className="flex items-center gap-1"> |
|
|
<Heart className="h-4 w-4" /> |
|
|
<span>{totalLikes.toLocaleString()} likes</span> |
|
|
</div> |
|
|
<div className="flex items-center gap-1"> |
|
|
<Download className="h-4 w-4" /> |
|
|
<span>{totalDownloads.toLocaleString()} downloads</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div className="flex-1 p-6"> |
|
|
<div className="max-w-6xl mx-auto space-y-6"> |
|
|
|
|
|
{/* Info Card */} |
|
|
<Card className="bg-blue-50 border-blue-200"> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-start gap-3"> |
|
|
<Sparkles className="h-5 w-5 text-blue-600 mt-0.5" /> |
|
|
<div> |
|
|
<h3 className="font-medium text-blue-900">Community-Powered AI</h3> |
|
|
<p className="text-sm text-blue-700 mt-1"> |
|
|
Explore specialized AI assistant templates created by experts and the community. |
|
|
Click "Use Template" to load any configuration directly into your Playground. |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
|
|
|
{/* Tabs */} |
|
|
<Tabs defaultValue="all" className="space-y-6"> |
|
|
<TabsList className="grid w-full grid-cols-3"> |
|
|
<TabsTrigger value="all" className="flex items-center gap-2"> |
|
|
<Users className="h-4 w-4" /> |
|
|
All Templates |
|
|
</TabsTrigger> |
|
|
<TabsTrigger value="featured" className="flex items-center gap-2"> |
|
|
<Star className="h-4 w-4" /> |
|
|
Featured |
|
|
</TabsTrigger> |
|
|
<TabsTrigger value="liked" className="flex items-center gap-2"> |
|
|
<Heart className="h-4 w-4" /> |
|
|
My Likes |
|
|
</TabsTrigger> |
|
|
</TabsList> |
|
|
|
|
|
{/* All Templates Tab */} |
|
|
<TabsContent value="all" className="space-y-6"> |
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
|
|
{communityTemplates.map((template) => ( |
|
|
<CommunityTemplateCard |
|
|
key={template.id} |
|
|
template={template} |
|
|
isLiked={likedTemplates.includes(template.id)} |
|
|
onLike={() => toggleLikeTemplate(template.id)} |
|
|
onUse={() => useTemplate(template)} |
|
|
/> |
|
|
))} |
|
|
</div> |
|
|
</TabsContent> |
|
|
|
|
|
{/* Featured Templates Tab */} |
|
|
<TabsContent value="featured" className="space-y-6"> |
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
|
|
{featuredTemplates.map((template) => ( |
|
|
<CommunityTemplateCard |
|
|
key={template.id} |
|
|
template={template} |
|
|
isLiked={likedTemplates.includes(template.id)} |
|
|
onLike={() => toggleLikeTemplate(template.id)} |
|
|
onUse={() => useTemplate(template)} |
|
|
featured={true} |
|
|
/> |
|
|
))} |
|
|
</div> |
|
|
</TabsContent> |
|
|
|
|
|
{/* Liked Templates Tab */} |
|
|
<TabsContent value="liked" className="space-y-6"> |
|
|
{likedTemplates.length > 0 ? ( |
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
|
|
{communityTemplates |
|
|
.filter(t => likedTemplates.includes(t.id)) |
|
|
.map((template) => ( |
|
|
<CommunityTemplateCard |
|
|
key={template.id} |
|
|
template={template} |
|
|
isLiked={true} |
|
|
onLike={() => toggleLikeTemplate(template.id)} |
|
|
onUse={() => useTemplate(template)} |
|
|
/> |
|
|
)) |
|
|
} |
|
|
</div> |
|
|
) : ( |
|
|
<Card className="text-center py-16"> |
|
|
<Heart className="h-16 w-16 mx-auto text-muted-foreground mb-6" /> |
|
|
<h3 className="text-xl font-medium mb-3">No liked templates yet</h3> |
|
|
<p className="text-muted-foreground mb-6 max-w-md mx-auto"> |
|
|
Explore the community templates and click the heart icon to save your favorites for easy access. |
|
|
</p> |
|
|
</Card> |
|
|
)} |
|
|
</TabsContent> |
|
|
</Tabs> |
|
|
|
|
|
{/* Stats Cards */} |
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6"> |
|
|
<Card> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-center justify-between"> |
|
|
<div> |
|
|
<div className="text-2xl font-bold text-blue-600"> |
|
|
{communityTemplates.length} |
|
|
</div> |
|
|
<div className="text-sm text-muted-foreground">Templates</div> |
|
|
</div> |
|
|
<Copy 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"> |
|
|
{communityTemplates.filter(t => t.isOfficial).length} |
|
|
</div> |
|
|
<div className="text-sm text-muted-foreground">Official</div> |
|
|
</div> |
|
|
<Award className="h-8 w-8 text-green-600" /> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
|
|
|
<Card> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-center justify-between"> |
|
|
<div> |
|
|
<div className="text-2xl font-bold text-red-500"> |
|
|
{totalLikes.toLocaleString()} |
|
|
</div> |
|
|
<div className="text-sm text-muted-foreground">Total Likes</div> |
|
|
</div> |
|
|
<Heart className="h-8 w-8 text-red-500" /> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
|
|
|
<Card> |
|
|
<CardContent className="pt-6"> |
|
|
<div className="flex items-center justify-between"> |
|
|
<div> |
|
|
<div className="text-2xl font-bold text-purple-600"> |
|
|
{totalDownloads.toLocaleString()} |
|
|
</div> |
|
|
<div className="text-sm text-muted-foreground">Downloads</div> |
|
|
</div> |
|
|
<TrendingUp className="h-8 w-8 text-purple-600" /> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
) |
|
|
} |
|
|
|
|
|
|
|
|
function CommunityTemplateCard({ |
|
|
template, |
|
|
isLiked, |
|
|
onLike, |
|
|
onUse, |
|
|
featured = false |
|
|
}: { |
|
|
template: CommunityTemplate |
|
|
isLiked: boolean |
|
|
onLike: () => void |
|
|
onUse: () => void |
|
|
featured?: boolean |
|
|
}) { |
|
|
return ( |
|
|
<Card className={`hover:shadow-lg transition-all duration-200 hover:-translate-y-1 ${featured ? 'ring-2 ring-yellow-200 shadow-md' : ''}`}> |
|
|
<CardHeader className="pb-3"> |
|
|
<div className="flex items-start justify-between"> |
|
|
<div className="flex-1"> |
|
|
<div className="flex items-center gap-2 mb-1"> |
|
|
<CardTitle className="text-base">{template.name}</CardTitle> |
|
|
{template.isOfficial && ( |
|
|
<Badge variant="default" className="text-xs px-2 py-0 bg-green-600"> |
|
|
<Award className="h-3 w-3 mr-1" /> |
|
|
Official |
|
|
</Badge> |
|
|
)} |
|
|
{featured && ( |
|
|
<Star className="h-4 w-4 text-yellow-500 fill-current" /> |
|
|
)} |
|
|
</div> |
|
|
<p className="text-xs text-blue-600 font-medium">by {template.author}</p> |
|
|
<p className="text-sm text-muted-foreground mt-2 line-clamp-2"> |
|
|
{template.description} |
|
|
</p> |
|
|
</div> |
|
|
<Button |
|
|
variant="ghost" |
|
|
size="sm" |
|
|
onClick={onLike} |
|
|
className={isLiked ? "text-red-500" : "text-muted-foreground hover:text-red-500"} |
|
|
title={isLiked ? "Unlike" : "Like"} |
|
|
> |
|
|
<Heart className={`h-4 w-4 ${isLiked ? 'fill-current' : ''}`} /> |
|
|
</Button> |
|
|
</div> |
|
|
</CardHeader> |
|
|
<CardContent className="space-y-4"> |
|
|
{/* Tags */} |
|
|
<div className="flex flex-wrap gap-1"> |
|
|
{template.tags.slice(0, 3).map((tag) => ( |
|
|
<Badge key={tag} variant="secondary" className="text-xs"> |
|
|
{tag} |
|
|
</Badge> |
|
|
))} |
|
|
</div> |
|
|
|
|
|
{/* Configuration */} |
|
|
<div className="grid grid-cols-2 gap-2 text-xs"> |
|
|
<div className="bg-gray-50 rounded p-2"> |
|
|
<span className="font-medium text-gray-600">Temperature:</span> |
|
|
<p className="text-gray-800">{template.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">{template.maxTokens}</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
{/* Stats & Action */} |
|
|
<div className="flex items-center justify-between"> |
|
|
<div className="flex items-center gap-4 text-xs text-muted-foreground"> |
|
|
<div className="flex items-center gap-1"> |
|
|
<Heart className="h-3 w-3" /> |
|
|
<span>{template.likes}</span> |
|
|
</div> |
|
|
<div className="flex items-center gap-1"> |
|
|
<Download className="h-3 w-3" /> |
|
|
<span>{template.downloads}</span> |
|
|
</div> |
|
|
</div> |
|
|
<Button size="sm" onClick={onUse} className="flex items-center gap-1"> |
|
|
<Copy className="h-3 w-3" /> |
|
|
Use |
|
|
</Button> |
|
|
</div> |
|
|
</CardContent> |
|
|
</Card> |
|
|
) |
|
|
} |
|
|
|