Skip to content

Commit

Permalink
Merge pull request #12 from vhpx/main
Browse files Browse the repository at this point in the history
feat: add basic gemini chat and test cases page
  • Loading branch information
vhpx committed Apr 17, 2024
2 parents a4f005c + b5eb1c9 commit 831fb88
Show file tree
Hide file tree
Showing 12 changed files with 6,285 additions and 0 deletions.
35 changes: 35 additions & 0 deletions app/api/chat/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { GoogleGenerativeAI } from '@google/generative-ai';
import { GoogleGenerativeAIStream, Message, StreamingTextResponse } from 'ai';

const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY || '');

// IMPORTANT! Set the runtime to edge
export const runtime = 'edge';

// convert messages from the Vercel AI SDK Format to the format
// that is expected by the Google GenAI SDK
const buildGoogleGenAIPrompt = (messages: Message[]) => ({
contents: messages
.filter(
(message) => message.role === 'user' || message.role === 'assistant'
)
.map((message) => ({
role: message.role === 'user' ? 'user' : 'model',
parts: [{ text: message.content }],
})),
});

export async function POST(req: Request) {
// Extract the `prompt` from the body of the request
const { messages } = await req.json();

const geminiStream = await genAI
.getGenerativeModel({ model: 'gemini-pro' })
.generateContentStream(buildGoogleGenAIPrompt(messages));

// Convert the response into a friendly text-stream
const stream = GoogleGenerativeAIStream(geminiStream);

// Respond with the stream
return new StreamingTextResponse(stream);
}
26 changes: 26 additions & 0 deletions app/chat/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use client';

import { useChat } from 'ai/react';

export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();

return (
<div>
{messages.map((m) => (
<div key={m.id}>
{m.role === 'user' ? 'User: ' : 'AI: '}
{m.content}
</div>
))}

<form onSubmit={handleSubmit}>
<input
value={input}
placeholder="Say something..."
onChange={handleInputChange}
/>
</form>
</div>
);
}
53 changes: 53 additions & 0 deletions app/tests/components/CollapsedLine.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
function CollapsedLine({
line,
open,
index,
handleOpen,
startLine,
}: {
line: string;
open: boolean;
index: number;
handleOpen: () => void;
startLine: number;
}) {
const isHead = index === 0;
return (
<div
className={`${
isHead || open ? "" : " hidden "
} w-full flex items-center gap-1 hover:bg-gray-800`}
onClick={() => isHead && handleOpen()}
>
<a className="text-slate-300 underline hover:text-blue-500 cursor-pointer flex justify-end w-6 md:w-8 lg:w-10 shrink-0 self-start">
{startLine + index}
</a>
{isHead && (
<svg
className={`flex-shrink-0 ${
open ? "rotate-90" : ""
} transition-transform`}
viewBox="0 0 16 16"
width="16"
height="16"
aria-hidden="false"
>
<path
className="fill-slate-200"
fill-rule="evenodd"
d="M6.22 3.22a.75.75 0 011.06 0l4.25 4.25a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 010-1.06z"
></path>
</svg>
)}
<span
className={`${
isHead ? "cursor-pointer " : "pl-5"
} flex items-center w-full `}
>
{line}
</span>
</div>
);
}

export default CollapsedLine;
47 changes: 47 additions & 0 deletions app/tests/components/TestBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useState } from "react";
import CollapsedLine from "./CollapsedLine";

function TestBlock({
block,
}: {
block: {
collapsed: boolean;
lineContent: string[];
startLine: number;
};
}) {
const [open, setOpen] = useState(false);
const handleOpen = () => {
setOpen(!open);
};
return (
<>
{block.collapsed ? (
block.lineContent.map((line, index) => (
<CollapsedLine
line={line}
open={open}
index={index}
handleOpen={handleOpen}
startLine={block.startLine}
/>
))
) : (
<div className="w-full flex gap-1 lg:gap-1.5 hover:bg-gray-800">
<a className="text-slate-300 underline hover:text-blue-500 cursor-pointer flex justify-end w-6 md:w-8 lg:w-10 shrink-0">
{block.startLine}
</a>
<span
className={`${
block.collapsed ? "cursor-pointer" : ""
} flex items-center w-full `}
>
{block.lineContent}
</span>
</div>
)}
</>
);
}

export default TestBlock;
27 changes: 27 additions & 0 deletions app/tests/components/TestBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import TestBlock from "./TestBlock";

function TestBody({
open,
content,
}: {
open: boolean;
content: {
collapsed: boolean;
lineContent: string[];
startLine: number;
}[];
}) {
return (
<div
className={`${
open ? "" : "hidden"
} w-full h-fit p-1 m-1 mb-3 text-xs lg:text-sm flex flex-col items-center rounded-md text-slate-200`}
>
{content.map((block, index) => (
<TestBlock block={block} key={index} />
))}
</div>
);
}

