Spaces:
Sleeping
Sleeping
File size: 4,533 Bytes
21753a3 d2c6ac6 4431829 d2c6ac6 b14a2f9 21753a3 36eb467 b14a2f9 1fda785 b14a2f9 d2c6ac6 b14a2f9 21753a3 b74d72a d2c6ac6 21753a3 94f2884 21753a3 a3dcdff d2c6ac6 a3dcdff d2c6ac6 21753a3 d2c6ac6 21753a3 94f2884 21753a3 d2c6ac6 21753a3 d2c6ac6 21753a3 1fda785 21753a3 1fda785 21753a3 1fda785 21753a3 c3e3d46 b15d87a 21753a3 b15d87a 21753a3 b15d87a 21753a3 b15d87a 21753a3 b15d87a d2c6ac6 21753a3 fb8d4f3 21753a3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
from flask import Flask, request, jsonify, render_template
import fitz # PyMuPDF for PDF text extraction
import faiss # FAISS for vector search
import numpy as np
import os
from sentence_transformers import SentenceTransformer
from huggingface_hub import InferenceClient
from typing import List, Tuple
app = Flask(__name__, template_folder=os.getcwd())
# Default settings
class ChatConfig:
MODEL = "google/gemma-3-27b-it"
DEFAULT_SYSTEM_MSG = "You are an AI assistant answering only based on the uploaded PDF."
DEFAULT_MAX_TOKENS = 512
DEFAULT_TEMP = 0.3
DEFAULT_TOP_P = 0.95
client = InferenceClient(ChatConfig.MODEL)
embed_model = SentenceTransformer("all-MiniLM-L6-v2", cache_folder="/tmp")
vector_dim = 384 # Embedding size
index = faiss.IndexFlatL2(vector_dim) # FAISS index
documents = [] # Store extracted text
def extract_text_from_pdf(pdf_path):
"""Extracts text from PDF"""
doc = fitz.open(pdf_path)
text_chunks = [page.get_text("text") for page in doc]
return text_chunks
def create_vector_db(text_chunks):
"""Embeds text chunks and adds them to FAISS index"""
global documents, index
documents = text_chunks
embeddings = embed_model.encode(text_chunks)
# Convert embeddings to np.float32 for FAISS
embeddings = np.array(embeddings, dtype=np.float32)
# Ensure that embeddings have the correct shape (should be 2D, with each vector having the right dimension)
if embeddings.ndim == 1: # If only one embedding, reshape it
embeddings = embeddings.reshape(1, -1)
# Add embeddings to the FAISS index
index.add(embeddings)
# Check if adding was successful (optional)
if index.ntotal == 0:
print("Error: FAISS index is empty after adding embeddings.")
def search_relevant_text(query):
"""Finds the most relevant text chunk for the given query"""
query_embedding = embed_model.encode([query])
_, closest_idx = index.search(np.array(query_embedding, dtype=np.float32), k=3)
return "\n".join([documents[i] for i in closest_idx[0]])
def generate_response(
message: str,
history: List[Tuple[str, str]],
system_message: str = ChatConfig.DEFAULT_SYSTEM_MSG,
max_tokens: int = ChatConfig.DEFAULT_MAX_TOKENS,
temperature: float = ChatConfig.DEFAULT_TEMP,
top_p: float = ChatConfig.DEFAULT_TOP_P
) -> str:
if not documents:
return "Please upload a PDF first."
context = search_relevant_text(message) # Get relevant content from PDF
messages = [{"role": "system", "content": system_message}]
for user_msg, bot_msg in history:
if user_msg:
messages.append({"role": "user", "content": user_msg})
if bot_msg:
messages.append({"role": "assistant", "content": bot_msg})
messages.append({"role": "user", "content": f"Context: {context}\nQuestion: {message}"})
response = ""
for chunk in client.chat_completion(
messages,
max_tokens=max_tokens,
stream=True,
temperature=temperature,
top_p=top_p,
):
token = chunk.choices[0].delta.content or ""
response += token
return response
@app.route('/')
def index():
"""Serve the HTML page for the user interface"""
return render_template('index.html')
UPLOAD_FOLDER = "/tmp/uploaded_files"
os.makedirs(UPLOAD_FOLDER, exist_ok=True) # Ensure the folder exists
@app.route('/upload_pdf', methods=['POST'])
def upload_pdf():
"""Handle PDF upload"""
if 'pdf' not in request.files:
return jsonify({"error": "No file part"}), 400 # Handle missing file
file = request.files['pdf']
if file.filename == "":
return jsonify({"error": "No selected file"}), 400 # Handle empty filename
pdf_path = os.path.join(UPLOAD_FOLDER, file.filename)
try:
file.save(pdf_path) # Save the uploaded PDF
# Extract text and create vector database
text_chunks = extract_text_from_pdf(pdf_path)
create_vector_db(text_chunks)
return jsonify({"message": "PDF uploaded and indexed successfully!"}), 200
except Exception as e:
return jsonify({"error": f"Error processing file: {str(e)}"}), 500
@app.route('/ask_question', methods=['POST'])
def ask_question():
"""Handle user question"""
message = request.json.get('message')
history = request.json.get('history', [])
response = generate_response(message, history)
return jsonify({"response": response})
if __name__ == '__main__':
app.run(debug=True)
|