Skip to content

Commit

Permalink
fix chat
Browse files Browse the repository at this point in the history
  • Loading branch information
khaosans committed Oct 5, 2024
1 parent 5f0fdda commit 2d1053a
Show file tree
Hide file tree
Showing 20 changed files with 824 additions and 1,242 deletions.
68 changes: 68 additions & 0 deletions DEVELOPMENT_NOTES.md
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.
224 changes: 30 additions & 194 deletions app/ai-agents/page.tsx
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>
</>
);
}
33 changes: 26 additions & 7 deletions app/analytics/page.tsx
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>
</>
)
}
18 changes: 18 additions & 0 deletions app/api/ollama-models/route.ts
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 });
}
}
Loading

0 comments on commit 2d1053a

Please sign in to comment.