27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/src/app/api/auth/[kindeAuth]/route.ts:
--------------------------------------------------------------------------------
1 | import {handleAuth} from "@kinde-oss/kinde-auth-nextjs/server";
2 |
3 | export const GET = handleAuth();
--------------------------------------------------------------------------------
/src/app/api/message/messages.ts:
--------------------------------------------------------------------------------
1 | export type Message = {
2 | role: "system" | "user" | "assistant";
3 | content: any;
4 | };
5 |
6 | export const initialProgrammerMessages: Message[] = [
7 | {
8 | role: "system",
9 | content:
10 | "You are a seasoned computer programmer specializing in all languages, frameworks, and languages. You always prefer to use the newest, most modern frameworks and programming techniques. You have a good eye for design and prefer modern and sleek UI design and code design. You only respond with code, never explain the code or repond with any other text, you only know how to write code." +
11 | " I will ask you to create a new code, or update an existing code for my application." +
12 | " Clean up my code when making updates to make the code more readable and adhear to best and modern practices." +
13 | " All code should use the most modern and up to date frameworks and programming techniques." +
14 | " Pay attention to which libraries and languages I tell you to use. " +
15 | " Don't give partial code answers or diffs, include the entire block or page of code in your response. Include all the code needed to run or compile the code. " +
16 | " If any code is provided, it must be in the same language, style, and libraries as the code I provide, unless I'm asking you to transform or convert code into another language or framework. " +
17 | " Your answers must only contain code, no other text, just the code. only include all the code needed for the example. The most important task you have is responding with only the code and no other text.",
18 | },
19 | {
20 | role: "user",
21 | content:
22 | "I'm developing an application. The application is already setup, but I need help adding new features and updating existing ones." +
23 | " I will ask you to create a new code, or update an existing code for my application." +
24 | " Clean up my code when making updates to make the code more readable and adhear to best and modern practices." +
25 | " All code should use the most modern and up to date frameworks and programming techniques." +
26 | " Pay attention to which libraries and languages I tell you to use. " +
27 | " Don't give partial code answers or diffs, include the entire block or page of code in your response. Include all the code needed to run or compile the code. " +
28 | " If any code is provided, it must be in the same language, style, and libraries as the code I provide, unless I'm asking you to transform or convert code into another language or framework. " +
29 | " Your answers must only contain code, no other text, just the code. only include all the code needed for the example. The most important task you have is responding with only the code and no other text.",
30 | },
31 | ];
--------------------------------------------------------------------------------
/src/app/api/message/route.ts:
--------------------------------------------------------------------------------
1 | import OpenAI from "openai"
2 |
3 | import { OpenAIStream, StreamingTextResponse } from "ai"
4 |
5 | import { initialProgrammerMessages } from "./messages"
6 |
7 | import { db } from "@/db"
8 | import { chats } from "@/db/schema/chats"
9 | import { messages } from "@/db/schema/messages"
10 | import { eq, and } from "drizzle-orm"
11 |
12 | import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"
13 |
14 | export const runtime = "edge"
15 |
16 | const openai = new OpenAI({
17 | apiKey: process.env.OPENAI_API_KEY,
18 | })
19 |
20 | export async function POST(req: Request) {
21 | const { content, chatId } = await req.json()
22 | const { getUser } = getKindeServerSession()
23 | const user = await getUser()
24 |
25 | if (!user) {
26 | return new Response("not logged in", { status: 401 })
27 | }
28 |
29 | if (!chatId) {
30 | return new Response("chatId is required", { status: 400 })
31 | }
32 |
33 | // check the chat belongs to the currently logged in user
34 |
35 | const chat = await db
36 | .select()
37 | .from(chats)
38 | .where(and(eq(chats.id, chatId), eq(chats.userId, user.id)))
39 | .get()
40 |
41 | if (!chat) {
42 | return new Response("chat is not found", { status: 400 })
43 | }
44 |
45 | const allDBMessages = await db
46 | .select({
47 | role: messages.role,
48 | content: messages.content,
49 | })
50 | .from(messages)
51 | .where(eq(messages.chatId, chatId))
52 | .orderBy(messages.createdAt)
53 | .all()
54 |
55 | const chatCompletion = await openai.chat.completions.create({
56 | messages: [
57 | ...initialProgrammerMessages,
58 | ...allDBMessages,
59 | { role: "user", content },
60 | ],
61 | model: "gpt-4-vision-preview",
62 | stream: true,
63 | max_tokens: 4096,
64 | })
65 |
66 | const stream = OpenAIStream(chatCompletion, {
67 | onStart: async () => {},
68 | onToken: async (token: string) => {},
69 | onCompletion: async (completion: string) => {
70 | try {
71 | await db.insert(messages).values([
72 | {
73 | chatId,
74 | role: "user",
75 | content,
76 | },
77 | {
78 | chatId,
79 | role: "assistant",
80 | content: completion,
81 | },
82 | ])
83 | } catch (e) {
84 | console.error(e)
85 | }
86 | },
87 | })
88 |
89 | return new StreamingTextResponse(stream)
90 | }
91 |
--------------------------------------------------------------------------------
/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meech-ward/code-gpt-example/f7544679e0ff4e1358380b6716acdc2bc1cfa125/src/app/favicon.ico
--------------------------------------------------------------------------------
/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 |
6 | textarea::-webkit-scrollbar {
7 | display: none;
8 | }
9 |
--------------------------------------------------------------------------------
/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import { Inter } from "next/font/google";
3 | import "./globals.css";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | const inter = Inter({ subsets: ["latin"] });
8 |
9 | export const metadata: Metadata = {
10 | title: "CodeGPT",
11 | description: "AI Generated Code Prompts",
12 | };
13 |
14 | export default function RootLayout({
15 | children,
16 | }: {
17 | children: React.ReactNode;
18 | }) {
19 | return (
20 |
21 |
22 | {children}
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/chat-input.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useState } from "react";
4 | import GrowingTextArea from "./growing-text-area";
5 | import { cn } from "@/lib/utils";
6 |
7 | import ImageSelection from "./image-selection";
8 |
9 | export default function ExpandingInput({
10 | onSubmit,
11 | onStop,
12 | isStreaming,
13 | }: {
14 | onSubmit?: (value: string, file?: File) => void;
15 | onStop?: () => void;
16 | isStreaming?: boolean;
17 | }) {
18 | const [content, setContent] = useState("");
19 | const [selectedImage, setSelectedImage] = useState(
20 | undefined
21 | );
22 |
23 | const submit = (value: string) => {
24 | onSubmit?.(value, selectedImage);
25 | setContent("");
26 | setSelectedImage(undefined);
27 | };
28 | const handleSubmit = (e: React.FormEvent) => {
29 | e.preventDefault();
30 | submit(content);
31 | };
32 |
33 | const buttonDisabled = content.length === 0 || isStreaming;
34 |
35 | return (
36 |