Deepak Yadav commited on
Commit
e50c54a
·
1 Parent(s): ad8d799

updated new version deepseek-r1

Browse files
app.py CHANGED
@@ -1,35 +1,137 @@
1
  import streamlit as st
2
  import os
3
- from components.sidebar import render_sidebar
4
- from components.chat_ui import display_chat
5
- from services.llm import initialize_qa_chain, initialize_chain
6
- from utils.helpers import get_file_size
 
7
 
8
- # import subprocess
9
- # process = subprocess.Popen("ollama serve", shell=True)
10
- # print(process)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- # App Title
13
- st.title("DocChatAI | Chat Using Documents")
 
14
 
15
- # Sidebar - Model Selection & File Upload
16
- selected_model, temperature, top_p, max_tokens, uploaded_file = render_sidebar()
 
 
17
 
18
- mode = False
19
- # Check if a PDF file is uploaded
20
- if uploaded_file is not None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  os.makedirs("docs", exist_ok=True)
22
  filepath = os.path.join("docs", uploaded_file.name)
23
 
24
- with open(filepath, "wb") as temp_file:
25
- temp_file.write(uploaded_file.read())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- with st.spinner('Please wait...'):
28
- qa_chain = initialize_qa_chain(filepath, selected_model, temperature, top_p, max_tokens)
29
- mode = True
30
- else:
31
 
32
- qa_chain = initialize_chain(selected_model, temperature, top_p, max_tokens)
 
 
33
 
34
- # Initialize and Display Chat History
35
- display_chat(qa_chain, mode)
 
1
  import streamlit as st
2
  import os
3
+ import time
4
+ from services.llm import initialize_llm, initialize_embeddings
5
+ from services.vector_store import create_vector_store, retrive_vector_store, generate_prompt
6
+ from services.pdf_processing import load_and_split_pdf
7
+ from utils.helpers import extract_thoughts, response_generator
8
 
9
+ # Custom CSS for chat styling
10
+ CHAT_CSS = """
11
+ <style>
12
+ .user-message {
13
+ text-align: right;
14
+ background-color: #3c8ce7;
15
+ color: white;
16
+ padding: 10px;
17
+ border-radius: 10px;
18
+ margin-bottom: 10px;
19
+ display: inline-block;
20
+ width: fit-content;
21
+ max-width: 70%;
22
+ margin-left: auto;
23
+ box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
24
+ }
25
+ .assistant-message {
26
+ text-align: left;
27
+ background-color: #d16ba5;
28
+ color: white;
29
+ padding: 10px;
30
+ border-radius: 10px;
31
+ margin-bottom: 10px;
32
+ display: inline-block;
33
+ width: fit-content;
34
+ max-width: 70%;
35
+ margin-right: auto;
36
+ box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
37
+ }
38
+ </style>
39
+ """
40
 
41
+ # Streamlit UI Setup
42
+ st.set_page_config(page_title="DocChatAI", layout="wide")
43
+ st.title("📄 DocChatAI | Chat Using Documents")
44
 
45
+ # Sidebar
46
+ st.sidebar.title("DocChatAI")
47
+ st.sidebar.subheader("Chat using PDF Document")
48
+ st.sidebar.write("---")
49
 
