From 9b065b225e86136def535d621179f5d59714c755 Mon Sep 17 00:00:00 2001 From: TJay Date: Sat, 16 Aug 2025 21:48:52 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20CLAUDE.md=20=E5=92=8C?= =?UTF-8?q?=20request=5Fflow=5Fdiagram.md=20=E6=96=87=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E7=B3=BB=E7=B5=B1=E9=96=8B=E7=99=BC=E6=8C=87?= =?UTF-8?q?=E5=B0=8E=E8=88=87=E8=AB=8B=E6=B1=82=E6=B5=81=E7=A8=8B=E5=9C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 97 +++++++++++++++++++++++++++ request_flow_diagram.md | 143 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 CLAUDE.md create mode 100644 request_flow_diagram.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..65d9d377 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,97 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Development Commands + +### Running the Application +```bash +# Quick start (recommended) +./run.sh + +# Manual start +cd backend && uv run uvicorn app:app --reload --port 8000 +``` + +### Environment Setup +```bash +# Install dependencies +uv sync + +# Environment variables required in .env: +ANTHROPIC_API_KEY=your_key_here +``` + +### Development Server +- Web Interface: http://localhost:8000 +- API Documentation: http://localhost:8000/docs +- Uses uvicorn with auto-reload for development + +## Architecture Overview + +This is a RAG (Retrieval-Augmented Generation) system for course materials with a clear separation between frontend, API, and processing layers. + +### Core RAG Flow +1. **Document Processing**: Course materials in `docs/` are parsed into structured lessons and chunked for vector storage +2. **Query Processing**: User queries trigger semantic search through ChromaDB, then Claude synthesizes responses +3. **Session Management**: Conversation history is maintained per session for context-aware responses + +### Key Components + +**RAG System (`rag_system.py`)**: Main orchestrator that coordinates all components. Handles the complete query lifecycle from user input to response generation. + +**Document Processor (`document_processor.py`)**: Parses course documents with expected format: +``` +Course Title: [title] +Course Link: [url] +Course Instructor: [instructor] + +Lesson 0: Introduction +Lesson Link: [lesson_url] +[content...] +``` + +**Vector Store (`vector_store.py`)**: ChromaDB integration with sentence transformers for semantic search. Stores both course metadata and content chunks with configurable overlap. + +**AI Generator (`ai_generator.py`)**: Anthropic Claude integration with tool calling. Uses a specialized system prompt for educational content and decides when to search vs. use general knowledge. + +**Session Manager (`session_manager.py`)**: Maintains conversation history with configurable message limits. Creates unique session IDs for context preservation. + +### Configuration System +All settings centralized in `config.py` with environment variable support: +- Chunk size/overlap for document processing +- Embedding model selection +- Search result limits +- Conversation history depth +- Claude model selection + +### Data Models +Pydantic models in `models.py` define the core entities: +- `Course`: Container with lessons and metadata +- `Lesson`: Individual lesson with optional links +- `CourseChunk`: Vector-searchable content pieces with course/lesson context + +### Tool Integration +The system uses a tool management pattern where Claude can call search tools via the `search_tools.py` module. Tools are registered with the AI generator and can be invoked based on query analysis. + +### Frontend Integration +Static files served from `frontend/` with a chat interface that maintains session state and displays responses with source citations. Uses relative API paths for deployment flexibility. + +## File Structure Context + +- `backend/app.py`: FastAPI application with CORS configuration and static file serving +- `docs/`: Course materials automatically loaded on startup +- `chroma_db/`: Persistent vector database storage +- Frontend files use cache-busting for development +- No test framework currently configured + +## Development Notes + +- Documents are automatically processed and indexed on server startup +- The system expects course documents to follow the structured format for proper parsing +- Session state is maintained in memory (not persistent across restarts) +- Vector embeddings use sentence-transformers with the all-MiniLM-L6-v2 model +- Claude model configured for claude-sonnet-4-20250514 with educational prompt optimization +- always use uv to run the server do not use pip directly +- make sure to use uv to all dependency +- use uv to run Python files \ No newline at end of file diff --git a/request_flow_diagram.md b/request_flow_diagram.md new file mode 100644 index 00000000..0991fe96 --- /dev/null +++ b/request_flow_diagram.md @@ -0,0 +1,143 @@ +# RAG System Request Flow Diagram + +```mermaid +sequenceDiagram + participant User + participant Frontend as Frontend
(script.js) + participant FastAPI as FastAPI
(app.py) + participant RAG as RAG System
(rag_system.py) + participant Session as Session Manager
(session_manager.py) + participant AI as AI Generator
(ai_generator.py) + participant Tools as Tool Manager
(search_tools.py) + participant Vector as Vector Store
(vector_store.py) + participant ChromaDB as ChromaDB
(chroma_db/) + participant Claude as Anthropic Claude
(API) + + User->>Frontend: 1. Types query & clicks send + Note over Frontend: chatInput.value = "What is RAG?" + + Frontend->>Frontend: 2. Add user message to UI + Frontend->>Frontend: 3. Show loading indicator + + Frontend->>FastAPI: 4. POST /api/query
{query: "What is RAG?", session_id: null} + + FastAPI->>RAG: 5. rag_system.query(query, session_id) + + RAG->>Session: 6. create_session() or get_history(session_id) + Session-->>RAG: 7. session_id & conversation history + + RAG->>AI: 8. generate_response(query, history, tools, tool_manager) + + AI->>Claude: 9. messages.create() with system prompt & tools + Note over Claude: Claude decides: "This needs a search" + + Claude->>AI: 10. Tool use request: search("RAG explanation") + + AI->>Tools: 11. Execute tool: CourseSearchTool.search() + + Tools->>Vector: 12. search_content("RAG explanation") + + Vector->>ChromaDB: 13. query() with embeddings + Note over ChromaDB: Semantic search through
course chunks + + ChromaDB-->>Vector: 14. Relevant course chunks + metadata + + Vector-->>Tools: 15. SearchResults with documents & sources + + Tools-->>AI: 16. Tool response with search results + + AI->>Claude: 17. Tool results back to Claude + Note over Claude: Claude synthesizes
search results into answer + + Claude-->>AI: 18. Generated natural language response + + AI-->>RAG: 19. Final answer string + + RAG->>Session: 20. add_exchange(session_id, query, answer) + + RAG-->>FastAPI: 21. (answer, sources) tuple + + FastAPI-->>Frontend: 22. QueryResponse JSON
{answer: "RAG is...", sources: [...], session_id: "abc123"} + + Frontend->>Frontend: 23. Remove loading indicator + Frontend->>Frontend: 24. addMessage() with markdown rendering + Frontend->>Frontend: 25. Display sources in collapsible section + + Frontend-->>User: 26. Show formatted response with sources +``` + +## Component Architecture + +```mermaid +graph TB + subgraph "Frontend Layer" + UI[index.html
Chat Interface] + JS[script.js
Event Handlers & API Calls] + CSS[style.css
Styling] + end + + subgraph "API Layer" + FastAPI[app.py
REST Endpoints
/api/query, /api/courses] + end + + subgraph "RAG Core" + RAGSys[rag_system.py
Main Orchestrator] + Session[session_manager.py
Conversation History] + AI[ai_generator.py
Claude Integration] + Tools[search_tools.py
Tool Management] + end + + subgraph "Data Processing" + DocProc[document_processor.py
Text Chunking & Parsing] + Vector[vector_store.py
Embedding & Search] + Models[models.py
Data Structures] + end + + subgraph "Storage" + ChromaDB[(ChromaDB
Vector Database)] + Docs[docs/
Course Materials] + end + + subgraph "External APIs" + Claude[Anthropic Claude
AI Generation] + end + + UI --> JS + JS --> FastAPI + FastAPI --> RAGSys + RAGSys --> Session + RAGSys --> AI + AI --> Tools + AI --> Claude + Tools --> Vector + Vector --> ChromaDB + DocProc --> Vector + DocProc --> Docs + Vector --> Models + Session --> Models + + classDef frontend fill:#e1f5fe + classDef api fill:#f3e5f5 + classDef core fill:#e8f5e8 + classDef data fill:#fff3e0 + classDef storage fill:#fce4ec + classDef external fill:#f1f8e9 + + class UI,JS,CSS frontend + class FastAPI api + class RAGSys,Session,AI,Tools core + class DocProc,Vector,Models data + class ChromaDB,Docs storage + class Claude external +``` + +## Data Flow Summary + +1. **User Input** → Frontend captures and validates +2. **HTTP Request** → JSON payload to FastAPI endpoint +3. **Session Management** → Create/retrieve conversation context +4. **AI Processing** → Claude analyzes query and decides on tool usage +5. **Vector Search** → Semantic search through course chunks +6. **Response Generation** → Claude synthesizes search results +7. **Response Delivery** → JSON back to frontend with sources +8. **UI Update** → Markdown rendering and source display \ No newline at end of file From bdc4bfd6efeffbcaf29855248ba37e8ad108f2ca Mon Sep 17 00:00:00 2001 From: TJay Date: Sun, 17 Aug 2025 09:33:29 +0800 Subject: [PATCH 2/6] Enhance RAG chatbot with new features and UI improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add course outline tool for structure queries - Implement new chat functionality with session clearing - Improve source links with clickable course/lesson URLs - Enhanced UI with better source formatting and new chat button - Update AI generator prompts for better tool usage - Add API endpoint for session management 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .claude/settings.local.json | 12 ++ .../page-2025-08-17T01-20-03-573Z.png | Bin 0 -> 38506 bytes .../page-2025-08-17T01-21-14-257Z.png | Bin 0 -> 38451 bytes CLAUDE.md | 5 +- backend/ai_generator.py | 26 ++-- backend/app.py | 31 ++++- backend/rag_system.py | 4 +- backend/search_tools.py | 104 +++++++++++++- frontend/index.html | 15 +- frontend/script.js | 56 +++++++- frontend/style.css | 129 +++++++++++++++++- 11 files changed, 350 insertions(+), 32 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 .playwright-mcp/page-2025-08-17T01-20-03-573Z.png create mode 100644 .playwright-mcp/page-2025-08-17T01-21-14-257Z.png diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..319c41d0 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,12 @@ +{ + "permissions": { + "allow": [ + "mcp__playwright__browser_navigate", + "mcp__playwright__browser_snapshot", + "mcp__playwright__browser_take_screenshot" + ], + "deny": [], + "ask": [], + "defaultMode": "acceptEdits" + } +} \ No newline at end of file diff --git a/.playwright-mcp/page-2025-08-17T01-20-03-573Z.png b/.playwright-mcp/page-2025-08-17T01-20-03-573Z.png new file mode 100644 index 0000000000000000000000000000000000000000..86e4ff8fa6c0074ec0ab5cda5ee9e14378b8964c GIT binary patch literal 38506 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 literal 0 HcmV?d00001 diff --git a/.playwright-mcp/page-2025-08-17T01-21-14-257Z.png b/.playwright-mcp/page-2025-08-17T01-21-14-257Z.png new file mode 100644 index 0000000000000000000000000000000000000000..e8cb5ff8865c7994d66da16a0a4ae0b1483577e3 GIT binary patch literal 38451 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 Tuple[Course, int]: """ diff --git a/backend/search_tools.py b/backend/search_tools.py index adfe8235..e2f07ee5 100644 --- a/backend/search_tools.py +++ b/backend/search_tools.py @@ -88,7 +88,7 @@ def execute(self, query: str, course_name: Optional[str] = None, lesson_number: def _format_results(self, results: SearchResults) -> str: """Format search results with course and lesson context""" formatted = [] - sources = [] # Track sources for the UI + sources = [] # Track sources for the UI with links for doc, meta in zip(results.documents, results.metadata): course_title = meta.get('course_title', 'unknown') @@ -100,11 +100,24 @@ def _format_results(self, results: SearchResults) -> str: header += f" - Lesson {lesson_num}" header += "]" - # Track source for the UI - source = course_title + # Build source with links + source_title = course_title if lesson_num is not None: - source += f" - Lesson {lesson_num}" - sources.append(source) + source_title += f" - Lesson {lesson_num}" + + # Get course and lesson links from vector store + course_link = self.store.get_course_link(course_title) + lesson_link = None + if lesson_num is not None: + lesson_link = self.store.get_lesson_link(course_title, lesson_num) + + # Create structured source object + source_obj = { + "title": source_title, + "course_link": course_link, + "lesson_link": lesson_link + } + sources.append(source_obj) formatted.append(f"{header}\n{doc}") @@ -113,6 +126,87 @@ def _format_results(self, results: SearchResults) -> str: return "\n\n".join(formatted) + +class CourseOutlineTool(Tool): + """Tool for getting course outlines including course info and lesson list""" + + def __init__(self, vector_store: VectorStore): + self.store = vector_store + + def get_tool_definition(self) -> Dict[str, Any]: + """Return Anthropic tool definition for this tool""" + return { + "name": "get_course_outline", + "description": "Get course outline including course title, link, and complete lesson list", + "input_schema": { + "type": "object", + "properties": { + "course_name": { + "type": "string", + "description": "Course title (partial matches work, e.g. 'MCP', 'Introduction')" + } + }, + "required": ["course_name"] + } + } + + def execute(self, course_name: str) -> str: + """ + Execute the outline tool to get course metadata. + + Args: + course_name: Course title to get outline for + + Returns: + Formatted course outline or error message + """ + # Use vector store to resolve the course name first + resolved_course_title = self.store._resolve_course_name(course_name) + + if not resolved_course_title: + return f"No course found matching '{course_name}'" + + # Get all courses metadata to find our specific course + all_courses = self.store.get_all_courses_metadata() + + target_course = None + for course_meta in all_courses: + if course_meta.get('title') == resolved_course_title: + target_course = course_meta + break + + if not target_course: + return f"Course metadata not found for '{resolved_course_title}'" + + # Format the outline response + return self._format_course_outline(target_course) + + def _format_course_outline(self, course_meta: Dict[str, Any]) -> str: + """Format course metadata into a readable outline""" + course_title = course_meta.get('title', 'Unknown Course') + course_link = course_meta.get('course_link', 'No link available') + instructor = course_meta.get('instructor', 'Unknown Instructor') + lessons = course_meta.get('lessons', []) + + # Build the outline + outline_parts = [ + f"Course Title: {course_title}", + f"Course Link: {course_link}", + f"Course Instructor: {instructor}", + f"Total Lessons: {len(lessons)}", + "", + "Lesson List:" + ] + + # Add each lesson + for lesson in lessons: + lesson_num = lesson.get('lesson_number', 'Unknown') + lesson_title = lesson.get('lesson_title', 'Unknown Title') + outline_parts.append(f"Lesson {lesson_num}: {lesson_title}") + + return "\n".join(outline_parts) + + class ToolManager: """Manages available tools for the AI""" diff --git a/frontend/index.html b/frontend/index.html index f8e25a62..2ad5f3f9 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -7,7 +7,7 @@ Course Materials Assistant - +

@@ -19,6 +19,17 @@

Course Materials Assistant