rairo commited on
Commit
4657d5e
Β·
verified Β·
1 Parent(s): 535e1c8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -88
app.py CHANGED
@@ -2,7 +2,7 @@ import streamlit as st
2
  import pandas as pd
3
  import base64
4
  import json
5
- from scrapegraphai.graphs import SmartScraperGraph, SearchGraph
6
  import nest_asyncio
7
  import os
8
  import subprocess
@@ -25,73 +25,62 @@ graph_config = {
25
  "api_key": GOOGLE_API_KEY,
26
  "model": "google_genai/gemini-2.0-flash-thinking-exp",
27
  },
 
 
28
  }
29
 
30
-
31
- def get_data(url):
32
- smart_scraper_graph = SmartScraperGraph(
33
- prompt=(
34
- "List me all grants or funds with: "
35
- "- Grant name/title\n"
36
- "- Short summary (50-100 characters)\n"
37
- "- Funding organization\n"
38
- "- Grant value (numeric only)\n"
39
- "- Application deadline\n"
40
- "- Eligible countries\n"
41
- "- Sector/field\n"
42
- "- Eligibility criteria\n"
43
- "Return in JSON format."
44
- ),
45
- source=url,
46
  config=graph_config,
47
  )
48
- return smart_scraper_graph.run()
49
-
50
 
51
- def process_multiple_urls(urls):
52
  """
53
- Process multiple URLs with enhanced progress tracking and user feedback.
54
  """
55
  all_data = {"grants": []}
56
  progress_bar = st.progress(0)
57
  status_container = st.empty()
58
- total_urls = len(urls)
59
 
60
- for index, url in enumerate(urls):
61
  try:
62
- url = url.strip()
63
- if not url:
64
  continue
65
 
66
- progress = (index + 1) / total_urls
67
  progress_bar.progress(progress)
68
  status_container.markdown(
69
  f"""
70
- **Processing Grant Opportunities** πŸš€
71
- Scanning URL {index+1} of {total_urls}: `{url}`
72
- <br>
73
- <p style='font-size: 0.9em; color: #6699CC;'>Completed: {index}/{total_urls} | Remaining: {total_urls - index - 1}</p>
74
- """,
75
  unsafe_allow_html=True,
76
  )
77
 
78
- result = get_data(url)
 
79
  if result and "grants" in result:
80
  all_data["grants"].extend(result["grants"])
81
  except Exception as e:
82
- st.error(f"⚠️ Error processing URL: {url} - {str(e)}")
83
  continue
84
 
85
  progress_bar.empty()
86
  status_container.empty()
87
  return all_data
88
 
89
-
90
  def convert_to_csv(data):
91
  df = pd.DataFrame(data["grants"])
92
  return df.to_csv(index=False).encode("utf-8")
93
 
94
-
95
  def convert_to_excel(data):
96
  df = pd.DataFrame(data["grants"])
97
  buffer = io.BytesIO()
@@ -99,26 +88,24 @@ def convert_to_excel(data):
99
  df.to_excel(writer, sheet_name="Grants", index=False)
100
  return buffer.getvalue()
101
 
102
-
103
  def create_knowledge_base(data):
104
  # Store JSON representation of data in session state
105
  st.session_state.knowledge_base_json = json.dumps(data, indent=2)
106
 
107
-
108
  def chat_with_knowledge_base(query):
109
  if "knowledge_base_json" not in st.session_state:
110
  return "Knowledge base not initialized. Please load grant data first."
111
 
112
  context = st.session_state.knowledge_base_json
113
  prompt = f"""
114
- You are an AI assistant that helps users analyze grant opportunities.
115
- Here is the extracted grant data in JSON format:
116
-
117
- {context}
118
 
119
- User's question: {query}
120
- Answer the question based on the provided grant data.
121
- """
 
 
122
 