50
+ # Model Selection
51
+ selected_model = st.sidebar.radio("Choose Model", ["deepseek-r1:1.5b"])
52
+ st.sidebar.write("---")
53
+
54
+ # Hyperparameters
55
+ temperature = st.sidebar.slider("Temperature", 0.0, 1.0, 0.7, 0.1)
56
+ top_p = st.sidebar.slider("Top-p (Nucleus Sampling)", 0.0, 1.0, 0.9, 0.05)
57
+ max_tokens = st.sidebar.number_input("Max Tokens", 10, 2048, 256, 10)
58
+ st.sidebar.write("---")
59
+
60
+ # File Upload
61
+ uploaded_file = st.sidebar.file_uploader("📂 Upload a PDF", type=["pdf"])
62
+ st.sidebar.write("---")
63
+
64
+ # About Section
65
+ st.sidebar.write("📌 **About Me**")
66
+ st.sidebar.write("👤 **Name:** Deepak Yadav")
67
+ st.sidebar.write("💡 **Bio:** Passionate about AI and Machine Learning.")
68
+ st.sidebar.markdown("[GitHub](https://github.com/deepak7376) | [LinkedIn](https://www.linkedin.com/in/dky7376/)")
69
+ st.sidebar.write("---")
70
+
71
+ # Initialize LLM
72
+ llm = initialize_llm(selected_model, temperature, top_p, max_tokens)
73
+ embeddings = initialize_embeddings()
74
+
75
+ # Document Handling
76
+ retriever = None
77
+ if uploaded_file:
78
  os.makedirs("docs", exist_ok=True)
79
  filepath = os.path.join("docs", uploaded_file.name)
80
 
81
+ with open(filepath, "wb") as f:
82
+ f.write(uploaded_file.read())
83
+
84
+ # Load and process PDF
85
+ splits = load_and_split_pdf(filepath)
86
+ vectorstore = create_vector_store(splits, embeddings)
87
+ retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 3})
88
+
89
+ # Apply custom CSS
90
+ st.markdown(CHAT_CSS, unsafe_allow_html=True)
91
+
92
+ # Initialize chat history
93
+ if "messages" not in st.session_state:
94
+ st.session_state.messages = []
95
+
96
+ # Display previous messages
97
+ for message in st.session_state.messages:
98
+ with st.chat_message(message["role"]):
99
+ st.markdown(message["content"])
100
+
101
+ # Chat Input
102
+ if user_input := st.chat_input("💬 Ask something..."):
103
+ st.session_state.messages.append({"role": "user", "content": user_input})
104
+
105
+ with st.chat_message("user"):
106
+ st.markdown(user_input)
107
+
108
+ # Measure response time
109
+ start_time = time.time()
110
+
111
+ # Generate response
112
+ context = retrive_vector_store(retriever, user_input) if retriever else "No context"
113
+ query = generate_prompt(context=context, question=user_input)
114
+ response = llm.invoke(query)
115
+
116
+ # Calculate response time
117
+ response_time = round(time.time() - start_time, 2)
118
+
119
+ # Extract thoughts and main answer
120
+ thinking_part, main_answer = extract_thoughts(response)
121
+
122
+ # Display AI response
123
+ with st.chat_message("assistant"):
124
+ if thinking_part:
125
+ with st.expander("💭 Thought Process"):
126
+ st.markdown(thinking_part)
127
 
128
+ # **Formatted Response Display**
129
+ formatted_response = f"""
130
+ {main_answer}
 
131
 
132
+ **Response Time:** {response_time} seconds
133
+ """
134
+ st.markdown(formatted_response, unsafe_allow_html=True)
135
 
