-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhelpers.py
More file actions
127 lines (120 loc) · 3.9 KB
/
Copy pathhelpers.py
File metadata and controls
127 lines (120 loc) · 3.9 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
import re
import json
import time
import uuid
import math
import boto3
import certifi
import requests
from dateutil import parser
from datetime import datetime
from pymongo import MongoClient
from config import (
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
AWS_REGION,
MONGO_URI,
DB_NAME,
DB_NAME_PAST,
TENDERS_COLLECTION,
EMBEDDINGS_COLLECTION,
DOCS_STATUS_COLLECTION,
VECTOR_COLLECTION,
RESULTS_COLLECTION,
COMPETITORS_COLLECTION,
PROFILES_COLLECTION,
SCORE_COLLECTION,
NOTIFICATIONS_COLLECTION,
DEEPSEEK_API_URL,
DEEPSEEK_API_KEY,
OLA_API_KEY,
OLA_MAPS_BASE_URL
)
s3 = boto3.client(
"s3",
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
region_name=AWS_REGION,
)
client = MongoClient(MONGO_URI, tlsCAFile=certifi.where())
db = client[DB_NAME]
db_past = client[DB_NAME_PAST]
collection = db[TENDERS_COLLECTION]
embedding_collection = db[EMBEDDINGS_COLLECTION]
status_collection = db[DOCS_STATUS_COLLECTION]
vector_collection = db[VECTOR_COLLECTION]
result_collection = db_past[RESULTS_COLLECTION]
competitor_collection = db_past[COMPETITORS_COLLECTION]
profile_collection = db[PROFILES_COLLECTION]
score_collection = db[SCORE_COLLECTION]
notification_collection = db[NOTIFICATIONS_COLLECTION]
def parse_date_naive(date_str):
if not date_str or str(date_str).strip() == "":
return None
try:
dt = datetime.strptime(date_str, "%d-%b-%Y %I:%M %p")
return dt
except:
try:
dt = parser.parse(date_str)
return dt.replace(tzinfo=None)
except:
return None
def query_deepseek(prompt, MODEL_NAME="deepseek-chat", retries=2, backoff=2):
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {DEEPSEEK_API_KEY}"}
payload = {
"model": MODEL_NAME,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.3
}
for attempt in range(1, retries + 1):
try:
response = requests.post(DEEPSEEK_API_URL, headers=headers, json=payload, timeout=30)
if response.status_code == 200:
data = response.json()
choices = data.get("choices", [])
if choices:
content = choices[0].get("message", {}).get("content", "").strip()
if content:
return content
return '{"city": "unknown"}'
elif response.status_code >= 500 or response.status_code == 429:
time.sleep(backoff * attempt)
continue
else:
return 'api_error'
except requests.exceptions.RequestException:
time.sleep(backoff * attempt)
return 'api_error'
def geocode_address(address):
headers = {
"X-Request-Id": str(uuid.uuid4()),
"X-Correlation-Id": str(uuid.uuid4())
}
params = {
"address": address,
"language": "English",
"api_key": OLA_API_KEY
}
try:
response = requests.get(OLA_MAPS_BASE_URL, headers=headers, params=params, timeout=15)
data = response.json()
results = data.get("geocodingResults", [])
if results:
loc = results[0].get("geometry", {}).get("location", {})
lat, lng = loc.get("lat"), loc.get("lng")
if lat is not None and lng is not None:
return [lat, lng]
except Exception as e:
print(f"❌ Error geocoding {address}: {e}")
return []
def haversine(coord1, coord2):
if not coord1 or not coord2:
return float("inf")
lat1, lon1 = coord1
lat2, lon2 = coord2
R = 6371.0
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = math.sin(dlat / 2) ** 2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2) ** 2
return R * (2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)))