forked from chainable-dev/the-front
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
824 additions
and
1,242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Development Notes | ||
|
||
## Linter Errors and TypeScript Issues | ||
|
||
We've encountered several TypeScript and linter errors in our components, particularly with `ChatModal.tsx` and `TopBar.tsx`. These errors are primarily related to the usage of Lucide icons and Next.js `Link` components. Here's a summary of the issues and potential solutions: | ||
|
||
### ChatModal.tsx | ||
|
||
1. Lucide icons (`X`, `ChevronDown`, `Send`) cannot be used directly as JSX components. | ||
Solution: Use `React.createElement` or update the import statement. | ||
|
||
```typescript | ||
import * as Icons from 'lucide-react'; | ||
|
||
// Then use like this: | ||
<Icons.X size={24} /> | ||
``` | ||
|
||
### TopBar.tsx | ||
|
||
1. Next.js `Link` component cannot be used directly as a JSX component. | ||
Solution: Wrap the `Link` component with an `a` tag or use the `legacyBehavior` prop. | ||
|
||
```typescript | ||
<Link href="/" passHref legacyBehavior> | ||
<a className="text-white hover:underline">Home</a> | ||
</Link> | ||
``` | ||
|
||
2. Lucide icons (`BarChart2`, `Settings`, `Bell`, `MessageCircle`) have the same issue as in ChatModal.tsx. | ||
Solution: Use the same approach as suggested for ChatModal.tsx. | ||
|
||
3. `ChatModal` component usage is causing a TypeScript error. | ||
Solution: Ensure that the `ChatModal` component is correctly typed and imported. | ||
|
||
## API Calls to Ollama | ||
|
||
When making API calls to Ollama, refer to the official API documentation: https://github.com/ollama/ollama/blob/main/docs/api.md | ||
|
||
Key points for API usage: | ||
|
||
1. Fetching available models: | ||
Endpoint: `GET http://localhost:11434/api/tags` | ||
|
||
2. Generating responses: | ||
Endpoint: `POST http://localhost:11434/api/generate` | ||
Body: | ||
```json | ||
{ | ||
"model": "selected_model_name", | ||
"prompt": "user_input", | ||
"stream": true | ||
} | ||
``` | ||
|
||
3. Ensure proper error handling and response parsing for streamed responses. | ||
|
||
4. Update the `fetchOllamaModels` and `handleSend` functions in `ChatModal.tsx` to use these endpoints correctly. | ||
|
||
Remember to handle CORS issues if they arise, possibly by setting up a proxy server or adjusting your Next.js API routes to forward requests to Ollama. | ||
|
||
## Next Steps | ||
|
||
1. Resolve TypeScript and linter errors by implementing the suggested solutions. | ||
2. Test the Ollama API integration thoroughly. | ||
3. Implement error handling for API calls. | ||
4. Consider adding a loading state while fetching models or generating responses. | ||
5. Optimize the chat interface for better user experience. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,212 +1,48 @@ | ||
//@ts-nocheck | ||
'use client'; | ||
|
||
import React, { useState } from 'react'; | ||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; | ||
import { Badge } from "@/components/ui/badge"; | ||
import React from 'react'; | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | ||
import { Bot, Plus } from 'lucide-react'; | ||
import { Button } from "@/components/ui/button"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Label } from "@/components/ui/label"; | ||
import { Textarea } from "@/components/ui/textarea"; | ||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; | ||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; | ||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; | ||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; | ||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; | ||
import { Bot, Code, Bug, Briefcase, Server, Plus, Edit, Trash2 } from 'lucide-react'; | ||
import DynamicWallpaper from '@/components/dynamic-wallpaper'; | ||
|
||
const initialAgents = [ | ||
{ id: 1, name: 'CodeMaster', role: 'Software Developer', expertise: 'Full-stack development', prompt: 'You are an expert full-stack developer. Provide detailed and efficient solutions to coding problems.', avatar: 'CM', icon: Code }, | ||
{ id: 2, name: 'BugHunter', role: 'QA Engineer', expertise: 'Test automation', prompt: 'You are a skilled QA engineer specializing in test automation. Identify potential issues and suggest comprehensive test strategies.', avatar: 'BH', icon: Bug }, | ||
{ id: 3, name: 'ProductGenius', role: 'Product Manager', expertise: 'Agile methodologies', prompt: 'You are an experienced product manager well-versed in agile methodologies. Provide insights on product strategy and feature prioritization.', avatar: 'PG', icon: Briefcase }, | ||
{ id: 4, name: 'InfraWizard', role: 'DevOps Engineer', expertise: 'Cloud infrastructure', prompt: 'You are a DevOps expert with deep knowledge of cloud infrastructure. Offer advice on optimizing deployment pipelines and infrastructure management.', avatar: 'IW', icon: Server }, | ||
const aiAgents = [ | ||
{ name: 'Task Scheduler', type: 'Productivity' }, | ||
{ name: 'Code Assistant', type: 'Development' }, | ||
{ name: 'Data Analyzer', type: 'Analytics' }, | ||
{ name: 'Customer Support Bot', type: 'Support' }, | ||
]; | ||
|
||
const initialTasks = [ | ||
{ id: 1, title: 'Implement user authentication', status: 'In Progress', assignedAgent: null }, | ||
{ id: 2, title: 'Design database schema', status: 'To Do', assignedAgent: null }, | ||
{ id: 3, title: 'Set up CI/CD pipeline', status: 'In Progress', assignedAgent: null }, | ||
{ id: 4, title: 'Create product roadmap', status: 'To Do', assignedAgent: null }, | ||
]; | ||
|
||
export default function AIAgentManagementDashboard() { | ||
const [agents, setAgents] = useState(initialAgents); | ||
const [tasks, setTasks] = useState(initialTasks); | ||
const [newAgent, setNewAgent] = useState({ name: '', role: '', expertise: '', prompt: '' }); | ||
const [editingAgent, setEditingAgent] = useState(null); | ||
|
||
const addAgent = () => { | ||
if (newAgent.name && newAgent.role && newAgent.expertise && newAgent.prompt) { | ||
setAgents([...agents, { ...newAgent, id: agents.length + 1, avatar: newAgent.name.substring(0, 2).toUpperCase(), icon: Bot }]); | ||
setNewAgent({ name: '', role: '', expertise: '', prompt: '' }); | ||
} | ||
}; | ||
|
||
const updateAgent = () => { | ||
if (editingAgent) { | ||
setAgents(agents.map(agent => | ||
agent.id === (editingAgent as typeof initialAgents[number]).id ? editingAgent : agent | ||
)); | ||
setEditingAgent(null); | ||
} | ||
}; | ||
|
||
const deleteAgent = (id: number | null) => { | ||
setAgents(agents.filter(agent => agent.id !== id)); | ||
setTasks(tasks.map(task => task.assignedAgent === id ? { ...task, assignedAgent: null } : task)); | ||
}; | ||
|
||
const assignAgentToTask = (taskId: number, agentId: number) => { | ||
setTasks(tasks.map(task => task.id === taskId ? { ...task, assignedAgent: agentId } : task)); | ||
}; | ||
|
||
export default function AIAgentsPage() { | ||
return ( | ||
<div className="container mx-auto py-10"> | ||
<h1 className="text-4xl font-bold mb-8">AI Agent Management Dashboard</h1> | ||
|
||
<Tabs defaultValue="agents" className="space-y-8"> | ||
<TabsList> | ||
<TabsTrigger value="agents">Agents</TabsTrigger> | ||
<TabsTrigger value="tasks">Tasks</TabsTrigger> | ||
</TabsList> | ||
|
||
<TabsContent value="agents"> | ||
<> | ||
<DynamicWallpaper primaryColor="cyan" secondaryColor="teal" /> | ||
<div className="min-h-screen p-8"> | ||
<div className="max-w-6xl mx-auto"> | ||
<div className="flex justify-between items-center mb-8"> | ||
<h1 className="text-4xl font-bold text-white">AI Agents</h1> | ||
<Button className="bg-cyan-600 hover:bg-cyan-700"> | ||
<Plus className="mr-2 h-4 w-4" /> | ||
Add Agent | ||
</Button> | ||
</div> | ||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> | ||
{agents.map((agent) => ( | ||
<Card key={agent.id}> | ||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> | ||
<CardTitle className="text-sm font-medium"> | ||
{aiAgents.map((agent, index) => ( | ||
<Card key={index} className="bg-gray-800 bg-opacity-80 backdrop-blur-sm border-gray-700"> | ||
<CardHeader> | ||
<CardTitle className="flex items-center text-cyan-400"> | ||
<Bot className="mr-2 h-6 w-6" /> | ||
{agent.name} | ||
</CardTitle> | ||
<Avatar> | ||
<AvatarImage src={`https://api.dicebear.com/6.x/initials/svg?seed=${agent.avatar}`} /> | ||
<AvatarFallback>{agent.avatar}</AvatarFallback> | ||
</Avatar> | ||
</CardHeader> | ||
<CardContent> | ||
<div className="text-sm">{agent.role}</div> | ||
<div className="text-sm text-muted-foreground">Expertise: {agent.expertise}</div> | ||
<div className="mt-2 text-xs text-muted-foreground">Prompt: {agent.prompt.substring(0, 100)}...</div> | ||
<p className="text-gray-300">Type: {agent.type}</p> | ||
</CardContent> | ||
<CardFooter className="flex justify-between"> | ||
<Dialog> | ||
<DialogTrigger asChild> | ||
<Button variant="outline" size="sm"> | ||
<Edit className="h-4 w-4 mr-2" /> Edit | ||
</Button> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>Edit Agent</DialogTitle> | ||
<DialogDescription>Make changes to the AI agent here.</DialogDescription> | ||
</DialogHeader> | ||
<div className="grid gap-4 py-4"> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="name" className="text-right">Name</Label> | ||
<Input id="name" value={editingAgent?.name} onChange={(e) => setEditingAgent({...editingAgent, name: e.target.value})} className="col-span-3" /> | ||
</div> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="role" className="text-right">Role</Label> | ||
<Input id="role" value={editingAgent?.role} onChange={(e) => setEditingAgent({...editingAgent, role: e.target.value})} className="col-span-3" /> | ||
</div> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="expertise" className="text-right">Expertise</Label> | ||
<Input id="expertise" value={editingAgent?.expertise} onChange={(e) => setEditingAgent({...editingAgent, expertise: e.target.value})} className="col-span-3" /> | ||
</div> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="prompt" className="text-right">Prompt</Label> | ||
<Textarea id="prompt" value={editingAgent?.prompt} onChange={(e) => setEditingAgent({...editingAgent, prompt: e.target.value})} className="col-span-3" /> | ||
</div> | ||
</div> | ||
<DialogFooter> | ||
<Button onClick={updateAgent}>Save changes</Button> | ||
</DialogFooter> | ||
</DialogContent> | ||
</Dialog> | ||
<Button variant="ghost" size="sm" onClick={() => deleteAgent(agent.id)}> | ||
<Trash2 className="h-4 w-4 mr-2" /> Delete | ||
</Button> | ||
</CardFooter> | ||
</Card> | ||
))} | ||
</div> | ||
|
||
<Card className="mt-6"> | ||
<CardHeader> | ||
<CardTitle>Add New AI Agent</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<div className="grid gap-4"> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="new-name" className="text-right">Name</Label> | ||
<Input id="new-name" value={newAgent.name} onChange={(e) => setNewAgent({...newAgent, name: e.target.value})} className="col-span-3" /> | ||
</div> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="new-role" className="text-right">Role</Label> | ||
<Input id="new-role" value={newAgent.role} onChange={(e) => setNewAgent({...newAgent, role: e.target.value})} className="col-span-3" /> | ||
</div> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="new-expertise" className="text-right">Expertise</Label> | ||
<Input id="new-expertise" value={newAgent.expertise} onChange={(e) => setNewAgent({...newAgent, expertise: e.target.value})} className="col-span-3" /> | ||
</div> | ||
<div className="grid grid-cols-4 items-center gap-4"> | ||
<Label htmlFor="new-prompt" className="text-right">Prompt</Label> | ||
<Textarea id="new-prompt" value={newAgent.prompt} onChange={(e) => setNewAgent({...newAgent, prompt: e.target.value})} className="col-span-3" /> | ||
</div> | ||
</div> | ||
</CardContent> | ||
<CardFooter> | ||
<Button onClick={addAgent}>Add Agent</Button> | ||
</CardFooter> | ||
</Card> | ||
</TabsContent> | ||
|
||
<TabsContent value="tasks"> | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Task Board</CardTitle> | ||
<CardDescription>Assign AI agents to tasks</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<Table> | ||
<TableHeader> | ||
<TableRow> | ||
<TableHead>Task</TableHead> | ||
<TableHead>Status</TableHead> | ||
<TableHead>Assigned Agent</TableHead> | ||
<TableHead>Action</TableHead> | ||
</TableRow> | ||
</TableHeader> | ||
<TableBody> | ||
{tasks.map((task) => ( | ||
<TableRow key={task.id}> | ||
<TableCell className="font-medium">{task.title}</TableCell> | ||
<TableCell> | ||
<Badge variant={task.status === 'In Progress' ? 'default' : 'secondary'}> | ||
{task.status} | ||
</Badge> | ||
</TableCell> | ||
<TableCell>{agents.find(agent => agent.id === task.assignedAgent)?.name || 'Unassigned'}</TableCell> | ||
<TableCell> | ||
<Select onValueChange={(value) => assignAgentToTask(task.id, parseInt(value))}> | ||
<SelectTrigger className="w-[180px]"> | ||
<SelectValue placeholder="Assign agent" /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
{agents.map((agent) => ( | ||
<SelectItem key={agent.id} value={agent.id.toString()}>{agent.name}</SelectItem> | ||
))} | ||
</SelectContent> | ||
</Select> | ||
</TableCell> | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
</Table> | ||
</CardContent> | ||
</Card> | ||
</TabsContent> | ||
</Tabs> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,33 @@ | ||
'use client'; | ||
|
||
import CostAnalytics from './cost-analytics' | ||
import AnalyticsDashboard from './analytics-dashboard' | ||
import React from 'react'; | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | ||
import { BarChart, LineChart, PieChart, TrendingUp } from 'lucide-react'; | ||
import DynamicWallpaper from '@/components/dynamic-wallpaper'; | ||
|
||
export default function AnalyticsPage() { | ||
return ( | ||
<div className="container mx-auto py-10"> | ||
<h1 className="text-4xl font-bold mb-8">Analytics Dashboard</h1> | ||
<AnalyticsDashboard /> | ||
<CostAnalytics /> | ||
</div> | ||
<> | ||
<DynamicWallpaper primaryColor="pink" secondaryColor="purple" /> | ||
<div className="min-h-screen p-8"> | ||
<div className="max-w-6xl mx-auto"> | ||
<h1 className="text-4xl font-bold mb-8 text-white">Analytics</h1> | ||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> | ||
<Card className="bg-gray-800 bg-opacity-80 backdrop-blur-sm border-gray-700"> | ||
<CardHeader> | ||
<CardTitle className="flex items-center text-pink-400"> | ||
<BarChart className="mr-2 h-6 w-6" /> | ||
Task Completion Rate | ||
</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<p className="text-2xl font-bold text-white">78%</p> | ||
</CardContent> | ||
</Card> | ||
{/* Repeat for other cards */} | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { NextResponse } from 'next/server'; | ||
|
||
export async function GET() { | ||
try { | ||
const response = await fetch('http://localhost:11434/api/tags'); | ||
const data = await response.json(); | ||
|
||
const models = data.models.map((model: any) => ({ | ||
name: model.name, | ||
size: model.size || 'Unknown' | ||
})); | ||
|
||
return NextResponse.json({ models }); | ||
} catch (error) { | ||
console.error('Error fetching Ollama models:', error); | ||
return NextResponse.json({ error: 'Failed to fetch Ollama models' }, { status: 500 }); | ||
} | ||
} |
Oops, something went wrong.