-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdata_processing.py
More file actions
287 lines (235 loc) · 9.24 KB
/
Copy pathdata_processing.py
File metadata and controls
287 lines (235 loc) · 9.24 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
import os
import re
import gspread
import time
from dotenv import load_dotenv
from serpapi import GoogleSearch
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from groq import Groq
import spacy
# Load environment variables from the .env file
load_dotenv()
# Constants
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
SERP_API_KEY = os.getenv("SERPAPI_KEY")
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
GOOGLE_SHEETS_CREDENTIALS_PATH = os.getenv("GOOGLE_SHEETS_CREDENTIALS_PATH")
# Load the pre-trained SpaCy model for NER
nlp = spacy.load("en_core_web_sm")
# Retry logic
MAX_RETRIES = 3
RETRY_DELAY = 2
def authenticate_google():
"""
Authenticate with Google API using OAuth2 and return credentials.
Returns:
google.oauth2.credentials.Credentials: Valid credentials object.
"""
credentials = None
if os.path.exists("token.json"):
credentials = Credentials.from_authorized_user_file("token.json", SCOPES)
if not credentials or not credentials.valid:
if credentials and credentials.expired and credentials.refresh_token:
credentials.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
GOOGLE_SHEETS_CREDENTIALS_PATH, SCOPES
)
credentials = flow.run_local_server(port=0)
# Save the token for future use
with open("token.json", "w") as token_file:
token_file.write(credentials.to_json())
return credentials
def connect_to_google_sheet(sheet_url):
"""
Connect to a Google Sheet using its URL.
Args:
sheet_url (str): The full Google Sheet URL.
Returns:
tuple: A connected Google Sheets service and the sheet ID.
"""
match = re.search(r"/d/([a-zA-Z0-9-_]+)", sheet_url)
if not match:
raise ValueError("Invalid Google Sheet URL. Could not extract spreadsheet ID.")
sheet_id = match.group(1)
try:
credentials = authenticate_google()
service = build("sheets", "v4", credentials=credentials)
return service, sheet_id
except Exception as e:
raise ValueError(f"Error connecting to Google Sheets: {e}")
def search_entity_info(entity):
"""
Perform a broad web search for the given entity and retrieve top 10 results.
Args:
entity (str): The entity to search for.
Returns:
list: A list of top search results, each containing title, URL, and snippet.
"""
search = GoogleSearch({
"q": entity, # Broad search for the entity
"api_key": SERP_API_KEY,
"num": 10, # Fetch top 10 results
"hl": "en", # Language
"gl": "us", # Target country
"filter": "1", # Exclude duplicate results
})
for attempt in range(MAX_RETRIES):
try:
results = search.get_dict()
# //print(f"Search results for {entity}: {results}")
if "organic_results" in results and results["organic_results"]:
return [
{
"title": result.get("title", "N/A"),
"url": result.get("link", "N/A"),
"snippet": result.get("snippet", "N/A"),
}
for result in results["organic_results"]
]
else:
return []
except Exception as e:
if attempt < MAX_RETRIES - 1:
time.sleep(RETRY_DELAY * (2 ** attempt))
else:
raise Exception(f"Error performing search: {e}")
return [] # Return an empty list if no results
def generate_query(entity, query_template):
"""
Generate a query by replacing placeholders in the query template with the entity.
Args:
entity (str): The entity being processed.
query_template (str): The user-defined query template.
Returns:
str: The generated query.
"""
return query_template.replace("{entity}", entity)
def extract_information_with_groq(entity, search_results, query_template, query_type):
"""
Use Groq to extract specific information based on user-defined query, search results, and query type.
Args:
entity (str): The entity being processed (e.g., a company or person name).
search_results (list): The web search results containing titles, URLs, and snippets.
query_template (str): The user-defined query template.
query_type (str): The query classification type (e.g., Age Extraction).
Returns:
str: Extracted information or "Data not found" if unsuccessful.
"""
client = Groq(api_key=GROQ_API_KEY)
# Generate query dynamically
query = query_template.replace("{entity}", entity)
# Aggregate search results into a context string
search_context = "\n\n".join(
f"Title: {result['title']}\nURL: {result['url']}\nSnippet: {result['snippet']}"
for result in search_results
)
# Refined prompt
prompt = f"""
Task: Extract the most relevant information for the following query based on the search results.
Query: "{query}"
Entity: {entity}
Query Type: {query_type}
Search Results:
{search_context}
Instructions:
- If you find the exact answer, provide it directly in one word.
- If relevant information is partially available, summarize the context.
- If no relevant information is available, return: "Data not found."
- Ensure the response is concise and accurate.
"""
for attempt in range(MAX_RETRIES):
try:
chat_completion = client.chat.completions.create(
messages=[{"role": "user", "content": prompt}],
model="llama3-8b-8192", # Example model for detailed extraction
)
return chat_completion.choices[0].message.content.strip()
except Exception as e:
if attempt < MAX_RETRIES - 1:
time.sleep(RETRY_DELAY * (2 ** attempt))
else:
raise Exception(f"Error calling Groq API: {e}")
def perform_ner(text):
"""
Perform Named Entity Recognition (NER) on the given text to extract entities like dates, people, etc.
Args:
text (str): The text to perform NER on.
Returns:
dict: Extracted entities as key-value pairs.
"""
doc = nlp(text)
entities = {}
for ent in doc.ents:
entities[ent.label_] = ent.text
return entities
def classify_query(query):
"""
Classify the query type based on its structure (e.g., extracting emails, addresses, etc.).
Args:
query (str): The query template.
Returns:
str: The classification of the query type (e.g., "email extraction").
"""
# Convert to lowercase to handle case insensitivity
query_lower = query.lower()
# Check for specific keywords to classify the query
if "net worth" in query_lower:
return "Net Worth"
elif "age" in query_lower or "born" in query_lower:
return "Age"
elif "career" in query_lower or "biography" in query_lower:
return "Biography"
elif "parents" in query_lower or "family" in query_lower:
return "Family Information"
elif "job" in query_lower or "career" in query_lower:
return "Career"
elif "education" in query_lower or "school" in query_lower:
return "Education"
elif "married" in query_lower or "spouse" in query_lower:
return "Personal Life"
elif "award" in query_lower or "achievement" in query_lower:
return "Awards & Achievements"
elif "history" in query_lower or "background" in query_lower:
return "Company Info"
elif "product" in query_lower or "service" in query_lower:
return "Product Info"
elif "news" in query_lower or "latest" in query_lower:
return "News"
elif "social media" in query_lower or "twitter" in query_lower or "instagram" in query_lower:
return "Social Media"
elif "charity" in query_lower or "philanthropy" in query_lower:
return "Philanthropy"
elif "property" in query_lower or "real estate" in query_lower:
return "Real Estate"
elif "health" in query_lower or "condition" in query_lower:
return "Health"
elif "event" in query_lower or "conference" in query_lower:
return "Events"
elif "fruit" in query_lower or "vegetable" in query_lower:
return "Fruit"
else:
return "Miscellaneous"
def preprocess_search_results(results):
"""
Preprocess the search results to clean and prepare them for extraction.
Args:
results (list): A list of search results, where each result is a dictionary with keys like 'title', 'snippet', etc.
Returns:
list: A list of cleaned search results.
"""
if not results or not isinstance(results, list):
return []
cleaned_results = []
for result in results:
if isinstance(result, dict):
cleaned_result = {
"title": result.get("title", "").strip(),
"url": result.get("url", "").strip(),
"snippet": result.get("snippet", "").strip(),
}
cleaned_results.append(cleaned_result)
return cleaned_results