136
+ # Save to session history
137
+ st.session_state.messages.append({"role": "assistant", "content": formatted_response})
components/__init__.py DELETED
File without changes
components/chat_ui.py DELETED
@@ -1,89 +0,0 @@
1
- import streamlit as st
2
- # from services.llm import process_answer
3
- import time
4
- import re
5
-
6
- # Custom CSS for chat styling
7
- CHAT_CSS = """
8
- <style>
9
- .user-message {
10
- text-align: right;
11
- background-color: #3c8ce7;
12
- color: white;
13
- padding: 10px;
14
- border-radius: 10px;
15
- margin-bottom: 10px;
16
- display: inline-block;
17
- width: fit-content;
18
- max-width: 70%;
19
- margin-left: auto;
20
- box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
21
- }
22
- .assistant-message {
23
- text-align: left;
24
- background-color: #d16ba5;
25
- color: white;
26
- padding: 10px;
27
- border-radius: 10px;
28
- margin-bottom: 10px;
29
- display: inline-block;
30
- width: fit-content;
31
- max-width: 70%;
32
- margin-right: auto;
33
- box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
34
- }
35
- </style>
36
- """
37
- def extract_thoughts(response_text):
38
- """Extracts <think>...</think> content and the main answer."""
39
- match = re.search(r"<think>(.*?)</think>", response_text, re.DOTALL)
40
- if match:
41
- thinking_part = match.group(1).strip()
42
- main_answer = re.sub(r"<think>.*?</think>", "", response_text, flags=re.DOTALL).strip()
43
- else:
44
- thinking_part = None
45
- main_answer = response_text.strip()
46
-
47
- return thinking_part, main_answer
48
-
49
- # Streamed response emulator
50
- def response_generator(response):
51
- for word in response.split():
52
- yield word + " "
53
- time.sleep(0.05)
54
-
55
- def display_chat(qa_chain, mode):
56
- st.markdown(CHAT_CSS, unsafe_allow_html=True)
57
-
58
- if "messages" not in st.session_state:
59
- st.session_state.messages = []
60
-
61
- for message in st.session_state.messages:
62
- with st.chat_message(message["role"]):
63
- st.markdown(message["content"])
64
-
65
- if prompt := st.chat_input("Ask something..."):
66
- st.session_state.messages.append({"role": "user", "content": prompt})
67
- with st.chat_message("user"):
68
- st.markdown(prompt)
69
-
70
- # Get chat response
71
- response = qa_chain.invoke({"input": prompt}) if mode else qa_chain.invoke({'context': prompt})
72
- if not response: # Handle empty responses
73
- response = {'answer': "I don't know."}
74
-
75
- if mode is False:
76
- response = {'answer': response}
77
-
78
- # Extract <think> part and main answer
79
- thinking_part, main_answer = extract_thoughts(response['answer'])
80
-
81
- # Display assistant response
82
- with st.chat_message("assistant"):
83
- if thinking_part:
84
- with st.expander("💭 Thought Process"):
85
- st.markdown(thinking_part) # Hidden by default, expandable
86
-
87
- response = st.write_stream(response_generator(main_answer))
88
-
89
- st.session_state.messages.append({"role": "assistant", "content": response})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/sidebar.py DELETED
@@ -1,35 +0,0 @@
1
- import streamlit as st
2
-
3
- def render_sidebar():
4
- st.sidebar.title("DocChatAI")
5
- st.sidebar.subheader("Chat using PDF Document")
6
- st.sidebar.write("-----------")
7
-
8
- # Model Selection
9
- model_options = ["deepseek-r1:1.5b"]
10
- selected_model = st.sidebar.radio("Choose Model", model_options)
11
-
12
- st.sidebar.write("-----------")
13
-
14
- # Hyperparameters
15
- temperature = st.sidebar.slider("Temperature", min_value=0.0, max_value=1.0, value=0.7, step=0.1)
16
- top_p = st.sidebar.slider("Top-p (Nucleus Sampling)", min_value=0.0, max_value=1.0, value=0.9, step=0.05)
17
- max_tokens = st.sidebar.number_input("Max Tokens", min_value=10, max_value=2048, value=256, step=10)
18
-
19
- st.sidebar.write("-----------")
20
-
21
- # File Upload
22
- uploaded_file = st.sidebar.file_uploader("Upload Documents", type=["pdf"])
23
-
24
- st.sidebar.write("-----------")
25
-
26
- # About Section
27
- st.sidebar.write("About Me")
28
- st.sidebar.write("Name: Deepak Yadav")
29
- st.sidebar.write("Bio: Passionate about AI and machine learning.")
30
- st.sidebar.write("[GitHub](https://github.com/deepak7376)")
31
- st.sidebar.write("[LinkedIn](https://www.linkedin.com/in/dky7376/)")
32
-
33
- st.sidebar.write("-----------")
34
-
35
- return selected_model, temperature, top_p, max_tokens, uploaded_file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
services/llm.py CHANGED
@@ -1,25 +1,10 @@
1
- import ollama
2
- from langchain.chains import RetrievalQA
3
- from langchain.chains import create_retrieval_chain
4
  from langchain_ollama import OllamaLLM
