Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
GuiBibeau committed Sep 18, 2024
1 parent 7f925e0 commit df580eb
Show file tree
Hide file tree
Showing 23 changed files with 1,881 additions and 275 deletions.
175 changes: 175 additions & 0 deletions akeru-search.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
"use client";

import { useState, useEffect, useRef } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Search } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
} from "@/components/ui/card";

export default function Component() {
const [query, setQuery] = useState("");
const [isSearching, setIsSearching] = useState(false);
const [searchResults, setSearchResults] = useState([]);
const [summary, setSummary] = useState("");
const searchInputRef = useRef(null);

const handleSearch = async (e) => {
e.preventDefault();
if (!query.trim()) return;

setIsSearching(true);
setSearchResults([]);
setSummary("");

const encodedQuery = encodeURIComponent(query);
// Updated URL to use localhost:8080
const response = await fetch(
`http://localhost:8080/search?q=${encodedQuery}&stream=true`
);
const reader = response.body.getReader();
const decoder = new TextDecoder();

let buffer = "";
let jsonStarted = false;
let summaryStarted = false;

while (true) {
const { done, value } = await reader.read();
if (done) break;

buffer += decoder.decode(value, { stream: true });

while (buffer.includes("\n")) {
const lineEndIndex = buffer.indexOf("\n");
const line = buffer.slice(0, lineEndIndex).trim();
buffer = buffer.slice(lineEndIndex + 1);

if (line === "START_JSON") {
jsonStarted = true;
continue;
}

if (line === "END_JSON") {
jsonStarted = false;
continue;
}

if (line === "START_SUMMARY") {
summaryStarted = true;
continue;
}

if (line === "END_SUMMARY") {
summaryStarted = false;
continue;
}

if (jsonStarted) {
try {
const jsonData = JSON.parse(line);
setSearchResults((prevResults) => [...prevResults, ...jsonData]);
} catch (error) {
console.error("Error parsing JSON:", error);
}
}

if (summaryStarted) {
setSummary((prevSummary) => prevSummary + line + "\n");
}
}
}

setIsSearching(false);
};

useEffect(() => {
if (isSearching) {
searchInputRef.current.blur();
}
}, [isSearching]);

return (
<div className="min-h-screen bg-black-100 flex flex-col items-center p-4">
<motion.div
initial={false}
animate={{
top: isSearching ? "1rem" : "40%",
width: isSearching ? "100%" : "80%",
maxWidth: isSearching ? "800px" : "600px",
}}
transition={{ duration: 0.5 }}
className="fixed left-1/2 transform -translate-x-1/2 w-full max-w-2xl px-4"
>
<form onSubmit={handleSearch} className="relative">
<Input
ref={searchInputRef}
type="text"
placeholder="Ask anything..."
value={query}
onChange={(e) => setQuery(e.target.value)}
className="w-full py-3 pl-4 pr-12 text-lg rounded-full shadow-lg"
/>
<Button
type="submit"
size="icon"
className="absolute right-2 top-1/2 transform -translate-y-1/2"
>
<Search className="h-5 w-5" />
<span className="sr-only">Search</span>
</Button>
</form>
</motion.div>

<AnimatePresence>
{isSearching && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 20 }}
className="mt-24 w-full max-w-4xl"
>
<div className="mb-8">
<h2 className="text-2xl font-bold mb-4">Sources</h2>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{searchResults.map((result, index) => (
<Card key={index}>
<CardHeader>
<CardTitle className="text-lg">{result.title}</CardTitle>
<CardDescription>{result.source}</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-gray-600">{result.summary}</p>
<a
href={result.url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:underline mt-2 inline-block"
>
Read more
</a>
</CardContent>
</Card>
))}
</div>
</div>
<div>
<h2 className="text-2xl font-bold mb-4">Summary</h2>
<Card>
<CardContent>
<p className="whitespace-pre-wrap">{summary}</p>
</CardContent>
</Card>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
35 changes: 35 additions & 0 deletions app/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Search } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { redirect } from "next/navigation";

async function searchAction(formData: FormData) {
"use server";
const query = formData.get("query")?.toString();
if (query?.trim()) {
redirect(`/search?q=${encodeURIComponent(query)}`);
}
}

export function SearchBar() {
return (
<div className="fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-2xl px-4">
<form action={searchAction} className="relative">
<Input
name="query"
type="text"
placeholder="Ask anything..."
className="w-full py-4 pl-5 pr-14 text-xl rounded-full shadow-lg text-white border-2 border-gray-700 focus:border-gray-500"
/>
<Button
type="submit"
size="icon"
className="absolute right-2 top-1/2 transform -translate-y-1/2 bg-transparent hover:bg-transparent"
>
<Search className="h-6 w-6 text-white" />
<span className="sr-only">Search</span>
</Button>
</form>
</div>
);
}
26 changes: 26 additions & 0 deletions app/api/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const query = searchParams.get("q");
console.log("query", query);

if (!query) {
return NextResponse.json(
{ error: "Query parameter is required" },
{ status: 400 }
);
}

const encodedQuery = encodeURIComponent(query);
const response = await fetch(
`http://localhost:8080/search?q=${encodedQuery}&stream=true`,
{
headers: {
Authorization: `Bearer ${process.env.AGENTS_API_KEY}`,
},
}
);

return new NextResponse(response.body);
}
65 changes: 65 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,68 @@ body {
text-wrap: balance;
}
}

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 10% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}

@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
4 changes: 2 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en">
<html lang="en" className="dark">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
className={`${geistSans.variable} ${geistMono.variable} antialiased bg-black text-white`}
>
{children}
</body>
Expand Down
Loading

0 comments on commit df580eb

Please sign in to comment.