Agboola commited on
Commit
8da6141
·
1 Parent(s): d899aed

deploy rag

Browse files
Files changed (4) hide show
  1. Dockerfile +11 -0
  2. app.py +147 -0
  3. requirements.txt +12 -0
  4. seplat.pdf +0 -0
Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
2
+
3
+ WORKDIR /app
4
+
5
+ COPY . .
6
+
7
+ RUN pip install --no-cache-dir -r requirements.txt
8
+
9
+ EXPOSE 7860
10
+
11
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel
3
+
4
+ from langchain_community.document_loaders import PyPDFLoader
5
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
6
+ from langchain_community.embeddings import HuggingFaceEmbeddings
7
+ from langchain_community.vectorstores import Chroma
8
+ from langchain_core.prompts import ChatPromptTemplate
9
+ from langchain_core.runnables import RunnablePassthrough
10
+ from langchain_core.output_parsers import StrOutputParser
11
+
12
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
13
+ from langchain_huggingface import HuggingFacePipeline
14
+
15
+ app = FastAPI()
16
+
17
+
18
+ # -----------------------
19
+ # Schema Validation
20
+ # -----------------------
21
+ class Query(BaseModel):
22
+ question: str
23
+
24
+
25
+ # -----------------------
26
+ # Load documents
27
+ # -----------------------
28
+
29
+ loader = PyPDFLoader("seplat.pdf")
30
+ docs = loader.load()
31
+
32
+ text_splitter = RecursiveCharacterTextSplitter(
33
+ chunk_size=1000,
34
+ chunk_overlap=200
35
+ )
36
+
37
+ doc_chunks = text_splitter.split_documents(docs)
38
+
39
+
40
+ # -----------------------
41
+ # Embedding Model
42
+ # -----------------------
43
+
44
+ embeddings = HuggingFaceEmbeddings(
45
+ model_name="all-MiniLM-L6-v2"
46
+ )
47
+
48
+
49
+ # -----------------------
50
+ # Vectorstore
51
+ # -----------------------
52
+
53
+ db = Chroma.from_documents(
54
+ documents=doc_chunks,
55
+ embedding=embeddings,
56
+ persist_directory="./chroma_db"
57
+ )
58
+
59
+ retriever = db.as_retriever(
60
+ search_type="similarity",
61
+ search_kwargs={"k": 1}
62
+ )
63
+
64
+
65
+ # -----------------------
66
+ # Prompt
67
+ # -----------------------
68
+
69
+ prompt_template = """
70
+ You are an AI assistant for Obiex.
71
+ Use ONLY the context below to answer the question.
72
+ If the answer is not in the context, say you don't know.
73
+
74
+ Context:
75
+ {context}
76
+
77
+ Question:
78
+ {question}
79
+
80
+ Answer:
81
+ """
82
+
83
+ prompt = ChatPromptTemplate.from_template(prompt_template)
84
+
85
+
86
+ # -----------------------
87
+ # LLM
88
+ # -----------------------
89
+
90
+ model_name = "microsoft/phi-4-mini-instruct"
91
+
92
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
93
+
94
+ model = AutoModelForCausalLM.from_pretrained(
95
+ model_name,
96
+ device_map="auto",
97
+ torch_dtype="auto"
98
+ )
99
+
100
+ text_gen_pipe = pipeline(
101
+ "text-generation",
102
+ model=model,
103
+ tokenizer=tokenizer,
104
+ max_new_tokens=256
105
+ )
106
+
107
+ llm = HuggingFacePipeline(pipeline=text_gen_pipe)
108
+
109
+
110
+ # -----------------------
111
+ # RAG chain
112
+ # -----------------------
113
+
114
+ rag_chain = (
115
+ {
116
+ "context": retriever,
117
+ "question": RunnablePassthrough()
118
+ }
119
+ | prompt
120
+ | llm
121
+ | StrOutputParser()
122
+ )
123
+
124
+
125
+ # -----------------------
126
+ # API endpoint
127
+ # -----------------------
128
+
129
+ @app.post("/query")
130
+ def query_rag(q: Query):
131
+ try:
132
+
133
+ docs = retriever.get_relevant_documents(q.question)
134
+ response = rag_chain.invoke(q.question)
135
+
136
+ return {
137
+ "question": q.question,
138
+ "answer": response,
139
+ "sources": [doc.metadata for doc in docs]
140
+ }
141
+
142
+ except Exception as e:
143
+ raise HTTPException(status_code=500, detail=str(e))
144
+
145
+ @app.get("/health")
146
+ def health():
147
+ return {"status": "ok"}
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ langchain
4
+ langchain-community
5
+ langchain-core
6
+ langchain-huggingface
7
+ chromadb
8
+ sentence-transformers
9
+ transformers
10
+ accelerate
11
+ pypdf
12
+ tiktoken
seplat.pdf ADDED
The diff for this file is too large to render. See raw diff