5
- from services.pdf_processing import load_and_split_pdf
6
- from services.vector_store import create_vector_store
7
- from langchain.chains.combine_documents import create_stuff_documents_chain
8
- from langchain_core.prompts import ChatPromptTemplate
9
- from langchain.prompts import PromptTemplate
10
  import streamlit as st
11
 
12
- PROMPT_TEMPLATE = """Question: {context}
13
-
14
- Answer: Let's think step by step."""
15
 
16
  @st.cache_resource
17
- def initialize_qa_chain(filepath, model_name, temperature, top_p, max_tokens):
18
- # Load and split the PDF
19
- splits = load_and_split_pdf(filepath)
20
- vectordb = create_vector_store(splits)
21
-
22
- # Use Ollama or Hugging Face LLM
23
  # Configure the LLM with additional parameters
24
  llm = OllamaLLM(
25
  model=model_name,
@@ -28,61 +13,9 @@ def initialize_qa_chain(filepath, model_name, temperature, top_p, max_tokens):
28
  max_tokens=max_tokens, # Limit the number of tokens in the output
29
  top_p=top_p # Nucleus sampling for controlling diversity
30
  )
31
-
32
-
33
- # # Define strict retrieval-based prompting
34
- # prompt_template = PromptTemplate(
35
- # template=(
36
- # "You are an AI assistant that only answers questions based on the provided document. "
37
- # "Do not use external knowledge. If you cannot find an answer in the document, respond with: 'I don't know.'\n\n"
38
- # "Document Context:\n{context}\n\n"
39
- # "User Question: {query}\n\n"
40
- # "Assistant Answer:"
41
- # ),
42
- # input_variables=["context", "query"]
43
- # )
44
-
45
- system_prompt = (
46
- "Use the given context to answer the question. "
47
- "If you don't know the answer, say you don't know. "
48
- "Use three sentence maximum and keep the answer concise. "
49
- "Context: {context}"
50
- )
51
- prompt = ChatPromptTemplate.from_messages(
52
- [
53
- ("system", system_prompt),
54
- ("human", "{input}"),
55
- ]
56
- )
57
- question_answer_chain = create_stuff_documents_chain(llm, prompt)
58
- chain = create_retrieval_chain(vectordb.as_retriever(), question_answer_chain)
59
-
60
- # return RetrievalQA.from_chain_type(
61
- # llm=llm,
62
- # chain_type="stuff",
63
- # retriever=vectordb.as_retriever(),
64
- # chain_type_kwargs={"prompt": prompt_template}
65
- # )
66
- return chain
67
 
68
  @st.cache_resource
69
- def initialize_chain(model_name, temperature, top_p, max_tokens):
70
- # Use Ollama or Hugging Face LLM
71
- # Configure the LLM with additional parameters
72
- llm = OllamaLLM(
73
- model=model_name,
74
- base_url="https://deepak7376-ollama-server.hf.space",
75
- temperature=temperature, # Controls randomness (0 = deterministic, 1 = max randomness)
76
- max_tokens=max_tokens, # Limit the number of tokens in the output
77
- top_p=top_p # Nucleus sampling for controlling diversity
78
- )
79
-
80
-
81
-
82
- prompt = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
83
-
84
- chain = prompt | llm
85
-
86
- return chain
87
-
88
-
 
 
 
 
1
  from langchain_ollama import OllamaLLM
2
+ from langchain_huggingface import HuggingFaceEmbeddings
 
 
 
 
3
  import streamlit as st
4
 
 
 
 
5
 