123
  llm = ChatGoogleGenerativeAI(
124
  model="gemini-2.0-flash-thinking-exp", google_api_key=GOOGLE_API_KEY, temperature=0
@@ -127,30 +114,25 @@ def chat_with_knowledge_base(query):
127
  response = llm.invoke(prompt)
128
  return response
129
 
130
-
131
  def get_shareable_link(file_data, file_name, file_type):
132
  b64 = base64.b64encode(file_data).decode()
133
  return f"data:{file_type};base64,{b64}"
134
 
135
-
136
  def main():
137
  st.set_page_config(page_title="Quantilytix Grant Finder", page_icon="πŸ’°", layout="wide")
138
  st.title("πŸ’° Quantilytix Grant Finder")
139
 
140
- # --- Introduction and Motivation ---
141
  st.markdown("""
142
- <div style="text-align: justify;">
143
- <p>
144
- Welcome to <b>Quantilytix Grant Finder</b>, an AI-powered platform designed to streamline the grant discovery process, especially for academics and researchers across the globe.
145
- </p>
146
-
147
- </div>
148
- """, unsafe_allow_html=True)
149
 
150
  st.sidebar.image("logoqb.jpeg", use_container_width=True)
151
  st.sidebar.header("Scrape & Configure")
152
 
153
- # Initialize session state
154
  if "scraped_data" not in st.session_state:
155
  st.session_state.scraped_data = None
156
  if "chat_history" not in st.session_state:
@@ -158,42 +140,39 @@ def main():
158
  if "chat_interface_active" not in st.session_state:
159
  st.session_state.chat_interface_active = False
160
 
161
- # URL Input in Sidebar
162
- url_input = st.sidebar.text_area(
163
- "Enter Grant URLs (one per line)",
164
  height=150,
165
- help="Input URLs from funding websites. Add each URL on a new line.",
166
- placeholder="e.g.,\nhttps://www.example-grants.org/opportunities\nhttps://another-funding-source.com/grants-list"
167
  )
168
 
169
- # Get Grants Button with Icon
170
  if st.sidebar.button("πŸ” Get Grant Opportunities"):
171
- if url_input:
172
- urls = [url.strip() for url in url_input.split("\n") if url.strip()]
173
- if urls:
174
  try:
175
- with st.spinner("Scraping in progress... Please wait patiently."):
176
- result = process_multiple_urls(urls)
177
  st.session_state.scraped_data = result
178
- st.success(f"βœ… Successfully scraped {len(result['grants'])} grant opportunities from {len(urls)} URLs!")
179
  except Exception as e:
180
- st.error(f"🚨 Scraping process encountered an error: {e}")
181
  else:
182
- st.warning("⚠️ Please enter valid URLs.")
183
  else:
184
- st.warning("⚠️ Please enter at least one URL to begin scraping.")
185
 
186
- # --- Main Panel for Data Display and Chat ---
187
  st.markdown("---")
188
 
189
  if st.session_state.scraped_data and st.session_state.scraped_data['grants']:
190
- st.header("πŸ“Š Scraped Grant Data")
191
 
192
- # Data Preview and Download Options in Main Panel
193
- with st.expander(f"πŸ“Š Preview Grant Data {len(st.session_state.scraped_data['grants'])} grants"):
194
  st.dataframe(st.session_state.scraped_data["grants"])
195
 
196
- col1, col2, col3 = st.columns([1, 1, 2]) # Adjust column widths for better layout
197
 
198
  with col1:
199
  selected_format = st.selectbox("Download As:", ("CSV", "Excel"), key="download_format_selector")
@@ -218,28 +197,28 @@ def main():
218
  email_body = urllib.parse.quote(f"Download the grant opportunities file here: {shareable_link}")
219
  email_url = f"mailto:?subject={email_subject}&body={email_body}"
220
 
221
- st.markdown("<div style='margin-top:10px;'>Share via:</div>", unsafe_allow_html=True) # Add some margin for better spacing
222
  st.markdown(f"πŸ“± [WhatsApp]({whatsapp_url}) | πŸ“§ [Email]({email_url})", unsafe_allow_html=True)
223
 
224
-
225
- # Knowledge Base and Chat Interface
226
  if st.button("🧠 Load as Knowledge Base & Chat"):
227
  with st.spinner("Loading data into knowledge base..."):
228
- st.session_state.qa_chain = create_knowledge_base(st.session_state.scraped_data)
229
  st.session_state.chat_interface_active = True
230
- st.session_state.chat_history = [] # Clear chat history on reload
231
  st.success("Knowledge base loaded! You can now chat with the Grants Bot.")
232
 
233
  if st.session_state.get("chat_interface_active"):
234
  st.markdown("---")
235
  st.header("πŸ’¬ Chat with Grants Bot")
236
- st.markdown("Ask questions about the scraped grants to get quick insights!")
237
 
238
  query = st.text_input("Your question:", key="chat_input")
239
  if query:
240
  with st.spinner("Generating response..."):
241
  response = chat_with_knowledge_base(query)
242
- st.session_state.chat_history.append({"query": query, "response": response["answer"]})
 
 
243
 
244
  if st.session_state.chat_history:
245
  st.subheader("Chat History")
@@ -247,17 +226,16 @@ def main():
247
  st.markdown(f"<div style='padding: 10px; border-radius: 5px; margin-bottom: 5px; background-color: #f0f2f6;'><strong>You:</strong> {chat['query']}</div>", unsafe_allow_html=True)
248
  st.markdown(f"<div style='padding: 10px; border-radius: 5px; margin-bottom: 10px; background-color: #e0e2e6;'><strong>Grants Bot:</strong> {chat['response']}</div>", unsafe_allow_html=True)
249
 
250
-
251
  else:
252
- st.info("⬅️ Enter URLs in the sidebar and click 'Get Grant Opportunities' to start scraping.")
253
 
254
  st.sidebar.markdown("---")
255
  st.sidebar.markdown(
256
  """
257
- <div style='text-align: center; font-size: 0.8em; color: grey;'>
258
- Powered by <a href="https://quantilytix.com" style='color: grey;'>Quantilytix</a> | &copy; 2025
259
- </div>
260
- """,
261
  unsafe_allow_html=True,
262
  )
263
 
 
2
  import pandas as pd
3
  import base64
4
  import json
5
+ from scrapegraphai.graphs import SearchGraph
6
  import nest_asyncio
7
  import os
8
  import subprocess
 
25
  "api_key": GOOGLE_API_KEY,
26
  "model": "google_genai/gemini-2.0-flash-thinking-exp",
27
  },
