diff --git a/backend/routes/ai.ts b/backend/routes/ai.ts index c7d63fba..44c224ad 100644 --- a/backend/routes/ai.ts +++ b/backend/routes/ai.ts @@ -143,7 +143,7 @@ router.post("/chat", authMiddleware, async (req, res) => { data: { id: conversationId, userId, - title: data.message.slice(0, 20) + "...", + title: data.message.slice(0, 35) + "...", type: "CONVERSATION", externalId: conversationId } diff --git a/frontend/app/(app)/apps/[id]/page.tsx b/frontend/app/(app)/apps/[id]/page.tsx index 3c941ee7..b7a18afd 100644 --- a/frontend/app/(app)/apps/[id]/page.tsx +++ b/frontend/app/(app)/apps/[id]/page.tsx @@ -2,7 +2,8 @@ import React, { useState, useRef } from "react"; import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; -import { ArrowUpIcon, SpinnerGapIcon, CopyIcon, CheckIcon } from "@phosphor-icons/react"; +import { SpinnerGapIcon, CopyIcon, CheckIcon } from "@phosphor-icons/react"; +import { ArrowUpIcon } from "lucide-react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import SyntaxHighlighter from "react-syntax-highlighter"; @@ -12,7 +13,26 @@ import { cn } from "@/lib/utils"; import { useUser } from "@/hooks/useUser"; import { useRouter } from "next/navigation"; -const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL ?? "http://localhost:3000"; +const BACKEND_URL = + process.env.NEXT_PUBLIC_BACKEND_URL ?? "http://localhost:3000"; + +const articleFeatures: { + id: number; + title: string; +}[] = [ + { + id: 1, + title: "Summarize articles instantly", + }, + { + id: 2, + title: "Turn long reads into key insights", + }, + { + id: 3, + title: "Get clear, concise summaries", + }, +]; interface AppPageProps { params: Promise<{ id: string }>; @@ -22,6 +42,7 @@ export default function AppPage({ params }: AppPageProps) { const [appId, setAppId] = React.useState(""); const [input, setInput] = useState(""); const [response, setResponse] = useState(""); + const [showWelcome, setShowWelcome] = useState(true); const [isLoading, setIsLoading] = useState(false); const [copied, setCopied] = useState(false); const [error, setError] = useState(null); @@ -93,17 +114,19 @@ export default function AppPage({ params }: AppPageProps) { try { const parsedData = JSON.parse(data); if (parsedData.error) { - setResponse(prev => prev + `Error: ${parsedData.error}\n`); + setResponse( + (prev) => prev + `Error: ${parsedData.error}\n`, + ); continue; } } catch { // If parsing fails, treat as plain text } } - + // For normal streaming, the data is raw text content if (data && data !== "[DONE]") { - setResponse(prev => prev + data); + setResponse((prev) => prev + data); } } catch (e) { console.error("Error processing data:", e); @@ -129,6 +152,7 @@ export default function AppPage({ params }: AppPageProps) { if (!input.trim() || isLoading) return; + setShowWelcome(false); setIsLoading(true); setResponse(""); setError(null); @@ -144,14 +168,16 @@ export default function AppPage({ params }: AppPageProps) { console.log(appId); console.log(BACKEND_URL); console.log(`${BACKEND_URL}/apps/${appId}`); + const currentArticleInput = input.trim(); + setInput(""); const response = await fetch(`${BACKEND_URL}/apps/${appId}`, { method: "POST", headers: { "Content-Type": "application/json", - "Authorization": `Bearer ${localStorage.getItem("token")}`, + Authorization: `Bearer ${localStorage.getItem("token")}`, }, body: JSON.stringify({ - article: input, + article: currentArticleInput, }), signal: abortControllerRef.current?.signal, }); @@ -167,168 +193,253 @@ export default function AppPage({ params }: AppPageProps) { }; return ( -
-
-

- {appId ? appId.replace(/-/g, " ").replace(/\b\w/g, l => l.toUpperCase()) : "App"} -

-

- {appId === "article-summarizer" - ? "Enter article text to get a summary" - : `Use the ${appId} app` - } -

- -
-
-