6
  @st.cache_resource
7
+ def initialize_llm(model_name, temperature, top_p, max_tokens):
 
 
 
 
 
8
  # Configure the LLM with additional parameters
9
  llm = OllamaLLM(
10
  model=model_name,
 
13
  max_tokens=max_tokens, # Limit the number of tokens in the output
14
  top_p=top_p # Nucleus sampling for controlling diversity
15
  )
16
+ return llm
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  @st.cache_resource
19
+ def initialize_embeddings():
20
+ embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
21
+ return embeddings
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
services/pdf_processing.py CHANGED
@@ -4,5 +4,6 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
4
  def load_and_split_pdf(filepath):
5
  loader = PyMuPDFLoader(filepath) # Use PyMuPDFLoader instead
6
  documents = loader.load()
7
- text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
8
- return text_splitter.split_documents(documents)
 
 
4
  def load_and_split_pdf(filepath):
5
  loader = PyMuPDFLoader(filepath) # Use PyMuPDFLoader instead
6
  documents = loader.load()
7
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
8
+ splits = text_splitter.split_documents(documents)
9
+ return splits
services/vector_store.py CHANGED
@@ -1,10 +1,25 @@
1
  from langchain_community.vectorstores import FAISS
2
- # from langchain_community.embeddings import SentenceTransformerEmbeddings
3
- # from langchain_community.embeddings.ollama import OllamaEmbeddings
4
- from langchain_huggingface import HuggingFaceEmbeddings
5
-
6
- def create_vector_store(splits):
7
- # embeddings = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2")
8
- embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
9
- # embeddings = OllamaEmbeddings(model="nomic-embed-text")
10
- return FAISS.from_documents(splits, embeddings)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from langchain_community.vectorstores import FAISS
2
+
3
+ def format_docs(docs):
4
+ return "\n\n".join(doc.page_content for doc in docs)
5
+
6
+ def create_vector_store(splits, embeddings):
7
+ vectorstore = FAISS.from_documents(splits, embeddings)
8
+ return vectorstore
9
+
10
+ def retrive_vector_store(retriever, query):
11
+ retrieved_docs = retriever.invoke(query)
12
+ return format_docs(retrieved_docs)
13
+
14
+ def generate_prompt(context="", question=""):
15
+ return f""""You are DocChatAI, a helpful AI assistant built by Deepak7376.
16
+ If the user provides context, use it to answer the question.
17
+ If no context is provided, rely on general knowledge.
18
+ If you don't know the answer, say you don't know.
19
+ Keep the answer concise.\n\n
20
+ "Context: <start_context> {context} </end_context>"
21
+
22
+ Human: {question}
23
+
24
+ Assistance: Let's think step by step.
25
+ """
utils/helpers.py CHANGED
@@ -1,7 +1,27 @@
1
  import os
 
 
2
 
3
  def get_file_size(file):
4
  file.seek(0, os.SEEK_END)
5
  size = file.tell()
6
  file.seek(0)
7
  return size
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
+ import re
3
+ import time
4
 
5
  def get_file_size(file):
6
  file.seek(0, os.SEEK_END)
7
  size = file.tell()
8
  file.seek(0)
9
  return size
10
+
11
+ def extract_thoughts(response_text):
12
+ """Extracts <think>...</think> content and the main answer."""
13
+ match = re.search(r"<think>(.*?)</think>", response_text, re.DOTALL)
14
+ if match:
15
+ thinking_part = match.group(1).strip()
16
+ main_answer = re.sub(r"<think>.*?</think>", "", response_text, flags=re.DOTALL).strip()
17
+ else:
18
+ thinking_part = None
19
+ main_answer = response_text.strip()
20
+
21
+ return thinking_part, main_answer
22
+
23
+ # Streamed response emulator
24
+ def response_generator(response):
25
+ for word in response.split():
26
+ yield word + " "
27
+ time.sleep(0.05)