File size: 3,223 Bytes
2d8c319
23a5488
 
42d3ee2
c7f06c3
2c8f8ec
c7f06c3
 
42d3ee2
c7f06c3
23a5488
02a4a64
 
3b4718c
 
 
 
c7f06c3
02a4a64
23a5488
02a4a64
c48b838
42d3ee2
c48b838
 
 
 
 
 
 
 
42d3ee2
 
 
f8c1ecf
c7f06c3
c48b838
 
 
23a5488
c48b838
3082616
 
c48b838
 
 
23a5488
 
c48b838
 
 
 
 
 
23a5488
c7f06c3
23a5488
c48b838
 
 
 
aeb0da4
23a5488
c48b838
 
23a5488
 
 
c7f06c3
23a5488
c48b838
23a5488
 
 
 
c48b838
23a5488
3082616
c48b838
 
f8c1ecf
c48b838
4d6816c
c48b838
 
 
 
 
 
2d88065
c48b838
 
 
 
23a5488
c48b838
 
 
0e5b4a4
c48b838
 
 
 
 
23a5488
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
import os
import gc
import torch
import gradio as gr
from langchain_community.document_loaders import PyMuPDFLoader, TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.chains import RetrievalQA
from langchain_community.llms import HuggingFacePipeline
from transformers import pipeline, AutoTokenizer, BitsAndBytesConfig
from huggingface_hub import login



torch.set_num_threads(2)

# HF Token handling
if os.environ.get("HF_TOKEN"):
    login(token=os.environ["HF_TOKEN"])

def load_documents(file_path="study_materials"):
    documents = []
    for filename in os.listdir(file_path):
        path = os.path.join(file_path, filename)
        if filename.endswith(".pdf"):
            loader = PyMuPDFLoader(path)
            documents.extend(loader.load())
        elif filename.endswith(".txt"):
            loader = TextLoader(path)
            documents.extend(loader.load())
    return documents

def create_qa_system():
    try:
        # Load and process documents
        documents = load_documents()
        if not documents:
            raise ValueError("📚 No study materials found")
            
        text_splitter = CharacterTextSplitter(
            chunk_size=1000,
            chunk_overlap=200,
            separator="\n\n"
        )
        texts = text_splitter.split_documents(documents)

        # Create embeddings
        embeddings = HuggingFaceEmbeddings(
            model_name="sentence-transformers/all-MiniLM-L6-v2"
        )
        
        # Vector store
        db = FAISS.from_documents(texts, embeddings)

        # LLM setup with CPU optimizations
        tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-large")
        pipe = pipeline(
            "text2text-generation",
            model="google/flan-t5-large",
            tokenizer=tokenizer,
            max_length=200,
            temperature=0.7,
            do_sample=True,
            top_k=50,
            device=-1,  # Force CPU usage
            model_kwargs={
                "torch_dtype": torch.float16,
                "low_cpu_mem_usage": True
            }
        )

        # Memory cleanup
        gc.collect()

        return RetrievalQA.from_llm(
            llm=HuggingFacePipeline(pipeline=pipe),
            retriever=db.as_retriever(search_kwargs={"k": 3}),
            return_source_documents=True
        )
    except Exception as e:
        raise gr.Error(f"Error: {str(e)}")

# Initialize system
try:
    qa = create_qa_system()
except Exception as e:
    print(f"Startup failed: {str(e)}")
    raise

def ask_question(question, history):
    try:
        result = qa.invoke({"query": question})
        answer = result["result"]
        sources = {os.path.basename(doc.metadata['source']) for doc in result['source_documents']}
        return f"{answer}\n\n📚 Sources: {', '.join(sources)}"
    except Exception as e:
        return f"Error: {str(e)[:150]}"

gr.ChatInterface(
    ask_question,
    title="Study Assistant",
    description="Upload PDF/TXT files in 'study_materials' folder and ask questions!",
    theme="soft"
).launch()