Subham9126 commited on
Commit
0233b81
·
verified ·
1 Parent(s): 63e27e1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +267 -92
app.py CHANGED
@@ -1,108 +1,283 @@
1
  import gradio as gr
2
- import pandas as pd
3
- import chromadb
4
- from chromadb.config import Settings
5
- from chromadb.utils import embedding_functions
 
 
 
 
 
 
6
 
7
- # Constants
8
- CSV_PATH = "ime-cdata - Sheet1.csv" # Replace with your actual CSV file path
9
- COLLECTION_NAME = "query_embeddings"
10
- EMBEDDING_MODEL = 'all-MiniLM-L6-v2'
11
 
12
- # Initialize embedding function
13
- embedding_function = embedding_functions.SentenceTransformerEmbeddingFunction(model_name=EMBEDDING_MODEL)
 
14
 
15
- # Initialize Chroma client
16
- chroma_client = chromadb.Client(Settings(persist_directory="./chroma_db"))
 
 
17
 
18
- def load_and_embed_data():
19
- # Load CSV
20
- df = pd.read_csv(CSV_PATH)
21
-
22
- # Create or get collection
23
- collection = chroma_client.get_or_create_collection(name=COLLECTION_NAME, embedding_function=embedding_function)
24
-
25
- # Check if collection is empty
26
- if collection.count() == 0:
27
- print("Embedding and storing data. This may take a while...")
28
- # Embed and store only the query column
29
- collection.add(
30
- documents=df['query'].tolist(),
31
- metadatas=df.to_dict('records'),
32
- ids=[str(i) for i in range(len(df))]
 
 
 
 
33
  )
34
- print("Data embedded and stored.")
35
- else:
36
- print("Data already embedded and stored.")
37
-
38
- return collection
39
 
40
- def search_similar_queries(query, collection, top_k=5):
41
  try:
42
- results = collection.query(
43
- query_texts=[query],
44
- n_results=top_k,
45
- include=["metadatas", "distances"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  )
47
-
48
- formatted_results = []
49
- for i in range(len(results['ids'][0])):
50
- metadata = results['metadatas'][0][i]
51
- result = {
52
- 'query': metadata.get('query', 'N/A'),
53
- 'similarity': 1 - results['distances'][0][i], # Convert distance to similarity
54
- 'uber_intent': metadata.get('uber_intent', 'N/A'),
55
- 'common_intent': metadata.get('common_intent', 'N/A'),
56
- 'sub_common_intent': metadata.get('sub_common_intent', 'N/A'),
57
- 'fsc': metadata.get('fsc', 'N/A'),
58
- 'language': metadata.get('language', 'N/A'),
59
- 'Name': metadata.get('Name', 'N/A')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
- formatted_results.append(result)
62
-
63
- return formatted_results
64
- except Exception as e:
65
- print(f"Error in search_similar_queries: {str(e)}")
66
- return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- def gradio_interface(query, top_k):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  try:
70
- results = search_similar_queries(query, collection, top_k)
 
 
 
 
 
 
 
71
 
72
- if not results:
73
- return "No results found or an error occurred."
74
 
75
- output = ""
76
- for i, result in enumerate(results, 1):
77
- output += f"Result {i}:\n"
78
- output += f"Query: {result['query']}\n"
79
- output += f"Similarity: {result['similarity']:.4f}\n"
80
- output += f"Uber Intent: {result['uber_intent']}\n"
81
- output += f"Common Intent: {result['common_intent']}\n"
82
- output += f"Sub-Common Intent: {result['sub_common_intent']}\n"
83
- output += f"FSC: {result['fsc']}\n"
84
- output += f"Language: {result['language']}\n"
85
- output += f"Name: {result['Name']}\n\n"
86
 
87
- return output
88
  except Exception as e:
89
- print(f"Error in gradio_interface: {str(e)}")
90
- return f"An error occurred: {str(e)}"
91
-
92
- # Load and embed data
93
- collection = load_and_embed_data()
94
-
95
- # Create Gradio interface
96
- iface = gr.Interface(
97
- fn=gradio_interface,
98
- inputs=[
99
- gr.Textbox(label="Enter your query"),
100
- gr.Slider(minimum=1, maximum=10, step=1, label="Top-K results", value=5)
101
- ],
102
- outputs=gr.Textbox(label="Results"),
103
- title="Query Similarity Search",
104
- description="Enter a query to find similar queries with associated metadata."
105
- )
106
-
107
- # Launch the interface
108
- iface.launch()
 
 
 
 
1
  import gradio as gr
2
+ import re
3
+ import asyncio
4
+ import aiohttp
5
+ from datetime import datetime, time
6
+ from typing import Dict, Optional, List
7
+ import pytz
8
+ import tzlocal
9
+ import logging
10
+ import json
11
+ from datetime import date
12
 
13
+ # --- Basic Setup ---
 
 
 
14
 
15
+ # 1. Logger Configuration
16
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
+ logger = logging.getLogger(__name__)
18
 
19
+ # 2. Custom Exception
20
+ class DateTimeValidationError(ValueError):
21
+ """Custom exception for datetime validation errors."""
22
+ pass
23
 
24
+ # 3. Assume hist_url is globally defined
25
+ hist_url = "https://groww.in/v1/api/charting_service/v2/chart/exchange/NSE/segment/CASH"
26
+
27
+
28
+ # --- Date/Time Functions ---
29
+
30
+ def validate_datetime_format(dt_str: str) -> datetime:
31
+ """
32
+ Validate datetime string in strict 'YYYY-MM-DD' format.
33
+ """
34
+ if not isinstance(dt_str, str):
35
+ logger.error(f"Expected string input, got {type(dt_str).__name__}")
36
+ raise TypeError(f"Input must be a string, got {type(dt_str).__name__}")
37
+
38
+ date_pattern = re.compile(r'^\d{4}-\d{2}-\d{2}$')
39
+ if not date_pattern.match(dt_str):
40
+ logger.error(f"Invalid date format: '{dt_str}'. Expected 'YYYY-MM-DD'")
41
+ raise DateTimeValidationError(
42
+ f"Invalid date format: '{dt_str}'. Expected 'YYYY-MM-DD'"
43
  )
 
 
 
 
 
44
 
 
45
  try:
46
+ parsed_date = datetime.strptime(dt_str, '%Y-%m-%d')
47
+ logger.debug(f"Successfully validated date: {dt_str}")
48
+ return parsed_date
49
+ except ValueError as e:
50
+ logger.error(f"Invalid date value: '{dt_str}' - {str(e)}")
51
+ raise DateTimeValidationError(
52
+ f"Invalid date value: '{dt_str}'. Please provide a valid calendar date."
53
+ ) from e
54
+
55
+ def _resolve_timezone(timezone: Optional[str]) -> pytz.BaseTzInfo:
56
+ """Resolve timezone string to pytz timezone object."""
57
+ if timezone:
58
+ try:
59
+ return pytz.timezone(timezone)
60
+ except pytz.UnknownTimeZoneError as e:
61
+ logger.error(f"Unknown timezone: '{timezone}'")
62
+ raise ValueError(f"Unknown timezone: '{timezone}'") from e
63
+ else:
64
+ local_tz = tzlocal.get_localzone()
65
+ logger.debug(f"Using local timezone: {local_tz}")
66
+ return local_tz
67
+
68
+ def convert_to_unixtimestamp(
69
+ date_time_str: str,
70
+ timezone: Optional[str] = None
71
+ ) -> int:
72
+ """
73
+ Convert datetime string to Unix timestamp in milliseconds with timezone handling.
74
+ """
75
+ if not isinstance(date_time_str, str):
76
+ logger.error(f"Expected string input, got {type(date_time_str).__name__}")
77
+ raise TypeError(
78
+ f"DateTime input must be a string in 'YYYY-MM-DD HH:MM' format, "
79
+ f"got {type(date_time_str).__name__}"
80
  )
81
+
82
+ try:
83
+ dt = datetime.strptime(date_time_str, '%Y-%m-%d %H:%M')
84
+ logger.debug(f"Successfully parsed datetime: {date_time_str}")
85
+ except ValueError as e:
86
+ logger.error(f"Invalid datetime format: '{date_time_str}'")
87
+ raise DateTimeValidationError(
88
+ f"Invalid datetime format: '{date_time_str}'. Expected 'YYYY-MM-DD HH:MM'"
89
+ ) from e
90
+
91
+ target_tz = _resolve_timezone(timezone)
92
+
93
+ if dt.tzinfo is None:
94
+ localized_dt = target_tz.localize(dt)
95
+ else:
96
+ localized_dt = dt.astimezone(target_tz)
97
+
98
+ timestamp_ms = int(localized_dt.timestamp() * 1000)
99
+ logger.debug(f"Converted '{date_time_str}' to timestamp: {timestamp_ms}")
100
+
101
+ return timestamp_ms
102
+
103
+ def get_time_range_in_unix_ms(
104
+ start_date_str: str,
105
+ end_date_str: str,
106
+ timezone: str = 'Asia/Kolkata'
107
+ ) -> Dict[str, int]:
108
+ """
109
+ Calculates the start and end Unix timestamps in milliseconds for a date range.
110
+ """
111
+ start_date = validate_datetime_format(start_date_str)
112
+ end_date = validate_datetime_format(end_date_str)
113
+
114
+ start_datetime = datetime.combine(start_date, time.min)
115
+ end_datetime = datetime.combine(end_date, time(23, 59))
116
+
117
+ start_datetime_str = start_datetime.strftime('%Y-%m-%d %H:%M')
118
+ end_datetime_str = end_datetime.strftime('%Y-%m-%d %H:%M')
119
+
120
+ start_timestamp = convert_to_unixtimestamp(start_datetime_str, timezone)
121
+ end_timestamp = convert_to_unixtimestamp(end_datetime_str, timezone)
122
+
123
+ return {
124
+ "start_timestamp_ms": start_timestamp,
125
+ "end_timestamp_ms": end_timestamp,
126
+ }
127
+
128
+
129
+ # --- Asynchronous API Function ---
130
+
131
+ async def call_price_api_async(
132
+ session: aiohttp.ClientSession,
133
+ ticker: str,
134
+ start: int,
135
+ end: int,
136
+ interval: int,
137
+ ) -> Dict:
138
+ """
139
+ Asynchronously calls the Groww candle API and returns the raw JSON response.
140
+ """
141
+ url = f"{hist_url}/{ticker}"
142
+ params = {
143
+ "startTimeInMillis": start,
144
+ "endTimeInMillis": end,
145
+ "intervalInMinutes": interval,
146
+ }
147
+
148
+ try:
149
+ async with session.get(url, params=params) as response:
150
+ response.raise_for_status()
151
+ json_data = await response.json()
152
+ return {
153
+ "ticker": ticker,
154
+ "interval": interval,
155
+ "data": json_data,
156
+ "error": None,
157
  }
158
+ except aiohttp.ClientError as e:
159
+ return {
160
+ "ticker": ticker,
161
+ "interval": interval,
162
+ "data": None,
163
+ "error": str(e),
164
+ }
165
+
166
+
167
+ # --- Main Processing Logic ---
168
+
169
+ async def main(tickers: List[str], start_time: int, end_time: int, intervals: List[int], progress: gr.Progress):
170
+ """
171
+ Main function to run the asynchronous API calls in batches.
172
+ """
173
+ results = []
174
+ batch_size = 30
175
+
176
+ async with aiohttp.ClientSession() as session:
177
+ for i in progress.tqdm(range(0, len(tickers), batch_size), desc="Processing Batches"):
178
+ batch_tickers = tickers[i:i+batch_size]
179
+ tasks = []
180
+ for ticker in batch_tickers:
181
+ for interval in intervals:
182
+ tasks.append(
183
+ call_price_api_async(session, ticker, start_time, end_time, interval)
184
+ )
185
+
186
+ batch_results = await asyncio.gather(*tasks)
187
+ results.extend(batch_results)
188
+
189
+ return results
190
+
191
+ def process_and_merge_data(results: list) -> str:
192
+ """
193
+ Processes and merges the raw API results for different intervals.
194
+ """
195
+ merged_data = {}
196
+
197
+ for result in results:
198
+ ticker = result.get("ticker")
199
+ interval = result.get("interval")
200
+ data = result.get("data")
201
+ error = result.get("error")
202
+
203
+ if ticker not in merged_data:
204
+ merged_data[ticker] = {"symbol": ticker}
205
+
206
+ if error:
207
+ merged_data[ticker][f"error_{interval}m"] = error
208
+ continue
209
+
210
+ if data and data.get("candles") and data["candles"]:
211
+ first_candle = data["candles"][0]
212
+
213
+ if interval == 1440:
214
+ merged_data[ticker]["day open"] = first_candle[1] if len(first_candle) > 1 else None
215
+ merged_data[ticker]["day high"] = first_candle[2] if len(first_candle) > 2 else None
216
+ merged_data[ticker]["day low"] = first_candle[3] if len(first_candle) > 3 else None
217
+ merged_data[ticker]["day close"] = first_candle[4] if len(first_candle) > 4 else None
218
+ elif interval == 15:
219
+ merged_data[ticker]["start open"] = first_candle[1] if len(first_candle) > 1 else None
220
+ merged_data[ticker]["start high"] = first_candle[2] if len(first_candle) > 2 else None
221
+ merged_data[ticker]["start low"] = first_candle[3] if len(first_candle) > 3 else None
222
+ merged_data[ticker]["start close"] = first_candle[4] if len(first_candle) > 4 else None
223
+ else:
224
+ merged_data[ticker][f"error_{interval}m"] = "No data or candles found"
225
+
226
+ final_results = list(merged_data.values())
227
+ return json.dumps(final_results, indent=4)
228
 
229
+ # --- Gradio Interface ---
230
+
231
+ async def run_backend_processing(tickers_text: str, progress=gr.Progress(track_tqdm=True)):
232
+ """
233
+ The main function to be called by the Gradio interface.
234
+ """
235
+ if not tickers_text.strip():
236
+ return "Please enter at least one ticker.", "{}"
237
+
238
+ tickers = [ticker.strip() for ticker in tickers_text.split('\n') if ticker.strip()]
239
+
240
+ today_str = date.today().strftime("%Y-%m-%d")
241
+
242
+ yield f"Starting processing for {len(tickers)} tickers for date: {today_str}", "{}"
243
+
244
  try:
245
+ time_range = get_time_range_in_unix_ms(today_str, today_str)
246
+ start_time = time_range["start_timestamp_ms"]
247
+ end_time = time_range["end_timestamp_ms"]
248
+ intervals = [1440, 15]
249
+
250
+ yield "Fetching data from API...", "{}"
251
+
252
+ results = await main(tickers, start_time, end_time, intervals, progress)
253
 
254
+ yield "Processing and merging data...", "{}"
 
255
 
256
+ processed_json = process_and_merge_data(results)
257
+
258
+ yield "Processing complete.", processed_json
 
 
 
 
 
 
 
 
259
 
 
260
  except Exception as e:
261
+ logger.error(f"An error occurred: {e}")
262
+ yield f"An error occurred: {e}", "{}"
263
+
264
+ with gr.Blocks() as demo:
265
+ gr.Markdown("# Backend Processing Logs")
266
+
267
+ with gr.Row():
268
+ with gr.Column(scale=1):
269
+ tickers_input = gr.Textbox(lines=10, label="Enter Tickers (one per line)")
270
+ start_button = gr.Button("Start Processing")
271
+
272
+ with gr.Column(scale=2):
273
+ logs_output = gr.Textbox(label="Logs", lines=15, interactive=False)
274
+ json_output = gr.JSON(label="Processed JSON Output")
275
+
276
+ start_button.click(
277
+ fn=run_backend_processing,
278
+ inputs=[tickers_input],
279
+ outputs=[logs_output, json_output]
280
+ )
281
+
282
+ if __name__ == "__main__":
283
+ demo.launch()