Janar Ramalingam commited on
Commit
51a7f02
1 Parent(s): 2547c6e

first cut working version

Browse files
.gitignore ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Logs and databases
7
+ *.log
8
+ *.sqlite3
9
+ *.db
10
+
11
+ # Testing directories
12
+ /.pytest_cache/
13
+ /nose-timer-master/
14
+
15
+ # Environment and compiled files
16
+ .env
17
+ .env.local
18
+ .env.*.local
19
+ *.pyc
20
+ *.swp
21
+ *.bak
22
+
23
+ # IDE files
24
+ .vscode/
25
+ .idea/
26
+ *.iml
27
+
28
+ # Distribution / packaging
29
+ /dist/
30
+ /build/
31
+ *.egg-info/
32
+
33
+ # Project specific
34
+ /config.yml
35
+ /instance/
36
+ /static/
Dockerfile ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python base image
2
+ FROM python:3.10-slim
3
+
4
+ # Set the working directory
5
+ WORKDIR /app
6
+
7
+ # Copy the requirements.txt file into the container
8
+ COPY requirements.txt .
9
+
10
+ # Install any needed packages specified in requirements.txt
11
+ RUN pip install --trusted-host pypi.python.org -r requirements.txt
12
+
13
+ # Copy the rest of the application code into the container
14
+ COPY api .
15
+
16
+ # Expose the port the app runs on
17
+ EXPOSE 8080
18
+
19
+ ENV OPENAI_API_KEY=zzz
20
+ ENV QDRANT_API_KEY=yyy
21
+ # Start the application using Uvicorn
22
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
README.md ADDED
File without changes
api/db/vector_store.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from qdrant_client import QdrantClient
3
+ from langchain.embeddings import OpenAIEmbeddings
4
+ from langchain.vectorstores import Qdrant
5
+
6
+ embeddings = OpenAIEmbeddings()
7
+ client = QdrantClient(url="https://32f125d3-5ab1-4058-a10a-bd38a1ebd647.us-east-1-0.aws.cloud.qdrant.io",
8
+ api_key=os.getenv("QDRANT_API_KEY"))
9
+
10
+ def get_instance(collection: str = "test"):
11
+ return Qdrant(client=client,collection_name=collection,embeddings=embeddings)
api/exception.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, File, HTTPException, Request
2
+ from fastapi.responses import JSONResponse
3
+ from typing import Any, Dict
4
+
5
+ async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
6
+ return JSONResponse(
7
+ status_code=500,
8
+ content={"message": "Internal server error"},
9
+ )
api/main.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from fastapi import FastAPI
3
+ from routes import embeddings, search, admin
4
+ from fastapi.middleware import Middleware
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from datetime import datetime
7
+ from uvicorn.logging import DefaultFormatter
8
+ import logging
9
+ import uvicorn
10
+ from exception import generic_exception_handler
11
+
12
+ logger = logging.getLogger(__name__)
13
+ handler = logging.StreamHandler()
14
+ handler.setFormatter(DefaultFormatter())
15
+ logger.addHandler(handler)
16
+
17
+ # Create the FastAPI instance
18
+ app = FastAPI()
19
+ app.include_router(embeddings.router)
20
+ app.include_router(search.router)
21
+ app.include_router(admin.router)
22
+ app.exception_handler(generic_exception_handler)
23
+
24
+ @app.middleware("http")
25
+ async def log_requests(request, call_next):
26
+ start_time = datetime.utcnow()
27
+ response = await call_next(request)
28
+ process_time = (datetime.utcnow() - start_time).total_seconds() * 1000
29
+ print(
30
+ f"{request.method} {request.url.path} {response.status_code} {process_time:.2f}ms"
31
+ )
32
+ return response
33
+
34
+
35
+ if __name__ == "__main__":
36
+ uvicorn.run(app, host="0.0.0.0", port=8080)
api/routes/admin.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #This is to init the vector store
2
+
3
+ from qdrant_client.models import VectorParams, Distance
4
+ from fastapi import APIRouter
5
+ from db import vector_store
6
+
7
+ router = APIRouter()
8
+
9
+ @router.put("/admin/v1/db")
10
+ async def recreate_collection(name: str = "test"):
11
+ print(f"creating collection {name} in db")
12
+ return vector_store.client.recreate_collection(collection_name=name,
13
+ vectors_config=VectorParams(size=1536, distance=Distance.COSINE))
api/routes/embeddings.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, UploadFile, File
2
+ import openai
3
+ import io
4
+ import os
5
+ from pypdf import PdfReader
6
+
7
+ router = APIRouter()
8
+
9
+ openai.api_key = os.getenv("OPENAI_API_KEY")
10
+
11
+ @router.post("/v1/embeddings")
12
+ async def embed_doc(file: UploadFile = File(...)):
13
+ #for now just truncate based on length of words
14
+ content = await file.read()
15
+ return openai.Embedding.create(input = content.decode("utf-8"), model = "text-embedding-ada-002")
api/routes/search.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, UploadFile, File
2
+ from fastapi.responses import JSONResponse
3
+ import openai
4
+ import io
5
+ import os
6
+ from pypdf import PdfReader
7
+ from langchain.embeddings.openai import OpenAIEmbeddings
8
+ from langchain.vectorstores import Qdrant
9
+ from langchain.schema import Document
10
+ from langchain.chains.question_answering import load_qa_chain
11
+ from langchain.llms import OpenAI
12
+ from db import vector_store
13
+
14
+ router = APIRouter()
15
+ _db = vector_store.get_instance()
16
+ _chain = load_qa_chain(OpenAI(temperature=0), chain_type="stuff")
17
+
18
+ @router.post("/v1/docs")
19
+ async def index_doc(file: UploadFile = File(...)):
20
+ async for doc in generate_documents(file):
21
+ _db.add_documents([doc])
22
+ #todo return something sensible
23
+ return JSONResponse(status_code=200, content={})
24
+
25
+ @router.get("/v1/docs")
26
+ async def search(query: str):
27
+ print(query)
28
+ docs = _db.similarity_search(query=query)
29
+ answer = _chain.run(input_documents=docs, question=query)
30
+ return JSONResponse(status_code=200, content={"answer": answer})
31
+
32
+ async def generate_documents(file: UploadFile):
33
+ num=0
34
+ async for txt in convert_documents(file):
35
+ num += 1
36
+ document = Document(page_content=txt,metadata={"page": num})
37
+ yield document
38
+
39
+ async def convert_documents(file: UploadFile):
40
+ #parse pdf document
41
+ if file.content_type == 'application/pdf':
42
+ content = await file.read()
43
+ pdf_reader = PdfReader(io.BytesIO(content))
44
+ try:
45
+ for page in pdf_reader.pages:
46
+ yield page.extract_text()
47
+ except Exception as e:
48
+ print(f"Exception {e}")
49
+ else:
50
+ return
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ openai
2
+ uvicorn
3
+ fastapi
4
+ python-multipart
5
+ numpy
6
+ pypdf
7
+ langchain
8
+ tiktoken
9
+ faiss-cpu
10
+ qdrant-client
11
+
setup.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("requirements.txt") as f:
4
+ requirements = f.read().splitlines()
5
+
6
+ setup(
7
+ name="doc_index",
8
+ version="0.1",
9
+ packages=find_packages(),
10
+ install_requires= requirements,
11
+ entry_points={
12
+ "console_scripts": [
13
+ # add any command-line scripts here
14
+ ]
15
+ },
16
+ )