├── .bolt ├── config.json └── prompt ├── .gitignore ├── README.md ├── eslint.config.js ├── index.html ├── package-lock.json ├── package.json ├── postcss.config.js ├── src ├── App.tsx ├── components │ ├── ChatArea.tsx │ ├── ChatInput.tsx │ ├── MessageBubble.tsx │ ├── ModelSelector.tsx │ └── __tests__ │ │ ├── ChatInput.test.tsx │ │ ├── MessageBubble.test.tsx │ │ └── ModelSelector.test.tsx ├── data │ └── models.ts ├── hooks │ ├── __tests__ │ │ └── useChat.test.tsx │ └── useChat.ts ├── index.css ├── main.tsx ├── services │ ├── __tests__ │ │ └── aiService.test.ts │ └── aiService.ts ├── test │ └── setup.ts ├── types │ └── index.ts └── vite-env.d.ts ├── tailwind.config.js ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── vitest.config.ts /.bolt/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": "bolt-vite-react-ts" 3 | } 4 | -------------------------------------------------------------------------------- /.bolt/prompt: -------------------------------------------------------------------------------- 1 | For all designs I ask you to make, have them be beautiful, not cookie cutter. Make webpages that are fully featured and worthy for production. 2 | 3 | By default, this template supports JSX syntax with Tailwind CSS classes, React hooks, and Lucide React for icons. Do not install other packages for UI themes, icons, etc unless absolutely necessary or I request them. 4 | 5 | Use icons from lucide-react for logos. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .env 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AI Assistant Client 2 | 3 | A beautiful, production-ready AI assistant client built with React, TypeScript, and Tailwind CSS. This application provides an intuitive interface for interacting with various large language models through a modern chat interface. 4 | 5 | ## 🌟 Features 6 | 7 | - **Multi-Model Support**: Choose from various AI models including GPT-4, Claude 3, and Gemini Pro 8 | - **Modern Chat Interface**: Clean, responsive design with message bubbles and real-time updates 9 | - **Copy Functionality**: Easily copy AI responses to clipboard 10 | - **Model Information**: Detailed descriptions and capabilities for each AI model 11 | - **Responsive Design**: Optimized for desktop, tablet, and mobile devices 12 | - **Loading States**: Smooth loading animations and feedback 13 | - **Error Handling**: Graceful error handling with user-friendly messages 14 | - **TypeScript**: Full type safety throughout the application 15 | - **Comprehensive Testing**: Unit tests with React Testing Library and Vitest 16 | 17 | ## 🚀 Getting Started 18 | 19 | ### Prerequisites 20 | 21 | - Node.js 18+ 22 | - npm or yarn 23 | 24 | ### Installation 25 | 26 | 1. Clone the repository: 27 | ```bash 28 | git clone 29 | cd ai-assistant-client 30 | ``` 31 | 32 | 2. Install dependencies: 33 | ```bash 34 | npm install 35 | ``` 36 | 37 | 3. Start the development server: 38 | ```bash 39 | npm run dev 40 | ``` 41 | 42 | 4. Open your browser and navigate to `http://localhost:5173` 43 | 44 | ## 🛠️ Available Scripts 45 | 46 | - `npm run dev` - Start development server 47 | - `npm run build` - Build for production 48 | - `npm run preview` - Preview production build 49 | - `npm run test` - Run unit tests 50 | - `npm run test:ui` - Run tests with UI 51 | - `npm run test:coverage` - Run tests with coverage report 52 | - `npm run lint` - Run ESLint 53 | 54 | ## 🏗️ Project Structure 55 | 56 | ``` 57 | src/ 58 | ├── components/ # Reusable UI components 59 | │ ├── ChatArea.tsx # Main chat display area 60 | │ ├── ChatInput.tsx # Message input component 61 | │ ├── MessageBubble.tsx # Individual message display 62 | │ └── ModelSelector.tsx # AI model selection dropdown 63 | ├── data/ # Static data and configurations 64 | │ └── models.ts # Available AI models configuration 65 | ├── hooks/ # Custom React hooks 66 | │ └── useChat.ts # Chat state management hook 67 | ├── services/ # External service integrations 68 | │ └── aiService.ts # AI API service (mock implementation) 69 | ├── test/ # Test configuration and setup 70 | │ └── setup.ts # Test environment setup 71 | ├── types/ # TypeScript type definitions 72 | │ └── index.ts # Shared interfaces and types 73 | ├── App.tsx # Main application component 74 | ├── main.tsx # Application entry point 75 | └── index.css # Global styles 76 | ``` 77 | 78 | ## 🎨 Design System 79 | 80 | The application uses a carefully crafted design system with: 81 | 82 | - **Color Palette**: 83 | - Primary: Blue (#3B82F6) 84 | - Secondary: Indigo (#6366F1) 85 | - Accent: Emerald (#10B981) 86 | - Status colors for success, warning, and error states 87 | 88 | - **Typography**: Optimized font hierarchy with proper spacing 89 | - **Spacing**: Consistent 8px grid system 90 | - **Animations**: Smooth transitions and micro-interactions 91 | - **Glass Morphism**: Modern translucent effects with backdrop blur 92 | 93 | ## 🧪 Testing 94 | 95 | The project includes comprehensive testing setup: 96 | 97 | - **Unit Tests**: Component testing with React Testing Library 98 | - **Type Safety**: Full TypeScript coverage 99 | - **Test Coverage**: Detailed coverage reporting 100 | - **Mock Services**: Isolated testing with service mocks 101 | 102 | Run tests: 103 | ```bash 104 | # Run all tests 105 | npm run test 106 | 107 | # Run tests with UI 108 | npm run test:ui 109 | 110 | # Generate coverage report 111 | npm run test:coverage 112 | ``` 113 | 114 | ## 🔧 Configuration 115 | 116 | ### Adding New AI Models 117 | 118 | To add support for new AI models, update the `src/data/models.ts` file: 119 | 120 | ```typescript 121 | export const availableModels: AIModel[] = [ 122 | // ... existing models 123 | { 124 | id: 'new-model-id', 125 | name: 'New Model Name', 126 | description: 'Model description', 127 | provider: 'Provider Name', 128 | capabilities: ['Capability 1', 'Capability 2'] 129 | } 130 | ]; 131 | ``` 132 | 133 | ### Integrating Real AI APIs 134 | 135 | The current implementation uses a mock AI service. To integrate with real AI APIs: 136 | 137 | 1. Update `src/services/aiService.ts` with actual API endpoints 138 | 2. Add API keys to environment variables 139 | 3. Implement proper error handling and rate limiting 140 | 4. Update the response parsing logic 141 | 142 | Example integration: 143 | ```typescript 144 | // src/services/aiService.ts 145 | export class AIService { 146 | static async generateResponse(messages: Message[], model: string): Promise { 147 | const response = await fetch('/api/chat', { 148 | method: 'POST', 149 | headers: { 150 | 'Content-Type': 'application/json', 151 | 'Authorization': `Bearer ${process.env.VITE_API_KEY}` 152 | }, 153 | body: JSON.stringify({ messages, model }) 154 | }); 155 | 156 | const data = await response.json(); 157 | return data.content; 158 | } 159 | } 160 | ``` 161 | 162 | ## 🚀 Production Deployment 163 | 164 | 1. Build the application: 165 | ```bash 166 | npm run build 167 | ``` 168 | 169 | 2. Deploy the `dist` folder to your hosting provider: 170 | - Netlify 171 | - Vercel 172 | - AWS S3 + CloudFront 173 | - Traditional web hosting 174 | 175 | ## 🤝 Contributing 176 | 177 | 1. Fork the repository 178 | 2. Create a feature branch: `git checkout -b feature/new-feature` 179 | 3. Make your changes and add tests 180 | 4. Run tests: `npm run test` 181 | 5. Run linting: `npm run lint` 182 | 6. Commit your changes: `git commit -m 'Add new feature'` 183 | 7. Push to the branch: `git push origin feature/new-feature` 184 | 8. Submit a pull request 185 | 186 | ## 📝 License 187 | 188 | This project is licensed under the MIT License - see the LICENSE file for details. 189 | 190 | ## 🆘 Support 191 | 192 | For support and questions: 193 | 194 | 1. Check the documentation above 195 | 2. Review existing issues in the GitHub repository 196 | 3. Create a new issue if your problem isn't already documented 197 | 198 | ## 🔮 Future Enhancements 199 | 200 | - [ ] Real AI API integrations (OpenAI, Anthropic, Google) 201 | - [ ] Chat history persistence 202 | - [ ] Export chat conversations 203 | - [ ] Custom model configuration 204 | - [ ] Voice input/output 205 | - [ ] File upload support 206 | - [ ] Multi-language support 207 | - [ ] Dark/light theme toggle 208 | - [ ] Advanced formatting options 209 | - [ ] Plugin system for extensions -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import globals from 'globals'; 3 | import reactHooks from 'eslint-plugin-react-hooks'; 4 | import reactRefresh from 'eslint-plugin-react-refresh'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': [ 23 | 'warn', 24 | { allowConstantExport: true }, 25 | ], 26 | }, 27 | } 28 | ); 29 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | AI Assistant Client 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ai-assistant-client", 3 | "private": true, 4 | "version": "1.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview", 11 | "test": "vitest", 12 | "test:ui": "vitest --ui", 13 | "test:coverage": "vitest --coverage" 14 | }, 15 | "dependencies": { 16 | "lucide-react": "^0.344.0", 17 | "react": "^18.3.1", 18 | "react-dom": "^18.3.1" 19 | }, 20 | "devDependencies": { 21 | "@eslint/js": "^9.9.1", 22 | "@testing-library/jest-dom": "^6.1.4", 23 | "@testing-library/react": "^14.1.2", 24 | "@testing-library/user-event": "^14.5.1", 25 | "@types/react": "^18.3.5", 26 | "@types/react-dom": "^18.3.0", 27 | "@vitejs/plugin-react": "^4.3.1", 28 | "autoprefixer": "^10.4.18", 29 | "eslint": "^9.9.1", 30 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 31 | "eslint-plugin-react-refresh": "^0.4.11", 32 | "globals": "^15.9.0", 33 | "jsdom": "^23.0.1", 34 | "postcss": "^8.4.35", 35 | "tailwindcss": "^3.4.1", 36 | "typescript": "^5.5.3", 37 | "typescript-eslint": "^8.3.0", 38 | "vite": "^5.4.2", 39 | "vitest": "^1.0.4" 40 | } 41 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Trash2, Sparkles } from 'lucide-react'; 3 | import { ModelSelector } from './components/ModelSelector'; 4 | import { ChatArea } from './components/ChatArea'; 5 | import { ChatInput } from './components/ChatInput'; 6 | import { useChat } from './hooks/useChat'; 7 | import { availableModels } from './data/models'; 8 | 9 | function App() { 10 | const [selectedModel, setSelectedModel] = React.useState('gpt-4-turbo'); 11 | const { messages, isLoading, sendMessage, clearChat } = useChat(selectedModel); 12 | 13 | return ( 14 |
15 |
16 | {/* Header */} 17 |
18 |
19 |
20 | 21 |
22 |
23 |

AI Assistant

24 |

Choose your model and start chatting

25 |
26 |
27 | 28 | {messages.length > 0 && ( 29 | 37 | )} 38 |
39 | 40 | {/* Model Selection */} 41 |
42 | 47 |
48 | 49 | {/* Chat Container */} 50 |
51 | 52 | {/* Input Area */} 53 |
54 | 59 |
60 |
61 | 62 | {/* Footer */} 63 |
64 | AI Assistant Client v1.0 - Built with React & TypeScript 65 |
66 |
67 |
68 | ); 69 | } 70 | 71 | export default App; -------------------------------------------------------------------------------- /src/components/ChatArea.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { MessageBubble } from './MessageBubble'; 3 | import { Message } from '../types'; 4 | 5 | interface ChatAreaProps { 6 | messages: Message[]; 7 | isLoading?: boolean; 8 | } 9 | 10 | export const ChatArea: React.FC = ({ messages, isLoading }) => { 11 | const messagesEndRef = React.useRef(null); 12 | 13 | React.useEffect(() => { 14 | messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); 15 | }, [messages]); 16 | 17 | if (messages.length === 0) { 18 | return ( 19 |
20 |
21 |
🤖
22 |

Welcome to AI Assistant

23 |

24 | Select a model above and start a conversation. Ask me anything! 25 |

26 |
27 |
28 | ); 29 | } 30 | 31 | return ( 32 |
33 | {messages.map((message) => ( 34 | 35 | ))} 36 | 37 | {isLoading && ( 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | )} 51 | 52 |
53 |
54 | ); 55 | }; -------------------------------------------------------------------------------- /src/components/ChatInput.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Send, Loader2 } from 'lucide-react'; 3 | 4 | interface ChatInputProps { 5 | onSendMessage: (message: string) => void; 6 | disabled?: boolean; 7 | placeholder?: string; 8 | } 9 | 10 | export const ChatInput: React.FC = ({ 11 | onSendMessage, 12 | disabled = false, 13 | placeholder = "Type your message..." 14 | }) => { 15 | const [message, setMessage] = React.useState(''); 16 | const textareaRef = React.useRef(null); 17 | 18 | const handleSubmit = (e: React.FormEvent) => { 19 | e.preventDefault(); 20 | if (message.trim() && !disabled) { 21 | onSendMessage(message.trim()); 22 | setMessage(''); 23 | if (textareaRef.current) { 24 | textareaRef.current.style.height = 'auto'; 25 | } 26 | } 27 | }; 28 | 29 | const handleKeyDown = (e: React.KeyboardEvent) => { 30 | if (e.key === 'Enter' && !e.shiftKey) { 31 | e.preventDefault(); 32 | handleSubmit(e); 33 | } 34 | }; 35 | 36 | const adjustHeight = () => { 37 | const textarea = textareaRef.current; 38 | if (textarea) { 39 | textarea.style.height = 'auto'; 40 | textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px'; 41 | } 42 | }; 43 | 44 | React.useEffect(() => { 45 | adjustHeight(); 46 | }, [message]); 47 | 48 | return ( 49 |
50 |
51 |