mtechaisouvik commited on
Commit
e1e283c
Β·
verified Β·
1 Parent(s): 5a915fd

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +191 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,193 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
1
+ import os
 
 
2
  import streamlit as st
3
+ import pickle
4
+ import time
5
+ import requests
6
+ from bs4 import BeautifulSoup
7
+ from langchain.llms import HuggingFacePipeline
8
+ from langchain.chains import RetrievalQAWithSourcesChain
9
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
10
+ from langchain.embeddings import HuggingFaceEmbeddings
11
+ from langchain.vectorstores import FAISS
12
+ from langchain.docstore.document import Document
13
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, pipeline
14
+
15
+ from dotenv import load_dotenv
16
+ load_dotenv()
17
+
18
+ st.title("Research Summarizer and Question Answering Tool πŸ“ˆ")
19
+ st.sidebar.title("Article URLs")
20
+
21
+ # Add option to choose input method
22
+ input_method = st.sidebar.radio("Input Method:", ["URLs", "Paste Text"])
23
+
24
+ # Initialize Hugging Face models
25
+ @st.cache_resource
26
+ def initialize_hf_models():
27
+ # Initialize tokenizer and model for text generation (using FLAN-T5 which is free and good for Q&A)
28
+ tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-base")
29
+ model = AutoModelForSeq2SeqLM.from_pretrained("google/flan-t5-base")
30
+
31
+ # Create pipeline
32
+ pipe = pipeline(
33
+ "text2text-generation",
34
+ model=model,
35
+ tokenizer=tokenizer,
36
+ max_length=500,
37
+ temperature=0.9,
38
+ )
39
+
40
+ # Create LangChain wrapper
41
+ llm = HuggingFacePipeline(pipeline=pipe)
42
+ return llm
43
+
44
+ llm = initialize_hf_models()
45
+
46
+ # Input fields based on selected method
47
+ if input_method == "URLs":
48
+ urls = []
49
+ for i in range(3):
50
+ url = st.sidebar.text_input(f"URL {i+1}")
51
+ urls.append(url)
52
+ process_button_label = "Process URLs"
53
+ else: # Paste Text
54
+ st.sidebar.info("πŸ’‘ Paste article text below (useful when websites block scraping)")
55
+ pasted_texts = []
56
+ for i in range(3):
57
+ text = st.sidebar.text_area(f"Article {i+1} Text:", height=100, key=f"text_{i}")
58
+ if text.strip():
59
+ pasted_texts.append(text)
60
+ process_button_label = "Process Texts"
61
+
62
+ process_url_clicked = st.sidebar.button(process_button_label)
63
+ file_path = "faiss_store_hf.pkl"
64
+
65
+ main_placeholder = st.empty()
66
+
67
+ def extract_text_from_url(url):
68
+ try:
69
+ # Enhanced headers to mimic a real browser more closely
70
+ headers = {
71
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
72
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
73
+ 'Accept-Language': 'en-US,en;q=0.5',
74
+ 'Accept-Encoding': 'gzip, deflate, br',
75
+ 'DNT': '1',
76
+ 'Connection': 'keep-alive',
77
+ 'Upgrade-Insecure-Requests': '1',
78
+ 'Sec-Fetch-Dest': 'document',
79
+ 'Sec-Fetch-Mode': 'navigate',
80
+ 'Sec-Fetch-Site': 'none',
81
+ 'Cache-Control': 'max-age=0',
82
+ }
83
+
84
+ # Add a delay to avoid rate limiting (increased for stricter sites)
85
+ time.sleep(2)
86
+
87
+ response = requests.get(url, headers=headers, timeout=15, allow_redirects=True)
88
+ response.raise_for_status()
89
+ soup = BeautifulSoup(response.text, 'html.parser')
90
+
91
+ # Remove unwanted elements
92
+ for tag in soup(['script', 'style', 'nav', 'header', 'footer', 'ads']):
93
+ tag.decompose()
94
+
95
+ # Extract text from paragraphs
96
+ paragraphs = soup.find_all('p')
97
+ text = ' '.join([p.get_text().strip() for p in paragraphs if p.get_text().strip()])
98
+
99
+ return text
100
+ except Exception as e:
101
+ st.error(f"Error processing {url}: {str(e)}")
102
+ return None
103
+
104
+ if process_url_clicked:
105
+ documents = []
106
+
107
+ if input_method == "URLs":
108
+ # Validate URLs
109
+ valid_urls = [url for url in urls if url.strip() != ""]
110
+ if not valid_urls:
111
+ st.error("Please enter at least one valid URL")
112
+ st.stop()
113
+
114
+ try:
115
+ # load data from URLs
116
+ main_placeholder.text("Data Loading...Started...βœ…βœ…βœ…")
117
+
118
+ for url in valid_urls:
119
+ text = extract_text_from_url(url)
120
+ if text:
121
+ doc = Document(page_content=text, metadata={"source": url})
122
+ documents.append(doc)
123
+
124
+ if not documents:
125
+ st.error("Could not fetch content from any of the URLs. Please check if the URLs are accessible.")
126
+ st.info("πŸ’‘ TIP: If websites are blocking access, try using 'Paste Text' method instead!")
127
+ st.stop()
128
+ except Exception as e:
129
+ st.error(f"An error occurred: {str(e)}")
130
+ st.stop()
131
+
132
+ else: # Paste Text method
133
+ if not pasted_texts:
134
+ st.error("Please paste at least one article text")
135
+ st.stop()
136
+
137
+ try:
138
+ # load data from pasted text
139
+ main_placeholder.text("Processing Pasted Text...Started...βœ…βœ…βœ…")
140
+
141
+ for idx, text in enumerate(pasted_texts):
142
+ doc = Document(page_content=text, metadata={"source": f"Pasted Article {idx+1}"})
143
+ documents.append(doc)
144
+
145
+ except Exception as e:
146
+ st.error(f"An error occurred: {str(e)}")
147
+ st.stop()
148
+
149
+ # Continue with text splitting (same for both methods)
150
+ if documents:
151
+ # split data
152
+ text_splitter = RecursiveCharacterTextSplitter(
153
+ separators=['\n\n', '\n', '.', ','],
154
+ chunk_size=1000
155
+ )
156
+ main_placeholder.text("Text Splitter...Started...βœ…βœ…βœ…")
157
+ docs = text_splitter.split_documents(documents)
158
+
159
+ if not docs:
160
+ st.error("No text content could be extracted.")
161
+ st.stop()
162
+
163
+ # create embeddings and save it to FAISS index
164
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
165
+ vectorstore = FAISS.from_documents(docs, embeddings)
166
+ main_placeholder.text("Embedding Vector Started Building...βœ…βœ…βœ…")
167
+ time.sleep(2)
168
+
169
+ # Save the FAISS index to a pickle file
170
+ with open(file_path, "wb") as f:
171
+ pickle.dump(vectorstore, f)
172
+
173
+ query = main_placeholder.text_input("Question: ")
174
+ if query:
175
+ if os.path.exists(file_path):
176
+ with open(file_path, "rb") as f:
177
+ vectorstore = pickle.load(f)
178
+ chain = RetrievalQAWithSourcesChain.from_llm(llm=llm, retriever=vectorstore.as_retriever())
179
+ result = chain({"question": query}, return_only_outputs=True)
180
+ # result will be a dictionary of this format --> {"answer": "", "sources": [] }
181
+ st.header("Answer")
182
+ st.write(result["answer"])
183
+
184
+ # Display sources, if available
185
+ sources = result.get("sources", "")
186
+ if sources:
187
+ st.subheader("Sources:")
188
+ sources_list = sources.split("\n") # Split the sources by newline
189
+ for source in sources_list:
190
+ st.write(source)
191
+
192
+
193