export default TestBody;
30 changes: 30 additions & 0 deletions app/tests/components/TestComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useState } from "react";
import TestHeader from "./TestHeader";
import TestBody from "./TestBody";

function TestComponents({
testInfo,
}: {
testInfo: {
name: string;
content: {
collapsed: boolean;
lineContent: string[];
startLine: number;
}[];
};
}) {
const [open, setOpen] = useState(false);
const handleOpen = () => {
// alert(open);
setOpen(!open);
};
return (
<div className="w-full md:w-4/5 lg:w-3/5 flex flex-col">
<TestHeader open={open} handleOpen={handleOpen} name={testInfo.name} />
<TestBody open={open} content={testInfo.content} />
</div>
);
}

export default TestComponents;
49 changes: 49 additions & 0 deletions app/tests/components/TestHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
function TestHeader({
open,
handleOpen,
name,
}: {
open: boolean;
handleOpen: () => void;
name: string;
}) {
return (
<div
onClick={() => handleOpen()}
className={`${
open ? "bg-slate-800" : ""
} w-full h-8 lg:h-9 lg:px-4 text-sm lg:text-base flex gap-1 md:gap-2 lg:gap-3 items-center hover:bg-slate-800 rounded-md transition-all text-slate-200 cursor-pointer`}
>
<svg
className={`flex-shrink-0 ${
open ? "rotate-90" : ""
} transition-transform`}
viewBox="0 0 16 16"
width="16"
height="16"
aria-hidden="false"
>
<path
className="fill-slate-200"
fill-rule="evenodd"
d="M6.22 3.22a.75.75 0 011.06 0l4.25 4.25a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 010-1.06z"
></path>
</svg>
<svg
className=" flex-shrink-0 mr-1"
viewBox="0 0 16 16"
width="16"
height="16"
aria-hidden="true"
>
<path
className="fill-slate-200"
d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm3.78-9.72a.751.751 0 0 0-.018-1.042.751.751 0 0 0-1.042-.018L6.75 9.19 5.28 7.72a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042l2 2a.75.75 0 0 0 1.06 0Z"
></path>
</svg>
<span className="flex items-center">{name}</span>
</div>
);
}

export default TestHeader;
53 changes: 53 additions & 0 deletions app/tests/data/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// simulate data from backend
export const data = new Array(10).fill(0).map((_, i) => ({
name: `Test ${i + 1}`,
content:
[
{
collapsed: false,
startLine: 1,
lineContent: "Lorem ipsum",
},
{
collapsed: true,
startLine: 2,
lineContent: [
"dolor sit amet",
"consectetur adipisicing elit.",
"Lorem ipsum dolor sit amet consectetur adipisicing elit.Dolor voluptatibus ea quasi illum pariatur aspernatur.Alias quia mollitia voluptatum modi consequuntur, eveniet Lorem ipsum dolor sit ai consequuntur, eveniet "
]
},
{
collapsed: false,
startLine: 5,
lineContent: "Dolor voluptatibus ea quasi illum pariatur aspernatur."
}
]
}));
/*
content:
[
{
collapsed: false,
startLine: 1,
lineContent: "Lorem ipsum",
},
{
collapsed: true,
startLine: 2,
lineContent: [
"dolor sit amet",
"consectetur adipisicing elit.",
"Lorem ipsum dolor sit amet consectetur adipisicing elit.Dolor voluptatibus ea quasi illum pariatur aspernatur.Alias quia mollitia voluptatum modi consequuntur, eveniet Lorem ipsum dolor sit amet consectetur adipisicing elit.Dolor voluptatibus ea quasi illum pariatur aspernatur.Alias quia mollitia voluptatum modi consequuntur, eveniet "
]
},
{
collapsed: false,
startLine: 5,
lineContent: "Dolor voluptatibus ea quasi illum pariatur aspernatur."
}
]
content: "Lorem ipsum dolor sit amet consectetur adipisicing elit.Dolor voluptatibus ea quasi illum pariatur aspernatur.Alias quia mollitia voluptatum modi consequuntur, eveniet ullam blanditiis maxime cumque iure.Magni sapiente a omnis voluptatibus eos.Placeat dolor necessitatibus ut officiis consequuntur vitae repudiandae, tempore ducimus fuga in, quis accusamus facilis libero.Dolores."
*/

19 changes: 19 additions & 0 deletions app/tests/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";

import TestComponent from "./components/TestComponent";
import { data } from "./data/data";

function page() {
return (
<div className="p-2 md:p-6 flex flex-col gap-2 bg-black w-full h-screen overflow-auto items-center">
<h1 className="text-xl md:text-2xl flex items-center text-white md:m-2 lg:m-3">
Test for branch X
</h1>
{data.map((_: any, i) => (
<TestComponent testInfo={_} />
))}
</div>
);
}

export default page;
Loading

1 comment on commit 831fb88

@vercel
Copy link

@vercel vercel bot commented on 831fb88 Apr 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.