28
+ "max_results": 2,
29
+ "verbose": True,
30
  }
31
 
32
+ def get_data(search_term):
33
+ # Combine the user input with 'grants'
34
+ full_prompt = f"search for {search_term} grants\n\nList me all grants or funds with:\n- Grant name/title\n- Short summary (50-100 characters)\n- Funding organization\n- Grant value (numeric only)\n- Application deadline\n- Eligible countries\n- Sector/field\n- Eligibility criteria\nReturn in JSON format."
35
+ search_graph = SearchGraph(
36
+ prompt=full_prompt,
 
 
 
 
 
 
 
 
 
 
 
37
  config=graph_config,
38
  )
39
+ return search_graph.run()
 
40
 
41
+ def process_multiple_search_terms(search_terms):
42
  """
43
+ Process multiple search terms with enhanced progress tracking and user feedback.
44
  """
45
  all_data = {"grants": []}
46
  progress_bar = st.progress(0)
47
  status_container = st.empty()
48
+ total_terms = len(search_terms)
49
 
50
+ for index, term in enumerate(search_terms):
51
  try:
52
+ term = term.strip()
53
+ if not term:
54
  continue
55
 
56
+ progress = (index + 1) / total_terms
57
  progress_bar.progress(progress)
58
  status_container.markdown(
59
  f"""
60
+ **Processing Grant Opportunities** πŸš€
61
+ Searching term {index+1} of {total_terms}: `{term}`
62
+ <br>
63
+ <p style='font-size: 0.9em; color: #6699CC;'>Completed: {index}/{total_terms} | Remaining: {total_terms - index - 1}</p>
64
+ """,
65
  unsafe_allow_html=True,
66
  )
