Spaces:
Sleeping
Sleeping
all in one go
Browse files- .gitignore +21 -200
- Data/machine_learning.txt +15 -0
- Data/python_intro.txt +13 -0
- Dockerfile +64 -0
- LICENSE +1 -1
- README.md +1 -0
- app.py +130 -0
- config/config.yaml +76 -0
- main.py +33 -0
- params.yaml +43 -0
- requirements.txt +29 -0
- setup.py +54 -0
- src/__init__.py +0 -0
- src/data_loader.py +157 -0
- src/embedding.py +40 -0
- src/search.py +114 -0
- src/vectorstore.py +103 -0
- temp.py +40 -0
- test_updates.py +123 -0
.gitignore
CHANGED
|
@@ -1,207 +1,28 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
*$py.class
|
| 5 |
-
|
| 6 |
-
# C extensions
|
| 7 |
-
*.so
|
| 8 |
-
|
| 9 |
-
# Distribution / packaging
|
| 10 |
-
.Python
|
| 11 |
-
build/
|
| 12 |
-
develop-eggs/
|
| 13 |
-
dist/
|
| 14 |
-
downloads/
|
| 15 |
-
eggs/
|
| 16 |
-
.eggs/
|
| 17 |
-
lib/
|
| 18 |
-
lib64/
|
| 19 |
-
parts/
|
| 20 |
-
sdist/
|
| 21 |
-
var/
|
| 22 |
-
wheels/
|
| 23 |
-
share/python-wheels/
|
| 24 |
-
*.egg-info/
|
| 25 |
-
.installed.cfg
|
| 26 |
-
*.egg
|
| 27 |
-
MANIFEST
|
| 28 |
-
|
| 29 |
-
# PyInstaller
|
| 30 |
-
# Usually these files are written by a python script from a template
|
| 31 |
-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
| 32 |
-
*.manifest
|
| 33 |
-
*.spec
|
| 34 |
-
|
| 35 |
-
# Installer logs
|
| 36 |
-
pip-log.txt
|
| 37 |
-
pip-delete-this-directory.txt
|
| 38 |
-
|
| 39 |
-
# Unit test / coverage reports
|
| 40 |
-
htmlcov/
|
| 41 |
-
.tox/
|
| 42 |
-
.nox/
|
| 43 |
-
.coverage
|
| 44 |
-
.coverage.*
|
| 45 |
-
.cache
|
| 46 |
-
nosetests.xml
|
| 47 |
-
coverage.xml
|
| 48 |
-
*.cover
|
| 49 |
-
*.py.cover
|
| 50 |
-
.hypothesis/
|
| 51 |
-
.pytest_cache/
|
| 52 |
-
cover/
|
| 53 |
-
|
| 54 |
-
# Translations
|
| 55 |
-
*.mo
|
| 56 |
-
*.pot
|
| 57 |
-
|
| 58 |
-
# Django stuff:
|
| 59 |
-
*.log
|
| 60 |
-
local_settings.py
|
| 61 |
-
db.sqlite3
|
| 62 |
-
db.sqlite3-journal
|
| 63 |
-
|
| 64 |
-
# Flask stuff:
|
| 65 |
-
instance/
|
| 66 |
-
.webassets-cache
|
| 67 |
-
|
| 68 |
-
# Scrapy stuff:
|
| 69 |
-
.scrapy
|
| 70 |
-
|
| 71 |
-
# Sphinx documentation
|
| 72 |
-
docs/_build/
|
| 73 |
-
|
| 74 |
-
# PyBuilder
|
| 75 |
-
.pybuilder/
|
| 76 |
-
target/
|
| 77 |
-
|
| 78 |
-
# Jupyter Notebook
|
| 79 |
-
.ipynb_checkpoints
|
| 80 |
-
|
| 81 |
-
# IPython
|
| 82 |
-
profile_default/
|
| 83 |
-
ipython_config.py
|
| 84 |
-
|
| 85 |
-
# pyenv
|
| 86 |
-
# For a library or package, you might want to ignore these files since the code is
|
| 87 |
-
# intended to run in multiple environments; otherwise, check them in:
|
| 88 |
-
# .python-version
|
| 89 |
-
|
| 90 |
-
# pipenv
|
| 91 |
-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
| 92 |
-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
| 93 |
-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
| 94 |
-
# install all needed dependencies.
|
| 95 |
-
#Pipfile.lock
|
| 96 |
-
|
| 97 |
-
# UV
|
| 98 |
-
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
| 99 |
-
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
| 100 |
-
# commonly ignored for libraries.
|
| 101 |
-
#uv.lock
|
| 102 |
-
|
| 103 |
-
# poetry
|
| 104 |
-
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
| 105 |
-
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
| 106 |
-
# commonly ignored for libraries.
|
| 107 |
-
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
| 108 |
-
#poetry.lock
|
| 109 |
-
#poetry.toml
|
| 110 |
|
| 111 |
-
#
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
#pdm.lock
|
| 116 |
-
#pdm.toml
|
| 117 |
-
.pdm-python
|
| 118 |
-
.pdm-build/
|
| 119 |
|
| 120 |
-
# pixi
|
| 121 |
-
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
| 122 |
-
#pixi.lock
|
| 123 |
-
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
| 124 |
-
# in the .venv directory. It is recommended not to include this directory in version control.
|
| 125 |
-
.pixi
|
| 126 |
|
| 127 |
-
#
|
| 128 |
-
__pypackages__/
|
| 129 |
-
|
| 130 |
-
# Celery stuff
|
| 131 |
-
celerybeat-schedule
|
| 132 |
-
celerybeat.pid
|
| 133 |
-
|
| 134 |
-
# SageMath parsed files
|
| 135 |
-
*.sage.py
|
| 136 |
-
|
| 137 |
-
# Environments
|
| 138 |
.env
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
env.bak/
|
| 145 |
-
venv.bak/
|
| 146 |
-
|
| 147 |
-
# Spyder project settings
|
| 148 |
-
.spyderproject
|
| 149 |
-
.spyproject
|
| 150 |
-
|
| 151 |
-
# Rope project settings
|
| 152 |
-
.ropeproject
|
| 153 |
-
|
| 154 |
-
# mkdocs documentation
|
| 155 |
-
/site
|
| 156 |
-
|
| 157 |
-
# mypy
|
| 158 |
-
.mypy_cache/
|
| 159 |
-
.dmypy.json
|
| 160 |
-
dmypy.json
|
| 161 |
-
|
| 162 |
-
# Pyre type checker
|
| 163 |
-
.pyre/
|
| 164 |
-
|
| 165 |
-
# pytype static type analyzer
|
| 166 |
-
.pytype/
|
| 167 |
-
|
| 168 |
-
# Cython debug symbols
|
| 169 |
-
cython_debug/
|
| 170 |
-
|
| 171 |
-
# PyCharm
|
| 172 |
-
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
| 173 |
-
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
| 174 |
-
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
| 175 |
-
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
| 176 |
-
#.idea/
|
| 177 |
-
|
| 178 |
-
# Abstra
|
| 179 |
-
# Abstra is an AI-powered process automation framework.
|
| 180 |
-
# Ignore directories containing user credentials, local state, and settings.
|
| 181 |
-
# Learn more at https://abstra.io/docs
|
| 182 |
-
.abstra/
|
| 183 |
-
|
| 184 |
-
# Visual Studio Code
|
| 185 |
-
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
| 186 |
-
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
| 187 |
-
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
| 188 |
-
# you could uncomment the following to ignore the entire vscode folder
|
| 189 |
-
# .vscode/
|
| 190 |
-
|
| 191 |
-
# Ruff stuff:
|
| 192 |
-
.ruff_cache/
|
| 193 |
|
| 194 |
-
#
|
| 195 |
-
|
|
|
|
| 196 |
|
| 197 |
-
#
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
# refer to https://docs.cursor.com/context/ignore-files
|
| 201 |
-
.cursorignore
|
| 202 |
-
.cursorindexingignore
|
| 203 |
|
| 204 |
-
#
|
| 205 |
-
|
| 206 |
-
marimo/_lsp/
|
| 207 |
-
__marimo__/
|
|
|
|
| 1 |
+
# gitignore template for LangChain products, e.g., LangGraph, LangSmith
|
| 2 |
+
# website: https://www.langchain.com/
|
| 3 |
+
# website: https://www.langchain.com/langgraph
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
+
# LangGraph
|
| 6 |
+
.langgraph_api/
|
| 7 |
+
|
| 8 |
+
vector_store/
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
+
# ignore .env
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
.env
|
| 13 |
+
__pycache__/
|
| 14 |
+
src/__pycache__/
|
| 15 |
+
# Environment
|
| 16 |
+
.env
|
| 17 |
+
.env.*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
+
# Python cache
|
| 20 |
+
__pycache__/
|
| 21 |
+
*.pyc
|
| 22 |
|
| 23 |
+
# Vector DB
|
| 24 |
+
faiss_store/
|
| 25 |
+
vector_store/
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
+
# LangGraph
|
| 28 |
+
.langgraph_api/
|
|
|
|
|
|
Data/machine_learning.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Machine Learning Basics
|
| 2 |
+
|
| 3 |
+
Machine learning is a subset of artificial intelligence that enables systems to learn and improve
|
| 4 |
+
from experience without being explicitly programmed. It focuses on developing computer programs
|
| 5 |
+
that can access data and use it to learn for themselves.
|
| 6 |
+
|
| 7 |
+
Types of Machine Learning:
|
| 8 |
+
1. Supervised Learning: Learning with labeled data
|
| 9 |
+
2. Unsupervised Learning: Finding patterns in unlabeled data
|
| 10 |
+
3. Reinforcement Learning: Learning through rewards and penalties
|
| 11 |
+
|
| 12 |
+
Applications include image recognition, speech processing, and recommendation systems
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
|
Data/python_intro.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Python Programming Introduction
|
| 2 |
+
|
| 3 |
+
Python is a high-level, interpreted programming language known for its simplicity and readability.
|
| 4 |
+
Created by Guido van Rossum and first released in 1991, Python has become one of the most popular
|
| 5 |
+
programming languages in the world.
|
| 6 |
+
|
| 7 |
+
Key Features:
|
| 8 |
+
- Easy to learn and use
|
| 9 |
+
- Extensive standard library
|
| 10 |
+
- Cross-platform compatibility
|
| 11 |
+
- Strong community support
|
| 12 |
+
|
| 13 |
+
Python is widely used in web development, data science, artificial intelligence, and automation.
|
Dockerfile
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modern Multi-stage Dockerfile for RAG System
|
| 2 |
+
FROM python:3.11-slim as builder
|
| 3 |
+
|
| 4 |
+
# Set environment variables
|
| 5 |
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
| 6 |
+
PYTHONUNBUFFERED=1 \
|
| 7 |
+
POETRY_NO_INTERACTION=1 \
|
| 8 |
+
POETRY_VENV_IN_PROJECT=1 \
|
| 9 |
+
POETRY_CACHE_DIR=/tmp/poetry_cache
|
| 10 |
+
|
| 11 |
+
# Install system dependencies
|
| 12 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 13 |
+
build-essential \
|
| 14 |
+
curl \
|
| 15 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 16 |
+
|
| 17 |
+
# Install Python dependencies
|
| 18 |
+
WORKDIR /app
|
| 19 |
+
COPY requirements.txt .
|
| 20 |
+
RUN pip install --no-cache-dir --upgrade pip && \
|
| 21 |
+
pip install --no-cache-dir -r requirements.txt
|
| 22 |
+
|
| 23 |
+
# Production stage
|
| 24 |
+
FROM python:3.11-slim as production
|
| 25 |
+
|
| 26 |
+
# Set environment variables
|
| 27 |
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
| 28 |
+
PYTHONUNBUFFERED=1 \
|
| 29 |
+
PYTHONPATH="/app/src:$PYTHONPATH"
|
| 30 |
+
|
| 31 |
+
# Install runtime dependencies only
|
| 32 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 33 |
+
curl \
|
| 34 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 35 |
+
|
| 36 |
+
# Create non-root user
|
| 37 |
+
RUN groupadd -r appuser && useradd -r -g appuser appuser
|
| 38 |
+
|
| 39 |
+
# Copy Python packages from builder stage
|
| 40 |
+
COPY --from=builder /usr/local/lib/python3.11/site-packages/ /usr/local/lib/python3.11/site-packages/
|
| 41 |
+
COPY --from=builder /usr/local/bin/ /usr/local/bin/
|
| 42 |
+
|
| 43 |
+
# Set working directory
|
| 44 |
+
WORKDIR /app
|
| 45 |
+
|
| 46 |
+
# Copy application code
|
| 47 |
+
COPY --chown=appuser:appuser . .
|
| 48 |
+
|
| 49 |
+
# Create necessary directories
|
| 50 |
+
RUN mkdir -p /app/faiss_store /app/data /app/logs && \
|
| 51 |
+
chown -R appuser:appuser /app
|
| 52 |
+
|
| 53 |
+
# Switch to non-root user
|
| 54 |
+
USER appuser
|
| 55 |
+
|
| 56 |
+
# Health check
|
| 57 |
+
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
| 58 |
+
CMD curl -f http://localhost:8000/health || exit 1
|
| 59 |
+
|
| 60 |
+
# Expose port
|
| 61 |
+
EXPOSE 8000
|
| 62 |
+
|
| 63 |
+
# Default command
|
| 64 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
|
LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
MIT License
|
| 2 |
|
| 3 |
-
Copyright (c)
|
| 4 |
|
| 5 |
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
| 1 |
MIT License
|
| 2 |
|
| 3 |
+
Copyright (c) 2025 Jeevant
|
| 4 |
|
| 5 |
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
of this software and associated documentation files (the "Software"), to deal
|
README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# Langchain-Model
|
app.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from typing import List, Optional
|
| 3 |
+
from contextlib import asynccontextmanager
|
| 4 |
+
|
| 5 |
+
from fastapi import FastAPI, HTTPException
|
| 6 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 7 |
+
from pydantic import BaseModel
|
| 8 |
+
from dotenv import load_dotenv
|
| 9 |
+
|
| 10 |
+
from src.search import RAGSearch, RetrievalResult
|
| 11 |
+
|
| 12 |
+
import uvicorn
|
| 13 |
+
|
| 14 |
+
load_dotenv()
|
| 15 |
+
|
| 16 |
+
# Global variable for RAG system
|
| 17 |
+
rag_search: Optional[RAGSearch] = None
|
| 18 |
+
|
| 19 |
+
@asynccontextmanager
|
| 20 |
+
async def lifespan(app: FastAPI):
|
| 21 |
+
# Startup
|
| 22 |
+
global rag_search
|
| 23 |
+
try:
|
| 24 |
+
persist_dir = os.getenv("PERSIST_DIR", "faiss_store")
|
| 25 |
+
embedding_model = os.getenv("EMBEDDING_MODEL", "all-MiniLM-L6-v2")
|
| 26 |
+
llm_model = os.getenv("LLM_MODEL", "llama-3.1-8b-instant")
|
| 27 |
+
|
| 28 |
+
rag_search = RAGSearch(
|
| 29 |
+
persist_dir=persist_dir,
|
| 30 |
+
embedding_model=embedding_model,
|
| 31 |
+
llm_model=llm_model,
|
| 32 |
+
)
|
| 33 |
+
print("[INFO] RAG system loaded successfully")
|
| 34 |
+
except Exception as e:
|
| 35 |
+
print(f"[ERROR] Failed to load RAG system: {e}")
|
| 36 |
+
raise
|
| 37 |
+
|
| 38 |
+
yield # Application runs here
|
| 39 |
+
|
| 40 |
+
# Shutdown (cleanup if needed)
|
| 41 |
+
print("[INFO] Shutting down RAG system")
|
| 42 |
+
|
| 43 |
+
# -------------------------
|
| 44 |
+
# FastAPI App
|
| 45 |
+
# -------------------------
|
| 46 |
+
app = FastAPI(
|
| 47 |
+
title="RAG Question Answering API",
|
| 48 |
+
description="FAISS + SentenceTransformers + Groq LLM",
|
| 49 |
+
version="2.0.0",
|
| 50 |
+
lifespan=lifespan
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
# CORS for React/Node clients
|
| 54 |
+
cors_origins = os.getenv("CORS_ORIGINS", "*").split(",")
|
| 55 |
+
app.add_middleware(
|
| 56 |
+
CORSMiddleware,
|
| 57 |
+
allow_origins=[o.strip() for o in cors_origins] if cors_origins else ["*"],
|
| 58 |
+
allow_credentials=True,
|
| 59 |
+
allow_methods=["*"],
|
| 60 |
+
allow_headers=["*"],
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
# -------------------------
|
| 64 |
+
# Request / Response Models
|
| 65 |
+
# -------------------------
|
| 66 |
+
class SourceItem(BaseModel):
|
| 67 |
+
index: int
|
| 68 |
+
distance: float
|
| 69 |
+
text: Optional[str] = None
|
| 70 |
+
|
| 71 |
+
class QueryRequest(BaseModel):
|
| 72 |
+
query: str
|
| 73 |
+
top_k: int = 3
|
| 74 |
+
|
| 75 |
+
class QueryResponse(BaseModel):
|
| 76 |
+
query: str
|
| 77 |
+
answer: str
|
| 78 |
+
sources: List[SourceItem]
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
# -------------------------
|
| 82 |
+
# Routes
|
| 83 |
+
# -------------------------
|
| 84 |
+
@app.get("/")
|
| 85 |
+
def root():
|
| 86 |
+
return {"message": "RAG API is running. Go to /docs"}
|
| 87 |
+
|
| 88 |
+
@app.get("/health")
|
| 89 |
+
def health():
|
| 90 |
+
if not rag_search:
|
| 91 |
+
return {"ready": False}
|
| 92 |
+
meta_count = len(rag_search.vectorstore.metadata) if rag_search.vectorstore else 0
|
| 93 |
+
return {
|
| 94 |
+
"ready": True,
|
| 95 |
+
"persist_dir": rag_search.vectorstore.persist_dir,
|
| 96 |
+
"documents_indexed": meta_count,
|
| 97 |
+
"embedding_model": rag_search.embedding_model,
|
| 98 |
+
"llm_model": rag_search.llm_model,
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
@app.post("/query", response_model=QueryResponse)
|
| 102 |
+
def query_rag(payload: QueryRequest):
|
| 103 |
+
if not rag_search:
|
| 104 |
+
raise HTTPException(status_code=503, detail="RAG system not ready")
|
| 105 |
+
|
| 106 |
+
try:
|
| 107 |
+
# Retrieve and summarize
|
| 108 |
+
sources: List[RetrievalResult] = rag_search.retrieve(payload.query, top_k=payload.top_k)
|
| 109 |
+
answer: str = rag_search.summarize(payload.query, sources)
|
| 110 |
+
|
| 111 |
+
# Map sources for response
|
| 112 |
+
resp_sources = [
|
| 113 |
+
SourceItem(index=s.index, distance=float(s.distance), text=s.text)
|
| 114 |
+
for s in sources
|
| 115 |
+
]
|
| 116 |
+
return QueryResponse(query=payload.query, answer=answer, sources=resp_sources)
|
| 117 |
+
except Exception as e:
|
| 118 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
# -------------------------
|
| 122 |
+
# Run locally
|
| 123 |
+
# -------------------------
|
| 124 |
+
if __name__ == "__main__":
|
| 125 |
+
uvicorn.run(
|
| 126 |
+
"app:app",
|
| 127 |
+
host="0.0.0.0",
|
| 128 |
+
port=int(os.getenv("PORT", "8000")),
|
| 129 |
+
reload=True
|
| 130 |
+
)
|
config/config.yaml
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Environment-specific Configuration
|
| 2 |
+
environment: "development"
|
| 3 |
+
|
| 4 |
+
# Database and Storage Settings
|
| 5 |
+
storage:
|
| 6 |
+
faiss_store_path: "faiss_store"
|
| 7 |
+
backup_enabled: true
|
| 8 |
+
backup_frequency: "daily"
|
| 9 |
+
|
| 10 |
+
# Model Configuration
|
| 11 |
+
models:
|
| 12 |
+
embedding:
|
| 13 |
+
provider: "sentence-transformers"
|
| 14 |
+
model_name: "all-MiniLM-L6-v2"
|
| 15 |
+
device: "cpu" # or "cuda" if GPU available
|
| 16 |
+
|
| 17 |
+
llm:
|
| 18 |
+
provider: "groq"
|
| 19 |
+
model_name: "llama-3.1-8b-instant"
|
| 20 |
+
api_key_env: "GROQ_API_KEY"
|
| 21 |
+
parameters:
|
| 22 |
+
temperature: 0.1
|
| 23 |
+
max_tokens: 1000
|
| 24 |
+
top_p: 0.9
|
| 25 |
+
|
| 26 |
+
# Processing Settings
|
| 27 |
+
processing:
|
| 28 |
+
text_splitter:
|
| 29 |
+
type: "recursive_character"
|
| 30 |
+
chunk_size: 1000
|
| 31 |
+
chunk_overlap: 200
|
| 32 |
+
separators: ["\n\n", "\n", " ", ""]
|
| 33 |
+
|
| 34 |
+
batch_processing:
|
| 35 |
+
enabled: true
|
| 36 |
+
batch_size: 100
|
| 37 |
+
|
| 38 |
+
# API Settings
|
| 39 |
+
api:
|
| 40 |
+
server:
|
| 41 |
+
host: "0.0.0.0"
|
| 42 |
+
port: 8000
|
| 43 |
+
workers: 1
|
| 44 |
+
reload: true
|
| 45 |
+
|
| 46 |
+
security:
|
| 47 |
+
cors_enabled: true
|
| 48 |
+
cors_origins: ["*"]
|
| 49 |
+
rate_limiting: false
|
| 50 |
+
|
| 51 |
+
features:
|
| 52 |
+
health_check: true
|
| 53 |
+
metrics: false
|
| 54 |
+
documentation: true
|
| 55 |
+
|
| 56 |
+
# Logging and Monitoring
|
| 57 |
+
logging:
|
| 58 |
+
level: "INFO"
|
| 59 |
+
file_enabled: false
|
| 60 |
+
file_path: "logs/app.log"
|
| 61 |
+
console_enabled: true
|
| 62 |
+
|
| 63 |
+
monitoring:
|
| 64 |
+
metrics_enabled: false
|
| 65 |
+
health_checks: true
|
| 66 |
+
|
| 67 |
+
# Development Settings
|
| 68 |
+
development:
|
| 69 |
+
debug: true
|
| 70 |
+
hot_reload: true
|
| 71 |
+
|
| 72 |
+
# Production Settings (override in production)
|
| 73 |
+
production:
|
| 74 |
+
debug: false
|
| 75 |
+
workers: 4
|
| 76 |
+
logging_level: "WARNING"
|
main.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Simple CLI test runner for RAG retrieval + summarization.
|
| 3 |
+
Run: python main.py
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from src.search import RAGSearch
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
if __name__ == "__main__":
|
| 10 |
+
# Check for GROQ API key
|
| 11 |
+
if not os.getenv("GROQ_API_KEY"):
|
| 12 |
+
print("WARNING: GROQ_API_KEY not found in environment variables.")
|
| 13 |
+
print("Please set it in a .env file or environment variable to use the LLM features.")
|
| 14 |
+
print("You can still test document loading and embeddings without it.")
|
| 15 |
+
|
| 16 |
+
try:
|
| 17 |
+
rag_search = RAGSearch(
|
| 18 |
+
persist_dir="faiss_store",
|
| 19 |
+
embedding_model="all-MiniLM-L6-v2",
|
| 20 |
+
llm_model="llama-3.1-8b-instant"
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
query = "What is Database Management System?"
|
| 24 |
+
answer = rag_search.search_and_summarize(query=query, top_k=3)
|
| 25 |
+
print("Query:", query)
|
| 26 |
+
print("Answer:\n", answer)
|
| 27 |
+
|
| 28 |
+
except Exception as e:
|
| 29 |
+
print(f"Error: {e}")
|
| 30 |
+
print("\nTroubleshooting:")
|
| 31 |
+
print("1. Make sure you have documents in 'Research/data/', 'data/', or 'Data/' directory")
|
| 32 |
+
print("2. Set GROQ_API_KEY in your .env file")
|
| 33 |
+
print("3. Run: pip install -r requirements.txt")
|
params.yaml
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# RAG System Configuration
|
| 2 |
+
rag:
|
| 3 |
+
embedding:
|
| 4 |
+
model: "all-MiniLM-L6-v2"
|
| 5 |
+
chunk_size: 1000
|
| 6 |
+
chunk_overlap: 200
|
| 7 |
+
|
| 8 |
+
vectorstore:
|
| 9 |
+
persist_dir: "faiss_store"
|
| 10 |
+
index_type: "faiss"
|
| 11 |
+
|
| 12 |
+
llm:
|
| 13 |
+
provider: "groq"
|
| 14 |
+
model: "llama-3.1-8b-instant"
|
| 15 |
+
temperature: 0.1
|
| 16 |
+
max_tokens: 1000
|
| 17 |
+
|
| 18 |
+
retrieval:
|
| 19 |
+
top_k: 5
|
| 20 |
+
similarity_threshold: 0.7
|
| 21 |
+
|
| 22 |
+
# API Configuration
|
| 23 |
+
api:
|
| 24 |
+
host: "0.0.0.0"
|
| 25 |
+
port: 8000
|
| 26 |
+
cors_origins: "*"
|
| 27 |
+
reload: true
|
| 28 |
+
|
| 29 |
+
# Data Configuration
|
| 30 |
+
data:
|
| 31 |
+
input_dir: "data"
|
| 32 |
+
supported_formats:
|
| 33 |
+
- "pdf"
|
| 34 |
+
- "txt"
|
| 35 |
+
- "csv"
|
| 36 |
+
- "xlsx"
|
| 37 |
+
- "docx"
|
| 38 |
+
- "json"
|
| 39 |
+
|
| 40 |
+
# Logging Configuration
|
| 41 |
+
logging:
|
| 42 |
+
level: "INFO"
|
| 43 |
+
format: "[%(levelname)s] %(asctime)s - %(name)s - %(message)s"
|
requirements.txt
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Core LangChain packages
|
| 2 |
+
langchain>=0.3.0
|
| 3 |
+
langchain-core>=0.3.0
|
| 4 |
+
langchain-community>=0.3.0
|
| 5 |
+
langchain-text-splitters>=0.3.0
|
| 6 |
+
langchain-groq>=0.2.0
|
| 7 |
+
|
| 8 |
+
# Document processing
|
| 9 |
+
pypdf>=4.0.1
|
| 10 |
+
pymupdf>=1.24.0
|
| 11 |
+
|
| 12 |
+
# Embeddings and vector databases
|
| 13 |
+
sentence-transformers>=3.0.0
|
| 14 |
+
faiss-cpu>=1.8.0
|
| 15 |
+
chromadb>=0.5.0
|
| 16 |
+
|
| 17 |
+
# Search and indexing
|
| 18 |
+
typesense>=0.19.0
|
| 19 |
+
|
| 20 |
+
# Web framework and API
|
| 21 |
+
fastapi>=0.115.0
|
| 22 |
+
uvicorn[standard]>=0.32.0
|
| 23 |
+
pydantic>=2.9.0
|
| 24 |
+
|
| 25 |
+
# Environment and utilities
|
| 26 |
+
python-dotenv>=1.0.0
|
| 27 |
+
|
| 28 |
+
# Build tools (only if needed for development)
|
| 29 |
+
setuptools>=75.0.0
|
setup.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import setuptools
|
| 2 |
+
|
| 3 |
+
with open("README.md", "r", encoding="utf-8") as f:
|
| 4 |
+
long_description = f.read()
|
| 5 |
+
|
| 6 |
+
__version__ = "2.0.0"
|
| 7 |
+
|
| 8 |
+
REPO_NAME = "Langchain_RAG_System"
|
| 9 |
+
AUTHOR_USER_NAME = "jeevant"
|
| 10 |
+
SRC_REPO = "langchain_rag"
|
| 11 |
+
AUTHOR_EMAIL = "jeevantmudgil10@gmail.com"
|
| 12 |
+
|
| 13 |
+
setuptools.setup(
|
| 14 |
+
name=SRC_REPO,
|
| 15 |
+
version=__version__,
|
| 16 |
+
author=AUTHOR_USER_NAME,
|
| 17 |
+
author_email=AUTHOR_EMAIL,
|
| 18 |
+
description="A modern RAG system using LangChain, FAISS, and Groq LLM",
|
| 19 |
+
long_description=long_description,
|
| 20 |
+
long_description_content_type="text/markdown",
|
| 21 |
+
url=f"https://github.com/{AUTHOR_USER_NAME}/{REPO_NAME}",
|
| 22 |
+
project_urls={
|
| 23 |
+
"Bug Tracker": f"https://github.com/{AUTHOR_USER_NAME}/{REPO_NAME}/issues",
|
| 24 |
+
"Documentation": f"https://github.com/{AUTHOR_USER_NAME}/{REPO_NAME}#readme",
|
| 25 |
+
},
|
| 26 |
+
package_dir={"": "src"},
|
| 27 |
+
packages=setuptools.find_packages(where="src"),
|
| 28 |
+
python_requires=">=3.8",
|
| 29 |
+
install_requires=[
|
| 30 |
+
"langchain>=0.3.0",
|
| 31 |
+
"langchain-core>=0.3.0",
|
| 32 |
+
"langchain-community>=0.3.0",
|
| 33 |
+
"langchain-text-splitters>=0.3.0",
|
| 34 |
+
"langchain-groq>=0.2.0",
|
| 35 |
+
"fastapi>=0.115.0",
|
| 36 |
+
"uvicorn[standard]>=0.32.0",
|
| 37 |
+
"sentence-transformers>=3.0.0",
|
| 38 |
+
"faiss-cpu>=1.8.0",
|
| 39 |
+
"python-dotenv>=1.0.0",
|
| 40 |
+
],
|
| 41 |
+
classifiers=[
|
| 42 |
+
"Development Status :: 4 - Beta",
|
| 43 |
+
"Intended Audience :: Developers",
|
| 44 |
+
"License :: OSI Approved :: MIT License",
|
| 45 |
+
"Operating System :: OS Independent",
|
| 46 |
+
"Programming Language :: Python :: 3",
|
| 47 |
+
"Programming Language :: Python :: 3.8",
|
| 48 |
+
"Programming Language :: Python :: 3.9",
|
| 49 |
+
"Programming Language :: Python :: 3.10",
|
| 50 |
+
"Programming Language :: Python :: 3.11",
|
| 51 |
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
| 52 |
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
| 53 |
+
],
|
| 54 |
+
)
|
src/__init__.py
ADDED
|
File without changes
|
src/data_loader.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
from typing import List, Any
|
| 3 |
+
from langchain_community.document_loaders import PyPDFLoader, TextLoader, CSVLoader
|
| 4 |
+
from langchain_community.document_loaders import Docx2txtLoader
|
| 5 |
+
from langchain_community.document_loaders.excel import UnstructuredExcelLoader
|
| 6 |
+
from langchain_community.document_loaders import JSONLoader
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def load_all_documents(data_dir: str) -> List[Any] :
|
| 10 |
+
|
| 11 |
+
data_path = Path(data_dir).resolve()
|
| 12 |
+
print(f"[DEBUG] Data Path : {data_path}")
|
| 13 |
+
document = []
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
## Pdf files
|
| 17 |
+
|
| 18 |
+
pdf_files = list(data_path.glob('**/*.pdf'))
|
| 19 |
+
print(f"[DEBUG] Found {len(pdf_files)} PDF files : { [str(f) for f in pdf_files] }")
|
| 20 |
+
for pdf_file in pdf_files:
|
| 21 |
+
print(f"[DEBUG] Loading PDF: {pdf_file}")
|
| 22 |
+
try:
|
| 23 |
+
loader = PyPDFLoader(str(pdf_file))
|
| 24 |
+
loaded = loader.load()
|
| 25 |
+
print(f"[DEBUG] Loaded {len(loaded)} PDF docs from {pdf_file}")
|
| 26 |
+
document.extend(loaded)
|
| 27 |
+
except Exception as e:
|
| 28 |
+
print(f"[ERROR] Failed to load PDF {pdf_file} : {e}")
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
## TXT files
|
| 33 |
+
|
| 34 |
+
txt_files = list(data_path.glob('**/*.txt'))
|
| 35 |
+
print(f'[DEBUG] Founded {len(txt_files)} TXT files: {[str(f) for f in txt_files]} ')
|
| 36 |
+
for txt_file in txt_files:
|
| 37 |
+
print(f"[DEBUG] Loading TXT : {txt_file}")
|
| 38 |
+
try:
|
| 39 |
+
loader = TextLoader(str(txt_file), encoding="utf-8")
|
| 40 |
+
loaded = loader.load()
|
| 41 |
+
print(f"[DEBUG] Loaded {len(loaded)} TXT docs from {txt_file}")
|
| 42 |
+
document.extend(loaded)
|
| 43 |
+
except Exception as e:
|
| 44 |
+
print(f"[ERROR] failed to load TXT {txt_file} : {e}")
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
## CSV files
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
csv_files = list(data_path.glob('**/*.csv'))
|
| 52 |
+
print(f"[DEBUG] Found {len((csv_files))} CSV files : {[str(f) for f in csv_files]}")
|
| 53 |
+
for csv_file in csv_files:
|
| 54 |
+
print(f"[DEBUG] Loading CSV : {csv_file}")
|
| 55 |
+
try :
|
| 56 |
+
loader = CSVLoader(str(csv_file))
|
| 57 |
+
loaded = loader.load()
|
| 58 |
+
print(f"[DEBUG] Loaded {len(loaded)} CSV docs from {csv_file}")
|
| 59 |
+
document.extend(loaded)
|
| 60 |
+
except Exception as e:
|
| 61 |
+
print(f"[ERROR] failed to load CSV {csv_file} : {e}")
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
## Excel files
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
xlsx_files = list(data_path.glob('**/*.xlsx'))
|
| 69 |
+
print(f"[DEBUG] Found {len(xlsx_files)} xlsx files : {[str(f) for f in xlsx_files]}")
|
| 70 |
+
for xlsx_file in xlsx_files:
|
| 71 |
+
print(f"[DEBUG] Loading XLSX : {xlsx_file}")
|
| 72 |
+
try :
|
| 73 |
+
loader = UnstructuredExcelLoader(str(xlsx_file))
|
| 74 |
+
loaded = loader.load()
|
| 75 |
+
print(f"[DEBUG] Loaded {(len(loaded))} XLSX docs from {xlsx_file}")
|
| 76 |
+
document.extend(loaded)
|
| 77 |
+
except Exception as e :
|
| 78 |
+
print(f"[ERROR] failed to load Excel {xlsx_file} : {e} ")
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
## Word file
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
word_files = list(data_path.glob('**/*.docx'))
|
| 86 |
+
print(f"[DEBUG] Found {len(word_files)} word files : {[str(f) for f in word_files]}")
|
| 87 |
+
for word_file in word_files:
|
| 88 |
+
print(f"[DEBUG] Loaded WORD : {word_file}")
|
| 89 |
+
try :
|
| 90 |
+
loader = Docx2txtLoader(str(word_file))
|
| 91 |
+
loaded = loader.load()
|
| 92 |
+
print(f"[DEBUG] Loaded {(len(loaded))} Word docs from {word_file}")
|
| 93 |
+
document.extend(loaded)
|
| 94 |
+
except Exception as e:
|
| 95 |
+
print(f"[ERROR] failed to load Word Document {word_file} : {e}")
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
## JSON files
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
json_files = list(data_path.glob('**/*.json'))
|
| 104 |
+
print(f"[DEBUG] Found {(len(json_files))} json files : {[str(f) for f in json_files]}")
|
| 105 |
+
for json_file in json_files:
|
| 106 |
+
print(f"[DEBUG] Loaded JSON : {(str(json_file))}")
|
| 107 |
+
try:
|
| 108 |
+
loader = JSONLoader(
|
| 109 |
+
str(json_file),
|
| 110 |
+
jq_schema=".",
|
| 111 |
+
text_content=False
|
| 112 |
+
)
|
| 113 |
+
loaded = loader.load()
|
| 114 |
+
print(f"[DEBUG] Loaded {(len(loaded))} JSON from {json_file}")
|
| 115 |
+
document.extend(loaded)
|
| 116 |
+
except Exception as e:
|
| 117 |
+
print(f"[ERROR] Failed to load JSON file{json_file} : {e}")
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
print(f"[DEBUG] Total Loaded Documents : {len(document)}")
|
| 121 |
+
return document
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
if __name__ == '__main__':
|
| 125 |
+
docs = load_all_documents('Research/data/pdf')
|
| 126 |
+
print(f"Loaded {len(docs)} document.")
|
| 127 |
+
print("Example document:", docs[0] if docs else None)
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
# def process_all_pdf(pdf_directory):
|
| 131 |
+
|
| 132 |
+
# all_documents = []
|
| 133 |
+
# pdf_dir = Path(pdf_directory)
|
| 134 |
+
|
| 135 |
+
# pdf_files = list(pdf_dir.glob('**/*.pdf'))
|
| 136 |
+
|
| 137 |
+
# print(f"found {len(pdf_files)} PDF files to Process")
|
| 138 |
+
|
| 139 |
+
# for pdf_files in pdf_files:
|
| 140 |
+
# print(f"\npreprocessing : {pdf_files.name}")
|
| 141 |
+
# try:
|
| 142 |
+
# loader = PyPDFLoader(str(pdf_files))
|
| 143 |
+
# documents = loader.load()
|
| 144 |
+
|
| 145 |
+
# for doc in documents:
|
| 146 |
+
# doc.metadata['source_file'] = pdf_files.name
|
| 147 |
+
# doc.metadata['file_type'] = 'pdf'
|
| 148 |
+
|
| 149 |
+
# all_documents.extend(documents)
|
| 150 |
+
# print(f" Loaded {len(documents)} pages")
|
| 151 |
+
# except Exception as e:
|
| 152 |
+
# print(f" Error : {e}")
|
| 153 |
+
|
| 154 |
+
# print(f"\n Total documents loaded : {len(all_documents)}")
|
| 155 |
+
# return all_documents
|
| 156 |
+
|
| 157 |
+
# all_pdf_files = process_all_pdf('./data')
|
src/embedding.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List, Any, Optional
|
| 2 |
+
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
| 3 |
+
from sentence_transformers import SentenceTransformer
|
| 4 |
+
import numpy as np
|
| 5 |
+
from src.data_loader import load_all_documents
|
| 6 |
+
|
| 7 |
+
class EmbeddingPipeline:
|
| 8 |
+
def __init__(self, model_name: str = 'all-MiniLM-L6-v2', chunk_size: int = 1000, chunk_overlap: int = 200):
|
| 9 |
+
self.model_name = model_name
|
| 10 |
+
self.chunk_size = chunk_size
|
| 11 |
+
self.chunk_overlap = chunk_overlap
|
| 12 |
+
self.model = SentenceTransformer(model_name)
|
| 13 |
+
print(f"[INFO] Loaded embedding model: {model_name}")
|
| 14 |
+
|
| 15 |
+
def chunk_documents(self, documents: List[Any]) -> List[Any]:
|
| 16 |
+
splitter = RecursiveCharacterTextSplitter(
|
| 17 |
+
chunk_size=self.chunk_size,
|
| 18 |
+
chunk_overlap=self.chunk_overlap,
|
| 19 |
+
length_function=len,
|
| 20 |
+
separators=["\n\n", "\n", " ", ""]
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
chunks = splitter.split_documents(documents)
|
| 24 |
+
print(f"[INFO] Split {len(documents)} documents into {len(chunks)} chunks.")
|
| 25 |
+
return chunks
|
| 26 |
+
|
| 27 |
+
def embed_chunks(self, chunks: List[Any]) -> np.ndarray:
|
| 28 |
+
texts = [chunk.page_content for chunk in chunks]
|
| 29 |
+
print(f"[INFO] Generating embeddings for {len(texts)} chunks...")
|
| 30 |
+
embeddings = self.model.encode(texts, show_progress_bar = True)
|
| 31 |
+
print(f"[INFO] Embeddings shape : {embeddings.shape}")
|
| 32 |
+
return embeddings
|
| 33 |
+
|
| 34 |
+
if __name__ == "__main__":
|
| 35 |
+
docs = load_all_documents('Research/data/pdf')
|
| 36 |
+
emb_pipe = EmbeddingPipeline()
|
| 37 |
+
chunks = emb_pipe.chunk_documents(docs)
|
| 38 |
+
embeddings = emb_pipe.embed_chunks(chunks)
|
| 39 |
+
print(f"[INFO] Example embeddings:", embeddings[0] if len(embeddings) > 0 else None)
|
| 40 |
+
|
src/search.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from dataclasses import dataclass
|
| 3 |
+
from typing import List, Optional
|
| 4 |
+
|
| 5 |
+
from dotenv import load_dotenv
|
| 6 |
+
from langchain_groq import ChatGroq
|
| 7 |
+
from langchain_core.messages import HumanMessage, SystemMessage
|
| 8 |
+
|
| 9 |
+
from src.vectorstore import FaissVectorStore
|
| 10 |
+
|
| 11 |
+
load_dotenv()
|
| 12 |
+
|
| 13 |
+
@dataclass
|
| 14 |
+
class RetrievalResult:
|
| 15 |
+
index: int
|
| 16 |
+
distance: float
|
| 17 |
+
text: Optional[str]
|
| 18 |
+
|
| 19 |
+
class RAGSearch:
|
| 20 |
+
def __init__(
|
| 21 |
+
self,
|
| 22 |
+
persist_dir: str = "faiss_store",
|
| 23 |
+
embedding_model: str = "all-MiniLM-L6-v2",
|
| 24 |
+
llm_model: str = "llama-3.1-8b-instant",
|
| 25 |
+
):
|
| 26 |
+
# Vector store setup
|
| 27 |
+
self.vectorstore = FaissVectorStore(persist_dir=persist_dir, embedding_model=embedding_model)
|
| 28 |
+
|
| 29 |
+
faiss_path = os.path.join(persist_dir, "faiss.index")
|
| 30 |
+
meta_path = os.path.join(persist_dir, "metadata.pkl")
|
| 31 |
+
|
| 32 |
+
if not (os.path.exists(faiss_path) and os.path.exists(meta_path)):
|
| 33 |
+
# Build from local 'Research/data' directory if index doesn't exist
|
| 34 |
+
from src.data_loader import load_all_documents
|
| 35 |
+
# Try multiple possible data directories
|
| 36 |
+
data_dirs = ["Research/data", "data", "Data"]
|
| 37 |
+
docs = []
|
| 38 |
+
|
| 39 |
+
for data_dir in data_dirs:
|
| 40 |
+
if os.path.exists(data_dir):
|
| 41 |
+
print(f"[INFO] Checking for documents in: {data_dir}")
|
| 42 |
+
docs = load_all_documents(data_dir)
|
| 43 |
+
if docs:
|
| 44 |
+
print(f"[INFO] Found {len(docs)} documents in {data_dir}")
|
| 45 |
+
break
|
| 46 |
+
|
| 47 |
+
if not docs:
|
| 48 |
+
print("[WARNING] No documents found in any data directory. Vector store will be empty.")
|
| 49 |
+
print("[INFO] Please add documents to 'Research/data/', 'data/', or 'Data/' directory.")
|
| 50 |
+
# Create empty index for now
|
| 51 |
+
self.vectorstore.index = None
|
| 52 |
+
self.vectorstore.metadata = []
|
| 53 |
+
else:
|
| 54 |
+
self.vectorstore.build_from_documents(docs)
|
| 55 |
+
else:
|
| 56 |
+
self.vectorstore.load()
|
| 57 |
+
|
| 58 |
+
# LLM setup
|
| 59 |
+
groq_api_key = os.getenv("GROQ_API_KEY")
|
| 60 |
+
if not groq_api_key:
|
| 61 |
+
raise ValueError("GROQ_API_KEY missing in environment")
|
| 62 |
+
self.llm_model = llm_model
|
| 63 |
+
self.embedding_model = embedding_model
|
| 64 |
+
self.llm = ChatGroq(api_key=groq_api_key, model=llm_model, temperature=0.1)
|
| 65 |
+
print(f"[INFO] Groq LLM initialized: {llm_model}")
|
| 66 |
+
|
| 67 |
+
def retrieve(self, query: str, top_k: int = 5) -> List[RetrievalResult]:
|
| 68 |
+
# Check if vector store is empty
|
| 69 |
+
if self.vectorstore.index is None or len(self.vectorstore.metadata) == 0:
|
| 70 |
+
print("[WARNING] Vector store is empty. No documents to search.")
|
| 71 |
+
return []
|
| 72 |
+
|
| 73 |
+
results = self.vectorstore.query(query_text=query, top_k=top_k)
|
| 74 |
+
out: List[RetrievalResult] = []
|
| 75 |
+
for r in results:
|
| 76 |
+
text = r["metadata"]["texts"] if r.get("metadata") and r["metadata"].get("texts") else None
|
| 77 |
+
out.append(RetrievalResult(index=int(r["index"]), distance=float(r["distance"]), text=text))
|
| 78 |
+
return out
|
| 79 |
+
|
| 80 |
+
def summarize(self, query: str, retrieved: List[RetrievalResult]) -> str:
|
| 81 |
+
if not retrieved:
|
| 82 |
+
return "No documents are available in the vector store. Please add some documents to the data directory and restart the application."
|
| 83 |
+
|
| 84 |
+
texts = [r.text for r in retrieved if r.text]
|
| 85 |
+
context = "\n\n".join(texts)
|
| 86 |
+
if not context:
|
| 87 |
+
return "No relevant documents found for your query."
|
| 88 |
+
|
| 89 |
+
# Using proper message formatting for better LLM interaction
|
| 90 |
+
system_message = SystemMessage(content="You are a helpful assistant that summarizes documents based on queries. Provide clear, concise summaries with relevant quotes when appropriate.")
|
| 91 |
+
human_message = HumanMessage(content=f"""
|
| 92 |
+
Based on the following context, answer the query: '{query}'
|
| 93 |
+
|
| 94 |
+
Context:
|
| 95 |
+
{context}
|
| 96 |
+
|
| 97 |
+
Please provide a comprehensive answer based solely on the provided context. If you quote specific information, indicate it clearly.
|
| 98 |
+
""")
|
| 99 |
+
|
| 100 |
+
try:
|
| 101 |
+
response = self.llm.invoke([system_message, human_message])
|
| 102 |
+
return response.content
|
| 103 |
+
except Exception as e:
|
| 104 |
+
return f"Error generating response: {str(e)}. Please check your GROQ_API_KEY is set correctly."
|
| 105 |
+
|
| 106 |
+
def search_and_summarize(self, query: str, top_k: int = 5) -> str:
|
| 107 |
+
retrieved = self.retrieve(query, top_k=top_k)
|
| 108 |
+
return self.summarize(query, retrieved)
|
| 109 |
+
|
| 110 |
+
if __name__ == "__main__":
|
| 111 |
+
rag_search = RAGSearch()
|
| 112 |
+
query = "What is Database Management System?"
|
| 113 |
+
summary = rag_search.search_and_summarize(query, top_k=3)
|
| 114 |
+
print("Summary:", summary)
|
src/vectorstore.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import faiss
|
| 3 |
+
import numpy as np
|
| 4 |
+
import pickle
|
| 5 |
+
from typing import List, Any
|
| 6 |
+
from sentence_transformers import SentenceTransformer
|
| 7 |
+
from src.embedding import EmbeddingPipeline
|
| 8 |
+
|
| 9 |
+
class FaissVectorStore:
|
| 10 |
+
def __init__(
|
| 11 |
+
self,
|
| 12 |
+
persist_dir: str = "faiss_store",
|
| 13 |
+
embedding_model: str = "all-MiniLM-L6-v2",
|
| 14 |
+
chunk_size: int = 1000,
|
| 15 |
+
chunk_overlap: int = 200,
|
| 16 |
+
):
|
| 17 |
+
self.persist_dir = persist_dir
|
| 18 |
+
os.makedirs(self.persist_dir, exist_ok=True)
|
| 19 |
+
self.index = None
|
| 20 |
+
self.metadata = []
|
| 21 |
+
self.embedding_model = embedding_model
|
| 22 |
+
self.model = SentenceTransformer(embedding_model)
|
| 23 |
+
self.chunk_size = chunk_size
|
| 24 |
+
self.chunk_overlap = chunk_overlap
|
| 25 |
+
print(f"[INFO] Loaded embedding model: {embedding_model}")
|
| 26 |
+
|
| 27 |
+
def build_from_documents(self, documents: List[Any]):
|
| 28 |
+
print(f"[INFO] Building vector store from {len(documents)} raw document(s)...")
|
| 29 |
+
emb_pipe = EmbeddingPipeline(
|
| 30 |
+
model_name=self.embedding_model,
|
| 31 |
+
chunk_size=self.chunk_size,
|
| 32 |
+
chunk_overlap=self.chunk_overlap,
|
| 33 |
+
)
|
| 34 |
+
chunks = emb_pipe.chunk_documents(documents)
|
| 35 |
+
embeddings = emb_pipe.embed_chunks(chunks)
|
| 36 |
+
metadatas = [{"texts": chunk.page_content} for chunk in chunks]
|
| 37 |
+
self.add_embeddings(np.array(embeddings).astype("float32"), metadatas)
|
| 38 |
+
self.save()
|
| 39 |
+
print(f"[INFO] Vector Store built and saved to {self.persist_dir}")
|
| 40 |
+
|
| 41 |
+
def add_embeddings(self, embeddings: np.ndarray, metadatas: List[Any] = None):
|
| 42 |
+
# Handle empty embeddings case
|
| 43 |
+
if embeddings.size == 0:
|
| 44 |
+
print("[WARNING] No embeddings to add. Vector store remains empty.")
|
| 45 |
+
return
|
| 46 |
+
|
| 47 |
+
dim = embeddings.shape[1]
|
| 48 |
+
if self.index is None:
|
| 49 |
+
self.index = faiss.IndexFlatL2(dim)
|
| 50 |
+
self.index.add(embeddings)
|
| 51 |
+
if metadatas:
|
| 52 |
+
self.metadata.extend(metadatas)
|
| 53 |
+
print(f"[INFO] Added {embeddings.shape[0]} vectors to Faiss Index.")
|
| 54 |
+
|
| 55 |
+
def save(self):
|
| 56 |
+
if self.index is None:
|
| 57 |
+
print("[WARNING] Cannot save: index is empty. Skipping save operation.")
|
| 58 |
+
return
|
| 59 |
+
faiss_path = os.path.join(self.persist_dir, "faiss.index")
|
| 60 |
+
meta_path = os.path.join(self.persist_dir, "metadata.pkl")
|
| 61 |
+
faiss.write_index(self.index, faiss_path)
|
| 62 |
+
with open(meta_path, "wb") as f:
|
| 63 |
+
pickle.dump(self.metadata, f)
|
| 64 |
+
print(f"[INFO] Saved Faiss index and metadata to {self.persist_dir}")
|
| 65 |
+
|
| 66 |
+
def load(self):
|
| 67 |
+
faiss_path = os.path.join(self.persist_dir, "faiss.index")
|
| 68 |
+
meta_path = os.path.join(self.persist_dir, "metadata.pkl")
|
| 69 |
+
if not (os.path.exists(faiss_path) and os.path.exists(meta_path)):
|
| 70 |
+
raise FileNotFoundError(f"Missing index/metadata in {self.persist_dir}. Build the store first.")
|
| 71 |
+
self.index = faiss.read_index(faiss_path)
|
| 72 |
+
with open(meta_path, "rb") as f:
|
| 73 |
+
self.metadata = pickle.load(f)
|
| 74 |
+
print(f"[INFO] Loaded Faiss Index and metadata from {self.persist_dir}")
|
| 75 |
+
|
| 76 |
+
def search(self, query_embeddings: np.ndarray, top_k: int = 5):
|
| 77 |
+
if self.index is None:
|
| 78 |
+
print("[WARNING] Vector store is empty. No results to return.")
|
| 79 |
+
return []
|
| 80 |
+
|
| 81 |
+
D, I = self.index.search(query_embeddings, top_k)
|
| 82 |
+
results = []
|
| 83 |
+
for idx, dist in zip(I[0], D[0]):
|
| 84 |
+
meta = self.metadata[idx] if idx < len(self.metadata) else None
|
| 85 |
+
results.append({"index": int(idx), "distance": float(dist), "metadata": meta})
|
| 86 |
+
return results
|
| 87 |
+
|
| 88 |
+
def query(self, query_text: str, top_k: int = 5):
|
| 89 |
+
if self.index is None:
|
| 90 |
+
print("[WARNING] Vector store is empty. No results to return.")
|
| 91 |
+
return []
|
| 92 |
+
|
| 93 |
+
print(f"[INFO] Querying vector store for: '{query_text}'")
|
| 94 |
+
query_emb = self.model.encode([query_text]).astype("float32")
|
| 95 |
+
return self.search(query_emb, top_k=top_k)
|
| 96 |
+
|
| 97 |
+
if __name__ == "__main__":
|
| 98 |
+
from src.data_loader import load_all_documents
|
| 99 |
+
docs = load_all_documents("data")
|
| 100 |
+
store = FaissVectorStore("faiss_store")
|
| 101 |
+
store.build_from_documents(docs)
|
| 102 |
+
store.load()
|
| 103 |
+
print(store.query("What is Database Management System?", top_k=3))
|
temp.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
import logging
|
| 4 |
+
|
| 5 |
+
logging.basicConfig(level=logging.INFO, format='[%(asctime)s]:(message)s:')
|
| 6 |
+
|
| 7 |
+
project_name = "testSummarizer"
|
| 8 |
+
|
| 9 |
+
list_of_files = [
|
| 10 |
+
".github/workflows/.gitkeep",
|
| 11 |
+
f"src/data_loader.py",
|
| 12 |
+
f"src/embedding.py",
|
| 13 |
+
f"src/__init__.py",
|
| 14 |
+
f"src/search.py",
|
| 15 |
+
f"src/vectorstore.py",
|
| 16 |
+
"config/config.yaml",
|
| 17 |
+
"params.yaml",
|
| 18 |
+
"app.py",
|
| 19 |
+
"main.py",
|
| 20 |
+
"Dockerfile",
|
| 21 |
+
"setup.py",
|
| 22 |
+
"research/trails.ipynb"
|
| 23 |
+
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
for filepath in list_of_files:
|
| 27 |
+
filepath = Path(filepath)
|
| 28 |
+
filedir, filename = os.path.split(filepath)
|
| 29 |
+
|
| 30 |
+
if filedir != "":
|
| 31 |
+
os.makedirs(filedir, exist_ok=True)
|
| 32 |
+
logging.info(f"Creating directry:{filepath} for the file {filepath}")
|
| 33 |
+
|
| 34 |
+
if (not os.path.exists(filepath)) or (os.path.getsize(filepath) == 0):
|
| 35 |
+
with open(filepath, 'w') as f:
|
| 36 |
+
pass
|
| 37 |
+
logging.info(f"Creating empty file: {filepath}")
|
| 38 |
+
|
| 39 |
+
else :
|
| 40 |
+
logging.info(f"{filename} is already exists.")
|
test_updates.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Test script to verify the updated Langchain RAG system works correctly.
|
| 4 |
+
"""
|
| 5 |
+
import sys
|
| 6 |
+
import os
|
| 7 |
+
import traceback
|
| 8 |
+
|
| 9 |
+
def test_imports():
|
| 10 |
+
"""Test that all required imports work."""
|
| 11 |
+
print("Testing imports...")
|
| 12 |
+
try:
|
| 13 |
+
# Core imports
|
| 14 |
+
from src.search import RAGSearch, RetrievalResult
|
| 15 |
+
from src.embedding import EmbeddingPipeline
|
| 16 |
+
from src.vectorstore import FaissVectorStore
|
| 17 |
+
from src.data_loader import load_all_documents
|
| 18 |
+
|
| 19 |
+
# External dependencies
|
| 20 |
+
import langchain
|
| 21 |
+
import langchain_core
|
| 22 |
+
import langchain_community
|
| 23 |
+
import langchain_text_splitters
|
| 24 |
+
import sentence_transformers
|
| 25 |
+
import faiss
|
| 26 |
+
import pydantic
|
| 27 |
+
import fastapi
|
| 28 |
+
import uvicorn
|
| 29 |
+
|
| 30 |
+
print("β
All imports successful!")
|
| 31 |
+
|
| 32 |
+
# Print versions
|
| 33 |
+
print(f"\nPackage versions:")
|
| 34 |
+
print(f"- LangChain: {langchain.__version__}")
|
| 35 |
+
print(f"- LangChain Core: {langchain_core.__version__}")
|
| 36 |
+
print(f"- Sentence Transformers: {sentence_transformers.__version__}")
|
| 37 |
+
print(f"- Pydantic: {pydantic.__version__}")
|
| 38 |
+
print(f"- FastAPI: {fastapi.__version__}")
|
| 39 |
+
|
| 40 |
+
return True
|
| 41 |
+
except Exception as e:
|
| 42 |
+
print(f"β Import failed: {e}")
|
| 43 |
+
traceback.print_exc()
|
| 44 |
+
return False
|
| 45 |
+
|
| 46 |
+
def test_basic_functionality():
|
| 47 |
+
"""Test basic functionality without requiring API keys."""
|
| 48 |
+
print("\nTesting basic functionality...")
|
| 49 |
+
try:
|
| 50 |
+
from src.embedding import EmbeddingPipeline
|
| 51 |
+
from src.vectorstore import FaissVectorStore
|
| 52 |
+
|
| 53 |
+
# Test embedding pipeline initialization
|
| 54 |
+
embedding_pipeline = EmbeddingPipeline()
|
| 55 |
+
print("β
Embedding pipeline initialized")
|
| 56 |
+
|
| 57 |
+
# Test vector store initialization
|
| 58 |
+
vector_store = FaissVectorStore(persist_dir="test_store", embedding_model="all-MiniLM-L6-v2")
|
| 59 |
+
print("β
Vector store initialized")
|
| 60 |
+
|
| 61 |
+
return True
|
| 62 |
+
except Exception as e:
|
| 63 |
+
print(f"β Basic functionality test failed: {e}")
|
| 64 |
+
traceback.print_exc()
|
| 65 |
+
return False
|
| 66 |
+
|
| 67 |
+
def test_config_loading():
|
| 68 |
+
"""Test configuration file loading."""
|
| 69 |
+
print("\nTesting configuration loading...")
|
| 70 |
+
try:
|
| 71 |
+
import yaml
|
| 72 |
+
|
| 73 |
+
# Test params.yaml
|
| 74 |
+
if os.path.exists("params.yaml"):
|
| 75 |
+
with open("params.yaml", "r") as f:
|
| 76 |
+
params = yaml.safe_load(f)
|
| 77 |
+
print("β
params.yaml loaded successfully")
|
| 78 |
+
|
| 79 |
+
# Test config.yaml
|
| 80 |
+
if os.path.exists("config/config.yaml"):
|
| 81 |
+
with open("config/config.yaml", "r") as f:
|
| 82 |
+
config = yaml.safe_load(f)
|
| 83 |
+
print("β
config/config.yaml loaded successfully")
|
| 84 |
+
|
| 85 |
+
return True
|
| 86 |
+
except Exception as e:
|
| 87 |
+
print(f"β Config loading failed: {e}")
|
| 88 |
+
return False
|
| 89 |
+
|
| 90 |
+
def main():
|
| 91 |
+
"""Run all tests."""
|
| 92 |
+
print("=== Updated Langchain RAG System Test ===\n")
|
| 93 |
+
|
| 94 |
+
all_passed = True
|
| 95 |
+
|
| 96 |
+
# Test imports
|
| 97 |
+
if not test_imports():
|
| 98 |
+
all_passed = False
|
| 99 |
+
|
| 100 |
+
# Test basic functionality
|
| 101 |
+
if not test_basic_functionality():
|
| 102 |
+
all_passed = False
|
| 103 |
+
|
| 104 |
+
# Test config loading
|
| 105 |
+
if not test_config_loading():
|
| 106 |
+
all_passed = False
|
| 107 |
+
|
| 108 |
+
print(f"\n{'='*50}")
|
| 109 |
+
if all_passed:
|
| 110 |
+
print("π All tests passed! Your project is successfully updated!")
|
| 111 |
+
print("\nNext steps:")
|
| 112 |
+
print("1. Set your GROQ_API_KEY in a .env file")
|
| 113 |
+
print("2. Place your documents in the 'data' directory")
|
| 114 |
+
print("3. Run: python main.py")
|
| 115 |
+
print("4. Or start the API: python app.py")
|
| 116 |
+
else:
|
| 117 |
+
print("β Some tests failed. Please check the errors above.")
|
| 118 |
+
return 1
|
| 119 |
+
|
| 120 |
+
return 0
|
| 121 |
+
|
| 122 |
+
if __name__ == "__main__":
|
| 123 |
+
sys.exit(main())
|