adi-123 commited on
Commit
372a807
·
verified ·
1 Parent(s): 8d71ae8

Upload 2 files

Browse files
Files changed (2) hide show
  1. app (2).py +87 -0
  2. utils (1).py +108 -0
app (2).py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from typing import List, IO
3
+
4
+ # Import utilities you finalised
5
+ from utils import (
6
+ get_pdf_text,
7
+ get_docx_text,
8
+ get_text_chunks,
9
+ get_vector_store,
10
+ user_input,
11
+ )
12
+
13
+ # ---------------------------------------------------------------------------#
14
+ # Main Streamlit application
15
+ # ---------------------------------------------------------------------------#
16
+ def main() -> None:
17
+ # ----- Page configuration ------------------------------------------------
18
+ st.set_page_config(
19
+ page_title="Docosphere",
20
+ page_icon="📄",
21
+ layout="wide"
22
+ )
23
+
24
+ st.title("📄 Docosphere")
25
+ st.markdown("*Where Documents Come Alive …*")
26
+
27
+ # Two-column layout: Q&A on left, file upload on right
28
+ col_left, col_right = st.columns([2, 1])
29
+
30
+ # --------------------- Right column – document upload -------------------
31
+ with col_right:
32
+ st.markdown("### 📁 Document Upload")
33
+ uploaded_files: List[IO[bytes]] = st.file_uploader(
34
+ "Upload PDF or Word files",
35
+ accept_multiple_files=True,
36
+ type=["pdf", "docx"],
37
+ help="You can select multiple files at once."
38
+ )
39
+
40
+ if st.button("🚀 Process Documents"):
41
+ if not uploaded_files:
42
+ st.warning("📋 Please upload at least one file first.")
43
+ return
44
+
45
+ with st.spinner("🔄 Extracting text & creating vector index…"):
46
+ combined_text = ""
47
+
48
+ pdfs = [f for f in uploaded_files if f.name.lower().endswith(".pdf")]
49
+ docs = [f for f in uploaded_files if f.name.lower().endswith(".docx")]
50
+
51
+ if pdfs:
52
+ combined_text += get_pdf_text(pdfs)
53
+ if docs:
54
+ combined_text += get_docx_text(docs)
55
+
56
+ if combined_text.strip():
57
+ chunks = get_text_chunks(combined_text)
58
+ get_vector_store(chunks)
59
+ st.success("✅ Documents processed! Ask away in the left panel.")
60
+ else:
61
+ st.warning("⚠️ No readable text found in the uploaded files.")
62
+
63
+ with st.expander("ℹ️ How to use"):
64
+ st.markdown(
65
+ """
66
+ 1. Upload one or more **PDF** or **Word** documents.\n
67
+ 2. Click **Process Documents** to build the knowledge index.\n
68
+ 3. Ask natural-language questions in the input box (left column).\n
69
+ 4. The assistant will either answer from its own model knowledge or
70
+ retrieve context from your documents when needed.
71
+ """
72
+ )
73
+
74
+ # ---------------------- Left column – chat interface --------------------
75
+ with col_left:
76
+ st.markdown("### 💬 Ask Your Question")
77
+ question: str = st.text_input(
78
+ "",
79
+ placeholder="Type a question about your documents or general topics…"
80
+ )
81
+
82
+ if question:
83
+ user_input(question)
84
+
85
+ # Entry-point guard
86
+ if __name__ == "__main__":
87
+ main()
utils (1).py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, tempfile, streamlit as st
2
+ from typing import List, IO, Tuple
3
+ from dotenv import load_dotenv
4
+ from PyPDF2 import PdfReader
5
+ from docx import Document
6
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
7
+ from langchain.schema import Document as LangchainDocument
8
+ from langchain_community.vectorstores import FAISS
9
+ from langchain_together.chat_models import ChatTogether
10
+ from langchain_together.embeddings import TogetherEmbeddings # <-- NEW
11
+ from langchain.prompts import PromptTemplate
12
+
13
+ load_dotenv()
14
+
15
+ # ---------- Helpers ---------------------------------------------------------
16
+ def get_together_api_key() -> str:
17
+ key = os.getenv("TOGETHER_API_KEY") or st.secrets.get("TOGETHER_API_KEY", None)
18
+ if not key:
19
+ raise EnvironmentError("TOGETHER_API_KEY not found in env or Streamlit secrets.")
20
+ return key
21
+
22
+ # ---------- File-reading utilities -----------------------------------------
23
+ def get_pdf_text(pdf_docs: List[IO[bytes]]) -> str:
24
+ txt = ""
25
+ for pdf in pdf_docs:
26
+ for page in PdfReader(pdf).pages:
27
+ if (t := page.extract_text()):
28
+ txt += t + "\n"
29
+ return txt
30
+
31
+ def get_docx_text(docx_docs: List[IO[bytes]]) -> str:
32
+ txt = ""
33
+ for d in docx_docs:
34
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as tmp:
35
+ tmp.write(d.getvalue()); tmp.flush()
36
+ try:
37
+ doc = Document(tmp.name)
38
+ txt += "\n".join(p.text for p in doc.paragraphs) + "\n"
39
+ finally:
40
+ os.unlink(tmp.name)
41
+ return txt
42
+
43
+ def get_text_chunks(text: str) -> List[str]:
44
+ return RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200).split_text(text)
45
+
46
+ # ---------- Vector-store build & save --------------------------------------
47
+ def get_vector_store(text_chunks: List[str]) -> None:
48
+ api_key = get_together_api_key()
49
+ embeddings = TogetherEmbeddings(model="BAAI/bge-base-en-v1.5", api_key=api_key)
50
+ vector_store = FAISS.from_texts(text_chunks, embedding=embeddings)
51
+ vector_store.save_local("faiss_index")
52
+
53
+ # ---------- QA chain helpers ----------------------------------------------
54
+ def get_conversational_chain() -> Tuple[ChatTogether, PromptTemplate]:
55
+ api_key = get_together_api_key()
56
+ llm = ChatTogether(model="meta-llama/Llama-3.3-70B-Instruct-Turbo-Free",
57
+ temperature=0.3, api_key=api_key)
58
+ prompt = PromptTemplate(
59
+ template=(
60
+ "As a professional assistant, provide a detailed and formally written "
61
+ "answer to the question using the provided context.\n\nContext:\n{context}\n\n"
62
+ "Question:\n{question}\n\nAnswer:"
63
+ ),
64
+ input_variables=["context", "question"]
65
+ )
66
+ return llm, prompt
67
+
68
+ def self_assess(question: str) -> str:
69
+ api_key = get_together_api_key()
70
+ llm = ChatTogether(model="meta-llama/Llama-3.3-70B-Instruct-Turbo-Free",
71
+ temperature=0.3, api_key=api_key)
72
+ msgs = [
73
+ {"role": "system", "content": "You are an expert assistant…"},
74
+ {"role": "user", "content": (
75
+ "If you can confidently answer the following question from your own "
76
+ "knowledge, do so; otherwise reply with 'NEED_RETRIEVAL'.\n\n"
77
+ f"Question: {question}"
78
+ )}
79
+ ]
80
+ return llm.invoke(msgs).content.strip()
81
+
82
+ def process_docs_for_query(docs: List[LangchainDocument], question: str) -> str:
83
+ if not docs:
84
+ return "Sorry, I couldn’t find relevant info in the documents."
85
+ ctx = "\n\n".join(d.page_content for d in docs)
86
+ llm, prompt = get_conversational_chain()
87
+ return llm.invoke(prompt.format(context=ctx, question=question)).content
88
+
89
+ # ---------- Main user-query orchestrator -----------------------------------
90
+ def user_input(user_question: str) -> None:
91
+ assessment = self_assess(user_question)
92
+ need_retrieval = assessment.upper() == "NEED_RETRIEVAL"
93
+ st.info("🔍 Searching documents…" if need_retrieval else "💡 Using model knowledge…")
94
+
95
+ try:
96
+ if need_retrieval:
97
+ api_key = get_together_api_key()
98
+ embeddings = TogetherEmbeddings(model="BAAI/bge-base-en-v1.5", api_key=api_key)
99
+ vs = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
100
+ docs = vs.similarity_search(user_question)
101
+ answer = process_docs_for_query(docs, user_question)
102
+ else:
103
+ answer = assessment
104
+
105
+ st.markdown("### Answer")
106
+ st.markdown(answer)
107
+ except Exception as e:
108
+ st.error(f"⚠️ Error: {e}")