diff --git a/.gitignore b/.gitignore deleted file mode 100644 index da1e8bb..0000000 --- a/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -__pycache__/ -*.pyc -*.pyo -*.pyd -.pytest_cache/ -*.log -backend.log -backend.err.log -.env -node_modules/ -dist/ -.DS_Store diff --git a/README.md b/README.md deleted file mode 100644 index 9ef279e..0000000 --- a/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# RAG-Powered Brand Product Search Engine - -This is the v2.0 upgrade of the Indian FMCG product catalog project: the -same discovery/enrichment pipeline (Ollama + pgvector + S3 image -storage), now with a **Retrieval-Augmented Generation (RAG) layer** and a -**React UI** in place of the old Streamlit app. - -Two independent pieces: - -- **`backend/`** - FastAPI service. Browse/search/chat endpoints over a - pgvector-backed catalog; a RAG chat endpoint that retrieves relevant - products and asks a local Ollama model to answer grounded in them. -- **`frontend/`** - React + Vite single-page app: product search/browse - grid, a conversational "Ask AI" panel with source citations, and an - admin page to ingest new brands. - -See **`docs/`** for the full architecture write-up, setup guide, and API -reference. The two component READMEs (`backend/README.md`, -`frontend/README.md`) are quick local references once you've read the -main docs once. - -> **v3.0 update:** this project now also includes a **Multi-Store -> Intelligence** layer - 5 simulated stores with independent pricing -> and inventory, ML-based dynamic discounts, trending-product -> detection, a hybrid recommendation engine, and a full analytics -> dashboard. See **`docs/CHANGES.docx`** for the complete write-up -> (architecture decisions, database schema, API reference, and setup -> guide), or jump straight to `backend/scripts/seed_store_intelligence.py` -> and `backend/scripts/train_ml_models.py` to try it. - -> **v3.1 update:** added an **AI Nutritional Intelligence** module - -> verified nutrition facts retrieved from Open Food Facts (never LLM- -> generated), transparent/configurable health & nutrition scoring, -> allergen and diet-compatibility detection, ML-based nutritional -> similarity and clustering, healthier-alternative suggestions, -> personalized nutrition recommendations, and a nutrition analytics -> dashboard. See **`docs/NUTRITION_MODULE.docx`** for the complete -> write-up, or jump straight to `backend/scripts/enrich_nutrition.py` -> and `backend/scripts/train_nutrition_models.py` to try it. - -## Fastest Path to Execute Project (Instant 1-Command Startup) - -The project now includes a **unified single-command launcher** and **automated background initialization**. You no longer need to manually run multiple seed scripts or manage separate terminals: - -```bash -# Single command from project root (starts Docker, Backend, and Frontend): -python run_project.py - -# Or on Windows, double-click: -start_app.bat -``` - -The system automatically: -1. Starts the PostgreSQL container via Docker Desktop. -2. Checks database status and skips redundant seeding for instant boot (< 2 seconds). -3. Launches Backend API (`http://localhost:8000`) and Frontend UI (`http://localhost:5173`) concurrently. -4. Auto-seeds missing catalogs or store intelligence in the background if the database is empty. - -### Individual Commands (Optional / Advanced) -- Backend: `start_backend.bat` or `python -m uvicorn app.main:app --reload --port 8000` -- Frontend: `start_frontend.bat` or `npm run dev` -- System Status API: `http://localhost:8000/api/system/status` - -## Why this exists (what changed from v1.0) - -The original project (`Project_LLM`) could discover, enrich, and store -products with embeddings in pgvector - but nothing ever read those -embeddings back out. There was no similarity-search function, no API -layer (`app/api/` was an empty folder), and the UI was a Streamlit app -that only ever queried the catalog by exact brand/category, never by -meaning. This project adds the missing retrieval layer -(`vector_store.semantic_search`), a RAG orchestration service -(`rag_service.py`), a full FastAPI surface, and a React UI to use it. - -It also fixes a real security issue: `app/infrastructure/settings.py` -used to hard-code a live database host/port/password as Python literal -fallbacks. Every credential now comes only from environment -variables/`.env` - see `backend/app/infrastructure/settings.py` for -details, and `docs/` for the full write-up. diff --git a/backend.err.log b/backend.err.log deleted file mode 100644 index e69de29..0000000 diff --git a/backend.log b/backend.log deleted file mode 100644 index e69de29..0000000 diff --git a/backend/README.md b/backend/README.md index dcb21ae..db048b2 100644 --- a/backend/README.md +++ b/backend/README.md @@ -12,6 +12,16 @@ documentation (`docs/`). This file is just a fast local reference. ## Quick start +### One-click (Windows) + +Double-click **`start_backend.bat`**. It picks up `venv\Scripts\python.exe` +if present (else falls back to system `python`), starts/creates the +`catalog_rag_postgres` Docker container from `docker-compose.yml`, +launches Ollama in the background if it's installed but not running, +seeds sample data if needed, then starts uvicorn on port 8000. + +### Manual + ```bash cd backend python3 -m venv .venv @@ -23,7 +33,7 @@ cp .env.example .env # then edit DB_PASSWORD etc. # Option A: already have a Postgres+pgvector catalog from the old project? # Just point .env at it (DB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASSWORD) - done. # Option B: starting fresh locally? -docker compose -f ../docker-compose.yml up -d +docker compose -f docker-compose.yml up -d python scripts/seed_sample_data.py # loads bundled sample catalogs instantly uvicorn app.main:app --reload --port 8000 diff --git a/docker-compose.yml b/backend/docker-compose.yml similarity index 100% rename from docker-compose.yml rename to backend/docker-compose.yml diff --git a/frontend/README.md b/frontend/README.md index 1219880..3c8382d 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -9,6 +9,14 @@ is a fast local reference. ## Quick start +### One-click (Windows) + +Double-click **`start_frontend.bat`**. It checks whether the backend is +reachable on port 8000 (just a warning, not a blocker) and starts the +Vite dev server. + +### Manual + ```bash cd frontend npm install @@ -17,7 +25,8 @@ npm run dev Open http://localhost:5173 - the Vite dev server proxies `/api/*` to `http://localhost:8000` automatically (see `vite.config.js`), so make -sure the backend is running there first (`../backend/README.md`). +sure the backend is running there first (`../backend/README.md`, +`../backend/start_backend.bat`). If your backend runs somewhere else, set `VITE_API_BASE_URL` in a local `.env` file (copy `.env.example`) instead of relying on the proxy. diff --git a/push_to_git.bat b/push_to_git.bat deleted file mode 100644 index 8aa29ad..0000000 --- a/push_to_git.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -set "PATH=C:\Users\srira\AppData\Local\Programs\Git\cmd;%PATH%" -echo Checking Git version... -git --version -echo. -echo Staging and committing changes... -git add . -git commit -m "Initial commit and updates" -echo. -echo Pushing to remote repository (https://gitapp.workolik.com/nearle_daily/Catalogue_pos_nearle.git)... -git push -u origin main -echo. -echo Done! -pause diff --git a/run_project.py b/run_project.py deleted file mode 100644 index 36f3db3..0000000 --- a/run_project.py +++ /dev/null @@ -1,217 +0,0 @@ -#!/usr/bin/env python3 -""" -Unified Single-Command Project Launcher for Brand Catalog Product LLM & RAG Intelligence Engine. - -Usage: - python run_project.py - -What this script automates: - 1. Checks & launches PostgreSQL via Docker Compose (`docker compose up -d`). - 2. Starts FastAPI backend server on http://localhost:8000 (with background auto-seeding). - 3. Waits until backend port 8000 is live & ready to receive connections. - 4. Starts Vite frontend dev server on http://localhost:5173. - 5. Keeps both servers running concurrently with instant hot-reloading & single Ctrl+C exit. -""" -import os -import sys -import time -import subprocess -import signal -import shutil -import urllib.request -from pathlib import Path - -if sys.platform == "win32": - try: - sys.stdout.reconfigure(encoding="utf-8", errors="replace") - sys.stderr.reconfigure(encoding="utf-8", errors="replace") - except Exception: - pass - - -ROOT_DIR = Path(__file__).resolve().parent -BACKEND_DIR = ROOT_DIR / "backend" -FRONTEND_DIR = ROOT_DIR / "frontend" -VENV_PYTHON = BACKEND_DIR / "venv" / "Scripts" / "python.exe" - -if not VENV_PYTHON.exists(): - VENV_PYTHON = Path(sys.executable) - - -def print_banner(): - print("\033[96m" + "=" * 70) - print(" šŸš€ BRAND CATALOG PRODUCT LLM & RAG INTELLIGENCE ENGINE") - print("=" * 70 + "\033[0m") - - -def start_docker(): - print("\nšŸ“¦ Checking PostgreSQL Docker container...") - compose_file = ROOT_DIR / "docker-compose.yml" - if not compose_file.exists(): - compose_file = BACKEND_DIR / "docker-compose.yml" - - if not shutil.which("docker"): - print("ā„¹ļø Docker CLI not found. Skipping container management.") - return - - # 1. Check if container is already running - try: - check_running = subprocess.run( - ["docker", "ps", "--filter", "name=catalog_rag_postgres", "--format", "{{.Names}}"], - capture_output=True, text=True - ) - if "catalog_rag_postgres" in check_running.stdout: - print("āœ… PostgreSQL container 'catalog_rag_postgres' is running on port 5432 (pgvector ready).") - return - except Exception: - pass - - # 2. Check if stopped container exists and start it - try: - check_all = subprocess.run( - ["docker", "ps", "-a", "--filter", "name=catalog_rag_postgres", "--format", "{{.Names}}"], - capture_output=True, text=True - ) - if "catalog_rag_postgres" in check_all.stdout: - print("šŸ”„ Starting existing 'catalog_rag_postgres' container...") - start_res = subprocess.run(["docker", "start", "catalog_rag_postgres"], capture_output=True, text=True) - if start_res.returncode == 0: - print("āœ… PostgreSQL container started on port 5432 (pgvector ready).") - return - except Exception: - pass - - # 3. Fallback to Docker Compose - if compose_file.exists(): - try: - res = subprocess.run( - ["docker", "compose", "-f", str(compose_file), "up", "-d", "--remove-orphans"], - capture_output=True, text=True - ) - if res.returncode == 0: - print("āœ… PostgreSQL container is running on port 5432 (pgvector ready).") - else: - stderr_msg = res.stderr.strip() - if "Conflict" in stderr_msg or "already in use" in stderr_msg: - print("āš ļø Container name conflict detected. Automatically resetting container...") - subprocess.run(["docker", "rm", "-f", "catalog_rag_postgres"], capture_output=True, text=True) - retry_res = subprocess.run( - ["docker", "compose", "-f", str(compose_file), "up", "-d"], - capture_output=True, text=True - ) - if retry_res.returncode == 0: - print("āœ… PostgreSQL container successfully recreated on port 5432 (pgvector ready).") - return - print("āš ļø Docker notice:", stderr_msg or "Ensure Docker Desktop is running if using Docker Postgres.") - except Exception as e: - print(f"āš ļø Docker check skipped: {e}") - - -def start_ollama(): - print("\nšŸ¦™ Checking Ollama LLM service...") - try: - req = urllib.request.urlopen("http://localhost:11434/api/tags", timeout=2) - if req.getcode() == 200: - print("āœ… Ollama LLM server is running on http://localhost:11434.") - return None - except Exception: - pass - - if not shutil.which("ollama"): - print("ā„¹ļø Ollama CLI not installed/found. Backend will use catalog-grounded fallback responses.") - return None - - try: - p = subprocess.Popen(["ollama", "serve"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - print("šŸš€ Automatically launched Ollama LLM server background process.") - return p - except Exception as e: - print(f"āš ļø Ollama auto-launch note: {e} (App will use catalog grounded fallback).") - return None - - -def wait_for_backend_ready(): - print("ā³ Waiting for backend API to initialize on port 8000...") - for _ in range(30): - try: - req = urllib.request.urlopen("http://127.0.0.1:8000/api/system/status", timeout=1) - if req.getcode() == 200: - print("āœ… Backend API is live and accepting connections on port 8000.") - return True - except Exception: - time.sleep(0.5) - return False - - -def main(): - print_banner() - start_docker() - p_ollama = start_ollama() - - processes = [] - if p_ollama: - processes.append(p_ollama) - - try: - # 1. Start Backend FastAPI Uvicorn - print("\n⚔ Starting Backend FastAPI Server (http://localhost:8000)...") - backend_cmd = [ - str(VENV_PYTHON), "-m", "uvicorn", "app.main:app", - "--reload", "--host", "0.0.0.0", "--port", "8000" - ] - env_backend = os.environ.copy() - env_backend["PYTHONPATH"] = str(BACKEND_DIR) - env_backend["PYTHONIOENCODING"] = "utf-8" - - p_backend = subprocess.Popen( - backend_cmd, cwd=str(BACKEND_DIR), env=env_backend - ) - processes.append(p_backend) - - # 2. Wait until Backend is ready before starting Vite frontend - wait_for_backend_ready() - - # 3. Start Frontend Vite Dev Server - print("šŸŽØ Starting Frontend Vite Server (http://localhost:5173)...") - npm_cmd = "npm.cmd" if sys.platform == "win32" else "npm" - p_frontend = subprocess.Popen( - [npm_cmd, "run", "dev"], cwd=str(FRONTEND_DIR), shell=(sys.platform == "win32") - ) - processes.append(p_frontend) - - print("\n\033[92m" + "=" * 70) - print(" šŸŽ‰ APPLICATION IS LIVE AND READY!") - print("=" * 70 + "\033[0m") - print(" šŸ‘‰ Web App UI: \033[94mhttp://localhost:5173\033[0m") - print(" šŸ‘‰ Backend API: \033[94mhttp://localhost:8000\033[0m") - print(" šŸ‘‰ API Docs: \033[94mhttp://localhost:8000/docs\033[0m") - print(" šŸ‘‰ System Status: \033[94mhttp://localhost:8000/api/system/status\033[0m") - print("=" * 70) - print(" (Press Ctrl+C to stop all servers gracefully)\n") - - # Monitor core processes (backend & frontend) - core_processes = [p_backend, p_frontend] - while True: - time.sleep(1) - for p in core_processes: - if p.poll() is not None: - print(f"āš ļø Core process PID {p.pid} exited with code {p.returncode}") - return - - except KeyboardInterrupt: - print("\nšŸ›‘ Stopping all services...") - finally: - for p in processes: - try: - p.terminate() - p.wait(timeout=3) - except Exception: - try: - p.kill() - except Exception: - pass - print("šŸ‘‹ Goodbye! All processes terminated.") - - -if __name__ == "__main__": - main() diff --git a/start_backend.bat b/start_backend.bat deleted file mode 100644 index 0d8497d..0000000 --- a/start_backend.bat +++ /dev/null @@ -1,8 +0,0 @@ -@echo off -title Kirana AI - Backend FastAPI Server -echo Starting Backend API (http://localhost:8000)... -cd /d "%~dp0backend" -if exist "venv\Scripts\activate.bat" call venv\Scripts\activate.bat -python scripts\seed_sample_data.py --skip-if-seeded -python -m uvicorn app.main:app --reload --port 8000 -pause diff --git a/start_frontend.bat b/start_frontend.bat deleted file mode 100644 index afc50ae..0000000 --- a/start_frontend.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -echo Starting Kirana AI Frontend (React + Vite)... -cd /d "%~dp0frontend" -npm run dev -pause