67
 
68
+ result = get_data(term)
69
+ # Expecting a JSON with a "grants" key
70
  if result and "grants" in result:
71
  all_data["grants"].extend(result["grants"])
72
  except Exception as e:
73
+ st.error(f"⚠️ Error processing search term: {term} - {str(e)}")
74
  continue
75
 
76
  progress_bar.empty()
77
  status_container.empty()
78
  return all_data
79
 
 
80
  def convert_to_csv(data):
81
  df = pd.DataFrame(data["grants"])
82
  return df.to_csv(index=False).encode("utf-8")
83
 
 
84
  def convert_to_excel(data):
85
  df = pd.DataFrame(data["grants"])
86
  buffer = io.BytesIO()
 
88
  df.to_excel(writer, sheet_name="Grants", index=False)
89
  return buffer.getvalue()
90
 
 
91
  def create_knowledge_base(data):
92
  # Store JSON representation of data in session state
93
  st.session_state.knowledge_base_json = json.dumps(data, indent=2)
94
 
 
95
  def chat_with_knowledge_base(query):
96
  if "knowledge_base_json" not in st.session_state:
97
  return "Knowledge base not initialized. Please load grant data first."
98
 
99
  context = st.session_state.knowledge_base_json
100
  prompt = f"""
101
+ You are an AI assistant that helps users analyze grant opportunities.
102
+ Here is the extracted grant data in JSON format:
 
 
103
 
104
+ {context}
105
+
106
+ User's question: {query}
107
+ Answer the question based on the provided grant data.
108
+ """
109
 
