Nav772 commited on
Commit
2395611
Β·
verified Β·
1 Parent(s): 66dedca

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +169 -0
app.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from langchain_community.document_loaders import PyPDFLoader
4
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
5
+ from langchain_huggingface import HuggingFaceEmbeddings
6
+ from langchain_community.vectorstores import FAISS
7
+ from huggingface_hub import InferenceClient
8
+ import tempfile
9
+ import os
10
+
11
+ # Initialize embedding model (runs on CPU, small enough for free tier)
12
+ embedding_model = HuggingFaceEmbeddings(
13
+ model_name="sentence-transformers/all-MiniLM-L6-v2",
14
+ model_kwargs={'device': 'cpu'}
15
+ )
16
+
17
+ # Initialize Inference Client (uses free API)
18
+ client = InferenceClient(model="HuggingFaceH4/zephyr-7b-beta")
19
+
20
+ # Global variable to store vectorstore
21
+ vectorstore = None
22
+
23
+ def process_pdf(pdf_file):
24
+ """Process uploaded PDF and create vector store."""
25
+ global vectorstore
26
+
27
+ if pdf_file is None:
28
+ return "Please upload a PDF file."
29
+
30
+ try:
31
+ # Load PDF
32
+ loader = PyPDFLoader(pdf_file.name)
33
+ documents = loader.load()
34
+
35
+ # Split into chunks
36
+ text_splitter = RecursiveCharacterTextSplitter(
37
+ chunk_size=1000,
38
+ chunk_overlap=200,
39
+ )
40
+ chunks = text_splitter.split_documents(documents)
41
+
42
+ # Create vector store
43
+ vectorstore = FAISS.from_documents(
44
+ documents=chunks,
45
+ embedding=embedding_model
46
+ )
47
+
48
+ return f"βœ… Successfully processed {len(documents)} pages into {len(chunks)} chunks. You can now ask questions!"
49
+
50
+ except Exception as e:
51
+ return f"❌ Error processing PDF: {str(e)}"
52
+
53
+ def answer_question(question):
54
+ """Answer question using RAG."""
55
+ global vectorstore
56
+
57
+ if vectorstore is None:
58
+ return "Please upload and process a PDF first.", ""
59
+
60
+ if not question.strip():
61
+ return "Please enter a question.", ""
62
+
63
+ try:
64
+ # Retrieve relevant chunks
65
+ docs = vectorstore.similarity_search(question, k=3)
66
+
67
+ # Format context
68
+ context = "\n\n".join([doc.page_content for doc in docs])
69
+
70
+ # Create prompt
71
+ prompt = f"""<|system|>
72
+ You are a helpful assistant that answers questions based on the provided context. Only use information from the context to answer. If the answer is not in the context, say "I cannot find this information in the document."
73
+ </s>
74
+ <|user|>
75
+ Context:
76
+ {context}
77
+
78
+ Question: {question}
79
+ </s>
80
+ <|assistant|>"""
81
+
82
+ # Call Inference API
83
+ response = client.text_generation(
84
+ prompt,
85
+ max_new_tokens=512,
86
+ temperature=0.7,
87
+ )
88
+
89
+ # Format sources
90
+ sources = []
91
+ for i, doc in enumerate(docs, 1):
92
+ page = doc.metadata.get('page', 'N/A')
93
+ if isinstance(page, int):
94
+ page += 1
95
+ preview = doc.page_content[:150].replace('\n', ' ')
96
+ sources.append(f"{i}. Page {page}: {preview}...")
97
+
98
+ sources_text = "\n".join(sources)
99
+
100
+ return response, sources_text
101
+
102
+ except Exception as e:
103
+ return f"❌ Error: {str(e)}", ""
104
+
105
+ # Create Gradio interface
106
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
107
+ gr.Markdown("""
108
+ # πŸ“š RAG Document Q&A System
109
+
110
+ Upload a PDF document and ask questions about its content.
111
+
112
+ **How it works:**
113
+ 1. Upload a PDF file
114
+ 2. Click "Process PDF" to analyze the document
115
+ 3. Ask questions about the document content
116
+ """)
117
+
118
+ with gr.Row():
119
+ with gr.Column(scale=1):
120
+ pdf_input = gr.File(label="Upload PDF", file_types=[".pdf"])
121
+ process_btn = gr.Button("πŸ“„ Process PDF", variant="primary")
122
+ status_output = gr.Textbox(label="Status", interactive=False)
123
+
124
+ with gr.Column(scale=2):
125
+ question_input = gr.Textbox(
126
+ label="Your Question",
127
+ placeholder="What is this document about?",
128
+ lines=2
129
+ )
130
+ ask_btn = gr.Button("πŸ” Ask Question", variant="primary")
131
+ answer_output = gr.Textbox(label="Answer", lines=6, interactive=False)
132
+ sources_output = gr.Textbox(label="Sources", lines=4, interactive=False)
133
+
134
+ gr.Markdown("""
135
+ ---
136
+ ### πŸ› οΈ Technical Details
137
+
138
+ | Component | Technology |
139
+ |-----------|------------|
140
+ | Embeddings | sentence-transformers/all-MiniLM-L6-v2 |
141
+ | Vector Store | FAISS |
142
+ | LLM | Zephyr-7B via Inference API |
143
+ | Chunking | 1000 chars, 200 overlap |
144
+
145
+ ### ⚠️ Development Challenges Documented
146
+
147
+ This project encountered several technical challenges:
148
+ - **LangChain API changes**: Package restructuring required updated imports
149
+ - **PDF parsing issues**: Required proper HTTP headers for downloads
150
+ - **LLM response quality**: FLAN-T5 produced short responses; switched to Zephyr-7B
151
+ - **Memory management**: Required explicit GPU cleanup between model loads
152
+
153
+ Built by [Nav772](https://huggingface.co/Nav772) as part of AI Engineering portfolio.
154
+ """)
155
+
156
+ # Connect buttons to functions
157
+ process_btn.click(
158
+ fn=process_pdf,
159
+ inputs=[pdf_input],
160
+ outputs=[status_output]
161
+ )
162
+
163
+ ask_btn.click(
164
+ fn=answer_question,
165
+ inputs=[question_input],
166
+ outputs=[answer_output, sources_output]
167
+ )
168
+
169
+ demo.launch()