diff --git a/README.md b/README.md index 275a8d8c..57153bf6 100644 --- a/README.md +++ b/README.md @@ -36,31 +36,45 @@ Follow these steps to get the application running locally for development and te **2. Install Dependencies:** -**Backend:** +**For Linux/Mac:** +**Backend:** ```bash cd backend pip install . ``` **Frontend:** - ```bash cd frontend npm install ``` + **3. Run Development Servers:** -**Backend & Frontend:** +**For Linux/Mac:** ```bash make dev ``` -This will run the backend and frontend development servers. Open your browser and navigate to the frontend development server URL (e.g., `http://localhost:5173/app`). + +**For Windows:** + +```batch +start-app.bat +``` + +This will run the backend and frontend development servers. Open your browser and navigate to the frontend development server URL (e.g., `http://localhost:5173/app`). _Alternatively, you can run the backend and frontend development servers separately. For the backend, open a terminal in the `backend/` directory and run `langgraph dev`. The backend API will be available at `http://127.0.0.1:2024`. It will also open a browser window to the LangGraph UI. For the frontend, open a terminal in the `frontend/` directory and run `npm run dev`. The frontend will be available at `http://localhost:5173`._ +**Windows Users:** If you don't have `make` installed, use the provided batch files: +- `start-app.bat` - Automatically installs dependencies (if needed) and starts both servers + + +**Note:** The `start-app.bat` will automatically install dependencies on first run and skip installation on subsequent runs if everything is already set up. + ## How the Backend Agent Works (High-Level) The core of the backend is a LangGraph agent defined in `backend/src/agent/graph.py`. It follows these steps: diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6e68e50b..af986a98 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -27,49 +27,67 @@ export default function App() { assistantId: "agent", messagesKey: "messages", onFinish: (event: any) => { - console.log(event); + console.log('Finish event:', event); }, onUpdateEvent: (event: any) => { + console.log('Received event:', event); let processedEvent: ProcessedEvent | null = null; - if (event.generate_query) { - processedEvent = { - title: "Generating Search Queries", - data: event.generate_query.query_list.join(", "), - }; - } else if (event.web_research) { - const sources = event.web_research.sources_gathered || []; - const numSources = sources.length; - const uniqueLabels = [ - ...new Set(sources.map((s: any) => s.label).filter(Boolean)), - ]; - const exampleLabels = uniqueLabels.slice(0, 3).join(", "); - processedEvent = { - title: "Web Research", - data: `Gathered ${numSources} sources. Related to: ${ - exampleLabels || "N/A" - }.`, - }; - } else if (event.reflection) { - processedEvent = { - title: "Reflection", - data: event.reflection.is_sufficient - ? "Search successful, generating final answer." - : `Need more information, searching for ${event.reflection.follow_up_queries.join( - ", " - )}`, - }; - } else if (event.finalize_answer) { - processedEvent = { - title: "Finalizing Answer", - data: "Composing and presenting the final answer.", - }; - hasFinalizeEventOccurredRef.current = true; - } - if (processedEvent) { - setProcessedEventsTimeline((prevEvents) => [ - ...prevEvents, - processedEvent!, - ]); + + try { + if (event?.messages?.[0]?.content) { + // Handle message content + const content = event.messages[0].content; + processedEvent = { + title: "Response", + data: Array.isArray(content) ? content.join("\n") : String(content), + }; + } else if (event?.generate_query?.query_list) { + const queryList = event.generate_query.query_list; + processedEvent = { + title: "Generating Search Queries", + data: Array.isArray(queryList) ? queryList.join(", ") : String(queryList), + }; + } else if (event?.web_research) { + const sources = event.web_research.sources_gathered || []; + const numSources = sources.length; + const uniqueLabels = [ + ...new Set(sources.map((s: any) => s?.label).filter(Boolean)), + ]; + const exampleLabels = uniqueLabels.slice(0, 3).join(", "); + processedEvent = { + title: "Web Research", + data: `Gathered ${numSources} sources. Related to: ${ + exampleLabels || "N/A" + }.`, + }; + } else if (event?.reflection) { + const followUpQueries = event.reflection.follow_up_queries; + processedEvent = { + title: "Reflection", + data: event.reflection.is_sufficient + ? "Search successful, generating final answer." + : `Need more information, searching for ${ + Array.isArray(followUpQueries) + ? followUpQueries.join(", ") + : followUpQueries || "additional information" + }`, + }; + } else if (event?.finalize_answer) { + processedEvent = { + title: "Finalizing Answer", + data: "Composing and presenting the final answer.", + }; + hasFinalizeEventOccurredRef.current = true; + } + + if (processedEvent) { + setProcessedEventsTimeline((prevEvents) => [ + ...prevEvents, + processedEvent!, + ]); + } + } catch (error) { + console.error('Error processing event:', error, event); } }, }); diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index b5490299..8f95495f 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -3,13 +3,42 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react-swc"; import tailwindcss from "@tailwindcss/vite"; +// Cross-platform fix for path resolution +// The usual `new URL(".", import.meta.url).pathname` breaks on Windows +// (e.g., "C:\path" turns into "/C:/path" and causes issues) +// This approach works reliably on all platforms + +function resolveSrcPath(): string { + try { + // Modern ESM approach (preferred for Linux/Mac) + const esmPath = new URL(".", import.meta.url).pathname; + // On Windows, pathname might have issues, so we validate it + const resolvedPath = path.resolve(esmPath, "./src"); + + // Quick validation - if the path looks wrong (common on Windows), use fallback + if (process.platform === "win32" && esmPath.startsWith("/C:")) { + throw new Error("Windows path issue detected"); + } + + return resolvedPath; + } catch { + // Fallback for Windows or any environment where ESM URL handling fails + return path.resolve(__dirname, "./src"); + } +} + +const srcPath = resolveSrcPath(); + +// Debug log for development (can be removed in production) +console.log(`[Vite Config] Resolved src path: ${srcPath}`); + // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), tailwindcss()], base: "/app/", resolve: { alias: { - "@": path.resolve(new URL(".", import.meta.url).pathname, "./src"), + "@": srcPath, }, }, server: { diff --git a/start-app.bat b/start-app.bat new file mode 100644 index 00000000..13b38292 --- /dev/null +++ b/start-app.bat @@ -0,0 +1,97 @@ +@echo off +title Gemini Fullstack LangGraph - Setup & Start + +echo ======================================== +echo Gemini Fullstack LangGraph Quickstart +echo ======================================== +echo. + +REM Check if this is first time setup +set FIRST_TIME=0 + +REM Check if backend dependencies are installed +echo Checking backend dependencies... +cd backend +pip show langgraph >nul 2>&1 +if %errorlevel% neq 0 ( + echo Backend dependencies not found. Installing... + set FIRST_TIME=1 + pip install . + if %errorlevel% neq 0 ( + echo Error: Failed to install backend dependencies + pause + exit /b 1 + ) + echo ✓ Backend dependencies installed successfully +) else ( + echo ✓ Backend dependencies already installed +) +cd .. + +REM Check if frontend dependencies are installed +echo Checking frontend dependencies... +if not exist "frontend\node_modules" ( + echo Frontend dependencies not found. Installing... + set FIRST_TIME=1 + cd frontend + npm install + if %errorlevel% neq 0 ( + echo Error: Failed to install frontend dependencies + pause + exit /b 1 + ) + echo ✓ Frontend dependencies installed successfully + cd .. +) else ( + echo ✓ Frontend dependencies already installed +) + +REM Check for .env file +echo. +echo Checking API key configuration... +if not exist "backend\.env" ( + echo ⚠️ WARNING: No .env file found in backend directory + echo. + echo Please create backend\.env with your Gemini API key: + echo GEMINI_API_KEY="your_actual_api_key_here" + echo. + echo Get your API key from: https://aistudio.google.com/app/apikey + echo. +) else ( + echo ✓ .env file found +) + +echo. +if %FIRST_TIME%==1 ( + echo ✓ Setup completed successfully! + echo. +) + +echo ======================================== +echo Starting Development Servers +echo ======================================== +echo. +echo Frontend: http://localhost:5173/app/ +echo Backend: http://127.0.0.1:2024 +echo. +echo Press Ctrl+C in any window to stop both servers +echo. + +REM Start backend server in a new window +start "Backend Server - LangGraph" cmd /k "cd /d %~dp0backend && echo Starting backend server... && langgraph dev" + +REM Wait a moment for backend to start +timeout /t 3 /nobreak >nul + +REM Start frontend server in a new window +start "Frontend Server - React/Vite" cmd /k "cd /d %~dp0frontend && echo Starting frontend server... && npm run dev" + +echo. +echo Both servers are starting in separate windows... +echo. +echo To stop the servers: +echo 1. Close both command prompt windows, or +echo 2. Press Ctrl+C in each window +echo. +echo Press any key to close this window... +pause >nul \ No newline at end of file