Spaces:
Sleeping
Sleeping
Praneeth Etta
commited on
Commit
·
ac6128c
1
Parent(s):
7ab13a2
hugging face space commit
Browse files- Dockerfile +89 -0
- backend/Dockerfile +0 -28
- backend/main.py +2 -2
- backend/{requirements.txt → requirements_be.txt} +0 -0
- backend/routes/feedback.py +1 -1
- backend/routes/search.py +5 -5
- backend/services/gemini_service.py +2 -1
- backend/services/qdrant_service.py +176 -4
- database/{requirements.txt → requirements_db.txt} +0 -0
- frontend/package-lock.json +0 -0
- frontend/package.json +0 -48
- frontend/postcss.config.js +0 -6
- frontend/public/index.html +0 -29
- frontend/public/manifest.json +0 -25
- frontend/src/App.js +0 -62
- frontend/src/components/Footer.js +0 -118
- frontend/src/components/Navbar.js +0 -116
- frontend/src/index.css +0 -131
- frontend/src/index.js +0 -11
- frontend/src/pages/About.js +0 -371
- frontend/src/pages/Analytics.js +0 -409
- frontend/src/pages/Home.js +0 -210
- frontend/src/pages/Search.js +0 -464
- frontend/src/utils/api.js +0 -138
- frontend/tailwind.config.js +0 -68
- requirements.txt +42 -0
Dockerfile
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# # Use official Python image with a more recent version
|
2 |
+
# FROM python:3.11-slim
|
3 |
+
|
4 |
+
# # Set working directory
|
5 |
+
# WORKDIR /app
|
6 |
+
|
7 |
+
# # Install system dependencies
|
8 |
+
# RUN apt-get update && apt-get install -y \
|
9 |
+
# gcc \
|
10 |
+
# && rm -rf /var/lib/apt/lists/*
|
11 |
+
|
12 |
+
# # Copy requirements from backend and install
|
13 |
+
# COPY backend/requirements.txt .
|
14 |
+
|
15 |
+
# # Upgrade pip to latest version to resolve dependency conflicts better
|
16 |
+
# RUN pip install --upgrade pip
|
17 |
+
|
18 |
+
# # Install Python dependencies
|
19 |
+
# RUN pip install --no-cache-dir -r requirements.txt
|
20 |
+
|
21 |
+
# # Copy the backend code
|
22 |
+
# COPY backend/ .
|
23 |
+
|
24 |
+
# # Expose the port your FastAPI app runs on
|
25 |
+
# EXPOSE 7860
|
26 |
+
|
27 |
+
# # Command to run the FastAPI app
|
28 |
+
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
29 |
+
|
30 |
+
# # Use official Python image with a more recent version
|
31 |
+
# FROM python:3.11-slim
|
32 |
+
|
33 |
+
# # Set working directory
|
34 |
+
# WORKDIR /app
|
35 |
+
|
36 |
+
# # Install system dependencies
|
37 |
+
# RUN apt-get update && apt-get install -y \
|
38 |
+
# gcc \
|
39 |
+
# && rm -rf /var/lib/apt/lists/*
|
40 |
+
|
41 |
+
# # Copy requirements from backend and install
|
42 |
+
# COPY backend/requirements.txt .
|
43 |
+
|
44 |
+
# # Upgrade pip to latest version to resolve dependency conflicts better
|
45 |
+
# RUN pip install --upgrade pip
|
46 |
+
|
47 |
+
# # Install Python dependencies
|
48 |
+
# RUN pip install --no-cache-dir -r requirements.txt
|
49 |
+
|
50 |
+
# # Copy the backend code
|
51 |
+
# COPY backend/ .
|
52 |
+
|
53 |
+
# # Expose the port your FastAPI app runs on
|
54 |
+
# EXPOSE 8000
|
55 |
+
|
56 |
+
# # Command to run the FastAPI app
|
57 |
+
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
58 |
+
|
59 |
+
|
60 |
+
# Use a lightweight Python image
|
61 |
+
FROM python:3.11-slim
|
62 |
+
|
63 |
+
# Set the working directory
|
64 |
+
WORKDIR /app
|
65 |
+
|
66 |
+
# Install system dependencies
|
67 |
+
RUN apt-get update && apt-get install -y \
|
68 |
+
gcc \
|
69 |
+
&& rm -rf /var/lib/apt/lists/*
|
70 |
+
|
71 |
+
# Copy the merged requirements.txt
|
72 |
+
COPY requirements.txt .
|
73 |
+
|
74 |
+
# Upgrade pip and install Python dependencies
|
75 |
+
RUN pip install --upgrade pip
|
76 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
77 |
+
|
78 |
+
# Copy the backend and database code
|
79 |
+
COPY backend/ ./backend/
|
80 |
+
COPY database/ ./database/
|
81 |
+
|
82 |
+
# Copy .env file (see note below)
|
83 |
+
COPY .env .env
|
84 |
+
|
85 |
+
# Expose the FastAPI port
|
86 |
+
EXPOSE 8000
|
87 |
+
|
88 |
+
# Start the FastAPI app
|
89 |
+
CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
backend/Dockerfile
DELETED
@@ -1,28 +0,0 @@
|
|
1 |
-
# Use official Python image with a more recent version
|
2 |
-
FROM python:3.11-slim
|
3 |
-
|
4 |
-
# Set working directory
|
5 |
-
WORKDIR /app
|
6 |
-
|
7 |
-
# Install system dependencies
|
8 |
-
RUN apt-get update && apt-get install -y \
|
9 |
-
gcc \
|
10 |
-
&& rm -rf /var/lib/apt/lists/*
|
11 |
-
|
12 |
-
# Copy requirements from backend and install
|
13 |
-
COPY backend/requirements.txt .
|
14 |
-
|
15 |
-
# Upgrade pip to latest version to resolve dependency conflicts better
|
16 |
-
RUN pip install --upgrade pip
|
17 |
-
|
18 |
-
# Install Python dependencies
|
19 |
-
RUN pip install --no-cache-dir -r requirements.txt
|
20 |
-
|
21 |
-
# Copy the backend code
|
22 |
-
COPY backend/ .
|
23 |
-
|
24 |
-
# Expose the port your FastAPI app runs on
|
25 |
-
EXPOSE 7860
|
26 |
-
|
27 |
-
# Command to run the FastAPI app
|
28 |
-
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/main.py
CHANGED
@@ -17,8 +17,8 @@ import structlog
|
|
17 |
from dotenv import load_dotenv
|
18 |
|
19 |
# Import routes
|
20 |
-
from routes.search import router as search_router
|
21 |
-
from routes.feedback import router as feedback_router
|
22 |
|
23 |
# Load environment variables
|
24 |
load_dotenv()
|
|
|
17 |
from dotenv import load_dotenv
|
18 |
|
19 |
# Import routes
|
20 |
+
from backend.routes.search import router as search_router
|
21 |
+
from backend.routes.feedback import router as feedback_router
|
22 |
|
23 |
# Load environment variables
|
24 |
load_dotenv()
|
backend/{requirements.txt → requirements_be.txt}
RENAMED
File without changes
|
backend/routes/feedback.py
CHANGED
@@ -6,7 +6,7 @@ import structlog
|
|
6 |
import time
|
7 |
from typing import Dict, Any
|
8 |
|
9 |
-
from models.schemas import FeedbackRequest, FeedbackResponse, ErrorResponse
|
10 |
|
11 |
router = APIRouter()
|
12 |
logger = structlog.get_logger()
|
|
|
6 |
import time
|
7 |
from typing import Dict, Any
|
8 |
|
9 |
+
from backend.models.schemas import FeedbackRequest, FeedbackResponse, ErrorResponse
|
10 |
|
11 |
router = APIRouter()
|
12 |
logger = structlog.get_logger()
|
backend/routes/search.py
CHANGED
@@ -12,11 +12,11 @@ import uuid
|
|
12 |
parent_dir = Path(__file__).parent.parent.parent
|
13 |
sys.path.append(str(parent_dir))
|
14 |
|
15 |
-
from models.schemas import SearchRequest, SearchResponse, ErrorResponse, SearchResult
|
16 |
-
from services.qdrant_service import QdrantService
|
17 |
-
from services.mcp_service import MCPService
|
18 |
-
from services.guardrails_service import GuardrailsService
|
19 |
-
from services.gemini_service import GeminiService
|
20 |
|
21 |
router = APIRouter()
|
22 |
logger = structlog.get_logger()
|
|
|
12 |
parent_dir = Path(__file__).parent.parent.parent
|
13 |
sys.path.append(str(parent_dir))
|
14 |
|
15 |
+
from backend.models.schemas import SearchRequest, SearchResponse, ErrorResponse, SearchResult
|
16 |
+
from backend.services.qdrant_service import QdrantService
|
17 |
+
from backend.services.mcp_service import MCPService
|
18 |
+
from backend.services.guardrails_service import GuardrailsService
|
19 |
+
from backend.services.gemini_service import GeminiService
|
20 |
|
21 |
router = APIRouter()
|
22 |
logger = structlog.get_logger()
|
backend/services/gemini_service.py
CHANGED
@@ -4,7 +4,7 @@ Gemini LLM service for final fallback when both KB and MCP have low confidence.
|
|
4 |
import os
|
5 |
import re
|
6 |
import structlog
|
7 |
-
import google.generativeai as genai
|
8 |
from typing import Dict, Optional
|
9 |
|
10 |
logger = structlog.get_logger()
|
@@ -22,6 +22,7 @@ class GeminiService:
|
|
22 |
return
|
23 |
|
24 |
try:
|
|
|
25 |
genai.configure(api_key=self.api_key)
|
26 |
self.model = genai.GenerativeModel('gemini-2.0-flash-exp')
|
27 |
logger.info("Gemini service initialized successfully")
|
|
|
4 |
import os
|
5 |
import re
|
6 |
import structlog
|
7 |
+
# import google.generativeai as genai
|
8 |
from typing import Dict, Optional
|
9 |
|
10 |
logger = structlog.get_logger()
|
|
|
22 |
return
|
23 |
|
24 |
try:
|
25 |
+
import google.generativeai as genai
|
26 |
genai.configure(api_key=self.api_key)
|
27 |
self.model = genai.GenerativeModel('gemini-2.0-flash-exp')
|
28 |
logger.info("Gemini service initialized successfully")
|
backend/services/qdrant_service.py
CHANGED
@@ -1,19 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
"""
|
2 |
Qdrant service for vector database operations.
|
3 |
"""
|
4 |
import sys
|
5 |
from pathlib import Path
|
6 |
import structlog
|
7 |
-
from typing import List, Dict, Any, Optional
|
8 |
|
9 |
# Add parent directory to import database module
|
10 |
parent_dir = Path(__file__).parent.parent.parent
|
11 |
sys.path.append(str(parent_dir))
|
12 |
|
|
|
|
|
|
|
|
|
13 |
try:
|
14 |
from database.qdrant_manager import QdrantManager
|
15 |
from database.utils import EmbeddingGenerator
|
16 |
-
from models.schemas import SearchResult, APILogEntry
|
17 |
except ImportError as e:
|
18 |
# Services will be initialized when packages are available
|
19 |
pass
|
@@ -62,7 +228,7 @@ class QdrantService:
|
|
62 |
logger.error("Failed to initialize Qdrant service", error=str(e))
|
63 |
# Service will work in degraded mode
|
64 |
|
65 |
-
async def search_similar(self, question: str, limit: int = 5) -> List[SearchResult]:
|
66 |
"""
|
67 |
Search for similar math problems in the knowledge base.
|
68 |
|
@@ -79,6 +245,9 @@ class QdrantService:
|
|
79 |
|
80 |
try:
|
81 |
import os
|
|
|
|
|
|
|
82 |
# Generate embedding for the question
|
83 |
query_embedding = self.embedding_generator.embed_text(question)
|
84 |
|
@@ -137,6 +306,9 @@ class QdrantService:
|
|
137 |
return
|
138 |
|
139 |
try:
|
|
|
|
|
|
|
140 |
# Create log entry
|
141 |
log_entry = APILogEntry(
|
142 |
endpoint=endpoint,
|
@@ -157,4 +329,4 @@ class QdrantService:
|
|
157 |
source=source)
|
158 |
|
159 |
except Exception as e:
|
160 |
-
logger.warning("Failed to log API call", error=str(e))
|
|
|
1 |
+
# """
|
2 |
+
# Qdrant service for vector database operations.
|
3 |
+
# """
|
4 |
+
# import sys
|
5 |
+
# from pathlib import Path
|
6 |
+
# import structlog
|
7 |
+
# from typing import List, Dict, Any, Optional
|
8 |
+
|
9 |
+
# # Add parent directory to import database module
|
10 |
+
# parent_dir = Path(__file__).parent.parent.parent
|
11 |
+
# sys.path.append(str(parent_dir))
|
12 |
+
|
13 |
+
# try:
|
14 |
+
# from database.qdrant_manager import QdrantManager
|
15 |
+
# from database.utils import EmbeddingGenerator
|
16 |
+
# from backend.models.schemas import SearchResult, APILogEntry
|
17 |
+
# except ImportError as e:
|
18 |
+
# # Services will be initialized when packages are available
|
19 |
+
# pass
|
20 |
+
|
21 |
+
# logger = structlog.get_logger()
|
22 |
+
|
23 |
+
# class QdrantService:
|
24 |
+
# """Service layer for Qdrant vector database operations."""
|
25 |
+
|
26 |
+
# def __init__(self):
|
27 |
+
# """Initialize Qdrant service."""
|
28 |
+
# self.qdrant_manager = None
|
29 |
+
# self.embedding_generator = None
|
30 |
+
# self._initialize()
|
31 |
+
|
32 |
+
# def _initialize(self):
|
33 |
+
# """Initialize Qdrant manager and embedding generator."""
|
34 |
+
# try:
|
35 |
+
# import os
|
36 |
+
# from dotenv import load_dotenv
|
37 |
+
|
38 |
+
# # Load .env from project root (3 levels up from services)
|
39 |
+
# env_path = Path(__file__).parent.parent.parent / '.env'
|
40 |
+
# load_dotenv(env_path)
|
41 |
+
|
42 |
+
# # Qdrant configuration from environment variables
|
43 |
+
# qdrant_config = {
|
44 |
+
# 'url': os.getenv('QDRANT_URL'),
|
45 |
+
# 'api_key': os.getenv('QDRANT_API_KEY'),
|
46 |
+
# 'collection_name': os.getenv('QDRANT_COLLECTION', 'nuinamath')
|
47 |
+
# }
|
48 |
+
|
49 |
+
# if not qdrant_config['url'] or not qdrant_config['api_key']:
|
50 |
+
# raise ValueError("QDRANT_URL and QDRANT_API_KEY must be set in environment variables")
|
51 |
+
|
52 |
+
# self.qdrant_manager = QdrantManager(
|
53 |
+
# url=qdrant_config['url'],
|
54 |
+
# api_key=qdrant_config['api_key']
|
55 |
+
# )
|
56 |
+
|
57 |
+
# self.embedding_generator = EmbeddingGenerator()
|
58 |
+
|
59 |
+
# logger.info("Qdrant service initialized successfully")
|
60 |
+
|
61 |
+
# except Exception as e:
|
62 |
+
# logger.error("Failed to initialize Qdrant service", error=str(e))
|
63 |
+
# # Service will work in degraded mode
|
64 |
+
|
65 |
+
# async def search_similar(self, question: str, limit: int = 5) -> List[SearchResult]:
|
66 |
+
# """
|
67 |
+
# Search for similar math problems in the knowledge base.
|
68 |
+
|
69 |
+
# Args:
|
70 |
+
# question: The math question to search for
|
71 |
+
# limit: Maximum number of results to return
|
72 |
+
|
73 |
+
# Returns:
|
74 |
+
# List of SearchResult objects
|
75 |
+
# """
|
76 |
+
# if not self.qdrant_manager or not self.embedding_generator:
|
77 |
+
# logger.warning("Qdrant service not properly initialized")
|
78 |
+
# return []
|
79 |
+
|
80 |
+
# try:
|
81 |
+
# import os
|
82 |
+
# # Generate embedding for the question
|
83 |
+
# query_embedding = self.embedding_generator.embed_text(question)
|
84 |
+
|
85 |
+
# # Search in Qdrant
|
86 |
+
# collection_name = os.getenv('QDRANT_COLLECTION', 'nuinamath')
|
87 |
+
# results = self.qdrant_manager.search_similar(
|
88 |
+
# collection_name=collection_name,
|
89 |
+
# query_vector=query_embedding,
|
90 |
+
# limit=limit
|
91 |
+
# )
|
92 |
+
|
93 |
+
# # Convert to SearchResult objects
|
94 |
+
# search_results = []
|
95 |
+
# for result in results:
|
96 |
+
# payload = result.payload
|
97 |
+
# search_result = SearchResult(
|
98 |
+
# problem=payload.get('problem', ''),
|
99 |
+
# solution=payload.get('solution', ''),
|
100 |
+
# score=result.score
|
101 |
+
# )
|
102 |
+
# search_results.append(search_result)
|
103 |
+
|
104 |
+
# logger.info("Knowledge base search completed",
|
105 |
+
# question_length=len(question),
|
106 |
+
# results_count=len(search_results),
|
107 |
+
# best_score=search_results[0].score if search_results else 0)
|
108 |
+
|
109 |
+
# return search_results
|
110 |
+
|
111 |
+
# except Exception as e:
|
112 |
+
# logger.error("Knowledge base search failed", error=str(e))
|
113 |
+
# return []
|
114 |
+
|
115 |
+
# async def log_api_call(
|
116 |
+
# self,
|
117 |
+
# endpoint: str,
|
118 |
+
# method: str,
|
119 |
+
# request_data: Dict[str, Any],
|
120 |
+
# response_data: Dict[str, Any],
|
121 |
+
# response_time_ms: float,
|
122 |
+
# source: str
|
123 |
+
# ):
|
124 |
+
# """
|
125 |
+
# Log API call to Qdrant for analytics.
|
126 |
+
|
127 |
+
# Args:
|
128 |
+
# endpoint: API endpoint called
|
129 |
+
# method: HTTP method
|
130 |
+
# request_data: Request payload
|
131 |
+
# response_data: Response payload
|
132 |
+
# response_time_ms: Response time in milliseconds
|
133 |
+
# source: Source of the response (KB/MCP)
|
134 |
+
# """
|
135 |
+
# if not self.qdrant_manager or not self.embedding_generator:
|
136 |
+
# logger.warning("Cannot log API call - Qdrant service not initialized")
|
137 |
+
# return
|
138 |
+
|
139 |
+
# try:
|
140 |
+
# # Create log entry
|
141 |
+
# log_entry = APILogEntry(
|
142 |
+
# endpoint=endpoint,
|
143 |
+
# method=method,
|
144 |
+
# request_data=request_data,
|
145 |
+
# response_data=response_data,
|
146 |
+
# response_time_ms=response_time_ms,
|
147 |
+
# source=source,
|
148 |
+
# status_code=200 # Default to 200 for successful responses
|
149 |
+
# )
|
150 |
+
|
151 |
+
# # TODO: Store log entry in Qdrant analytics collection
|
152 |
+
# # For now, just log to stdout
|
153 |
+
# logger.info("API call logged",
|
154 |
+
# endpoint=endpoint,
|
155 |
+
# method=method,
|
156 |
+
# response_time_ms=response_time_ms,
|
157 |
+
# source=source)
|
158 |
+
|
159 |
+
# except Exception as e:
|
160 |
+
# logger.warning("Failed to log API call", error=str(e))
|
161 |
+
|
162 |
+
|
163 |
"""
|
164 |
Qdrant service for vector database operations.
|
165 |
"""
|
166 |
import sys
|
167 |
from pathlib import Path
|
168 |
import structlog
|
169 |
+
from typing import List, Dict, Any, Optional, TYPE_CHECKING
|
170 |
|
171 |
# Add parent directory to import database module
|
172 |
parent_dir = Path(__file__).parent.parent.parent
|
173 |
sys.path.append(str(parent_dir))
|
174 |
|
175 |
+
# Import for type checking only
|
176 |
+
if TYPE_CHECKING:
|
177 |
+
from backend.models.schemas import SearchResult, APILogEntry
|
178 |
+
|
179 |
try:
|
180 |
from database.qdrant_manager import QdrantManager
|
181 |
from database.utils import EmbeddingGenerator
|
182 |
+
from backend.models.schemas import SearchResult, APILogEntry
|
183 |
except ImportError as e:
|
184 |
# Services will be initialized when packages are available
|
185 |
pass
|
|
|
228 |
logger.error("Failed to initialize Qdrant service", error=str(e))
|
229 |
# Service will work in degraded mode
|
230 |
|
231 |
+
async def search_similar(self, question: str, limit: int = 5) -> List['SearchResult']:
|
232 |
"""
|
233 |
Search for similar math problems in the knowledge base.
|
234 |
|
|
|
245 |
|
246 |
try:
|
247 |
import os
|
248 |
+
# Import SearchResult here to avoid NameError
|
249 |
+
from backend.models.schemas import SearchResult
|
250 |
+
|
251 |
# Generate embedding for the question
|
252 |
query_embedding = self.embedding_generator.embed_text(question)
|
253 |
|
|
|
306 |
return
|
307 |
|
308 |
try:
|
309 |
+
# Import APILogEntry here to avoid NameError
|
310 |
+
from backend.models.schemas import APILogEntry
|
311 |
+
|
312 |
# Create log entry
|
313 |
log_entry = APILogEntry(
|
314 |
endpoint=endpoint,
|
|
|
329 |
source=source)
|
330 |
|
331 |
except Exception as e:
|
332 |
+
logger.warning("Failed to log API call", error=str(e))
|
database/{requirements.txt → requirements_db.txt}
RENAMED
File without changes
|
frontend/package-lock.json
DELETED
The diff for this file is too large to render.
See raw diff
|
|
frontend/package.json
DELETED
@@ -1,48 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"name": "mathgenius-ai-frontend",
|
3 |
-
"version": "1.0.0",
|
4 |
-
"private": true,
|
5 |
-
"dependencies": {
|
6 |
-
"@testing-library/jest-dom": "^5.16.4",
|
7 |
-
"@testing-library/react": "^13.3.0",
|
8 |
-
"@testing-library/user-event": "^13.5.0",
|
9 |
-
"react": "^18.2.0",
|
10 |
-
"react-dom": "^18.2.0",
|
11 |
-
"react-router-dom": "^6.8.0",
|
12 |
-
"react-scripts": "5.0.1",
|
13 |
-
"katex": "^0.16.4",
|
14 |
-
"react-katex": "^3.0.1",
|
15 |
-
"react-hot-toast": "^2.4.0",
|
16 |
-
"lucide-react": "^0.263.1",
|
17 |
-
"web-vitals": "^2.1.4"
|
18 |
-
},
|
19 |
-
"scripts": {
|
20 |
-
"start": "react-scripts start",
|
21 |
-
"build": "react-scripts build",
|
22 |
-
"test": "react-scripts test",
|
23 |
-
"eject": "react-scripts eject"
|
24 |
-
},
|
25 |
-
"eslintConfig": {
|
26 |
-
"extends": [
|
27 |
-
"react-app",
|
28 |
-
"react-app/jest"
|
29 |
-
]
|
30 |
-
},
|
31 |
-
"browserslist": {
|
32 |
-
"production": [
|
33 |
-
">0.2%",
|
34 |
-
"not dead",
|
35 |
-
"not op_mini all"
|
36 |
-
],
|
37 |
-
"development": [
|
38 |
-
"last 1 chrome version",
|
39 |
-
"last 1 firefox version",
|
40 |
-
"last 1 safari version"
|
41 |
-
]
|
42 |
-
},
|
43 |
-
"devDependencies": {
|
44 |
-
"autoprefixer": "^10.4.13",
|
45 |
-
"postcss": "^8.4.21",
|
46 |
-
"tailwindcss": "^3.2.4"
|
47 |
-
}
|
48 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/postcss.config.js
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
module.exports = {
|
2 |
-
plugins: {
|
3 |
-
tailwindcss: {},
|
4 |
-
autoprefixer: {},
|
5 |
-
},
|
6 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/public/index.html
DELETED
@@ -1,29 +0,0 @@
|
|
1 |
-
<!DOCTYPE html>
|
2 |
-
<html lang="en">
|
3 |
-
<head>
|
4 |
-
<meta charset="utf-8" />
|
5 |
-
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
6 |
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
7 |
-
<meta name="theme-color" content="#0ea5e9" />
|
8 |
-
<meta
|
9 |
-
name="description"
|
10 |
-
content="MathGenius AI - Advanced Math Problem Solver using RAG and AI"
|
11 |
-
/>
|
12 |
-
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
13 |
-
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
14 |
-
|
15 |
-
<!-- Google Fonts -->
|
16 |
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
17 |
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
18 |
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
19 |
-
|
20 |
-
<!-- KaTeX CSS -->
|
21 |
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">
|
22 |
-
|
23 |
-
<title>MathGenius AI - Smart Math Problem Solver</title>
|
24 |
-
</head>
|
25 |
-
<body>
|
26 |
-
<noscript>You need to enable JavaScript to run this app.</noscript>
|
27 |
-
<div id="root"></div>
|
28 |
-
</body>
|
29 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/public/manifest.json
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"short_name": "MathGenius AI",
|
3 |
-
"name": "MathGenius AI - Smart Math Problem Solver",
|
4 |
-
"icons": [
|
5 |
-
{
|
6 |
-
"src": "favicon.ico",
|
7 |
-
"sizes": "64x64 32x32 24x24 16x16",
|
8 |
-
"type": "image/x-icon"
|
9 |
-
},
|
10 |
-
{
|
11 |
-
"src": "logo192.png",
|
12 |
-
"type": "image/png",
|
13 |
-
"sizes": "192x192"
|
14 |
-
},
|
15 |
-
{
|
16 |
-
"src": "logo512.png",
|
17 |
-
"type": "image/png",
|
18 |
-
"sizes": "512x512"
|
19 |
-
}
|
20 |
-
],
|
21 |
-
"start_url": ".",
|
22 |
-
"display": "standalone",
|
23 |
-
"theme_color": "#0ea5e9",
|
24 |
-
"background_color": "#ffffff"
|
25 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/App.js
DELETED
@@ -1,62 +0,0 @@
|
|
1 |
-
import React from 'react';
|
2 |
-
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
3 |
-
import { Toaster } from 'react-hot-toast';
|
4 |
-
|
5 |
-
// Components
|
6 |
-
import Navbar from './components/Navbar';
|
7 |
-
import Footer from './components/Footer';
|
8 |
-
|
9 |
-
// Pages
|
10 |
-
import Home from './pages/Home';
|
11 |
-
import Search from './pages/Search';
|
12 |
-
import Analytics from './pages/Analytics';
|
13 |
-
import About from './pages/About';
|
14 |
-
|
15 |
-
function App() {
|
16 |
-
return (
|
17 |
-
<Router>
|
18 |
-
<div className="min-h-screen bg-gray-50 flex flex-col">
|
19 |
-
<Navbar />
|
20 |
-
|
21 |
-
<main className="flex-1">
|
22 |
-
<Routes>
|
23 |
-
<Route path="/" element={<Home />} />
|
24 |
-
<Route path="/search" element={<Search />} />
|
25 |
-
<Route path="/analytics" element={<Analytics />} />
|
26 |
-
<Route path="/about" element={<About />} />
|
27 |
-
</Routes>
|
28 |
-
</main>
|
29 |
-
|
30 |
-
<Footer />
|
31 |
-
|
32 |
-
{/* Toast notifications */}
|
33 |
-
<Toaster
|
34 |
-
position="top-right"
|
35 |
-
toastOptions={{
|
36 |
-
duration: 3000,
|
37 |
-
style: {
|
38 |
-
background: '#fff',
|
39 |
-
color: '#374151',
|
40 |
-
boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
41 |
-
border: '1px solid #e5e7eb',
|
42 |
-
},
|
43 |
-
success: {
|
44 |
-
iconTheme: {
|
45 |
-
primary: '#10b981',
|
46 |
-
secondary: '#fff',
|
47 |
-
},
|
48 |
-
},
|
49 |
-
error: {
|
50 |
-
iconTheme: {
|
51 |
-
primary: '#ef4444',
|
52 |
-
secondary: '#fff',
|
53 |
-
},
|
54 |
-
},
|
55 |
-
}}
|
56 |
-
/>
|
57 |
-
</div>
|
58 |
-
</Router>
|
59 |
-
);
|
60 |
-
}
|
61 |
-
|
62 |
-
export default App;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/Footer.js
DELETED
@@ -1,118 +0,0 @@
|
|
1 |
-
import React from 'react';
|
2 |
-
import { Link } from 'react-router-dom';
|
3 |
-
import { Brain, Sparkles, Github, Linkedin, Mail, Heart } from 'lucide-react';
|
4 |
-
|
5 |
-
const Footer = () => {
|
6 |
-
const currentYear = new Date().getFullYear();
|
7 |
-
|
8 |
-
return (
|
9 |
-
<footer className="bg-white border-t border-gray-200">
|
10 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
11 |
-
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
|
12 |
-
{/* Brand */}
|
13 |
-
<div className="col-span-1 md:col-span-2">
|
14 |
-
<Link to="/" className="flex items-center space-x-3 mb-4">
|
15 |
-
<div className="bg-gradient-to-r from-primary-600 to-secondary-600 p-2 rounded-lg">
|
16 |
-
<Brain className="h-6 w-6 text-white" />
|
17 |
-
</div>
|
18 |
-
<div className="flex items-center space-x-1">
|
19 |
-
<span className="text-xl font-bold gradient-text">MathGenius</span>
|
20 |
-
<Sparkles className="h-4 w-4 text-secondary-500" />
|
21 |
-
<span className="text-xl font-bold text-gray-700">AI</span>
|
22 |
-
</div>
|
23 |
-
</Link>
|
24 |
-
<p className="text-gray-600 mb-4 max-w-md">
|
25 |
-
Advanced AI-powered math problem solver using Retrieval-Augmented Generation (RAG)
|
26 |
-
to provide accurate, step-by-step solutions from a curated knowledge base.
|
27 |
-
</p>
|
28 |
-
<div className="flex space-x-4">
|
29 |
-
<a
|
30 |
-
href="https://github.com/bhoomika-254"
|
31 |
-
target="_blank"
|
32 |
-
rel="noopener noreferrer"
|
33 |
-
className="text-gray-400 hover:text-primary-600 transition-colors"
|
34 |
-
>
|
35 |
-
<Github className="h-5 w-5" />
|
36 |
-
</a>
|
37 |
-
<a
|
38 |
-
href="https://linkedin.com/in/bhoomika-254"
|
39 |
-
target="_blank"
|
40 |
-
rel="noopener noreferrer"
|
41 |
-
className="text-gray-400 hover:text-primary-600 transition-colors"
|
42 |
-
>
|
43 |
-
<Linkedin className="h-5 w-5" />
|
44 |
-
</a>
|
45 |
-
<a
|
46 |
-
href="mailto:[email protected]"
|
47 |
-
className="text-gray-400 hover:text-primary-600 transition-colors"
|
48 |
-
>
|
49 |
-
<Mail className="h-5 w-5" />
|
50 |
-
</a>
|
51 |
-
</div>
|
52 |
-
</div>
|
53 |
-
|
54 |
-
{/* Quick Links */}
|
55 |
-
<div>
|
56 |
-
<h3 className="text-sm font-semibold text-gray-900 tracking-wider uppercase mb-4">
|
57 |
-
Navigation
|
58 |
-
</h3>
|
59 |
-
<ul className="space-y-2">
|
60 |
-
<li>
|
61 |
-
<Link to="/" className="text-gray-600 hover:text-primary-600 transition-colors">
|
62 |
-
Home
|
63 |
-
</Link>
|
64 |
-
</li>
|
65 |
-
<li>
|
66 |
-
<Link to="/search" className="text-gray-600 hover:text-primary-600 transition-colors">
|
67 |
-
Search
|
68 |
-
</Link>
|
69 |
-
</li>
|
70 |
-
<li>
|
71 |
-
<Link to="/analytics" className="text-gray-600 hover:text-primary-600 transition-colors">
|
72 |
-
Analytics
|
73 |
-
</Link>
|
74 |
-
</li>
|
75 |
-
<li>
|
76 |
-
<Link to="/about" className="text-gray-600 hover:text-primary-600 transition-colors">
|
77 |
-
About
|
78 |
-
</Link>
|
79 |
-
</li>
|
80 |
-
</ul>
|
81 |
-
</div>
|
82 |
-
|
83 |
-
{/* Technology */}
|
84 |
-
<div>
|
85 |
-
<h3 className="text-sm font-semibold text-gray-900 tracking-wider uppercase mb-4">
|
86 |
-
Technology
|
87 |
-
</h3>
|
88 |
-
<ul className="space-y-2">
|
89 |
-
<li className="text-gray-600">React + Tailwind CSS</li>
|
90 |
-
<li className="text-gray-600">FastAPI Backend</li>
|
91 |
-
<li className="text-gray-600">Qdrant Vector DB</li>
|
92 |
-
<li className="text-gray-600">RAG Architecture</li>
|
93 |
-
<li className="text-gray-600">KaTeX Math Rendering</li>
|
94 |
-
</ul>
|
95 |
-
</div>
|
96 |
-
</div>
|
97 |
-
|
98 |
-
{/* Bottom Bar */}
|
99 |
-
<div className="mt-12 pt-8 border-t border-gray-200">
|
100 |
-
<div className="flex flex-col md:flex-row justify-between items-center">
|
101 |
-
<div className="flex items-center space-x-1 text-gray-600">
|
102 |
-
<span>© {currentYear} MathGenius AI. Made with</span>
|
103 |
-
<Heart className="h-4 w-4 text-red-500" />
|
104 |
-
<span>for educational purposes.</span>
|
105 |
-
</div>
|
106 |
-
<div className="mt-4 md:mt-0">
|
107 |
-
<p className="text-sm text-gray-500">
|
108 |
-
Built for recruiters & portfolio showcase
|
109 |
-
</p>
|
110 |
-
</div>
|
111 |
-
</div>
|
112 |
-
</div>
|
113 |
-
</div>
|
114 |
-
</footer>
|
115 |
-
);
|
116 |
-
};
|
117 |
-
|
118 |
-
export default Footer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/Navbar.js
DELETED
@@ -1,116 +0,0 @@
|
|
1 |
-
import React, { useState } from 'react';
|
2 |
-
import { Link, useLocation } from 'react-router-dom';
|
3 |
-
import { Calculator, Menu, X, Brain, Sparkles } from 'lucide-react';
|
4 |
-
|
5 |
-
const Navbar = () => {
|
6 |
-
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
7 |
-
const location = useLocation();
|
8 |
-
|
9 |
-
const navigation = [
|
10 |
-
{ name: 'Home', href: '/', icon: null },
|
11 |
-
{ name: 'Search', href: '/search', icon: null },
|
12 |
-
{ name: 'Analytics', href: '/analytics', icon: null },
|
13 |
-
{ name: 'About', href: '/about', icon: null },
|
14 |
-
];
|
15 |
-
|
16 |
-
const isActivePage = (href) => {
|
17 |
-
if (href === '/') return location.pathname === '/';
|
18 |
-
return location.pathname.startsWith(href);
|
19 |
-
};
|
20 |
-
|
21 |
-
return (
|
22 |
-
<nav className="bg-white border-b border-gray-200 sticky top-0 z-50 backdrop-blur-sm bg-white/95">
|
23 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
24 |
-
<div className="flex justify-between items-center h-16">
|
25 |
-
{/* Logo */}
|
26 |
-
<Link to="/" className="flex items-center space-x-3 group">
|
27 |
-
<div className="relative">
|
28 |
-
<div className="absolute inset-0 bg-gradient-to-r from-primary-600 to-secondary-600 rounded-lg blur opacity-25 group-hover:opacity-40 transition-opacity"></div>
|
29 |
-
<div className="relative bg-gradient-to-r from-primary-600 to-secondary-600 p-2 rounded-lg">
|
30 |
-
<Brain className="h-6 w-6 text-white" />
|
31 |
-
</div>
|
32 |
-
</div>
|
33 |
-
<div className="flex items-center space-x-1">
|
34 |
-
<span className="text-xl font-bold gradient-text">MathGenius</span>
|
35 |
-
<Sparkles className="h-4 w-4 text-secondary-500" />
|
36 |
-
<span className="text-xl font-bold text-gray-700">AI</span>
|
37 |
-
</div>
|
38 |
-
</Link>
|
39 |
-
|
40 |
-
{/* Desktop Navigation */}
|
41 |
-
<div className="hidden md:flex items-center space-x-8">
|
42 |
-
{navigation.map((item) => (
|
43 |
-
<Link
|
44 |
-
key={item.name}
|
45 |
-
to={item.href}
|
46 |
-
className={`px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 ${
|
47 |
-
isActivePage(item.href)
|
48 |
-
? 'bg-primary-100 text-primary-700'
|
49 |
-
: 'text-gray-600 hover:text-primary-600 hover:bg-gray-100'
|
50 |
-
}`}
|
51 |
-
>
|
52 |
-
{item.name}
|
53 |
-
</Link>
|
54 |
-
))}
|
55 |
-
|
56 |
-
{/* CTA Button */}
|
57 |
-
<Link
|
58 |
-
to="/search"
|
59 |
-
className="btn btn-primary btn-sm ml-4"
|
60 |
-
>
|
61 |
-
<Calculator className="h-4 w-4 mr-2" />
|
62 |
-
Try Now
|
63 |
-
</Link>
|
64 |
-
</div>
|
65 |
-
|
66 |
-
{/* Mobile menu button */}
|
67 |
-
<div className="md:hidden">
|
68 |
-
<button
|
69 |
-
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
70 |
-
className="inline-flex items-center justify-center p-2 rounded-lg text-gray-600 hover:text-primary-600 hover:bg-gray-100 transition-colors"
|
71 |
-
>
|
72 |
-
{isMenuOpen ? (
|
73 |
-
<X className="h-6 w-6" />
|
74 |
-
) : (
|
75 |
-
<Menu className="h-6 w-6" />
|
76 |
-
)}
|
77 |
-
</button>
|
78 |
-
</div>
|
79 |
-
</div>
|
80 |
-
|
81 |
-
{/* Mobile Navigation */}
|
82 |
-
{isMenuOpen && (
|
83 |
-
<div className="md:hidden py-4 border-t border-gray-200">
|
84 |
-
<div className="flex flex-col space-y-2">
|
85 |
-
{navigation.map((item) => (
|
86 |
-
<Link
|
87 |
-
key={item.name}
|
88 |
-
to={item.href}
|
89 |
-
onClick={() => setIsMenuOpen(false)}
|
90 |
-
className={`px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 ${
|
91 |
-
isActivePage(item.href)
|
92 |
-
? 'bg-primary-100 text-primary-700'
|
93 |
-
: 'text-gray-600 hover:text-primary-600 hover:bg-gray-100'
|
94 |
-
}`}
|
95 |
-
>
|
96 |
-
{item.name}
|
97 |
-
</Link>
|
98 |
-
))}
|
99 |
-
|
100 |
-
<Link
|
101 |
-
to="/search"
|
102 |
-
onClick={() => setIsMenuOpen(false)}
|
103 |
-
className="btn btn-primary btn-sm mt-4 self-start"
|
104 |
-
>
|
105 |
-
<Calculator className="h-4 w-4 mr-2" />
|
106 |
-
Try Now
|
107 |
-
</Link>
|
108 |
-
</div>
|
109 |
-
</div>
|
110 |
-
)}
|
111 |
-
</div>
|
112 |
-
</nav>
|
113 |
-
);
|
114 |
-
};
|
115 |
-
|
116 |
-
export default Navbar;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/index.css
DELETED
@@ -1,131 +0,0 @@
|
|
1 |
-
@tailwind base;
|
2 |
-
@tailwind components;
|
3 |
-
@tailwind utilities;
|
4 |
-
|
5 |
-
@layer base {
|
6 |
-
* {
|
7 |
-
box-sizing: border-box;
|
8 |
-
}
|
9 |
-
|
10 |
-
body {
|
11 |
-
@apply bg-gray-50 text-gray-900 font-sans;
|
12 |
-
font-feature-settings: "rlig" 1, "calt" 1;
|
13 |
-
}
|
14 |
-
|
15 |
-
html {
|
16 |
-
scroll-behavior: smooth;
|
17 |
-
}
|
18 |
-
}
|
19 |
-
|
20 |
-
@layer components {
|
21 |
-
.btn {
|
22 |
-
@apply inline-flex items-center justify-center rounded-lg font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed;
|
23 |
-
}
|
24 |
-
|
25 |
-
.btn-primary {
|
26 |
-
@apply btn bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500 shadow-lg hover:shadow-xl;
|
27 |
-
}
|
28 |
-
|
29 |
-
.btn-secondary {
|
30 |
-
@apply btn bg-gray-200 text-gray-800 hover:bg-gray-300 focus:ring-gray-500;
|
31 |
-
}
|
32 |
-
|
33 |
-
.btn-outline {
|
34 |
-
@apply btn border-2 border-primary-600 text-primary-600 hover:bg-primary-600 hover:text-white focus:ring-primary-500;
|
35 |
-
}
|
36 |
-
|
37 |
-
.btn-sm {
|
38 |
-
@apply px-3 py-2 text-sm;
|
39 |
-
}
|
40 |
-
|
41 |
-
.btn-md {
|
42 |
-
@apply px-4 py-2.5 text-base;
|
43 |
-
}
|
44 |
-
|
45 |
-
.btn-lg {
|
46 |
-
@apply px-6 py-3 text-lg;
|
47 |
-
}
|
48 |
-
|
49 |
-
.input {
|
50 |
-
@apply w-full rounded-lg border border-gray-300 px-4 py-2.5 text-gray-900 placeholder-gray-500 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200;
|
51 |
-
}
|
52 |
-
|
53 |
-
.textarea {
|
54 |
-
@apply input resize-none;
|
55 |
-
}
|
56 |
-
|
57 |
-
.card {
|
58 |
-
@apply bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden;
|
59 |
-
}
|
60 |
-
|
61 |
-
.card-hover {
|
62 |
-
@apply card transition-all duration-200 hover:shadow-lg hover:border-gray-300;
|
63 |
-
}
|
64 |
-
|
65 |
-
.badge {
|
66 |
-
@apply inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium;
|
67 |
-
}
|
68 |
-
|
69 |
-
.badge-primary {
|
70 |
-
@apply badge bg-primary-100 text-primary-800;
|
71 |
-
}
|
72 |
-
|
73 |
-
.badge-secondary {
|
74 |
-
@apply badge bg-secondary-100 text-secondary-800;
|
75 |
-
}
|
76 |
-
|
77 |
-
.badge-success {
|
78 |
-
@apply badge bg-green-100 text-green-800;
|
79 |
-
}
|
80 |
-
|
81 |
-
.badge-warning {
|
82 |
-
@apply badge bg-yellow-100 text-yellow-800;
|
83 |
-
}
|
84 |
-
|
85 |
-
.badge-error {
|
86 |
-
@apply badge bg-red-100 text-red-800;
|
87 |
-
}
|
88 |
-
|
89 |
-
.gradient-text {
|
90 |
-
@apply bg-gradient-to-r from-primary-600 to-secondary-600 bg-clip-text text-transparent;
|
91 |
-
}
|
92 |
-
|
93 |
-
.math-content {
|
94 |
-
@apply leading-relaxed text-gray-900;
|
95 |
-
}
|
96 |
-
|
97 |
-
.math-content .section {
|
98 |
-
@apply mb-6;
|
99 |
-
}
|
100 |
-
|
101 |
-
.math-content .katex {
|
102 |
-
@apply text-gray-900;
|
103 |
-
}
|
104 |
-
|
105 |
-
.math-content .katex-display {
|
106 |
-
@apply my-4 text-center;
|
107 |
-
}
|
108 |
-
|
109 |
-
.math-content h4 {
|
110 |
-
@apply text-lg font-semibold text-gray-900 border-b border-gray-200 pb-2;
|
111 |
-
}
|
112 |
-
|
113 |
-
.loading-spinner {
|
114 |
-
@apply animate-spin h-5 w-5 border-2 border-gray-300 border-t-primary-600 rounded-full;
|
115 |
-
}
|
116 |
-
}
|
117 |
-
|
118 |
-
@layer utilities {
|
119 |
-
.text-balance {
|
120 |
-
text-wrap: balance;
|
121 |
-
}
|
122 |
-
|
123 |
-
.scrollbar-hide {
|
124 |
-
-ms-overflow-style: none;
|
125 |
-
scrollbar-width: none;
|
126 |
-
}
|
127 |
-
|
128 |
-
.scrollbar-hide::-webkit-scrollbar {
|
129 |
-
display: none;
|
130 |
-
}
|
131 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/index.js
DELETED
@@ -1,11 +0,0 @@
|
|
1 |
-
import React from 'react';
|
2 |
-
import ReactDOM from 'react-dom/client';
|
3 |
-
import './index.css';
|
4 |
-
import App from './App';
|
5 |
-
|
6 |
-
const root = ReactDOM.createRoot(document.getElementById('root'));
|
7 |
-
root.render(
|
8 |
-
<React.StrictMode>
|
9 |
-
<App />
|
10 |
-
</React.StrictMode>
|
11 |
-
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/pages/About.js
DELETED
@@ -1,371 +0,0 @@
|
|
1 |
-
import React from 'react';
|
2 |
-
import {
|
3 |
-
Brain,
|
4 |
-
Database,
|
5 |
-
Zap,
|
6 |
-
Shield,
|
7 |
-
Globe,
|
8 |
-
Target,
|
9 |
-
Code,
|
10 |
-
Layers,
|
11 |
-
GitBranch,
|
12 |
-
Server,
|
13 |
-
Cpu,
|
14 |
-
Network
|
15 |
-
} from 'lucide-react';
|
16 |
-
|
17 |
-
const About = () => {
|
18 |
-
const features = [
|
19 |
-
{
|
20 |
-
icon: Brain,
|
21 |
-
title: "Advanced AI Processing",
|
22 |
-
description: "Powered by state-of-the-art language models and vector search technology for intelligent math problem solving."
|
23 |
-
},
|
24 |
-
{
|
25 |
-
icon: Database,
|
26 |
-
title: "5000+ Math Problems",
|
27 |
-
description: "Comprehensive knowledge base containing over 5,000 carefully curated math problems with detailed solutions."
|
28 |
-
},
|
29 |
-
{
|
30 |
-
icon: Zap,
|
31 |
-
title: "Lightning Fast",
|
32 |
-
description: "Optimized vector search with sub-second response times. Average query resolution in under 1.2 seconds."
|
33 |
-
},
|
34 |
-
{
|
35 |
-
icon: Shield,
|
36 |
-
title: "Quality Assured",
|
37 |
-
description: "Built-in guardrails and validation systems ensure accurate, safe, and educationally appropriate responses."
|
38 |
-
},
|
39 |
-
{
|
40 |
-
icon: Globe,
|
41 |
-
title: "Web-Enhanced",
|
42 |
-
description: "Model Context Protocol (MCP) integration provides real-time web search fallback for comprehensive coverage."
|
43 |
-
},
|
44 |
-
{
|
45 |
-
icon: Target,
|
46 |
-
title: "High Precision",
|
47 |
-
description: "Confidence scoring and quality assessment ensure reliable solutions with 86% average confidence rating."
|
48 |
-
}
|
49 |
-
];
|
50 |
-
|
51 |
-
const techStack = [
|
52 |
-
{
|
53 |
-
category: "Backend",
|
54 |
-
icon: Server,
|
55 |
-
technologies: [
|
56 |
-
{ name: "FastAPI", description: "High-performance Python web framework" },
|
57 |
-
{ name: "Qdrant", description: "Vector database for similarity search" },
|
58 |
-
{ name: "Sentence Transformers", description: "384-dimensional embeddings" },
|
59 |
-
{ name: "Model Context Protocol", description: "Web search integration" }
|
60 |
-
]
|
61 |
-
},
|
62 |
-
{
|
63 |
-
category: "Frontend",
|
64 |
-
icon: Code,
|
65 |
-
technologies: [
|
66 |
-
{ name: "React", description: "Modern UI component library" },
|
67 |
-
{ name: "Tailwind CSS", description: "Utility-first styling framework" },
|
68 |
-
{ name: "KaTeX", description: "Beautiful math equation rendering" },
|
69 |
-
{ name: "React Router", description: "Client-side routing" }
|
70 |
-
]
|
71 |
-
},
|
72 |
-
{
|
73 |
-
category: "Infrastructure",
|
74 |
-
icon: Network,
|
75 |
-
technologies: [
|
76 |
-
{ name: "Hugging Face Spaces", description: "Backend deployment platform" },
|
77 |
-
{ name: "Netlify", description: "Frontend hosting and deployment" },
|
78 |
-
{ name: "GitHub", description: "Version control and CI/CD" },
|
79 |
-
{ name: "VS Code", description: "Development environment" }
|
80 |
-
]
|
81 |
-
}
|
82 |
-
];
|
83 |
-
|
84 |
-
const architecture = [
|
85 |
-
{
|
86 |
-
step: "1",
|
87 |
-
title: "Input Validation",
|
88 |
-
description: "Question preprocessing and safety checks using guardrails service",
|
89 |
-
icon: Shield
|
90 |
-
},
|
91 |
-
{
|
92 |
-
step: "2",
|
93 |
-
title: "Vector Search",
|
94 |
-
description: "Semantic similarity search against 5,000+ problem embeddings in Qdrant",
|
95 |
-
icon: Database
|
96 |
-
},
|
97 |
-
{
|
98 |
-
step: "3",
|
99 |
-
title: "Decision Logic",
|
100 |
-
description: "Intelligent routing between knowledge base and web search based on confidence",
|
101 |
-
icon: GitBranch
|
102 |
-
},
|
103 |
-
{
|
104 |
-
step: "4",
|
105 |
-
title: "Response Generation",
|
106 |
-
description: "Solution synthesis with step-by-step explanations and quality scoring",
|
107 |
-
icon: Cpu
|
108 |
-
},
|
109 |
-
{
|
110 |
-
step: "5",
|
111 |
-
title: "Analytics & Feedback",
|
112 |
-
description: "Performance tracking, user feedback collection, and continuous improvement",
|
113 |
-
icon: Target
|
114 |
-
}
|
115 |
-
];
|
116 |
-
|
117 |
-
const metrics = [
|
118 |
-
{ label: "Math Problems", value: "5,005", suffix: "+" },
|
119 |
-
{ label: "Vector Dimensions", value: "384", suffix: "" },
|
120 |
-
{ label: "Confidence Threshold", value: "80", suffix: "%" },
|
121 |
-
{ label: "Average Response Time", value: "1.2", suffix: "s" },
|
122 |
-
{ label: "Knowledge Base Hit Rate", value: "82", suffix: "%" },
|
123 |
-
{ label: "Solution Accuracy", value: "94", suffix: "%" }
|
124 |
-
];
|
125 |
-
|
126 |
-
return (
|
127 |
-
<div className="min-h-screen bg-gray-50">
|
128 |
-
{/* Hero Section */}
|
129 |
-
<div className="bg-gradient-to-br from-blue-600 via-purple-600 to-indigo-800 text-white">
|
130 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
|
131 |
-
<div className="text-center">
|
132 |
-
<div className="flex justify-center mb-6">
|
133 |
-
<div className="p-4 bg-white/10 rounded-2xl backdrop-blur-sm">
|
134 |
-
<Brain className="h-16 w-16 text-white" />
|
135 |
-
</div>
|
136 |
-
</div>
|
137 |
-
|
138 |
-
<h1 className="text-4xl md:text-6xl font-bold mb-6">
|
139 |
-
About <span className="bg-gradient-to-r from-yellow-400 to-orange-400 bg-clip-text text-transparent">MathGenius AI</span>
|
140 |
-
</h1>
|
141 |
-
|
142 |
-
<p className="text-xl md:text-2xl text-blue-100 max-w-3xl mx-auto leading-relaxed">
|
143 |
-
An advanced Retrieval-Augmented Generation (RAG) system designed to solve mathematical problems
|
144 |
-
with high accuracy, speed, and educational value.
|
145 |
-
</p>
|
146 |
-
|
147 |
-
<div className="mt-10 grid grid-cols-2 md:grid-cols-3 gap-8">
|
148 |
-
{metrics.map((metric, index) => (
|
149 |
-
<div key={index} className="text-center">
|
150 |
-
<div className="text-3xl md:text-4xl font-bold text-white">
|
151 |
-
{metric.value}<span className="text-blue-300">{metric.suffix}</span>
|
152 |
-
</div>
|
153 |
-
<div className="text-blue-200 text-sm md:text-base mt-1">
|
154 |
-
{metric.label}
|
155 |
-
</div>
|
156 |
-
</div>
|
157 |
-
))}
|
158 |
-
</div>
|
159 |
-
</div>
|
160 |
-
</div>
|
161 |
-
</div>
|
162 |
-
|
163 |
-
{/* Features Section */}
|
164 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
|
165 |
-
<div className="text-center mb-16">
|
166 |
-
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
167 |
-
Why Choose <span className="gradient-text">MathGenius AI</span>?
|
168 |
-
</h2>
|
169 |
-
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
170 |
-
Built with cutting-edge technology and designed for both students and educators
|
171 |
-
</p>
|
172 |
-
</div>
|
173 |
-
|
174 |
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
175 |
-
{features.map((feature, index) => (
|
176 |
-
<div key={index} className="card p-8 hover-lift text-center">
|
177 |
-
<div className="flex justify-center mb-4">
|
178 |
-
<div className="p-3 bg-blue-100 rounded-full">
|
179 |
-
<feature.icon className="h-8 w-8 text-blue-600" />
|
180 |
-
</div>
|
181 |
-
</div>
|
182 |
-
<h3 className="text-xl font-semibold text-gray-900 mb-3">
|
183 |
-
{feature.title}
|
184 |
-
</h3>
|
185 |
-
<p className="text-gray-600 leading-relaxed">
|
186 |
-
{feature.description}
|
187 |
-
</p>
|
188 |
-
</div>
|
189 |
-
))}
|
190 |
-
</div>
|
191 |
-
</div>
|
192 |
-
|
193 |
-
{/* Architecture Section */}
|
194 |
-
<div className="bg-white py-20">
|
195 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
196 |
-
<div className="text-center mb-16">
|
197 |
-
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
198 |
-
<span className="gradient-text">RAG Architecture</span>
|
199 |
-
</h2>
|
200 |
-
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
201 |
-
Our 5-step pipeline ensures accurate, fast, and reliable math problem solving
|
202 |
-
</p>
|
203 |
-
</div>
|
204 |
-
|
205 |
-
<div className="space-y-8">
|
206 |
-
{architecture.map((step, index) => (
|
207 |
-
<div key={index} className="flex items-center space-x-6 p-6 bg-gray-50 rounded-xl">
|
208 |
-
<div className="flex-shrink-0">
|
209 |
-
<div className="w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-full flex items-center justify-center">
|
210 |
-
<span className="text-2xl font-bold text-white">{step.step}</span>
|
211 |
-
</div>
|
212 |
-
</div>
|
213 |
-
|
214 |
-
<div className="flex-1">
|
215 |
-
<div className="flex items-center space-x-3 mb-2">
|
216 |
-
<step.icon className="h-6 w-6 text-blue-600" />
|
217 |
-
<h3 className="text-xl font-semibold text-gray-900">{step.title}</h3>
|
218 |
-
</div>
|
219 |
-
<p className="text-gray-600">{step.description}</p>
|
220 |
-
</div>
|
221 |
-
|
222 |
-
{index < architecture.length - 1 && (
|
223 |
-
<div className="hidden md:block">
|
224 |
-
<div className="w-8 h-0.5 bg-gradient-to-r from-blue-500 to-purple-600" />
|
225 |
-
</div>
|
226 |
-
)}
|
227 |
-
</div>
|
228 |
-
))}
|
229 |
-
</div>
|
230 |
-
</div>
|
231 |
-
</div>
|
232 |
-
|
233 |
-
{/* Technology Stack */}
|
234 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
|
235 |
-
<div className="text-center mb-16">
|
236 |
-
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
237 |
-
<span className="gradient-text">Technology Stack</span>
|
238 |
-
</h2>
|
239 |
-
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
240 |
-
Built with modern, industry-standard technologies for performance and scalability
|
241 |
-
</p>
|
242 |
-
</div>
|
243 |
-
|
244 |
-
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
245 |
-
{techStack.map((category, index) => (
|
246 |
-
<div key={index} className="card p-8">
|
247 |
-
<div className="flex items-center space-x-3 mb-6">
|
248 |
-
<div className="p-2 bg-blue-100 rounded-lg">
|
249 |
-
<category.icon className="h-6 w-6 text-blue-600" />
|
250 |
-
</div>
|
251 |
-
<h3 className="text-xl font-semibold text-gray-900">{category.category}</h3>
|
252 |
-
</div>
|
253 |
-
|
254 |
-
<div className="space-y-4">
|
255 |
-
{category.technologies.map((tech, techIndex) => (
|
256 |
-
<div key={techIndex} className="border-l-2 border-blue-200 pl-4">
|
257 |
-
<h4 className="font-medium text-gray-900">{tech.name}</h4>
|
258 |
-
<p className="text-sm text-gray-600">{tech.description}</p>
|
259 |
-
</div>
|
260 |
-
))}
|
261 |
-
</div>
|
262 |
-
</div>
|
263 |
-
))}
|
264 |
-
</div>
|
265 |
-
</div>
|
266 |
-
|
267 |
-
{/* Mission Section */}
|
268 |
-
<div className="bg-gradient-to-r from-blue-600 to-purple-600 text-white py-20">
|
269 |
-
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
270 |
-
<h2 className="text-3xl md:text-4xl font-bold mb-6">Our Mission</h2>
|
271 |
-
<p className="text-xl leading-relaxed text-blue-100 mb-8">
|
272 |
-
To democratize access to high-quality math education by providing instant, accurate,
|
273 |
-
and detailed solutions to mathematical problems. We believe that everyone deserves
|
274 |
-
access to excellent mathematical guidance, regardless of their location or resources.
|
275 |
-
</p>
|
276 |
-
|
277 |
-
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 mt-12">
|
278 |
-
<div className="p-6 bg-white/10 backdrop-blur-sm rounded-xl">
|
279 |
-
<Target className="h-10 w-10 text-yellow-400 mx-auto mb-4" />
|
280 |
-
<h3 className="text-lg font-semibold mb-2">Accuracy First</h3>
|
281 |
-
<p className="text-blue-100 text-sm">
|
282 |
-
Every solution is validated through multiple quality checks and confidence scoring
|
283 |
-
</p>
|
284 |
-
</div>
|
285 |
-
|
286 |
-
<div className="p-6 bg-white/10 backdrop-blur-sm rounded-xl">
|
287 |
-
<Zap className="h-10 w-10 text-yellow-400 mx-auto mb-4" />
|
288 |
-
<h3 className="text-lg font-semibold mb-2">Speed Matters</h3>
|
289 |
-
<p className="text-blue-100 text-sm">
|
290 |
-
Lightning-fast responses help students stay in their learning flow
|
291 |
-
</p>
|
292 |
-
</div>
|
293 |
-
|
294 |
-
<div className="p-6 bg-white/10 backdrop-blur-sm rounded-xl">
|
295 |
-
<Layers className="h-10 w-10 text-yellow-400 mx-auto mb-4" />
|
296 |
-
<h3 className="text-lg font-semibold mb-2">Always Learning</h3>
|
297 |
-
<p className="text-blue-100 text-sm">
|
298 |
-
Our system continuously improves through user feedback and new data
|
299 |
-
</p>
|
300 |
-
</div>
|
301 |
-
</div>
|
302 |
-
</div>
|
303 |
-
</div>
|
304 |
-
|
305 |
-
{/* Developer Section */}
|
306 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
|
307 |
-
<div className="text-center">
|
308 |
-
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-6">
|
309 |
-
Built for <span className="gradient-text">Excellence</span>
|
310 |
-
</h2>
|
311 |
-
|
312 |
-
<div className="max-w-3xl mx-auto">
|
313 |
-
<p className="text-lg text-gray-600 mb-8">
|
314 |
-
MathGenius AI represents the cutting edge of educational technology, combining advanced
|
315 |
-
AI research with practical engineering to create a tool that truly helps students learn.
|
316 |
-
</p>
|
317 |
-
|
318 |
-
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 text-left">
|
319 |
-
<div className="p-6 bg-blue-50 rounded-xl">
|
320 |
-
<h3 className="font-semibold text-gray-900 mb-3">For Students</h3>
|
321 |
-
<ul className="space-y-2 text-gray-600">
|
322 |
-
<li>• Get instant help with math homework</li>
|
323 |
-
<li>• Learn through step-by-step solutions</li>
|
324 |
-
<li>• Practice with thousands of problems</li>
|
325 |
-
<li>• Build confidence in mathematical concepts</li>
|
326 |
-
</ul>
|
327 |
-
</div>
|
328 |
-
|
329 |
-
<div className="p-6 bg-purple-50 rounded-xl">
|
330 |
-
<h3 className="font-semibold text-gray-900 mb-3">For Educators</h3>
|
331 |
-
<ul className="space-y-2 text-gray-600">
|
332 |
-
<li>• Supplement classroom instruction</li>
|
333 |
-
<li>• Provide 24/7 student support</li>
|
334 |
-
<li>• Access detailed solution analytics</li>
|
335 |
-
<li>• Enhance learning outcomes</li>
|
336 |
-
</ul>
|
337 |
-
</div>
|
338 |
-
</div>
|
339 |
-
</div>
|
340 |
-
</div>
|
341 |
-
</div>
|
342 |
-
|
343 |
-
{/* Contact/Support Section */}
|
344 |
-
<div className="bg-gray-900 text-white py-16">
|
345 |
-
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
346 |
-
<h2 className="text-3xl font-bold mb-6">Ready to Get Started?</h2>
|
347 |
-
<p className="text-xl text-gray-300 mb-8">
|
348 |
-
Join thousands of students already improving their math skills with MathGenius AI
|
349 |
-
</p>
|
350 |
-
|
351 |
-
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
352 |
-
<button className="btn btn-primary btn-lg">
|
353 |
-
Start Solving Problems
|
354 |
-
</button>
|
355 |
-
<button className="btn btn-outline btn-lg border-white text-white hover:bg-white hover:text-gray-900">
|
356 |
-
View Analytics
|
357 |
-
</button>
|
358 |
-
</div>
|
359 |
-
|
360 |
-
<div className="mt-12 pt-8 border-t border-gray-700">
|
361 |
-
<p className="text-gray-400">
|
362 |
-
Built with ❤️ for the math education community
|
363 |
-
</p>
|
364 |
-
</div>
|
365 |
-
</div>
|
366 |
-
</div>
|
367 |
-
</div>
|
368 |
-
);
|
369 |
-
};
|
370 |
-
|
371 |
-
export default About;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/pages/Analytics.js
DELETED
@@ -1,409 +0,0 @@
|
|
1 |
-
import React, { useState, useEffect } from 'react';
|
2 |
-
import { BarChart3, TrendingUp, Database, Clock, Target, Users, Globe, Brain } from 'lucide-react';
|
3 |
-
|
4 |
-
const Analytics = () => {
|
5 |
-
const [stats, setStats] = useState({
|
6 |
-
totalQueries: 0,
|
7 |
-
averageResponseTime: 0,
|
8 |
-
kbHitRate: 0,
|
9 |
-
averageConfidence: 0,
|
10 |
-
totalUsers: 0,
|
11 |
-
popularTopics: [],
|
12 |
-
responseTimeHistory: [],
|
13 |
-
confidenceDistribution: [],
|
14 |
-
sourceBreakdown: { KB: 0, MCP: 0 }
|
15 |
-
});
|
16 |
-
|
17 |
-
const [timeframe, setTimeframe] = useState('7d');
|
18 |
-
const [isLoading, setIsLoading] = useState(true);
|
19 |
-
|
20 |
-
useEffect(() => {
|
21 |
-
// Simulate loading analytics data
|
22 |
-
// In a real app, this would fetch from your backend
|
23 |
-
const loadAnalytics = async () => {
|
24 |
-
setIsLoading(true);
|
25 |
-
|
26 |
-
// Simulate API delay
|
27 |
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
28 |
-
|
29 |
-
// Mock data - replace with actual API call
|
30 |
-
const mockData = {
|
31 |
-
totalQueries: 2847,
|
32 |
-
averageResponseTime: 1.2,
|
33 |
-
kbHitRate: 0.82,
|
34 |
-
averageConfidence: 0.86,
|
35 |
-
totalUsers: 156,
|
36 |
-
popularTopics: [
|
37 |
-
{ topic: 'Quadratic Equations', count: 342, percentage: 12.0 },
|
38 |
-
{ topic: 'Calculus Derivatives', count: 298, percentage: 10.5 },
|
39 |
-
{ topic: 'Linear Algebra', count: 267, percentage: 9.4 },
|
40 |
-
{ topic: 'Trigonometry', count: 234, percentage: 8.2 },
|
41 |
-
{ topic: 'Integration', count: 198, percentage: 7.0 },
|
42 |
-
{ topic: 'Statistics', count: 187, percentage: 6.6 }
|
43 |
-
],
|
44 |
-
responseTimeHistory: [
|
45 |
-
{ date: '2024-01-01', avgTime: 1.1 },
|
46 |
-
{ date: '2024-01-02', avgTime: 1.3 },
|
47 |
-
{ date: '2024-01-03', avgTime: 1.0 },
|
48 |
-
{ date: '2024-01-04', avgTime: 1.4 },
|
49 |
-
{ date: '2024-01-05', avgTime: 1.2 },
|
50 |
-
{ date: '2024-01-06', avgTime: 1.1 },
|
51 |
-
{ date: '2024-01-07', avgTime: 1.2 }
|
52 |
-
],
|
53 |
-
confidenceDistribution: [
|
54 |
-
{ range: '90-100%', count: 1520, percentage: 53.4 },
|
55 |
-
{ range: '80-89%', count: 823, percentage: 28.9 },
|
56 |
-
{ range: '70-79%', count: 341, percentage: 12.0 },
|
57 |
-
{ range: '60-69%', count: 118, percentage: 4.1 },
|
58 |
-
{ range: '50-59%', count: 45, percentage: 1.6 }
|
59 |
-
],
|
60 |
-
sourceBreakdown: { KB: 82, MCP: 18 }
|
61 |
-
};
|
62 |
-
|
63 |
-
setStats(mockData);
|
64 |
-
setIsLoading(false);
|
65 |
-
};
|
66 |
-
|
67 |
-
loadAnalytics();
|
68 |
-
}, [timeframe]);
|
69 |
-
|
70 |
-
const StatCard = ({ icon: Icon, title, value, subtitle, trend, color = 'blue' }) => (
|
71 |
-
<div className="card p-6 hover-lift">
|
72 |
-
<div className="flex items-center justify-between">
|
73 |
-
<div>
|
74 |
-
<p className="text-gray-600 text-sm font-medium">{title}</p>
|
75 |
-
<p className="text-2xl font-bold text-gray-900 mt-1">{value}</p>
|
76 |
-
{subtitle && <p className="text-sm text-gray-500 mt-1">{subtitle}</p>}
|
77 |
-
</div>
|
78 |
-
<div className={`p-3 rounded-full bg-${color}-100`}>
|
79 |
-
<Icon className={`h-6 w-6 text-${color}-600`} />
|
80 |
-
</div>
|
81 |
-
</div>
|
82 |
-
{trend && (
|
83 |
-
<div className="mt-4 flex items-center">
|
84 |
-
<TrendingUp className="h-4 w-4 text-green-500 mr-1" />
|
85 |
-
<span className="text-sm text-green-600 font-medium">{trend}</span>
|
86 |
-
<span className="text-sm text-gray-500 ml-1">vs last period</span>
|
87 |
-
</div>
|
88 |
-
)}
|
89 |
-
</div>
|
90 |
-
);
|
91 |
-
|
92 |
-
const ProgressBar = ({ label, percentage, color = 'blue' }) => (
|
93 |
-
<div className="mb-4">
|
94 |
-
<div className="flex justify-between text-sm font-medium text-gray-700 mb-1">
|
95 |
-
<span>{label}</span>
|
96 |
-
<span>{percentage.toFixed(1)}%</span>
|
97 |
-
</div>
|
98 |
-
<div className="w-full bg-gray-200 rounded-full h-2">
|
99 |
-
<div
|
100 |
-
className={`bg-${color}-600 h-2 rounded-full transition-all duration-300`}
|
101 |
-
style={{ width: `${percentage}%` }}
|
102 |
-
/>
|
103 |
-
</div>
|
104 |
-
</div>
|
105 |
-
);
|
106 |
-
|
107 |
-
if (isLoading) {
|
108 |
-
return (
|
109 |
-
<div className="min-h-screen bg-gray-50 py-8">
|
110 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
111 |
-
<div className="text-center">
|
112 |
-
<div className="loading-spinner mx-auto mb-4" />
|
113 |
-
<p className="text-gray-600">Loading analytics...</p>
|
114 |
-
</div>
|
115 |
-
</div>
|
116 |
-
</div>
|
117 |
-
);
|
118 |
-
}
|
119 |
-
|
120 |
-
return (
|
121 |
-
<div className="min-h-screen bg-gray-50 py-8">
|
122 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
123 |
-
{/* Header */}
|
124 |
-
<div className="mb-8">
|
125 |
-
<div className="flex justify-between items-center">
|
126 |
-
<div>
|
127 |
-
<h1 className="text-3xl font-bold text-gray-900">
|
128 |
-
<span className="gradient-text">Analytics</span> Dashboard
|
129 |
-
</h1>
|
130 |
-
<p className="text-gray-600 mt-2">
|
131 |
-
System performance and usage insights
|
132 |
-
</p>
|
133 |
-
</div>
|
134 |
-
|
135 |
-
<div className="flex space-x-2">
|
136 |
-
{['24h', '7d', '30d', '90d'].map((period) => (
|
137 |
-
<button
|
138 |
-
key={period}
|
139 |
-
onClick={() => setTimeframe(period)}
|
140 |
-
className={`px-3 py-1 rounded-md text-sm font-medium transition-colors ${
|
141 |
-
timeframe === period
|
142 |
-
? 'bg-blue-600 text-white'
|
143 |
-
: 'bg-white text-gray-700 hover:bg-gray-50 border border-gray-300'
|
144 |
-
}`}
|
145 |
-
>
|
146 |
-
{period}
|
147 |
-
</button>
|
148 |
-
))}
|
149 |
-
</div>
|
150 |
-
</div>
|
151 |
-
</div>
|
152 |
-
|
153 |
-
{/* Key Metrics */}
|
154 |
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
155 |
-
<StatCard
|
156 |
-
icon={Users}
|
157 |
-
title="Total Queries"
|
158 |
-
value={stats.totalQueries.toLocaleString()}
|
159 |
-
subtitle="Math problems solved"
|
160 |
-
trend="+12.5%"
|
161 |
-
color="blue"
|
162 |
-
/>
|
163 |
-
|
164 |
-
<StatCard
|
165 |
-
icon={Clock}
|
166 |
-
title="Avg Response Time"
|
167 |
-
value={`${stats.averageResponseTime}s`}
|
168 |
-
subtitle="Lightning fast"
|
169 |
-
trend="-8.2%"
|
170 |
-
color="green"
|
171 |
-
/>
|
172 |
-
|
173 |
-
<StatCard
|
174 |
-
icon={Database}
|
175 |
-
title="KB Hit Rate"
|
176 |
-
value={`${(stats.kbHitRate * 100).toFixed(1)}%`}
|
177 |
-
subtitle="Knowledge base efficiency"
|
178 |
-
trend="+3.1%"
|
179 |
-
color="purple"
|
180 |
-
/>
|
181 |
-
|
182 |
-
<StatCard
|
183 |
-
icon={Target}
|
184 |
-
title="Avg Confidence"
|
185 |
-
value={`${(stats.averageConfidence * 100).toFixed(1)}%`}
|
186 |
-
subtitle="Solution accuracy"
|
187 |
-
trend="+5.7%"
|
188 |
-
color="orange"
|
189 |
-
/>
|
190 |
-
</div>
|
191 |
-
|
192 |
-
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
|
193 |
-
{/* Popular Topics */}
|
194 |
-
<div className="card p-6">
|
195 |
-
<div className="flex items-center justify-between mb-6">
|
196 |
-
<h2 className="text-xl font-semibold text-gray-900">Popular Topics</h2>
|
197 |
-
<Brain className="h-5 w-5 text-gray-400" />
|
198 |
-
</div>
|
199 |
-
|
200 |
-
<div className="space-y-4">
|
201 |
-
{stats.popularTopics.map((topic, index) => (
|
202 |
-
<div key={index} className="flex justify-between items-center">
|
203 |
-
<div className="flex-1">
|
204 |
-
<div className="flex justify-between items-center mb-1">
|
205 |
-
<span className="text-sm font-medium text-gray-900">{topic.topic}</span>
|
206 |
-
<span className="text-sm text-gray-600">{topic.count} queries</span>
|
207 |
-
</div>
|
208 |
-
<ProgressBar percentage={topic.percentage} color="blue" />
|
209 |
-
</div>
|
210 |
-
</div>
|
211 |
-
))}
|
212 |
-
</div>
|
213 |
-
|
214 |
-
<div className="mt-4 pt-4 border-t border-gray-200">
|
215 |
-
<p className="text-xs text-gray-500">
|
216 |
-
Based on {stats.totalQueries.toLocaleString()} total queries
|
217 |
-
</p>
|
218 |
-
</div>
|
219 |
-
</div>
|
220 |
-
|
221 |
-
{/* Confidence Distribution */}
|
222 |
-
<div className="card p-6">
|
223 |
-
<div className="flex items-center justify-between mb-6">
|
224 |
-
<h2 className="text-xl font-semibold text-gray-900">Confidence Distribution</h2>
|
225 |
-
<Target className="h-5 w-5 text-gray-400" />
|
226 |
-
</div>
|
227 |
-
|
228 |
-
<div className="space-y-4">
|
229 |
-
{stats.confidenceDistribution.map((range, index) => (
|
230 |
-
<div key={index} className="flex justify-between items-center">
|
231 |
-
<div className="flex-1">
|
232 |
-
<div className="flex justify-between items-center mb-1">
|
233 |
-
<span className="text-sm font-medium text-gray-900">{range.range}</span>
|
234 |
-
<span className="text-sm text-gray-600">{range.count} responses</span>
|
235 |
-
</div>
|
236 |
-
<ProgressBar
|
237 |
-
percentage={range.percentage}
|
238 |
-
color={index === 0 ? 'green' : index === 1 ? 'blue' : index === 2 ? 'yellow' : 'red'}
|
239 |
-
/>
|
240 |
-
</div>
|
241 |
-
</div>
|
242 |
-
))}
|
243 |
-
</div>
|
244 |
-
|
245 |
-
<div className="mt-4 pt-4 border-t border-gray-200">
|
246 |
-
<p className="text-xs text-gray-500">
|
247 |
-
Higher confidence scores indicate more accurate solutions
|
248 |
-
</p>
|
249 |
-
</div>
|
250 |
-
</div>
|
251 |
-
</div>
|
252 |
-
|
253 |
-
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
254 |
-
{/* Source Breakdown */}
|
255 |
-
<div className="card p-6">
|
256 |
-
<div className="flex items-center justify-between mb-6">
|
257 |
-
<h2 className="text-xl font-semibold text-gray-900">Source Breakdown</h2>
|
258 |
-
<Globe className="h-5 w-5 text-gray-400" />
|
259 |
-
</div>
|
260 |
-
|
261 |
-
<div className="space-y-6">
|
262 |
-
<div className="text-center">
|
263 |
-
<div className="relative inline-flex items-center justify-center w-32 h-32">
|
264 |
-
<svg className="w-32 h-32 transform -rotate-90">
|
265 |
-
<circle
|
266 |
-
cx="64"
|
267 |
-
cy="64"
|
268 |
-
r="56"
|
269 |
-
stroke="currentColor"
|
270 |
-
strokeWidth="8"
|
271 |
-
fill="transparent"
|
272 |
-
className="text-gray-200"
|
273 |
-
/>
|
274 |
-
<circle
|
275 |
-
cx="64"
|
276 |
-
cy="64"
|
277 |
-
r="56"
|
278 |
-
stroke="currentColor"
|
279 |
-
strokeWidth="8"
|
280 |
-
fill="transparent"
|
281 |
-
strokeDasharray={`${2 * Math.PI * 56}`}
|
282 |
-
strokeDashoffset={`${2 * Math.PI * 56 * (1 - stats.sourceBreakdown.KB / 100)}`}
|
283 |
-
className="text-blue-600"
|
284 |
-
/>
|
285 |
-
</svg>
|
286 |
-
<div className="absolute inset-0 flex items-center justify-center">
|
287 |
-
<span className="text-2xl font-bold text-gray-900">{stats.sourceBreakdown.KB}%</span>
|
288 |
-
</div>
|
289 |
-
</div>
|
290 |
-
</div>
|
291 |
-
|
292 |
-
<div className="space-y-3">
|
293 |
-
<div className="flex items-center justify-between">
|
294 |
-
<div className="flex items-center">
|
295 |
-
<div className="w-3 h-3 bg-blue-600 rounded-full mr-2" />
|
296 |
-
<span className="text-sm font-medium text-gray-900">Knowledge Base</span>
|
297 |
-
</div>
|
298 |
-
<span className="text-sm text-gray-600">{stats.sourceBreakdown.KB}%</span>
|
299 |
-
</div>
|
300 |
-
|
301 |
-
<div className="flex items-center justify-between">
|
302 |
-
<div className="flex items-center">
|
303 |
-
<div className="w-3 h-3 bg-gray-300 rounded-full mr-2" />
|
304 |
-
<span className="text-sm font-medium text-gray-900">Web Search (MCP)</span>
|
305 |
-
</div>
|
306 |
-
<span className="text-sm text-gray-600">{stats.sourceBreakdown.MCP}%</span>
|
307 |
-
</div>
|
308 |
-
</div>
|
309 |
-
</div>
|
310 |
-
</div>
|
311 |
-
|
312 |
-
{/* System Health */}
|
313 |
-
<div className="card p-6">
|
314 |
-
<div className="flex items-center justify-between mb-6">
|
315 |
-
<h2 className="text-xl font-semibold text-gray-900">System Health</h2>
|
316 |
-
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse" />
|
317 |
-
</div>
|
318 |
-
|
319 |
-
<div className="space-y-4">
|
320 |
-
<div className="flex justify-between items-center">
|
321 |
-
<span className="text-sm font-medium text-gray-700">Database Status</span>
|
322 |
-
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
323 |
-
Healthy
|
324 |
-
</span>
|
325 |
-
</div>
|
326 |
-
|
327 |
-
<div className="flex justify-between items-center">
|
328 |
-
<span className="text-sm font-medium text-gray-700">MCP Service</span>
|
329 |
-
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
330 |
-
Active
|
331 |
-
</span>
|
332 |
-
</div>
|
333 |
-
|
334 |
-
<div className="flex justify-between items-center">
|
335 |
-
<span className="text-sm font-medium text-gray-700">Guardrails</span>
|
336 |
-
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
337 |
-
Enabled
|
338 |
-
</span>
|
339 |
-
</div>
|
340 |
-
|
341 |
-
<div className="flex justify-between items-center">
|
342 |
-
<span className="text-sm font-medium text-gray-700">Vector Index</span>
|
343 |
-
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
344 |
-
5,005 entries
|
345 |
-
</span>
|
346 |
-
</div>
|
347 |
-
|
348 |
-
<div className="flex justify-between items-center">
|
349 |
-
<span className="text-sm font-medium text-gray-700">Uptime</span>
|
350 |
-
<span className="text-sm text-gray-600">99.9%</span>
|
351 |
-
</div>
|
352 |
-
</div>
|
353 |
-
</div>
|
354 |
-
|
355 |
-
{/* Performance Metrics */}
|
356 |
-
<div className="card p-6">
|
357 |
-
<div className="flex items-center justify-between mb-6">
|
358 |
-
<h2 className="text-xl font-semibold text-gray-900">Performance</h2>
|
359 |
-
<BarChart3 className="h-5 w-5 text-gray-400" />
|
360 |
-
</div>
|
361 |
-
|
362 |
-
<div className="space-y-4">
|
363 |
-
<div>
|
364 |
-
<div className="flex justify-between text-sm font-medium text-gray-700 mb-1">
|
365 |
-
<span>Response Time (avg)</span>
|
366 |
-
<span>{stats.averageResponseTime}s</span>
|
367 |
-
</div>
|
368 |
-
<ProgressBar percentage={85} color="green" />
|
369 |
-
</div>
|
370 |
-
|
371 |
-
<div>
|
372 |
-
<div className="flex justify-between text-sm font-medium text-gray-700 mb-1">
|
373 |
-
<span>Accuracy Score</span>
|
374 |
-
<span>{(stats.averageConfidence * 100).toFixed(1)}%</span>
|
375 |
-
</div>
|
376 |
-
<ProgressBar percentage={stats.averageConfidence * 100} color="blue" />
|
377 |
-
</div>
|
378 |
-
|
379 |
-
<div>
|
380 |
-
<div className="flex justify-between text-sm font-medium text-gray-700 mb-1">
|
381 |
-
<span>User Satisfaction</span>
|
382 |
-
<span>92.3%</span>
|
383 |
-
</div>
|
384 |
-
<ProgressBar percentage={92.3} color="purple" />
|
385 |
-
</div>
|
386 |
-
|
387 |
-
<div>
|
388 |
-
<div className="flex justify-between text-sm font-medium text-gray-700 mb-1">
|
389 |
-
<span>Cache Hit Rate</span>
|
390 |
-
<span>78.5%</span>
|
391 |
-
</div>
|
392 |
-
<ProgressBar percentage={78.5} color="orange" />
|
393 |
-
</div>
|
394 |
-
</div>
|
395 |
-
</div>
|
396 |
-
</div>
|
397 |
-
|
398 |
-
{/* Footer Note */}
|
399 |
-
<div className="mt-8 text-center">
|
400 |
-
<p className="text-sm text-gray-500">
|
401 |
-
Analytics data is updated in real-time. All metrics are calculated for the selected time period.
|
402 |
-
</p>
|
403 |
-
</div>
|
404 |
-
</div>
|
405 |
-
</div>
|
406 |
-
);
|
407 |
-
};
|
408 |
-
|
409 |
-
export default Analytics;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/pages/Home.js
DELETED
@@ -1,210 +0,0 @@
|
|
1 |
-
import React from 'react';
|
2 |
-
import { Link } from 'react-router-dom';
|
3 |
-
import { ArrowRight, Calculator, Brain, Zap, Shield, Globe, Database } from 'lucide-react';
|
4 |
-
|
5 |
-
const Home = () => {
|
6 |
-
const features = [
|
7 |
-
{
|
8 |
-
icon: Brain,
|
9 |
-
title: 'AI-Powered Solutions',
|
10 |
-
description: 'Advanced RAG architecture combines knowledge base search with intelligent web fallback',
|
11 |
-
color: 'primary'
|
12 |
-
},
|
13 |
-
{
|
14 |
-
icon: Database,
|
15 |
-
title: '5,000+ Math Problems',
|
16 |
-
description: 'Curated knowledge base with comprehensive step-by-step solutions',
|
17 |
-
color: 'secondary'
|
18 |
-
},
|
19 |
-
{
|
20 |
-
icon: Zap,
|
21 |
-
title: 'Lightning Fast',
|
22 |
-
description: 'Vector similarity search delivers relevant results in milliseconds',
|
23 |
-
color: 'yellow'
|
24 |
-
},
|
25 |
-
{
|
26 |
-
icon: Shield,
|
27 |
-
title: 'Quality Assured',
|
28 |
-
description: 'Multi-layer validation ensures accurate and safe responses',
|
29 |
-
color: 'green'
|
30 |
-
},
|
31 |
-
{
|
32 |
-
icon: Globe,
|
33 |
-
title: 'Web Fallback',
|
34 |
-
description: 'Intelligent fallback to web search when knowledge base confidence is low',
|
35 |
-
color: 'blue'
|
36 |
-
},
|
37 |
-
{
|
38 |
-
icon: Calculator,
|
39 |
-
title: 'Beautiful Math',
|
40 |
-
description: 'KaTeX rendering for properly formatted mathematical expressions',
|
41 |
-
color: 'purple'
|
42 |
-
}
|
43 |
-
];
|
44 |
-
|
45 |
-
const stats = [
|
46 |
-
{ label: 'Math Problems Solved', value: '10,000+', color: 'primary' },
|
47 |
-
{ label: 'Average Response Time', value: '<2s', color: 'secondary' },
|
48 |
-
{ label: 'Accuracy Rate', value: '95%', color: 'green' },
|
49 |
-
{ label: 'Knowledge Base Size', value: '5,005', color: 'blue' }
|
50 |
-
];
|
51 |
-
|
52 |
-
const getColorClasses = (color) => {
|
53 |
-
const colors = {
|
54 |
-
primary: 'text-primary-600 bg-primary-100',
|
55 |
-
secondary: 'text-secondary-600 bg-secondary-100',
|
56 |
-
yellow: 'text-yellow-600 bg-yellow-100',
|
57 |
-
green: 'text-green-600 bg-green-100',
|
58 |
-
blue: 'text-blue-600 bg-blue-100',
|
59 |
-
purple: 'text-purple-600 bg-purple-100'
|
60 |
-
};
|
61 |
-
return colors[color] || colors.primary;
|
62 |
-
};
|
63 |
-
|
64 |
-
return (
|
65 |
-
<div className="min-h-screen">
|
66 |
-
{/* Hero Section */}
|
67 |
-
<section className="relative bg-gradient-to-br from-primary-50 via-white to-secondary-50 py-20 overflow-hidden">
|
68 |
-
<div className="absolute inset-0 bg-grid-pattern opacity-5"></div>
|
69 |
-
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
70 |
-
<div className="text-center">
|
71 |
-
<h1 className="text-4xl md:text-6xl font-bold text-gray-900 mb-6">
|
72 |
-
Meet <span className="gradient-text">MathGenius AI</span>
|
73 |
-
<br />
|
74 |
-
Your Smart Math Companion
|
75 |
-
</h1>
|
76 |
-
<p className="text-xl text-gray-600 mb-8 max-w-3xl mx-auto text-balance">
|
77 |
-
Advanced AI-powered math problem solver using Retrieval-Augmented Generation (RAG)
|
78 |
-
to provide accurate, step-by-step solutions from a curated knowledge base of 5,000+ problems.
|
79 |
-
</p>
|
80 |
-
|
81 |
-
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
82 |
-
<Link
|
83 |
-
to="/search"
|
84 |
-
className="btn btn-primary btn-lg group"
|
85 |
-
>
|
86 |
-
<Calculator className="h-5 w-5 mr-2" />
|
87 |
-
Try MathGenius AI
|
88 |
-
<ArrowRight className="h-5 w-5 ml-2 group-hover:translate-x-1 transition-transform" />
|
89 |
-
</Link>
|
90 |
-
|
91 |
-
<Link
|
92 |
-
to="/about"
|
93 |
-
className="btn btn-outline btn-lg"
|
94 |
-
>
|
95 |
-
Learn How It Works
|
96 |
-
</Link>
|
97 |
-
</div>
|
98 |
-
|
99 |
-
{/* Quick Stats */}
|
100 |
-
<div className="grid grid-cols-2 md:grid-cols-4 gap-6 mt-16">
|
101 |
-
{stats.map((stat, index) => (
|
102 |
-
<div key={index} className="text-center">
|
103 |
-
<div className={`text-3xl font-bold ${stat.color === 'primary' ? 'text-primary-600' :
|
104 |
-
stat.color === 'secondary' ? 'text-secondary-600' :
|
105 |
-
stat.color === 'green' ? 'text-green-600' :
|
106 |
-
'text-blue-600'}`}>
|
107 |
-
{stat.value}
|
108 |
-
</div>
|
109 |
-
<div className="text-sm text-gray-600 mt-1">{stat.label}</div>
|
110 |
-
</div>
|
111 |
-
))}
|
112 |
-
</div>
|
113 |
-
</div>
|
114 |
-
</div>
|
115 |
-
</section>
|
116 |
-
|
117 |
-
{/* Features Section */}
|
118 |
-
<section className="py-20 bg-white">
|
119 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
120 |
-
<div className="text-center mb-16">
|
121 |
-
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
122 |
-
Powerful Features
|
123 |
-
</h2>
|
124 |
-
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
125 |
-
Built with cutting-edge AI technology to deliver the most accurate and helpful math solutions
|
126 |
-
</p>
|
127 |
-
</div>
|
128 |
-
|
129 |
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
130 |
-
{features.map((feature, index) => (
|
131 |
-
<div
|
132 |
-
key={index}
|
133 |
-
className="card-hover p-6 group"
|
134 |
-
>
|
135 |
-
<div className={`w-12 h-12 rounded-lg flex items-center justify-center mb-4 ${getColorClasses(feature.color)} group-hover:scale-110 transition-transform`}>
|
136 |
-
<feature.icon className="h-6 w-6" />
|
137 |
-
</div>
|
138 |
-
<h3 className="text-xl font-semibold text-gray-900 mb-2">
|
139 |
-
{feature.title}
|
140 |
-
</h3>
|
141 |
-
<p className="text-gray-600">
|
142 |
-
{feature.description}
|
143 |
-
</p>
|
144 |
-
</div>
|
145 |
-
))}
|
146 |
-
</div>
|
147 |
-
</div>
|
148 |
-
</section>
|
149 |
-
|
150 |
-
{/* How It Works Section */}
|
151 |
-
<section className="py-20 bg-gray-50">
|
152 |
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
153 |
-
<div className="text-center mb-16">
|
154 |
-
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
155 |
-
How It Works
|
156 |
-
</h2>
|
157 |
-
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
158 |
-
Our 5-step RAG pipeline ensures you get the most accurate and helpful responses
|
159 |
-
</p>
|
160 |
-
</div>
|
161 |
-
|
162 |
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-8">
|
163 |
-
{[
|
164 |
-
{ step: '1', title: 'Input Validation', desc: 'Guardrails ensure safe and valid math questions' },
|
165 |
-
{ step: '2', title: 'Knowledge Search', desc: 'Vector similarity search across 5,000+ problems' },
|
166 |
-
{ step: '3', title: 'Smart Decision', desc: 'AI decides between knowledge base or web search' },
|
167 |
-
{ step: '4', title: 'Response Validation', desc: 'Quality checks and safety validation' },
|
168 |
-
{ step: '5', title: 'Analytics & Learning', desc: 'Performance tracking and continuous improvement' }
|
169 |
-
].map((item, index) => (
|
170 |
-
<div key={index} className="text-center">
|
171 |
-
<div className="w-16 h-16 bg-gradient-to-r from-primary-600 to-secondary-600 rounded-full flex items-center justify-center text-white text-xl font-bold mx-auto mb-4">
|
172 |
-
{item.step}
|
173 |
-
</div>
|
174 |
-
<h3 className="text-lg font-semibold text-gray-900 mb-2">
|
175 |
-
{item.title}
|
176 |
-
</h3>
|
177 |
-
<p className="text-sm text-gray-600">
|
178 |
-
{item.desc}
|
179 |
-
</p>
|
180 |
-
</div>
|
181 |
-
))}
|
182 |
-
</div>
|
183 |
-
</div>
|
184 |
-
</section>
|
185 |
-
|
186 |
-
{/* CTA Section */}
|
187 |
-
<section className="py-20 bg-gradient-to-r from-primary-600 to-secondary-600">
|
188 |
-
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
189 |
-
<h2 className="text-3xl md:text-4xl font-bold text-white mb-4">
|
190 |
-
Ready to Solve Your Math Problems?
|
191 |
-
</h2>
|
192 |
-
<p className="text-xl text-primary-100 mb-8">
|
193 |
-
Experience the power of AI-driven math solutions. Get started in seconds.
|
194 |
-
</p>
|
195 |
-
|
196 |
-
<Link
|
197 |
-
to="/search"
|
198 |
-
className="inline-flex items-center px-8 py-4 bg-white text-primary-600 font-semibold rounded-lg hover:bg-gray-50 transition-colors shadow-lg hover:shadow-xl group"
|
199 |
-
>
|
200 |
-
<Calculator className="h-5 w-5 mr-2" />
|
201 |
-
Start Solving Problems
|
202 |
-
<ArrowRight className="h-5 w-5 ml-2 group-hover:translate-x-1 transition-transform" />
|
203 |
-
</Link>
|
204 |
-
</div>
|
205 |
-
</section>
|
206 |
-
</div>
|
207 |
-
);
|
208 |
-
};
|
209 |
-
|
210 |
-
export default Home;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/pages/Search.js
DELETED
@@ -1,464 +0,0 @@
|
|
1 |
-
import React, { useState } from 'react';
|
2 |
-
import { Search as SearchIcon, Send, Clock, Database, Globe, ThumbsUp, ThumbsDown, Copy, Share2 } from 'lucide-react';
|
3 |
-
import { InlineMath, BlockMath } from 'react-katex';
|
4 |
-
import 'katex/dist/katex.min.css';
|
5 |
-
import toast from 'react-hot-toast';
|
6 |
-
|
7 |
-
import { searchMathProblem, submitFeedback, formatResponseTime, getSourceDisplayName, getConfidenceLevel } from '../utils/api';
|
8 |
-
|
9 |
-
const Search = () => {
|
10 |
-
const [question, setQuestion] = useState('');
|
11 |
-
const [isLoading, setIsLoading] = useState(false);
|
12 |
-
const [searchResult, setSearchResult] = useState(null);
|
13 |
-
const [error, setError] = useState(null);
|
14 |
-
|
15 |
-
const handleSearch = async (e) => {
|
16 |
-
e.preventDefault();
|
17 |
-
|
18 |
-
if (!question.trim()) {
|
19 |
-
toast.error('Please enter a math question');
|
20 |
-
return;
|
21 |
-
}
|
22 |
-
|
23 |
-
setIsLoading(true);
|
24 |
-
setError(null);
|
25 |
-
setSearchResult(null);
|
26 |
-
|
27 |
-
try {
|
28 |
-
const result = await searchMathProblem(question);
|
29 |
-
|
30 |
-
if (result.success) {
|
31 |
-
setSearchResult(result.data);
|
32 |
-
toast.success('Solution found!');
|
33 |
-
} else {
|
34 |
-
setError(result.error);
|
35 |
-
toast.error('Failed to get solution');
|
36 |
-
}
|
37 |
-
} catch (err) {
|
38 |
-
setError('An unexpected error occurred');
|
39 |
-
toast.error('Something went wrong');
|
40 |
-
} finally {
|
41 |
-
setIsLoading(false);
|
42 |
-
}
|
43 |
-
};
|
44 |
-
|
45 |
-
const handleFeedback = async (isCorrect) => {
|
46 |
-
if (!searchResult) return;
|
47 |
-
|
48 |
-
try {
|
49 |
-
const feedbackData = {
|
50 |
-
question: question,
|
51 |
-
response: searchResult.final_answer,
|
52 |
-
correct: isCorrect,
|
53 |
-
response_id: searchResult.response_id
|
54 |
-
};
|
55 |
-
|
56 |
-
const result = await submitFeedback(feedbackData);
|
57 |
-
|
58 |
-
if (result.success) {
|
59 |
-
toast.success('Thanks for your feedback!');
|
60 |
-
} else {
|
61 |
-
toast.error('Error submitting feedback');
|
62 |
-
}
|
63 |
-
} catch (err) {
|
64 |
-
toast.error('Failed to submit feedback');
|
65 |
-
}
|
66 |
-
};
|
67 |
-
|
68 |
-
const copyToClipboard = (text) => {
|
69 |
-
navigator.clipboard.writeText(text);
|
70 |
-
toast.success('Copied to clipboard!');
|
71 |
-
};
|
72 |
-
|
73 |
-
const shareResult = () => {
|
74 |
-
if (navigator.share) {
|
75 |
-
navigator.share({
|
76 |
-
title: 'MathGenius AI Solution',
|
77 |
-
text: `Question: ${question}\n\nSolution: ${searchResult?.final_answer}`,
|
78 |
-
url: window.location.href,
|
79 |
-
});
|
80 |
-
} else {
|
81 |
-
copyToClipboard(`Question: ${question}\n\nSolution: ${searchResult?.final_answer}`);
|
82 |
-
}
|
83 |
-
};
|
84 |
-
|
85 |
-
const renderMathContent = (content) => {
|
86 |
-
if (!content) return '';
|
87 |
-
|
88 |
-
// Convert LaTeX \(...\) and \[...\] to $...$ and $$...$$ format
|
89 |
-
let processedContent = content
|
90 |
-
.replace(/\\?\\\(/g, '$') // \( -> $
|
91 |
-
.replace(/\\?\\\)/g, '$') // \) -> $
|
92 |
-
.replace(/\\?\\\[/g, '$$') // \[ -> $$
|
93 |
-
.replace(/\\?\\\]/g, '$$'); // \] -> $$
|
94 |
-
|
95 |
-
// Handle line breaks and create formatted sections
|
96 |
-
const sections = processedContent.split(/\n\s*\n/); // Split on empty lines
|
97 |
-
|
98 |
-
return (
|
99 |
-
<div className="space-y-4">
|
100 |
-
{sections.map((section, sectionIndex) => {
|
101 |
-
const lines = section.split('\n');
|
102 |
-
|
103 |
-
return (
|
104 |
-
<div key={sectionIndex} className="section">
|
105 |
-
{lines.map((line, lineIndex) => {
|
106 |
-
// Check if line is a section header
|
107 |
-
if (line.match(/^(Solution Steps?|Final Answer|Verification):/i)) {
|
108 |
-
return (
|
109 |
-
<h4 key={lineIndex} className="text-lg font-semibold text-gray-900 mt-6 mb-3 first:mt-0">
|
110 |
-
{line}
|
111 |
-
</h4>
|
112 |
-
);
|
113 |
-
}
|
114 |
-
|
115 |
-
// Process math in the line with robust error handling
|
116 |
-
try {
|
117 |
-
const mathRegex = /\$\$(.+?)\$\$|\$(.+?)\$/g;
|
118 |
-
const parts = line.split(mathRegex);
|
119 |
-
|
120 |
-
if (parts.length === 1 && !line.trim()) {
|
121 |
-
return null; // Skip empty lines
|
122 |
-
}
|
123 |
-
|
124 |
-
return (
|
125 |
-
<div key={lineIndex} className="mb-2 leading-relaxed">
|
126 |
-
{parts.map((part, partIndex) => {
|
127 |
-
if (partIndex % 3 === 1) {
|
128 |
-
// Block math ($$...$$)
|
129 |
-
try {
|
130 |
-
// Clean the math expression before rendering
|
131 |
-
const cleanMath = part.trim();
|
132 |
-
if (!cleanMath) return null;
|
133 |
-
return <BlockMath key={partIndex} math={cleanMath} />;
|
134 |
-
} catch (e) {
|
135 |
-
console.warn('KaTeX block math error:', e.message, 'for expression:', part);
|
136 |
-
return (
|
137 |
-
<div key={partIndex} className="inline-block text-gray-800 font-mono bg-gray-100 px-2 py-1 rounded border">
|
138 |
-
{part}
|
139 |
-
</div>
|
140 |
-
);
|
141 |
-
}
|
142 |
-
} else if (partIndex % 3 === 2) {
|
143 |
-
// Inline math ($...$)
|
144 |
-
try {
|
145 |
-
// Clean the math expression before rendering
|
146 |
-
const cleanMath = part.trim();
|
147 |
-
if (!cleanMath) return null;
|
148 |
-
return <InlineMath key={partIndex} math={cleanMath} />;
|
149 |
-
} catch (e) {
|
150 |
-
console.warn('KaTeX inline math error:', e.message, 'for expression:', part);
|
151 |
-
return (
|
152 |
-
<span key={partIndex} className="text-gray-800 font-mono bg-gray-100 px-1 rounded border">
|
153 |
-
{part}
|
154 |
-
</span>
|
155 |
-
);
|
156 |
-
}
|
157 |
-
} else {
|
158 |
-
// Regular text
|
159 |
-
return part ? <span key={partIndex}>{part}</span> : null;
|
160 |
-
}
|
161 |
-
})}
|
162 |
-
</div>
|
163 |
-
);
|
164 |
-
} catch (e) {
|
165 |
-
console.warn('Error processing line:', e.message, 'for line:', line);
|
166 |
-
return <div key={lineIndex} className="mb-2 leading-relaxed text-gray-800">{line}</div>;
|
167 |
-
}
|
168 |
-
})}
|
169 |
-
</div>
|
170 |
-
);
|
171 |
-
})}
|
172 |
-
</div>
|
173 |
-
);
|
174 |
-
};
|
175 |
-
|
176 |
-
const exampleQuestions = [
|
177 |
-
"Solve the quadratic equation: x² + 5x + 6 = 0",
|
178 |
-
"Find the derivative of f(x) = 3x² + 2x - 1",
|
179 |
-
"What is the integral of sin(x) dx?",
|
180 |
-
"Calculate the limit: lim(x→0) (sin(x)/x)",
|
181 |
-
"Solve the system: 2x + 3y = 7, x - y = 1"
|
182 |
-
];
|
183 |
-
|
184 |
-
return (
|
185 |
-
<div className="min-h-screen bg-gray-50 py-8">
|
186 |
-
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
187 |
-
{/* Header */}
|
188 |
-
<div className="text-center mb-8">
|
189 |
-
<h1 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
190 |
-
<span className="gradient-text">Search & Solve</span> Math Problems
|
191 |
-
</h1>
|
192 |
-
<p className="text-lg text-gray-600">
|
193 |
-
Ask any math question and get detailed, step-by-step solutions
|
194 |
-
</p>
|
195 |
-
</div>
|
196 |
-
|
197 |
-
{/* Search Form */}
|
198 |
-
<div className="card p-6 mb-8">
|
199 |
-
<form onSubmit={handleSearch} className="space-y-4">
|
200 |
-
<div className="relative">
|
201 |
-
<SearchIcon className="absolute left-3 top-3.5 h-5 w-5 text-gray-400" />
|
202 |
-
<textarea
|
203 |
-
value={question}
|
204 |
-
onChange={(e) => setQuestion(e.target.value)}
|
205 |
-
placeholder="Enter your math question here... (e.g., Solve x² + 5x + 6 = 0)"
|
206 |
-
className="textarea pl-10 h-32 resize-none"
|
207 |
-
disabled={isLoading}
|
208 |
-
/>
|
209 |
-
</div>
|
210 |
-
|
211 |
-
<div className="flex justify-between items-center">
|
212 |
-
<span className="text-sm text-gray-500">
|
213 |
-
{question.length}/1000 characters
|
214 |
-
</span>
|
215 |
-
|
216 |
-
<button
|
217 |
-
type="submit"
|
218 |
-
disabled={isLoading || !question.trim()}
|
219 |
-
className="btn btn-primary btn-md"
|
220 |
-
>
|
221 |
-
{isLoading ? (
|
222 |
-
<>
|
223 |
-
<div className="loading-spinner mr-2" />
|
224 |
-
Solving...
|
225 |
-
</>
|
226 |
-
) : (
|
227 |
-
<>
|
228 |
-
<Send className="h-4 w-4 mr-2" />
|
229 |
-
Solve Problem
|
230 |
-
</>
|
231 |
-
)}
|
232 |
-
</button>
|
233 |
-
</div>
|
234 |
-
</form>
|
235 |
-
|
236 |
-
{/* Example Questions */}
|
237 |
-
<div className="mt-6 pt-6 border-t border-gray-200">
|
238 |
-
<h3 className="text-sm font-medium text-gray-700 mb-3">Try these examples:</h3>
|
239 |
-
<div className="flex flex-wrap gap-2">
|
240 |
-
{exampleQuestions.map((example, index) => (
|
241 |
-
<button
|
242 |
-
key={index}
|
243 |
-
onClick={() => setQuestion(example)}
|
244 |
-
disabled={isLoading}
|
245 |
-
className="text-xs px-3 py-1 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-full transition-colors"
|
246 |
-
>
|
247 |
-
{example}
|
248 |
-
</button>
|
249 |
-
))}
|
250 |
-
</div>
|
251 |
-
</div>
|
252 |
-
</div>
|
253 |
-
|
254 |
-
{/* Error State */}
|
255 |
-
{error && (
|
256 |
-
<div className="card p-6 mb-8 border-red-200 bg-red-50">
|
257 |
-
<div className="flex items-center">
|
258 |
-
<div className="flex-shrink-0">
|
259 |
-
<div className="w-10 h-10 bg-red-100 rounded-full flex items-center justify-center">
|
260 |
-
<SearchIcon className="h-5 w-5 text-red-600" />
|
261 |
-
</div>
|
262 |
-
</div>
|
263 |
-
<div className="ml-4">
|
264 |
-
<h3 className="text-lg font-medium text-red-900">Error</h3>
|
265 |
-
<p className="text-red-700">{error}</p>
|
266 |
-
</div>
|
267 |
-
</div>
|
268 |
-
</div>
|
269 |
-
)}
|
270 |
-
|
271 |
-
{/* Search Results */}
|
272 |
-
{searchResult && (
|
273 |
-
<div className="space-y-6">
|
274 |
-
{/* Result Header */}
|
275 |
-
<div className="card p-6">
|
276 |
-
<div className="flex items-start justify-between mb-4">
|
277 |
-
<div className="flex-1">
|
278 |
-
<h2 className="text-xl font-semibold text-gray-900 mb-2">Solution</h2>
|
279 |
-
<div className="flex items-center space-x-4 text-sm text-gray-600">
|
280 |
-
<div className="flex items-center">
|
281 |
-
<Clock className="h-4 w-4 mr-1" />
|
282 |
-
{formatResponseTime(searchResult.response_time_ms)}
|
283 |
-
</div>
|
284 |
-
|
285 |
-
<div className="flex items-center">
|
286 |
-
{searchResult.source === 'KB' ? (
|
287 |
-
<Database className="h-4 w-4 mr-1" />
|
288 |
-
) : (
|
289 |
-
<Globe className="h-4 w-4 mr-1" />
|
290 |
-
)}
|
291 |
-
{getSourceDisplayName(searchResult.source)}
|
292 |
-
</div>
|
293 |
-
|
294 |
-
{searchResult.metadata?.confidence_score && (
|
295 |
-
<div className="flex items-center">
|
296 |
-
<span className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${
|
297 |
-
getConfidenceLevel(searchResult.metadata.confidence_score).color === 'green'
|
298 |
-
? 'bg-green-100 text-green-800'
|
299 |
-
: getConfidenceLevel(searchResult.metadata.confidence_score).color === 'yellow'
|
300 |
-
? 'bg-yellow-100 text-yellow-800'
|
301 |
-
: 'bg-red-100 text-red-800'
|
302 |
-
}`}>
|
303 |
-
{getConfidenceLevel(searchResult.metadata.confidence_score).level} Confidence
|
304 |
-
</span>
|
305 |
-
</div>
|
306 |
-
)}
|
307 |
-
</div>
|
308 |
-
</div>
|
309 |
-
|
310 |
-
<div className="flex space-x-2">
|
311 |
-
<button
|
312 |
-
onClick={() => copyToClipboard(searchResult.final_answer)}
|
313 |
-
className="btn btn-secondary btn-sm"
|
314 |
-
>
|
315 |
-
<Copy className="h-4 w-4" />
|
316 |
-
</button>
|
317 |
-
<button
|
318 |
-
onClick={shareResult}
|
319 |
-
className="btn btn-secondary btn-sm"
|
320 |
-
>
|
321 |
-
<Share2 className="h-4 w-4" />
|
322 |
-
</button>
|
323 |
-
</div>
|
324 |
-
</div>
|
325 |
-
|
326 |
-
<div className="bg-gray-50 rounded-lg p-4 border border-gray-200">
|
327 |
-
<h3 className="font-medium text-gray-900 mb-2">Your Question:</h3>
|
328 |
-
<p className="text-gray-700">{question}</p>
|
329 |
-
</div>
|
330 |
-
</div>
|
331 |
-
|
332 |
-
{/* Answer */}
|
333 |
-
<div className="card p-6">
|
334 |
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">Step-by-Step Solution</h3>
|
335 |
-
|
336 |
-
<div className="prose max-w-none">
|
337 |
-
<div className="bg-white p-6 rounded-lg border border-gray-200 math-content">
|
338 |
-
{renderMathContent(searchResult.final_answer)}
|
339 |
-
</div>
|
340 |
-
</div>
|
341 |
-
|
342 |
-
{searchResult.explanation && (
|
343 |
-
<div className="mt-4 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
344 |
-
<h4 className="font-medium text-blue-900 mb-2">Explanation:</h4>
|
345 |
-
<p className="text-blue-800 text-sm">{searchResult.explanation}</p>
|
346 |
-
</div>
|
347 |
-
)}
|
348 |
-
</div>
|
349 |
-
|
350 |
-
{/* Additional Results */}
|
351 |
-
{searchResult.results && searchResult.results.length > 1 && (
|
352 |
-
<div className="card p-6">
|
353 |
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">Related Solutions</h3>
|
354 |
-
|
355 |
-
<div className="space-y-4">
|
356 |
-
{searchResult.results.slice(1).map((result, index) => (
|
357 |
-
<div key={index} className="p-4 bg-gray-50 rounded-lg border border-gray-200">
|
358 |
-
<div className="flex justify-between items-start mb-2">
|
359 |
-
<h4 className="font-medium text-gray-900">Alternative Solution {index + 1}</h4>
|
360 |
-
<span className="text-xs text-gray-500">
|
361 |
-
Score: {(result.score * 100).toFixed(1)}%
|
362 |
-
</span>
|
363 |
-
</div>
|
364 |
-
<p className="text-gray-700 text-sm mb-2">{result.problem}</p>
|
365 |
-
<div className="text-sm text-gray-600">
|
366 |
-
{renderMathContent(result.solution)}
|
367 |
-
</div>
|
368 |
-
</div>
|
369 |
-
))}
|
370 |
-
</div>
|
371 |
-
</div>
|
372 |
-
)}
|
373 |
-
|
374 |
-
{/* Feedback */}
|
375 |
-
<div className="card p-6">
|
376 |
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">Was this solution helpful?</h3>
|
377 |
-
|
378 |
-
<div className="flex space-x-4">
|
379 |
-
<button
|
380 |
-
onClick={() => handleFeedback(true)}
|
381 |
-
className="btn btn-outline btn-md group"
|
382 |
-
>
|
383 |
-
<ThumbsUp className="h-4 w-4 mr-2 group-hover:text-green-600" />
|
384 |
-
Yes, helpful
|
385 |
-
</button>
|
386 |
-
|
387 |
-
<button
|
388 |
-
onClick={() => handleFeedback(false)}
|
389 |
-
className="btn btn-outline btn-md group"
|
390 |
-
>
|
391 |
-
<ThumbsDown className="h-4 w-4 mr-2 group-hover:text-red-600" />
|
392 |
-
Needs improvement
|
393 |
-
</button>
|
394 |
-
</div>
|
395 |
-
|
396 |
-
<p className="text-sm text-gray-600 mt-3">
|
397 |
-
Your feedback helps us improve the quality of our solutions.
|
398 |
-
</p>
|
399 |
-
</div>
|
400 |
-
|
401 |
-
{/* Metadata */}
|
402 |
-
{searchResult.metadata && (
|
403 |
-
<div className="card p-6">
|
404 |
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">Technical Details</h3>
|
405 |
-
|
406 |
-
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 text-sm">
|
407 |
-
<div>
|
408 |
-
<span className="font-medium text-gray-700">Response ID:</span>
|
409 |
-
<br />
|
410 |
-
<span className="text-gray-600 font-mono text-xs">{searchResult.response_id}</span>
|
411 |
-
</div>
|
412 |
-
|
413 |
-
{searchResult.metadata.confidence_score && (
|
414 |
-
<div>
|
415 |
-
<span className="font-medium text-gray-700">Confidence:</span>
|
416 |
-
<br />
|
417 |
-
<span className="text-gray-600">{(searchResult.metadata.confidence_score * 100).toFixed(1)}%</span>
|
418 |
-
</div>
|
419 |
-
)}
|
420 |
-
|
421 |
-
{searchResult.metadata.kb_results_count !== undefined && (
|
422 |
-
<div>
|
423 |
-
<span className="font-medium text-gray-700">KB Results:</span>
|
424 |
-
<br />
|
425 |
-
<span className="text-gray-600">{searchResult.metadata.kb_results_count}</span>
|
426 |
-
</div>
|
427 |
-
)}
|
428 |
-
|
429 |
-
{searchResult.metadata.search_strategy && (
|
430 |
-
<div>
|
431 |
-
<span className="font-medium text-gray-700">Strategy:</span>
|
432 |
-
<br />
|
433 |
-
<span className="text-gray-600">{searchResult.metadata.search_strategy}</span>
|
434 |
-
</div>
|
435 |
-
)}
|
436 |
-
|
437 |
-
{searchResult.metadata.response_quality && (
|
438 |
-
<div>
|
439 |
-
<span className="font-medium text-gray-700">Quality Score:</span>
|
440 |
-
<br />
|
441 |
-
<span className="text-gray-600">{(searchResult.metadata.response_quality * 100).toFixed(1)}%</span>
|
442 |
-
</div>
|
443 |
-
)}
|
444 |
-
|
445 |
-
{searchResult.metadata.guardrails_applied !== undefined && (
|
446 |
-
<div>
|
447 |
-
<span className="font-medium text-gray-700">Safety Check:</span>
|
448 |
-
<br />
|
449 |
-
<span className="text-gray-600">
|
450 |
-
{searchResult.metadata.guardrails_applied ? 'Applied' : 'Passed'}
|
451 |
-
</span>
|
452 |
-
</div>
|
453 |
-
)}
|
454 |
-
</div>
|
455 |
-
</div>
|
456 |
-
)}
|
457 |
-
</div>
|
458 |
-
)}
|
459 |
-
</div>
|
460 |
-
</div>
|
461 |
-
);
|
462 |
-
};
|
463 |
-
|
464 |
-
export default Search;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/utils/api.js
DELETED
@@ -1,138 +0,0 @@
|
|
1 |
-
// API configuration
|
2 |
-
const API_BASE_URL = process.env.NODE_ENV === 'production'
|
3 |
-
? 'https://your-huggingface-space-url.hf.space' // Replace with actual HF Space URL
|
4 |
-
: 'http://localhost:8000';
|
5 |
-
|
6 |
-
// API endpoints
|
7 |
-
export const API_ENDPOINTS = {
|
8 |
-
search: `${API_BASE_URL}/api/search`,
|
9 |
-
feedback: `${API_BASE_URL}/api/feedback`,
|
10 |
-
};
|
11 |
-
|
12 |
-
// Search function
|
13 |
-
export const searchMathProblem = async (question) => {
|
14 |
-
try {
|
15 |
-
const response = await fetch(API_ENDPOINTS.search, {
|
16 |
-
method: 'POST',
|
17 |
-
headers: {
|
18 |
-
'Content-Type': 'application/json',
|
19 |
-
},
|
20 |
-
body: JSON.stringify({ question }),
|
21 |
-
});
|
22 |
-
|
23 |
-
if (!response.ok) {
|
24 |
-
throw new Error(`HTTP error! status: ${response.status}`);
|
25 |
-
}
|
26 |
-
|
27 |
-
const data = await response.json();
|
28 |
-
return {
|
29 |
-
success: true,
|
30 |
-
data,
|
31 |
-
};
|
32 |
-
} catch (error) {
|
33 |
-
console.error('Search API error:', error);
|
34 |
-
return {
|
35 |
-
success: false,
|
36 |
-
error: error.message,
|
37 |
-
};
|
38 |
-
}
|
39 |
-
};
|
40 |
-
|
41 |
-
// Feedback function
|
42 |
-
export const submitFeedback = async (feedbackData) => {
|
43 |
-
try {
|
44 |
-
const response = await fetch(API_ENDPOINTS.feedback, {
|
45 |
-
method: 'POST',
|
46 |
-
headers: {
|
47 |
-
'Content-Type': 'application/json',
|
48 |
-
},
|
49 |
-
body: JSON.stringify(feedbackData),
|
50 |
-
});
|
51 |
-
|
52 |
-
if (!response.ok) {
|
53 |
-
throw new Error(`HTTP error! status: ${response.status}`);
|
54 |
-
}
|
55 |
-
|
56 |
-
const data = await response.json();
|
57 |
-
return {
|
58 |
-
success: true,
|
59 |
-
data,
|
60 |
-
};
|
61 |
-
} catch (error) {
|
62 |
-
console.error('Feedback API error:', error);
|
63 |
-
return {
|
64 |
-
success: false,
|
65 |
-
error: error.message,
|
66 |
-
};
|
67 |
-
}
|
68 |
-
};
|
69 |
-
|
70 |
-
// Helper function to format response time
|
71 |
-
export const formatResponseTime = (ms) => {
|
72 |
-
if (ms < 1000) {
|
73 |
-
return `${Math.round(ms)}ms`;
|
74 |
-
}
|
75 |
-
return `${(ms / 1000).toFixed(2)}s`;
|
76 |
-
};
|
77 |
-
|
78 |
-
// Helper function to get source display name
|
79 |
-
export const getSourceDisplayName = (source) => {
|
80 |
-
switch (source) {
|
81 |
-
case 'KB':
|
82 |
-
return 'Knowledge Base';
|
83 |
-
case 'MCP':
|
84 |
-
return 'Web Search';
|
85 |
-
default:
|
86 |
-
return source;
|
87 |
-
}
|
88 |
-
};
|
89 |
-
|
90 |
-
// Helper function to get confidence level
|
91 |
-
export const getConfidenceLevel = (score) => {
|
92 |
-
if (score >= 0.8) return { level: 'High', color: 'green' };
|
93 |
-
if (score >= 0.6) return { level: 'Medium', color: 'yellow' };
|
94 |
-
if (score >= 0.4) return { level: 'Low', color: 'orange' };
|
95 |
-
return { level: 'Very Low', color: 'red' };
|
96 |
-
};
|
97 |
-
|
98 |
-
// Mock analytics data - replace with real API call when backend analytics endpoint is ready
|
99 |
-
export const getAnalyticsData = async (timeframe = '7d') => {
|
100 |
-
// Simulate API delay
|
101 |
-
await new Promise(resolve => setTimeout(resolve, 500));
|
102 |
-
|
103 |
-
return {
|
104 |
-
success: true,
|
105 |
-
data: {
|
106 |
-
totalQueries: 2847,
|
107 |
-
averageResponseTime: 1.2,
|
108 |
-
kbHitRate: 0.82,
|
109 |
-
averageConfidence: 0.86,
|
110 |
-
totalUsers: 156,
|
111 |
-
popularTopics: [
|
112 |
-
{ topic: 'Quadratic Equations', count: 342, percentage: 12.0 },
|
113 |
-
{ topic: 'Calculus Derivatives', count: 298, percentage: 10.5 },
|
114 |
-
{ topic: 'Linear Algebra', count: 267, percentage: 9.4 },
|
115 |
-
{ topic: 'Trigonometry', count: 234, percentage: 8.2 },
|
116 |
-
{ topic: 'Integration', count: 198, percentage: 7.0 },
|
117 |
-
{ topic: 'Statistics', count: 187, percentage: 6.6 }
|
118 |
-
],
|
119 |
-
responseTimeHistory: [
|
120 |
-
{ date: '2024-01-01', avgTime: 1.1 },
|
121 |
-
{ date: '2024-01-02', avgTime: 1.3 },
|
122 |
-
{ date: '2024-01-03', avgTime: 1.0 },
|
123 |
-
{ date: '2024-01-04', avgTime: 1.4 },
|
124 |
-
{ date: '2024-01-05', avgTime: 1.2 },
|
125 |
-
{ date: '2024-01-06', avgTime: 1.1 },
|
126 |
-
{ date: '2024-01-07', avgTime: 1.2 }
|
127 |
-
],
|
128 |
-
confidenceDistribution: [
|
129 |
-
{ range: '90-100%', count: 1520, percentage: 53.4 },
|
130 |
-
{ range: '80-89%', count: 823, percentage: 28.9 },
|
131 |
-
{ range: '70-79%', count: 341, percentage: 12.0 },
|
132 |
-
{ range: '60-69%', count: 118, percentage: 4.1 },
|
133 |
-
{ range: '50-59%', count: 45, percentage: 1.6 }
|
134 |
-
],
|
135 |
-
sourceBreakdown: { KB: 82, MCP: 18 }
|
136 |
-
}
|
137 |
-
};
|
138 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/tailwind.config.js
DELETED
@@ -1,68 +0,0 @@
|
|
1 |
-
/** @type {import('tailwindcss').Config} */
|
2 |
-
module.exports = {
|
3 |
-
content: [
|
4 |
-
"./src/**/*.{js,jsx,ts,tsx}",
|
5 |
-
],
|
6 |
-
theme: {
|
7 |
-
extend: {
|
8 |
-
colors: {
|
9 |
-
primary: {
|
10 |
-
50: '#f0f9ff',
|
11 |
-
100: '#e0f2fe',
|
12 |
-
200: '#bae6fd',
|
13 |
-
300: '#7dd3fc',
|
14 |
-
400: '#38bdf8',
|
15 |
-
500: '#0ea5e9',
|
16 |
-
600: '#0284c7',
|
17 |
-
700: '#0369a1',
|
18 |
-
800: '#075985',
|
19 |
-
900: '#0c4a6e',
|
20 |
-
},
|
21 |
-
secondary: {
|
22 |
-
50: '#fdf4ff',
|
23 |
-
100: '#fae8ff',
|
24 |
-
200: '#f5d0fe',
|
25 |
-
300: '#f0abfc',
|
26 |
-
400: '#e879f9',
|
27 |
-
500: '#d946ef',
|
28 |
-
600: '#c026d3',
|
29 |
-
700: '#a21caf',
|
30 |
-
800: '#86198f',
|
31 |
-
900: '#701a75',
|
32 |
-
},
|
33 |
-
gray: {
|
34 |
-
50: '#f9fafb',
|
35 |
-
100: '#f3f4f6',
|
36 |
-
200: '#e5e7eb',
|
37 |
-
300: '#d1d5db',
|
38 |
-
400: '#9ca3af',
|
39 |
-
500: '#6b7280',
|
40 |
-
600: '#4b5563',
|
41 |
-
700: '#374151',
|
42 |
-
800: '#1f2937',
|
43 |
-
900: '#111827',
|
44 |
-
}
|
45 |
-
},
|
46 |
-
fontFamily: {
|
47 |
-
sans: ['Inter', 'system-ui', 'sans-serif'],
|
48 |
-
mono: ['JetBrains Mono', 'monospace'],
|
49 |
-
},
|
50 |
-
animation: {
|
51 |
-
'fade-in': 'fadeIn 0.5s ease-in-out',
|
52 |
-
'slide-up': 'slideUp 0.3s ease-out',
|
53 |
-
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
54 |
-
},
|
55 |
-
keyframes: {
|
56 |
-
fadeIn: {
|
57 |
-
'0%': { opacity: '0' },
|
58 |
-
'100%': { opacity: '1' },
|
59 |
-
},
|
60 |
-
slideUp: {
|
61 |
-
'0%': { transform: 'translateY(10px)', opacity: '0' },
|
62 |
-
'100%': { transform: 'translateY(0)', opacity: '1' },
|
63 |
-
},
|
64 |
-
}
|
65 |
-
},
|
66 |
-
},
|
67 |
-
plugins: [],
|
68 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# FastAPI and web server
|
2 |
+
# fastapi==0.104.1
|
3 |
+
fastapi>=0.111.0,<1.0.0
|
4 |
+
# uvicorn[standard]==0.24.0
|
5 |
+
uvicorn[standard]
|
6 |
+
|
7 |
+
# HTTP client
|
8 |
+
httpx>=0.26.0
|
9 |
+
|
10 |
+
# Qdrant vector database
|
11 |
+
qdrant-client==1.8.0
|
12 |
+
|
13 |
+
# AI Guardrails
|
14 |
+
guardrails-ai==0.4.5
|
15 |
+
|
16 |
+
# Google Generative AI (Gemini)
|
17 |
+
google-generativeai==0.8.3
|
18 |
+
|
19 |
+
# Environment management
|
20 |
+
python-dotenv==1.0.0
|
21 |
+
|
22 |
+
# Structured logging
|
23 |
+
structlog==23.2.0
|
24 |
+
|
25 |
+
# Data processing and embeddings
|
26 |
+
datasets==2.18.0
|
27 |
+
pandas==2.1.4
|
28 |
+
sentence-transformers==2.2.2
|
29 |
+
huggingface_hub>=0.23.0 # Added to ensure compatibility with datasets==2.18.0
|
30 |
+
|
31 |
+
# MCP client (for web search integration)
|
32 |
+
# fastmcp==0.3.0
|
33 |
+
fastmcp
|
34 |
+
|
35 |
+
# Data validation
|
36 |
+
pydantic>=2.7.0,<3.0.0
|
37 |
+
|
38 |
+
# JSON handling
|
39 |
+
orjson==3.9.10
|
40 |
+
|
41 |
+
# Progress tracking
|
42 |
+
tqdm>=4.66.0
|