110
  llm = ChatGoogleGenerativeAI(
111
  model="gemini-2.0-flash-thinking-exp", google_api_key=GOOGLE_API_KEY, temperature=0
 
114
  response = llm.invoke(prompt)
115
  return response
116
 
 
117
  def get_shareable_link(file_data, file_name, file_type):
118
  b64 = base64.b64encode(file_data).decode()
119
  return f"data:{file_type};base64,{b64}"
120
 
 
121
  def main():
122
  st.set_page_config(page_title="Quantilytix Grant Finder", page_icon="πŸ’°", layout="wide")
123
  st.title("πŸ’° Quantilytix Grant Finder")
124
 
 
125
  st.markdown("""
126
+ <div style="text-align: justify;">
127
+ <p>
128
+ Welcome to <b>Quantilytix Grant Finder</b>, an AI-powered platform designed to streamline the grant discovery process, especially for academics and researchers across the globe.
129
+ </p>
130
+ </div>
131
+ """, unsafe_allow_html=True)
 
132
 
133
  st.sidebar.image("logoqb.jpeg", use_container_width=True)
134
  st.sidebar.header("Scrape & Configure")
135
 
 
136
  if "scraped_data" not in st.session_state:
137
  st.session_state.scraped_data = None
138
  if "chat_history" not in st.session_state:
 
140
  if "chat_interface_active" not in st.session_state:
141
  st.session_state.chat_interface_active = False
142
 
143
+ # Search Term Input in Sidebar
144
+ search_input = st.sidebar.text_area(
145
+ "Enter Search Terms (one per line)",
146
  height=150,
147
+ help="Input search terms to discover grant opportunities. Each term will be combined with 'grants' for the search.",
148
+ placeholder="e.g.,\neducation\nresearch\ntechnology"
149
  )
150
 
 
151
  if st.sidebar.button("πŸ” Get Grant Opportunities"):
152
+ if search_input:
153
+ search_terms = [term.strip() for term in search_input.split("\n") if term.strip()]
154
+ if search_terms:
155
  try:
156
+ with st.spinner("Searching in progress... Please wait patiently."):
157
+ result = process_multiple_search_terms(search_terms)
158
  st.session_state.scraped_data = result
159
+ st.success(f"βœ… Successfully found {len(result['grants'])} grant opportunities from {len(search_terms)} search terms!")
160
  except Exception as e:
161
+ st.error(f"🚨 Searching process encountered an error: {e}")
162
  else:
163
+ st.warning("⚠️ Please enter valid search terms.")
164
  else:
165
+ st.warning("⚠️ Please enter at least one search term to begin.")
166
 
 
167
  st.markdown("---")
168
 
169
  if st.session_state.scraped_data and st.session_state.scraped_data['grants']:
170
+ st.header("πŸ“Š Found Grant Data")
171
 
172
+ with st.expander(f"πŸ“Š Preview Grant Data ({len(st.session_state.scraped_data['grants'])} grants)"):
 
173
  st.dataframe(st.session_state.scraped_data["grants"])
174
 
175
+ col1, col2, col3 = st.columns([1, 1, 2])
176
 
177
  with col1:
178
  selected_format = st.selectbox("Download As:", ("CSV", "Excel"), key="download_format_selector")
 
197
  email_body = urllib.parse.quote(f"Download the grant opportunities file here: {shareable_link}")
198
  email_url = f"mailto:?subject={email_subject}&body={email_body}"
199
 
200
+ st.markdown("<div style='margin-top:10px;'>Share via:</div>", unsafe_allow_html=True)
201
  st.markdown(f"πŸ“± [WhatsApp]({whatsapp_url}) | πŸ“§ [Email]({email_url})", unsafe_allow_html=True)
202
 
 
 
203
  if st.button("🧠 Load as Knowledge Base & Chat"):
204
  with st.spinner("Loading data into knowledge base..."):
205
+ create_knowledge_base(st.session_state.scraped_data)
206
  st.session_state.chat_interface_active = True
207
+ st.session_state.chat_history = []
208
  st.success("Knowledge base loaded! You can now chat with the Grants Bot.")
209
 
210
  if st.session_state.get("chat_interface_active"):
211
  st.markdown("---")
212
  st.header("πŸ’¬ Chat with Grants Bot")
213
+ st.markdown("Ask questions about the found grants to get quick insights!")
214
 
215
  query = st.text_input("Your question:", key="chat_input")
216
  if query:
217
  with st.spinner("Generating response..."):
218
  response = chat_with_knowledge_base(query)
219
+ # Assume response returns a dictionary with key 'answer'
220
+ answer = response["answer"] if isinstance(response, dict) and "answer" in response else response
221
+ st.session_state.chat_history.append({"query": query, "response": answer})
222
 
223
  if st.session_state.chat_history:
224
  st.subheader("Chat History")
 
226
  st.markdown(f"<div style='padding: 10px; border-radius: 5px; margin-bottom: 5px; background-color: #f0f2f6;'><strong>You:</strong> {chat['query']}</div>", unsafe_allow_html=True)
227
  st.markdown(f"<div style='padding: 10px; border-radius: 5px; margin-bottom: 10px; background-color: #e0e2e6;'><strong>Grants Bot:</strong> {chat['response']}</div>", unsafe_allow_html=True)
228
 
 
229
  else:
230
+ st.info("⬅️ Enter search terms in the sidebar and click 'Get Grant Opportunities' to start searching.")
231
 
232
  st.sidebar.markdown("---")
233
  st.sidebar.markdown(
234
  """
235
+ <div style='text-align: center; font-size: 0.8em; color: grey;'>
236
+ Powered by <a href="https://quantilytix.com" style='color: grey;'>Quantilytix</a> | &copy; 2025
237
+ </div>
238
+ """,
239
  unsafe_allow_html=True,
240
  )
241