1# AI Chat App
2
3A sleek, dark-themed AI chat application built with React on Val Town using the OpenAI API.
4
5## Features
7- React-based chat interface with component architecture
8- Elegant dark theme with purple/indigo accents
9- Powered by OpenAI's GPT models
10- Modern, responsive design with Tailwind CSS
11- TypeScript for type safety and better developer experience
18```
19โโโ backend/
20โ โโโ index.ts # Backend API with Hono and OpenAI integration
21โโโ frontend/
22โ โโโ components/ # React components
342. Messages are managed with React state
353. API requests are sent to the backend endpoint
364. The backend uses the OpenAI API to generate responses
375. Responses are formatted with enhanced markdown support and displayed in the chat interface
386. UI includes loading indicators and smooth animations for better user experience
44- **Tailwind CSS**: For styling without custom CSS files
45- **Hono**: Lightweight web framework for the backend
46- **OpenAI API**: For generating AI responses
47- **CSS Animations**: For smooth transitions and loading indicators
48
49## Requirements
50
51This app requires an OpenAI API key to be set as an environment variable in Val Town.
52
53## Setup
54
551. Fork this project in Val Town
562. Add your OpenAI API key as an environment variable named `OPENAI_API_KEY`
573. Run the project
58
61You can customize the app by:
62- Modifying React components to add new features
63- Changing the OpenAI model in the backend (currently using gpt-4o-mini)
64- Adjusting the max tokens parameter for longer or shorter responses
65- Modifying the color scheme by changing the Tailwind classes
1import { Hono } from "https://esm.sh/hono@3.12.6";
2import { cors } from "https://esm.sh/hono@3.12.6/cors";
3import { OpenAI } from "https://esm.town/v/std/openai";
4import { serveFile } from "https://esm.town/v/std/utils@85-main/index.ts";
5
15app.use("/*", cors());
16
17// Initialize OpenAI client
18const openai = new OpenAI();
19
20// API endpoint to handle chat requests
28 }
29
30 const completion = await openai.chat.completions.create({
31 messages,
32 model: "gpt-4o-mini", // Using a smaller model for cost efficiency
39 });
40 } catch (error) {
41 console.error("Error calling OpenAI:", error);
42 return c.json({ error: "Failed to process chat request" }, 500);
43 }
99 </div>
100 <h1 className="text-4xl font-bold text-center bg-clip-text text-transparent bg-gradient-to-r from-indigo-400 to-purple-500">AI Chat Assistant</h1>
101 <p className="text-center text-indigo-200 mt-2 opacity-80">Powered by OpenAI</p>
102 </header>
103
198 },
199 {
200 "title": "An Introduction to OpenAI fine-tuning",
201 "slug": "an-introduction-to-openai-fine-tuning",
202 "link": "/blog/an-introduction-to-openai-fine-tuning",
203 "description": "How to customize OpenAI to your liking",
204 "pubDate": "Fri, 25 Aug 2023 00:00:00 GMT",
205 "author": "Steve Krouse",
417 "slug": "val-town-newsletter-16",
418 "link": "/blog/val-town-newsletter-16",
419 "description": "Our seed round, growing team, Codeium completions, @std/openai, and more",
420 "pubDate": "Mon, 22 Apr 2024 00:00:00 GMT",
421 "author": "Steve Krouse",
137Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
138
139### OpenAI
140```ts
141import { OpenAI } from "https://esm.town/v/std/openai";
142const openai = new OpenAI();
143const completion = await openai.chat.completions.create({
144 messages: [
145 { role: "user", content: "Say hello in a creative way" },
198 },
199 {
200 "title": "An Introduction to OpenAI fine-tuning",
201 "slug": "an-introduction-to-openai-fine-tuning",
202 "link": "/blog/an-introduction-to-openai-fine-tuning",
203 "description": "How to customize OpenAI to your liking",
204 "pubDate": "Fri, 25 Aug 2023 00:00:00 GMT",
205 "author": "Steve Krouse",
417 "slug": "val-town-newsletter-16",
418 "link": "/blog/val-town-newsletter-16",
419 "description": "Our seed round, growing team, Codeium completions, @std/openai, and more",
420 "pubDate": "Mon, 22 Apr 2024 00:00:00 GMT",
421 "author": "Steve Krouse",
198 },
199 {
200 "title": "An Introduction to OpenAI fine-tuning",
201 "slug": "an-introduction-to-openai-fine-tuning",
202 "link": "/blog/an-introduction-to-openai-fine-tuning",
203 "description": "How to customize OpenAI to your liking",
204 "pubDate": "Fri, 25 Aug 2023 00:00:00 GMT",
205 "author": "Steve Krouse",
417 "slug": "val-town-newsletter-16",
418 "link": "/blog/val-town-newsletter-16",
419 "description": "Our seed round, growing team, Codeium completions, @std/openai, and more",
420 "pubDate": "Mon, 22 Apr 2024 00:00:00 GMT",
421 "author": "Steve Krouse",
198 },
199 {
200 "title": "An Introduction to OpenAI fine-tuning",
201 "slug": "an-introduction-to-openai-fine-tuning",
202 "link": "/blog/an-introduction-to-openai-fine-tuning",
203 "description": "How to customize OpenAI to your liking",
204 "pubDate": "Fri, 25 Aug 2023 00:00:00 GMT",
205 "author": "Steve Krouse",
417 "slug": "val-town-newsletter-16",
418 "link": "/blog/val-town-newsletter-16",
419 "description": "Our seed round, growing team, Codeium completions, @std/openai, and more",
420 "pubDate": "Mon, 22 Apr 2024 00:00:00 GMT",
421 "author": "Steve Krouse",
198 },
199 {
200 "title": "An Introduction to OpenAI fine-tuning",
201 "slug": "an-introduction-to-openai-fine-tuning",
202 "link": "/blog/an-introduction-to-openai-fine-tuning",
203 "description": "How to customize OpenAI to your liking",
204 "pubDate": "Fri, 25 Aug 2023 00:00:00 GMT",
205 "author": "Steve Krouse",
417 "slug": "val-town-newsletter-16",
418 "link": "/blog/val-town-newsletter-16",
419 "description": "Our seed round, growing team, Codeium completions, @std/openai, and more",
420 "pubDate": "Mon, 22 Apr 2024 00:00:00 GMT",
421 "author": "Steve Krouse",
137Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
138
139### OpenAI
140```ts
141import { OpenAI } from "https://esm.town/v/std/openai";
142const openai = new OpenAI();
143const completion = await openai.chat.completions.create({
144 messages: [
145 { role: "user", content: "Say hello in a creative way" },