mishrabp commited on
Commit
bc72cf5
·
verified ·
1 Parent(s): e33bf9e

Upload folder using huggingface_hub

Browse files
Dockerfile CHANGED
@@ -21,7 +21,7 @@ COPY uv.lock .
21
 
22
  # Copy required folders
23
  COPY common/ ./common/
24
- COPY src/chatbot_v2/ ./src/chatbot_v2/
25
 
26
  # Install dependencies using uv, then export and install with pip to system
27
  RUN uv sync --frozen --no-dev && \
@@ -32,4 +32,4 @@ COPY run.py .
32
 
33
  EXPOSE 7860
34
 
35
- CMD ["python", "run.py", "chatbot_v2", "--port", "7860"]
 
21
 
22
  # Copy required folders
23
  COPY common/ ./common/
24
+ COPY src/chatbot/ ./src/chatbot/
25
 
26
  # Install dependencies using uv, then export and install with pip to system
27
  RUN uv sync --frozen --no-dev && \
 
32
 
33
  EXPOSE 7860
34
 
35
+ CMD ["python", "run.py", "chatbot", "--port", "7860"]
common/utility/autogen_model_factory.py CHANGED
@@ -51,23 +51,47 @@ class AutoGenModelFactory:
51
  # GOOGLE (GEMINI) via OpenAI Compat
52
  # ----------------------------------------------------------------------
53
  elif provider.lower() == "google" or provider.lower() == "gemini":
 
 
 
 
 
 
 
 
 
54
  return OpenAIChatCompletionClient(
55
  model=model_name,
56
  base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
57
  api_key=os.environ["GOOGLE_API_KEY"],
58
- model_info=model_info, # Pass full model_info for capabilities
59
  temperature=temperature,
 
 
 
60
  )
61
 
62
  # ----------------------------------------------------------------------
63
  # GROQ
64
  # ----------------------------------------------------------------------
65
  elif provider.lower() == "groq":
 
 
 
 
 
 
 
 
 
66
  return OpenAIChatCompletionClient(
67
  model=model_name,
68
  base_url="https://api.groq.com/openai/v1",
69
  api_key=os.environ["GROQ_API_KEY"],
 
70
  temperature=temperature,
 
 
71
  )
72
 
73
  # ----------------------------------------------------------------------
 
51
  # GOOGLE (GEMINI) via OpenAI Compat
52
  # ----------------------------------------------------------------------
53
  elif provider.lower() == "google" or provider.lower() == "gemini":
54
+ if model_info is None:
55
+ model_info = {
56
+ "family": "gemini",
57
+ "vision": False,
58
+ "function_calling": True,
59
+ "json_output": True,
60
+ "structured_output": False
61
+ }
62
+
63
  return OpenAIChatCompletionClient(
64
  model=model_name,
65
  base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
66
  api_key=os.environ["GOOGLE_API_KEY"],
67
+ model_info=model_info,
68
  temperature=temperature,
69
+ max_tokens=2048,
70
+ structured_output=False, # Disable for Gemini compatibility
71
+ extra_headers={"x-goog-api-key": os.environ["GOOGLE_API_KEY"]}
72
  )
73
 
74
  # ----------------------------------------------------------------------
75
  # GROQ
76
  # ----------------------------------------------------------------------
77
  elif provider.lower() == "groq":
78
+ if model_info is None:
79
+ model_info = {
80
+ "family": "llama", # Use llama family for Groq
81
+ "vision": False,
82
+ "function_calling": True,
83
+ "json_output": True,
84
+ "structured_output": False
85
+ }
86
+
87
  return OpenAIChatCompletionClient(
88
  model=model_name,
89
  base_url="https://api.groq.com/openai/v1",
90
  api_key=os.environ["GROQ_API_KEY"],
91
+ model_info=model_info,
92
  temperature=temperature,
93
+ structured_output=False, # Disable for Groq compatibility
94
+ max_tokens=2048
95
  )
96
 
97
  # ----------------------------------------------------------------------
pyproject.toml CHANGED
@@ -61,6 +61,7 @@ dependencies = [
61
  "autogen-agentchat==0.4.7",
62
  "autogen-ext[grpc,mcp,ollama,openai]==0.4.7",
63
  "asyncio",
 
64
 
65
  # =======================
66
  # MCP
@@ -136,6 +137,11 @@ dependencies = [
136
  "ddgs>=9.9.2",
137
  "duckduckgo_search",
138
  "azure-identity>=1.25.1",
 
 
 
 
 
139
 
140
  # =======================
141
  # OBSERVABILITY
 
61
  "autogen-agentchat==0.4.7",
62
  "autogen-ext[grpc,mcp,ollama,openai]==0.4.7",
63
  "asyncio",
64
+ "phidata>=2.0.0",
65
 
66
  # =======================
67
  # MCP
 
137
  "ddgs>=9.9.2",
138
  "duckduckgo_search",
139
  "azure-identity>=1.25.1",
140
+ "azure-mgmt-resource>=23.0.1",
141
+ "azure-mgmt-compute>=30.3.0",
142
+ "azure-mgmt-monitor>=6.0.2",
143
+ "azure-monitor-query>=1.2.0",
144
+ "PyGithub>=2.1.1",
145
 
146
  # =======================
147
  # OBSERVABILITY
run.py CHANGED
@@ -18,7 +18,7 @@ import subprocess
18
  import argparse
19
  from pathlib import Path
20
  from typing import Dict, Optional
21
- from agents import Runner, SQLiteSession
22
  # from agents import set_trace_processors
23
  # from langsmith.wrappers import OpenAIAgentsTracingProcessor
24
 
@@ -56,6 +56,7 @@ APP_REGISTRY: Dict[str, Dict[str, str]] = {
56
  "trip-planner": {
57
  "path": "src/trip-planner",
58
  "entry": "main.py",
 
59
  "description": "Trip Planner - Detailed trip itinerary planning"
60
  },
61
  "chatbot_v1": {
@@ -85,8 +86,9 @@ APP_REGISTRY: Dict[str, Dict[str, str]] = {
85
  },
86
  "market-analyst": {
87
  "path": "src/market-analyst",
88
- "entry": "app.py",
89
- "description": "Market Analyst - Multi-agent market analysis tool"
 
90
  },
91
  "image": {
92
  "path": "src/image-generator",
@@ -98,10 +100,88 @@ APP_REGISTRY: Dict[str, Dict[str, str]] = {
98
  "entry": "app.py",
99
  "description": "Interview Assistant - Multi-agent interview tool"
100
  },
101
- "finadvisor": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  "path": "src/finadvisor",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  "entry": "app.py",
104
- "description": "Financial Advisor - Multi-agent financial advisor tool"
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
106
  }
107
 
@@ -177,15 +257,63 @@ def launch_app(app_name: str, port: Optional[int] = None):
177
  print(f"📂 Location: {config['path']}")
178
  print(f"🌐 Entry Point: {app_file}")
179
 
180
- # Build streamlit command
181
- cmd = ["streamlit", "run", app_file]
182
 
183
- # Add port if specified
184
- if port:
185
- cmd.extend(["--server.port", str(port)])
186
- print(f"🔌 Port: {port}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  else:
188
- print(f"🔌 Port: 8501 (default)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
  print("\n" + "=" * 70)
191
  print("\n🎯 Starting application...\n")
@@ -198,12 +326,25 @@ def launch_app(app_name: str, port: Optional[int] = None):
198
  try:
199
  # Change to app directory and run
200
  os.chdir(app_dir)
201
- subprocess.run(cmd, env=env)
 
 
 
 
 
 
 
 
202
  except KeyboardInterrupt:
203
  print("\n\n👋 Application stopped by user")
204
  except FileNotFoundError:
205
- print("\n❌ Error: Streamlit not found. Please install it:")
206
- print(" pip install streamlit")
 
 
 
 
 
207
  sys.exit(1)
208
  except Exception as e:
209
  print(f"\n❌ Error launching app: {e}")
 
18
  import argparse
19
  from pathlib import Path
20
  from typing import Dict, Optional
21
+ # from agents import Runner, SQLiteSession
22
  # from agents import set_trace_processors
23
  # from langsmith.wrappers import OpenAIAgentsTracingProcessor
24
 
 
56
  "trip-planner": {
57
  "path": "src/trip-planner",
58
  "entry": "main.py",
59
+ "type": "fastapi",
60
  "description": "Trip Planner - Detailed trip itinerary planning"
61
  },
62
  "chatbot_v1": {
 
86
  },
87
  "market-analyst": {
88
  "path": "src/market-analyst",
89
+ "entry": "backend/main.py",
90
+ "type": "fastapi",
91
+ "description": "Market Analyst - Decoupled Multi-agent market analysis (Vue.js + FastAPI)"
92
  },
93
  "image": {
94
  "path": "src/image-generator",
 
100
  "entry": "app.py",
101
  "description": "Interview Assistant - Multi-agent interview tool"
102
  },
103
+ "finadvisor-lg": {
104
+ "path": "src/finadvisor",
105
+ "entry": "app-lg.py",
106
+ "description": "Financial Advisor - Multi-agent financial advisor tool using LangGraph"
107
+ }
108
+ ,
109
+ "finadvisor-oai": {
110
+ "path": "src/finadvisor",
111
+ "entry": "app-oai.py",
112
+ "description": "Financial Advisor - Multi-agent financial advisor tool using OpenAI"
113
+ }
114
+ ,
115
+ "finadvisor-phi": {
116
+ "path": "src/finadvisor",
117
+ "entry": "app-phi.py",
118
+ "description": "Financial Advisor - Multi-agent financial advisor tool using Phidata"
119
+ }
120
+ ,
121
+ "finadvisor-ag": {
122
  "path": "src/finadvisor",
123
+ "entry": "app-ag.py",
124
+ "description": "Financial Advisor - Multi-agent financial advisor tool using Autogen"
125
+ },
126
+ "mcp-trader": {
127
+ "path": "src/mcp-trader",
128
+ "entry": "server.py",
129
+ "type": "script",
130
+ "description": "Strategies MCP Server - FastMCP server for trading strategies"
131
+ },
132
+ "mcp-web": {
133
+ "path": "src/mcp-web",
134
+ "entry": "server.py",
135
+ "type": "script",
136
+ "description": "Web MCP Server - Search, Extract, Wikipedia, Arxiv"
137
+ },
138
+ "mcp-azure-sre": {
139
+ "path": "src/mcp-azure-sre",
140
+ "entry": "server.py",
141
+ "type": "script",
142
+ "description": "Azure SRE MCP Server - Manage Azure Resources & Monitoring"
143
+ },
144
+ "mcp-rag-secure": {
145
+ "path": "src/mcp-rag-secure",
146
+ "entry": "server.py",
147
+ "type": "script",
148
+ "description": "Secure RAG MCP Server - Multi-tenant knowledge base"
149
+ },
150
+ "mcp-trading-research": {
151
+ "path": "src/mcp-trading-research",
152
+ "entry": "server.py",
153
+ "type": "script",
154
+ "description": "Trading Research MCP Server - News, Insider, Analysts"
155
+ },
156
+ "mcp-github": {
157
+ "path": "src/mcp-github",
158
+ "entry": "server.py",
159
+ "type": "script",
160
+ "description": "GitHub MCP Server - Issues, PRs, Alerts"
161
+ },
162
+ "mcp-seo": {
163
+ "path": "src/mcp-seo",
164
+ "entry": "server.py",
165
+ "type": "script",
166
+ "description": "SEO & ADA MCP Server - Website Audits"
167
+ },
168
+ "github-portal": {
169
+ "path": "src/github-portal",
170
  "entry": "app.py",
171
+ "type": "streamlit",
172
+ "description": "GitHub Portal - Repository health dashboard for issues, security, and pipelines"
173
+ },
174
+ "mcp-hub": {
175
+ "path": "src/mcp-hub",
176
+ "entry": "package.json",
177
+ "type": "npm",
178
+ "description": "MCP Hub - Discovery and monitoring portal (Vue.js)"
179
+ },
180
+ "test": {
181
+ "path": ".",
182
+ "entry": "tests",
183
+ "type": "test",
184
+ "description": "Run Project Tests - Executes pytest suite"
185
  }
186
  }
187
 
 
257
  print(f"📂 Location: {config['path']}")
258
  print(f"🌐 Entry Point: {app_file}")
259
 
260
+ app_type = config.get("type", "streamlit")
 
261
 
262
+ # Decoupled App Logic: Build frontend if needed
263
+ if app_name == "market-analyst":
264
+ frontend_dir = project_root / "src/market-analyst/frontend"
265
+ dist_dir = frontend_dir / "dist"
266
+ if not dist_dir.exists():
267
+ print("\n🛠️ Frontend build missing. Building now...")
268
+ subprocess.run(["npm", "run", "build"], cwd=frontend_dir, shell=True)
269
+ print("✅ Frontend built.\n")
270
+
271
+ python_exe = sys.executable
272
+
273
+ # Build command based on app type
274
+ if app_type == "fastapi":
275
+ # Extract module name from entry point (e.g. backend/main.py -> backend.main)
276
+ module_path = app_file.replace(".py", "").replace("/", ".").replace("\\", ".")
277
+ cmd = [python_exe, "-m", "uvicorn", f"{module_path}:app", "--host", "0.0.0.0"]
278
+ default_port = 8000
279
+ elif app_type == "script":
280
+ cmd = [python_exe, app_file]
281
+ default_port = None
282
+ elif app_type == "test":
283
+ cmd = [python_exe, "-m", "pytest", app_file, "-v"]
284
+ default_port = None
285
+ elif app_type == "npm":
286
+ cmd = ["npm", "run", "dev"]
287
+ default_port = 5173
288
  else:
289
+ cmd = [python_exe, "-m", "streamlit", "run", app_file]
290
+ default_port = 8501
291
+
292
+ # Add port if specified
293
+ actual_port = port if port else default_port
294
+
295
+ if app_type in ["streamlit", "fastapi", "npm"]:
296
+ if port:
297
+ if app_type == "fastapi":
298
+ cmd.extend(["--port", str(port)])
299
+ elif app_type == "npm":
300
+ cmd.extend(["--", "--port", str(port)])
301
+ else:
302
+ cmd.extend(["--server.port", str(port)])
303
+ print(f"🔌 Port: {port}")
304
+ else:
305
+ print(f"🔌 Port: {default_port} (default)")
306
+
307
+ # Kill any process using the target port (Port is only relevant for web apps)
308
+ try:
309
+ import platform
310
+ if platform.system() != "Windows":
311
+ # Use fuser on Linux/Mac to kill processes on the port
312
+ kill_cmd = ["fuser", "-k", f"{actual_port}/tcp"]
313
+ subprocess.run(kill_cmd, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
314
+ print(f"🧹 Cleaned up port {actual_port}")
315
+ except Exception:
316
+ pass # Silently continue if cleanup fails
317
 
318
  print("\n" + "=" * 70)
319
  print("\n🎯 Starting application...\n")
 
326
  try:
327
  # Change to app directory and run
328
  os.chdir(app_dir)
329
+ is_windows = sys.platform == "win32"
330
+
331
+ # Special case for mcp-hub: launch backend API first
332
+ if app_name == "mcp-hub":
333
+ print("🚀 Starting MCP Hub Backend API on port 8001...")
334
+ api_cmd = [python_exe, "api.py"]
335
+ subprocess.Popen(api_cmd, env=env, shell=is_windows)
336
+
337
+ subprocess.run(cmd, env=env, shell=is_windows)
338
  except KeyboardInterrupt:
339
  print("\n\n👋 Application stopped by user")
340
  except FileNotFoundError:
341
+ binary = "command"
342
+ if app_type == "fastapi": binary = "uvicorn"
343
+ elif app_type == "streamlit": binary = "streamlit"
344
+ elif app_type == "test": binary = "pytest"
345
+
346
+ print(f"\n❌ Error: {binary} not found in the current environment.")
347
+ print(f" Please install it: pip install {binary}")
348
  sys.exit(1)
349
  except Exception as e:
350
  print(f"\n❌ Error launching app: {e}")
src/chatbot_v1/Dockerfile ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ ENV PYTHONUNBUFFERED=1 \
4
+ DEBIAN_FRONTEND=noninteractive \
5
+ PYTHONPATH=/app:/app/common:$PYTHONPATH
6
+
7
+ WORKDIR /app
8
+
9
+ # System deps
10
+ RUN apt-get update && apt-get install -y \
11
+ git build-essential curl \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ # Install uv
15
+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh
16
+ ENV PATH="/root/.local/bin:$PATH"
17
+
18
+ # Copy project metadata
19
+ COPY pyproject.toml .
20
+ COPY uv.lock .
21
+
22
+ # Copy required folders
23
+ COPY common/ ./common/
24
+ COPY src/chatbot/ ./src/chatbot/
25
+
26
+ # Install dependencies using uv, then export and install with pip to system
27
+ RUN uv sync --frozen --no-dev && \
28
+ uv pip install -e . --system
29
+
30
+ # Copy entry point
31
+ COPY run.py .
32
+
33
+ EXPOSE 7860
34
+
35
+ CMD ["python", "run.py", "chatbot", "--port", "7860"]
src/chatbot_v1/README.md ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: AI Chatbot
3
+ emoji: 🤖
4
+ colorFrom: pink
5
+ colorTo: yellow
6
+ sdk: docker
7
+ sdk_version: "0.0.1"
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ tags:
12
+ - text-generation
13
+ - agentic-ai
14
+ - openai-sdk
15
+ short_description: An Experimental Agentic Chatbot (uses OpenAI Agent SDK)
16
+ ---
17
+
18
+ # AI Chatbot
19
+
20
+ This is an experimental chatbot for chatting with AI. It is equipped with agents & tools to give you realtime data from the web. It uses **OpenAI - SDK** and **OpenAI - Agents**...
21
+
22
+ ## Features
23
+ - Predefined prompts for quick analysis
24
+ - Chat interface with AI responses
25
+ - Enter key support and responsive design
26
+ - Latest messages appear on top
27
+
28
+ ## Usage
29
+ 1. Type a message or select a predefined prompt
30
+ 2. Press **Enter** or click **Send**
31
+ 3. AI responses appear instantly in the chat interface
32
+
33
+ ## Supported APIs
34
+ - OpenAI
35
+ - Google
36
+ - GROQ
37
+ - SERPER
38
+ - News API
39
+
40
+ ## Notes
41
+ - Make sure your API keys are configured in the Space secrets
42
+ - Built using Streamlit and deployed as a Docker Space
43
+
44
+ ## References
45
+
46
+ https://openai.github.io/openai-agents-python/
47
+
48
+ https://github.com/openai/openai-agents-python/tree/main/examples/mcp
49
+
50
+ ## Project Folder Structure
51
+
52
+ ```
53
+ chatbot/
54
+ ├── app.py # Main Streamlit chatbot interface
55
+ ├── appagents/
56
+ │ ├── __init__.py # Package initialization
57
+ │ ├── OrchestratorAgent.py # Main orchestrator - coordinates all agents
58
+ │ ├── FinancialAgent.py # Financial data and analysis agent
59
+ │ ├── NewsAgent.py # News retrieval and summarization agent
60
+ │ ├── SearchAgent.py # General web search agent
61
+ │ └── InputValidationAgent.py # Input validation and sanitization agent
62
+ ├── core/
63
+ │ ├── __init__.py # Package initialization
64
+ │ └── logger.py # Centralized logging configuration
65
+ ├── tools/
66
+ │ ├── __init__.py # Package initialization
67
+ │ ├── google_tools.py # Google search API wrapper
68
+ │ ├── yahoo_tools.py # Yahoo Finance API wrapper
69
+ │ ├── news_tools.py # News API wrapper
70
+ │ └── time_tools.py # Time-related utility functions
71
+ ├── prompts/
72
+ │ ├── economic_news.txt # Prompt for economic news analysis
73
+ │ ├── market_sentiment.txt # Prompt for market sentiment analysis
74
+ │ ├── news_headlines.txt # Prompt for news headline summarization
75
+ │ ├── trade_recommendation.txt # Prompt for trade recommendations
76
+ │ └── upcoming_earnings.txt # Prompt for upcoming earnings alerts
77
+ ├── Dockerfile # Docker configuration for container deployment
78
+ ├── pyproject.toml # Project metadata and dependencies (copied from root)
79
+ ├── uv.lock # Locked dependency versions (copied from root)
80
+ ├── README.md # Project documentation
81
+ └── run.py # Script to run the application locally
82
+ ```
83
+
84
+ ## File Descriptions
85
+
86
+ ### UI Layer
87
+ - **app.py** - Main Streamlit chatbot interface that provides:
88
+ - Chat message display with user and AI messages
89
+ - Text input for user queries
90
+ - Predefined prompt buttons for quick analysis
91
+ - Real-time AI responses
92
+ - Support for Enter key submission
93
+ - Responsive design with latest messages appearing first
94
+
95
+ ### Agents (`appagents/`)
96
+ - **OrchestratorAgent.py** - Main orchestrator that:
97
+ - Coordinates communication between all specialized agents
98
+ - Routes user queries to appropriate agents
99
+ - Manages conversation flow and context
100
+ - Integrates tool responses
101
+
102
+ - **FinancialAgent.py** - Financial data and analysis:
103
+ - Retrieves stock prices and financial metrics
104
+ - Performs financial analysis using Yahoo Finance API
105
+ - Provides market insights and recommendations
106
+ - Integrates with yahoo_tools for data fetching
107
+
108
+ - **NewsAgent.py** - News retrieval and summarization:
109
+ - Fetches latest news articles
110
+ - Summarizes news content
111
+ - Integrates with News API for real-time updates
112
+ - Provides news-based market insights
113
+
114
+ - **SearchAgent.py** - General web search:
115
+ - Performs web searches for general queries
116
+ - Integrates with Google Search / Serper API
117
+ - Returns relevant search results
118
+ - Supports multi-source data gathering
119
+
120
+ - **InputValidationAgent.py** - Input validation:
121
+ - Sanitizes user input
122
+ - Validates query format and content
123
+ - Prevents malicious inputs
124
+ - Ensures appropriate content
125
+
126
+ ### Core Utilities (`core/`)
127
+ - **logger.py** - Centralized logging configuration:
128
+ - Provides consistent logging across agents
129
+ - Handles different log levels
130
+ - Formats log messages for clarity
131
+
132
+ ### Tools (`tools/`)
133
+ - **google_tools.py** - Google Search API wrapper:
134
+ - Executes web searches via Google Search / Serper API
135
+ - Parses and returns search results
136
+ - Handles API authentication
137
+
138
+ - **yahoo_tools.py** - Yahoo Finance API integration:
139
+ - Retrieves stock price data
140
+ - Fetches financial metrics and indicators
141
+ - Provides historical price data
142
+ - Returns earnings information
143
+
144
+ - **news_tools.py** - News API integration:
145
+ - Fetches latest news articles
146
+ - Filters news by category and keywords
147
+ - Returns news headlines and summaries
148
+ - Provides market-related news feeds
149
+
150
+ - **time_tools.py** - Time utility functions:
151
+ - Provides current time information
152
+ - Formats timestamps
153
+ - Handles timezone conversions
154
+
155
+ ### Prompts (`prompts/`)
156
+ Predefined prompts for specialized analysis:
157
+ - **economic_news.txt** - Analyzes economic news and implications
158
+ - **market_sentiment.txt** - Analyzes market sentiment trends
159
+ - **news_headlines.txt** - Summarizes and explains news headlines
160
+ - **trade_recommendation.txt** - Provides trading recommendations
161
+ - **upcoming_earnings.txt** - Alerts about upcoming earnings reports
162
+
163
+ ### Configuration Files
164
+ - **Dockerfile** - Container deployment:
165
+ - Builds Docker image with Python 3.12
166
+ - Installs dependencies using `uv`
167
+ - Sets up Streamlit server on port 8501
168
+ - Configures PYTHONPATH for module imports
169
+
170
+ - **pyproject.toml** - Project metadata:
171
+ - Package name: "agents"
172
+ - Python version requirement: 3.12
173
+ - Lists all dependencies (OpenAI, LangChain, Streamlit, etc.)
174
+
175
+ - **uv.lock** - Dependency lock file:
176
+ - Ensures reproducible builds
177
+ - Pins exact versions of all dependencies
178
+
179
+ ## Key Technologies
180
+
181
+ | Component | Technology | Purpose |
182
+ |-----------|-----------|---------|
183
+ | LLM Framework | OpenAI Agents | Multi-agent orchestration |
184
+ | Chat Interface | Streamlit | User interaction and display |
185
+ | Web Search | Google Search / Serper API | Web search results |
186
+ | Financial Data | Yahoo Finance API | Stock prices and metrics |
187
+ | News Data | News API | Latest news articles |
188
+ | Async Operations | AsyncIO | Parallel agent execution |
189
+ | Dependencies | UV | Fast Python package management |
190
+ | Containerization | Docker | Cloud deployment |
191
+
192
+ ## Predefined Prompts
193
+
194
+ The chatbot includes quick-access buttons for common analysis:
195
+
196
+ 1. **Economic News** - Analyzes current economic trends and news
197
+ 2. **Market Sentiment** - Provides market sentiment analysis
198
+ 3. **News Headlines** - Summarizes latest news headlines
199
+ 4. **Trade Recommendation** - Suggests trading strategies
200
+ 5. **Upcoming Earnings** - Lists upcoming company earnings
201
+
202
+ ## Running Locally
203
+
204
+ ```bash
205
+ # Install dependencies
206
+ uv sync
207
+
208
+ # Set environment variables defined in .env.name file
209
+ export OPENAI_API_KEY="your-key"
210
+ export SERPER_API_KEY="your-key"
211
+ export NEWS_API_KEY="your-key"
212
+
213
+ # Run the Streamlit app (from the root)
214
+ python run.py chatbot
215
+ ```
216
+
217
+ ## Deployment
218
+
219
+ The project is deployed on Hugging Face Spaces as a Docker container:
220
+ - **Space**: https://huggingface.co/spaces/mishrabp/chatbot-app
221
+ - **URL**: https://mishrabp-chatbot-app.hf.space
222
+ - **Trigger**: Automatic deployment on push to `main` branch
223
+ - **Configuration**: `.github/workflows/chatbot-app-hf.yml`
src/chatbot_v1/aagents/__init__.py ADDED
File without changes
src/chatbot_v1/aagents/input_validation_agent.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import json
4
+ from agents import Agent, OpenAIChatCompletionsModel, Runner, GuardrailFunctionOutput
5
+ from pydantic import BaseModel
6
+ from openai import AsyncOpenAI
7
+ from core.model import get_model_client
8
+
9
+ class ValidatedOutput(BaseModel):
10
+ is_valid: bool
11
+ reasoning: str
12
+
13
+ input_validation_agent = Agent(
14
+ name="Guardrail Input Validation Agent",
15
+ instructions="""
16
+ You are a highly efficient and specialized **Agent** 🌐. Your sole function is to validate the user inputs.
17
+
18
+ ## Core Directives & Priorities
19
+ 1. You should flag if the user uses unparaliamentary language ONLY.
20
+ 2. You MUST give reasoning for the same.
21
+
22
+ ## Rules
23
+ - If it contains any of these, mark `"is_valid": false` and explain **why** in `"reasoning"`.
24
+ - Otherwise, mark `"is_valid": true` with reasoning like "The input follows respectful communication guidelines."
25
+
26
+
27
+ ## Output Format (MANDATORY)
28
+ * Return a JSON object with the following structure:
29
+ {
30
+ "is_valid": <boolean>,
31
+ "reasoning": <string>
32
+ }
33
+ """,
34
+ model=get_model_client(),
35
+ output_type=ValidatedOutput,
36
+ )
37
+ input_validation_agent.description = "A guardrail agent that validates user input for unparliamentary language."
38
+
39
+ async def input_validation_guardrail(ctx, agent, input_data):
40
+ result = await Runner.run(input_validation_agent, input_data, context=ctx.context)
41
+ raw_output = result.final_output
42
+
43
+ # Handle different return shapes gracefully
44
+ if isinstance(raw_output, ValidatedOutput):
45
+ final_output = raw_output
46
+ print("Parsed ValidatedOutput:", final_output)
47
+ else:
48
+ final_output = ValidatedOutput(
49
+ is_valid=False,
50
+ reasoning=f"Unexpected output type: {type(raw_output)}"
51
+ )
52
+
53
+ return GuardrailFunctionOutput(
54
+ output_info=final_output,
55
+ tripwire_triggered=not final_output.is_valid,
56
+ )
57
+
58
+ __all__ = ["input_validation_agent", "input_validation_guardrail", "ValidatedOutput"]
src/chatbot_v1/aagents/orchestrator_agent.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import asyncio
4
+ from common.aagents.search_agent import search_agent
5
+ from common.aagents.news_agent import news_agent
6
+ from common.aagents.yf_agent import yf_agent
7
+ from aagents.input_validation_agent import input_validation_guardrail
8
+ from agents import Agent, OpenAIChatCompletionsModel, Runner, function_tool
9
+ from openai import AsyncOpenAI
10
+ from core.model import get_model_client
11
+
12
+ # ----------------------------------------------------------
13
+ # PARALLEL EXECUTION TOOL
14
+ # ----------------------------------------------------------
15
+ @function_tool
16
+ async def prompt_broadcaster(query: str, include_finance: bool = True, include_news: bool = True, include_search: bool = True) -> str:
17
+ """
18
+ Broadcasts the search query to selected specialized agents in parallel and aggregates their responses.
19
+
20
+ Args:
21
+ query: The user's question or topic to research.
22
+ include_finance: Whether to include the Yahoo Finance agent (default: True).
23
+ include_news: Whether to include the News agent (default: True).
24
+ include_search: Whether to include the Web Search agent (default: True).
25
+
26
+ Returns:
27
+ Combined reports from the selected agents.
28
+ """
29
+
30
+
31
+ # A better approach for variable tasks is to map them.
32
+ active_agents = []
33
+ if include_finance: active_agents.append(("YahooFinanceAgent", Runner.run(yf_agent, query)))
34
+ if include_news: active_agents.append(("NewsAgent", Runner.run(news_agent, query)))
35
+ if include_search: active_agents.append(("WebSearchAgent", Runner.run(search_agent, query)))
36
+
37
+ if not active_agents:
38
+ return "No agents were selected for this query."
39
+
40
+ # Run in parallel
41
+ agent_names = [name for name, _ in active_agents]
42
+ coroutines = [coro for _, coro in active_agents]
43
+
44
+ results = await asyncio.gather(*coroutines, return_exceptions=True)
45
+
46
+ outputs = []
47
+ for name, res in zip(agent_names, results):
48
+ if isinstance(res, Exception):
49
+ outputs.append(f"❌ {name} Error: {str(res)}")
50
+ else:
51
+ outputs.append(f"✅ {name} Report:\n{res.final_output}")
52
+
53
+ combined_response = "\n--- START OF AGENT REPORTS ---\n\n" + "\n\n-----------------------------------\n\n".join(outputs) + "\n\n--- END OF AGENT REPORTS ---"
54
+
55
+ return combined_response
56
+
57
+ orchestrator_agent = Agent(
58
+ name="AI Chat Orchestrator",
59
+ tools=[prompt_broadcaster],
60
+ instructions="""
61
+ You are the **AI Chat Orchestrator**.
62
+ Your goal is to provide a comprehensive, multi-perspective answer by synthesizing data from specialized sub-agents.
63
+
64
+ **Workflow**:
65
+ 1. **Analyze Request**: Understand the user's question.
66
+ 2. **Determine Needs**: Decide which specialized agents are required.
67
+ * **Finance**: For stock prices, market trends, company financials, or analyst ratings.
68
+ * **News**: For recent events, headlines, or breaking news.
69
+ * **Web Search**: For general knowledge, history, facts, or broad research.
70
+ 3. **Broadcast Query**: Call the `prompt_broadcaster` tool with the `query` and set the `include_*` flags to True/False accordingly.
71
+ * *Optimization Tip*: efficiently select ONLY the necessary agents to reduce latency.
72
+ 4. **Synthesize Results**: Read the returned "Agent Reports".
73
+ * Combine the financial data (prices, sentiment), news headlines, and general search context.
74
+ * Compare and contrast findings if necessary.
75
+ * Resolve conflicts by prioritizing specific data (e.g., Yahoo Finance for prices) over general text.
76
+ 5. **Final Response**: Generate a clear, professional, and well-structured summary for the user. Do not simply paste the individual reports.
77
+
78
+ **Final Response Structure**:
79
+ You should adapt the response structure based on the user's query type:
80
+
81
+ * **For Market/Finance Queries**: Use the "Market Analysis" style with a Financial Snapshot (Price, Sentinel, Ratings), Key Developments, and Synthesis.
82
+ * **For News/Research**: Use a clear "Executive Summary" followed by "Key Findings" and "Details".
83
+ * **For General Chat**: Maintain a conversational but professional tone. Use markdown for clarity (bullet points, bold text).
84
+ * **For Coding Requests**: Provide clear code blocks and explanations.
85
+
86
+ **Constraint**:
87
+ * Do NOT try to answer based on your own knowledge if live data is needed/requested.
88
+ * Use `prompt_broadcaster` when the query implies a need for external information.
89
+ * If agents return "No data", explicitly state that in the relevant section.
90
+ """,
91
+ model=get_model_client(),
92
+ )
93
+ orchestrator_agent.description = "An intelligent orchestrator that queries Finance, News, and Search agents in parallel and synthesizes a comprehensive response."
94
+
95
+
96
+ __all__ = ["orchestrator_agent"]
src/chatbot_v1/app.py ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ import uuid
4
+ import asyncio
5
+ # import trace_config
6
+ import logging
7
+ import streamlit as st
8
+ from aagents.orchestrator_agent import orchestrator_agent
9
+ from agents import Runner, trace, SQLiteSession
10
+ from agents.exceptions import InputGuardrailTripwireTriggered
11
+ # from langsmith import traceable
12
+
13
+ from traceloop.sdk import Traceloop
14
+ from opentelemetry.sdk.trace import Span
15
+
16
+ # --- Monkeypatch to fix "Invalid type Omit" errors ---
17
+ # This filters out 'NotGiven'/'Omit' values from OpenAI that crash the OTel exporter
18
+ _original_set_attribute = Span.set_attribute
19
+
20
+ def _safe_set_attribute(self, key, value):
21
+ # Check string representation of type to avoid importing specific internal types
22
+ type_str = str(type(value))
23
+ if "Omit" in type_str or "NotGiven" in type_str:
24
+ return self
25
+ return _original_set_attribute(self, key, value)
26
+
27
+ Span.set_attribute = _safe_set_attribute
28
+ # -----------------------------------------------------
29
+
30
+ Traceloop.init(
31
+ disable_batch=True,
32
+ api_key="tl_1c19b8e8fcfd411fb9fcdb02d381faef"
33
+ )
34
+
35
+ # -----------------------------
36
+ # Configuration & Utils
37
+ # -----------------------------
38
+ st.set_page_config(
39
+ page_title="AI Assistant",
40
+ layout="wide",
41
+ page_icon="🤖"
42
+ )
43
+
44
+ def load_prompts(folder="prompts"):
45
+ prompts = []
46
+ prompt_labels = []
47
+ if os.path.exists(folder):
48
+ for file_path in glob.glob(os.path.join(folder, "*.txt")):
49
+ with open(file_path, "r", encoding="utf-8") as f:
50
+ content = f.read().strip()
51
+ if content:
52
+ prompts.append(content)
53
+
54
+ prompt_labels.append(os.path.basename(file_path).replace("_", " ").replace(".txt", "").title())
55
+ return prompts, prompt_labels
56
+
57
+ prompts, prompt_labels = load_prompts()
58
+
59
+ # -----------------------------
60
+ # Session State
61
+ # -----------------------------
62
+ if "messages" not in st.session_state:
63
+ st.session_state.messages = []
64
+
65
+ if "ai_session_id" not in st.session_state:
66
+ st.session_state.ai_session_id = str(uuid.uuid4())
67
+
68
+ # Persistent SQLite session
69
+ if "ai_session" not in st.session_state:
70
+ st.session_state.ai_session = SQLiteSession(f"conversation_{st.session_state.ai_session_id}.db")
71
+
72
+ session = st.session_state.ai_session
73
+
74
+ # -----------------------------
75
+ # Premium Styling
76
+ # -----------------------------
77
+ st.markdown("""
78
+ <style>
79
+ /* ---------------------------------------------------------------------
80
+ 1. GLOBAL & RESET
81
+ --------------------------------------------------------------------- */
82
+ * {
83
+ box-sizing: border-box;
84
+ }
85
+
86
+ .stApp, [data-testid="stAppViewContainer"] {
87
+ /* Standard Streamlit background */
88
+ background-color: #f8f9fa;
89
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
90
+ }
91
+
92
+ html {
93
+ -webkit-text-size-adjust: 100%; /* Prevent iOS font boosting */
94
+ }
95
+
96
+ /* ---------------------------------------------------------------------
97
+ 2. LAYOUT & HERO BANNER
98
+ --------------------------------------------------------------------- */
99
+
100
+ /* Mobile font optimization */
101
+ @media (max-width: 768px) {
102
+ /* Target all markdown text specifically */
103
+ .stMarkdown p, .stMarkdown li, .stChatMessage p, .message-content, .stDataFrame, .stTable {
104
+ font-size: 16px !important;
105
+ line-height: 1.6 !important;
106
+ color: #1a1a1a !important;
107
+ }
108
+
109
+ h1, h2, h3, h4, h5, h6 {
110
+ color: #1a1a1a !important;
111
+ }
112
+ }
113
+
114
+ /* Desktop Layout */
115
+ @media (min-width: 769px) {
116
+ .block-container {
117
+ padding-top: 0 !important;
118
+ padding-bottom: 2rem !important;
119
+ padding-left: 5rem !important;
120
+ padding-right: 5rem !important;
121
+ max-width: 100% !important;
122
+ }
123
+
124
+ .hero-container {
125
+ margin-top: -3rem;
126
+ margin-left: -5rem;
127
+ margin-right: -5rem;
128
+ /* Simple negative margins to pull edge-to-edge */
129
+ padding: 2.5rem 1rem 2rem 1rem; /* Compact desktop padding */
130
+ }
131
+ }
132
+
133
+ /* Mobile Layout */
134
+ @media (max-width: 768px) {
135
+ .block-container {
136
+ padding-left: 1rem !important;
137
+ padding-right: 1rem !important;
138
+ padding-top: 0 !important;
139
+ }
140
+
141
+ .hero-container {
142
+ margin-top: -2rem;
143
+ margin-left: -1rem;
144
+ margin-right: -1rem;
145
+ /* Break out of the 1rem padding */
146
+ padding: 2rem 1rem 1.5rem 1rem; /* Compact mobile padding */
147
+ border-radius: 0 0 12px 12px;
148
+ }
149
+
150
+ /* Ensure font sizes are standard (Streamlit defaults is ~16px) */
151
+ /* We DO NOT override them to 17px/fixed, allowing system zoom to work. */
152
+ }
153
+
154
+ /* Hero Styling */
155
+ .hero-container {
156
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
157
+ color: white;
158
+ text-align: center;
159
+ border-radius: 0 0 16px 16px;
160
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
161
+ margin-bottom: 2rem;
162
+ }
163
+
164
+ .hero-title {
165
+ font-size: 2rem; /* Slightly smaller */
166
+ font-weight: 700;
167
+ margin-bottom: 0.25rem;
168
+ color: white !important;
169
+ }
170
+ .hero-subtitle {
171
+ font-size: 1rem;
172
+ opacity: 0.95;
173
+ font-weight: 400;
174
+ color: rgba(255,255,255,0.95) !important;
175
+ }
176
+
177
+ /* Remove Header Decoration */
178
+ header[data-testid="stHeader"] {
179
+ background-color: transparent !important;
180
+ height: 0 !important;
181
+ z-index: 100;
182
+ }
183
+ div[data-testid="stDecoration"] { display: none; }
184
+
185
+ /* ---------------------------------------------------------------------
186
+ 3. COMPONENT STYLING (Healthcare-like)
187
+ --------------------------------------------------------------------- */
188
+
189
+ /* Chat Bubbles - Clean & Readable */
190
+ .stChatMessage {
191
+ background-color: white;
192
+ border-radius: 12px;
193
+ border: 1px solid #e5e5e5;
194
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05);
195
+ padding: 1rem;
196
+ }
197
+
198
+ .stChatMessage[data-testid="stChatMessage"]:nth-of-type(odd) {
199
+ background-color: #f8f9fa;
200
+ }
201
+
202
+ /* Input Fields */
203
+ .stTextInput input {
204
+ border-radius: 20px; /* Matching healthcare-assistant roundness */
205
+ border: 1px solid #ddd;
206
+ padding: 0.75rem 1rem;
207
+ }
208
+
209
+ /* Buttons */
210
+ .stButton button {
211
+ border-radius: 20px; /* Matching healthcare-assistant */
212
+ min-height: 48px;
213
+ font-weight: 500;
214
+ }
215
+
216
+ /* Sidebar */
217
+ section[data-testid="stSidebar"] {
218
+ background-color: #ffffff;
219
+ border-right: 1px solid #eaeaea;
220
+ }
221
+
222
+ /* Minimize Sidebar Top Padding */
223
+ section[data-testid="stSidebar"] .block-container {
224
+ padding-top: 0rem !important;
225
+ padding-bottom: 0rem !important;
226
+ }
227
+ </style>
228
+ """, unsafe_allow_html=True)
229
+
230
+ # -----------------------------
231
+ # Logic
232
+ # -----------------------------
233
+ # @traceable(name="chatbot")
234
+ async def get_ai_response(prompt: str) -> str:
235
+ try:
236
+ agent = orchestrator_agent
237
+ # Ensure session is valid
238
+ current_session = st.session_state.ai_session
239
+ current_session = st.session_state.ai_session
240
+ with trace("Chatbot Agent Run"): # Keep existing custom trace wrapper
241
+ # Run agent
242
+ result = await Runner.run(agent, prompt, session=current_session)
243
+ return result.final_output
244
+ except InputGuardrailTripwireTriggered as e:
245
+ reasoning = getattr(e, "reasoning", None) \
246
+ or getattr(getattr(e, "output", None), "reasoning", None) \
247
+ or getattr(getattr(e, "guardrail_output", None), "reasoning", None) \
248
+ or "Guardrail triggered, but no reasoning provided."
249
+ return f"⚠️ **Guardrail Blocked Input**\n\n{reasoning}"
250
+ except Exception as e:
251
+ return f"❌ **Error**: {str(e)}"
252
+
253
+ # -----------------------------
254
+ # Sidebar - Quick Actions
255
+ # -----------------------------
256
+ with st.sidebar:
257
+ st.markdown("### ⚡ Quick Starters")
258
+ st.markdown("Select a prompt to start:")
259
+
260
+ # We use a trick with st.button to act as input triggers
261
+ # If a button is clicked, we'll handle it in the main loop logic
262
+ selected_prompt = None
263
+ for idx, prompt_text in enumerate(prompts):
264
+ label = prompt_labels[idx] if idx < len(prompt_labels) else f"Prompt {idx+1}"
265
+ if st.button(label, key=f"sidebar_btn_{idx}", use_container_width=True):
266
+ # Reset conversation
267
+ st.session_state.messages = []
268
+ st.session_state.ai_session_id = str(uuid.uuid4())
269
+ # Recreate session object with new ID
270
+ st.session_state.ai_session = SQLiteSession(f"conversation_{st.session_state.ai_session_id}.db")
271
+ selected_prompt = prompt_text
272
+
273
+ st.markdown("---")
274
+ if st.button("🗑️ Clear Conversation", use_container_width=True):
275
+ st.session_state.messages = []
276
+ st.rerun()
277
+
278
+ # -----------------------------
279
+ # Main Content
280
+ # -----------------------------
281
+
282
+ # Hero Banner (Always visible & Sticky)
283
+ st.markdown("""
284
+ <div class="hero-container" role="banner">
285
+ <div class="hero-title">🤖 AI Companion</div>
286
+ <div class="hero-subtitle">Your intelligent partner for research, analysis, and more.</div>
287
+ </div>
288
+ """, unsafe_allow_html=True)
289
+
290
+ # Display Chat History
291
+ for message in st.session_state.messages:
292
+ with st.chat_message(message["role"]):
293
+ st.markdown(message["content"], unsafe_allow_html=True)
294
+
295
+ # Chat Input Handling
296
+ # We handle both the chat input widget and the sidebar selection here
297
+ if prompt := (st.chat_input("Type your message...") or selected_prompt):
298
+ # User Message
299
+ st.session_state.messages.append({"role": "user", "content": prompt})
300
+ with st.chat_message("user"):
301
+ st.markdown(prompt)
302
+
303
+ # Assistant Response
304
+ with st.chat_message("assistant"):
305
+ with st.spinner("Thinking..."):
306
+ response_text = asyncio.run(get_ai_response(prompt))
307
+ st.markdown(response_text, unsafe_allow_html=True)
308
+
309
+
310
+
311
+ st.session_state.messages.append({"role": "assistant", "content": response_text})
312
+
313
+ # If it was a sidebar click, we need to rerun to clear the selection state potentially,
314
+ # but st.chat_input usually handles focus. With buttons, a rerun happens automatically
315
+ # but we want to make sure the input box is cleared (which 'selected_prompt' doesn't use).
316
+ if selected_prompt:
317
+ st.rerun()
src/chatbot_v1/prompts/economic_news.txt ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Provide a concise update on **major economic indicators released recently** in USA.
3
+
4
+ ###### Include
5
+ - **Interest Rates**: Latest central bank decisions, current policy rates, and forward guidance.
6
+ - **Labor Market**: Unemployment rate, job creation figures, and key labor metrics (if available).
7
+ - **Inflation**: CPI, PCE, or other inflation data with MoM and YoY changes.
8
+ - **Growth Indicators**: GDP, PMIs, or industrial production released recently.
9
+ - **Market Reaction**: Brief impact on equities, bonds, FX, and commodities.
10
+
11
+ ###### Guidelines
12
+ - Compare results against forecasts and prior releases
13
+ - Highlight notable surprises and their implications
14
+ - Keep the summary brief, factual, and structured
15
+ - **Always retrieve numerical data from primary or authoritative sources**
16
+
17
+ ###### Fallback
18
+ - If no relevant data was released recently, explicitly state **“No major economic indicators were released during this period.”**
19
+ - If data is partially unavailable, summarize what is available and clearly note missing indicators.
20
+ - Do not infer or fabricate numbers under any circumstance.
21
+
22
+ ###### Output Style
23
+ - Concise, factual, and well-structured
24
+ - Use clear bullet points or short paragraphs
25
+ - Avoid speculation unless explicitly labeled as interpretation
26
+ - **Cite data sources clearly**
27
+ - Use color and emoji to make it more engaging.
src/chatbot_v1/prompts/entertainment_updates.txt ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Provide the **top 5 recent movie or series updates** that are trending or newly released in USA.
3
+
4
+ ###### For each title, include:
5
+ - **Title in bold** and optionally use **color or emojis** to make it fun (e.g., 🎬, 🍿, 🌟)
6
+ - A **short, 2–3 line snippet** that generates excitement or humor about the plot, cast, or vibe
7
+ - **Platform or source** where it can be watched (Netflix, Prime, Disney+, etc.)
8
+ - **Release date or premiere date**
9
+
10
+ ###### Requirements / Guidelines
11
+ - Focus on **recent releases** (last 2–4 weeks) or currently trending content
12
+ - Keep the tone **fun, witty, and engaging**, like a friend recommending a show
13
+ - Use **emojis liberally** to emphasize excitement, genre, or humor
14
+ - Call out the **main actors and actresses** to build the interest
15
+ - Where possible, add a **light humorous quip or pun** about the movie/series
16
+ - If color is supported, use HTML span tags, e.g., `<span style="color:orange">Title</span>` for emphasis
17
+
18
+ ###### Fallback
19
+ - If fewer than 5 titles are available, provide what is available and indicate:
20
+ **“Only X recent releases found.”**
21
+ - Do not fabricate platforms or release dates — only use verified sources
22
+
23
+ ###### Output Style
24
+ - List format (1–5) sorted by **popularity or release date**
25
+ - **Title + snippet + watch source + release date** per entry
26
+ - Use **color, emojis, and humor** to make the output visually appealing and fun to read
src/chatbot_v1/prompts/india_news.txt ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Tell me the **top 3 headlines from India**.
3
+
4
+ ###### For each headline, provide:
5
+ - **Title in bold**
6
+ - A **3‑line summary**
7
+ - **Publish date and time**
8
+ - A **link to the exact source URL**
9
+
10
+ ###### Requirements
11
+ - Use authoritative news sources (e.g., major national/regional news outlets)
12
+ - Headlines should be **recent (last 24 hours)**
13
+ - Provide timestamps in **UTC**
14
+ - If publish date/time is not available, indicate “Date/Time not provided”
15
+
16
+ ###### Fallback
17
+ - If fewer than 3 headlines are found, provide what is available and state:
18
+ **“Only X recent headlines found for India.”**
19
+ - Do not fabricate headlines, dates, or URLs
20
+
21
+ ###### Output Style
22
+ - Structured list sorted by **most recent first**
23
+ - Clear and concise formatting as requested
24
+ - Use color and emoji to make it more engaging.
25
+ - Use `<span style="color:...">` for coloring the title if the renderer supports it
26
+ - Keep the output **concise, factual, and visually engaging**
src/chatbot_v1/prompts/market_sentiment.txt ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Act as a **Senior Market Analyst** and provide a concise market sentiment update for the **US Stock Market / S&P 500**.
3
+
4
+ ###### Steps
5
+ 1. **Data Gathering**: Search for the **top 5 financial news headlines** from the last 24 hours related to the [US Stock Market / S&P 500].
6
+ 2. **Market Check**: Retrieve the **current value** and **today’s percentage change** for:
7
+ - **S&P 500 (SPX)**
8
+ - **VIX (Volatility Index)**
9
+ 3. **Synthesis**: Based on the **tone of the news headlines** and the **index performance**, determine whether the **current market sentiment** is:
10
+ - **Bullish**
11
+ - **Bearish**
12
+ - **Neutral**
13
+ 4. **Output**: Provide a:
14
+ - **Sentiment Score (1–10)**
15
+ - **Top 3 key drivers** influencing this sentiment
16
+
17
+ ###### Guidelines
18
+ - Prioritize **reliable financial news sources** (e.g., Bloomberg, Reuters, WSJ, CNBC)
19
+ - Use **accurate, real-time market data** for indices
20
+ - Base sentiment on both **news tone** and **market movement**
21
+ - Avoid subjective or unsupported judgments
22
+
23
+ ###### Fallback
24
+ - If no relevant financial headlines are found in the last 24 hours, clearly state:
25
+ **“No significant market news available in the last 24 hours.”**
26
+ - If either index value or change is unavailable, report available data and note missing values explicitly
27
+ - Do not invent or estimate values — only use verified data
28
+
29
+ ###### Output Style
30
+ - Concise, factual, and structured
31
+ - Use clear bullet points or short paragraphs
32
+ - Include numerical values and data timestamps
33
+ - Provide **sources for headlines and index data**
34
+ - Use color and emoji to make it more engaging.
src/chatbot_v1/prompts/news_headlines.txt ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Tell me the **top 3 USA headlines**. Use **emojis** and, where supported, **HTML color tags** to make the output engaging.
3
+
4
+ ###### For each headline, provide:
5
+ - **Title in bold** and optionally in color, e.g., `<span style="color:blue">Title</span>`
6
+ - A **3-line summary** with an emoji indicating the type of news:
7
+ - 📰 Politics
8
+ - 💼 Business
9
+ - 🌎 World
10
+ - ⚡ Breaking news
11
+ - **Publish date and time** (UTC)
12
+ - A **link to the exact source URL**
13
+
14
+ ###### Requirements
15
+ - Use **credible news sources** (Reuters, AP, BBC, Guardian, etc.)
16
+ - Headlines should be **recent (last 24 hours)**
17
+ - If publish time is unavailable, indicate **“Time not provided”**
18
+
19
+ ###### Fallback
20
+ - If fewer than 3 headlines are found, state:
21
+ **“Only X recent headlines found for the USA.”**
22
+ - Do not fabricate headlines, dates, or URLs
23
+
24
+ ###### Output Style
25
+ - Structured list sorted by **most recent first**
26
+ - Use emojis consistently to indicate news type
27
+ - Use `<span style="color:...">` for coloring the title if the renderer supports it
28
+ - Keep the output **concise, factual, and visually engaging**
src/chatbot_v1/prompts/odia_news.txt ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Tell me the **top 3 headlines from Odisha**.
3
+
4
+ ###### For each headline, provide:
5
+ - **Title in bold**
6
+ - A **3‑line summary**
7
+ - **Publish date and time**
8
+ - A **link to the exact source URL**
9
+
10
+ ###### Requirements
11
+ - Use authoritative news sources (e.g., major national/regional news outlets)
12
+ - Headlines should be **recent (last 24 hours)**
13
+ - Provide timestamps in **UTC**
14
+ - If publish date/time is not available, indicate “Date/Time not provided”
15
+
16
+ ###### Fallback
17
+ - If fewer than 3 headlines are found, provide what is available and state:
18
+ **“Only X recent headlines found for Odisha.”**
19
+ - Do not fabricate headlines, dates, or URLs
20
+
21
+ ###### Output Style
22
+ - Structured list sorted by **most recent first**
23
+ - Clear and concise formatting as requested
24
+ - Use color and emoji to make it more engaging.
25
+ - Use `<span style="color:...">` for coloring the title if the renderer supports it
26
+ - Keep the output **concise, factual, and visually engaging**
src/chatbot_v1/prompts/trade_recommendation.txt ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Recommend **three option spreads** with **>80% probability of profit**. Perform a thorough analysis of each underlying’s **3-month price trend** and current **market sentiment** before selecting spreads.
3
+
4
+ ###### Steps
5
+ 1. **Stock selection & analysis**
6
+ - Analyze the **last 3 months** of price action (trend, volatility, support/resistance).
7
+ - Assess market sentiment from the **last 7 days** of headlines and social/analyst tone.
8
+ 2. **Spread construction**
9
+ - For each of the **3 recommended spreads**, specify:
10
+ - **Underlying ticker**
11
+ - **Spread type** (e.g., bull put, bear call, iron condor)
12
+ - **Exact expiry date** (YYYY-MM-DD)
13
+ - **Each leg**: side (sell/buy), option type (put/call), **strike price**
14
+ - **Premium entry**: exact net credit/debit per share (use live bid/ask midpoint)
15
+ - **Position size guidance** (risk per trade as % of portfolio) — optional
16
+ 3. **Probability & rationale**
17
+ - Provide a **quantitative probability of profit (%)** (clearly state model/method used).
18
+ - Give a concise **rationale** linking 3-month trend, implied volatility, and sentiment to the spread choice.
19
+ - Show key supporting numbers: current spot, IV30, recent volatility, and relevant news headlines (with timestamps).
20
+
21
+ ###### Requirements / Guidelines
22
+ - Target **>80% probability of profit** for each spread. Explain how the probability was computed (IV-based log-normal, normal approximation, or risk-neutral model).
23
+ - **Always** use live option-chain quotes (bid/ask midpoint) and authoritative sources for prices/IV (e.g., exchange data, major market data providers).
24
+ - Compare outcomes **vs. forecasts / recent range** and note any idiosyncratic risk (earnings, events).
25
+ - Include **exact timestamps** (UTC) for all quoted prices.
26
+ - Provide **sources** for price, IV, and headlines.
27
+
28
+ ###### Fallback
29
+ - If live option-chain or price data is unavailable, state: **“Live market data unavailable — cannot generate exact strike/premium. Provide analysis based on most recent available snapshot.”**
30
+ - If sentiment or 3-month history is incomplete, present what is available and **explicitly list missing items**.
31
+ - **Do not fabricate** strikes, premiums, probabilities, or news — only use verified data.
32
+
33
+ ###### Output Style
34
+ - For each spread, use a compact block with:
35
+ - Ticker — Spread type — Expiry (YYYY-MM-DD) — Net premium — PO P (%)
36
+ - Legs: bullet list of exact leg details (sell/buy, put/call, strike, premium)
37
+ - Rationale: 2–3 short sentences linking trend & sentiment to the trade
38
+ - Sources & timestamps
39
+ - Keep language concise, factual, and machine/agent friendly for downstream parsing.
40
+ - Use color and emoji to make it more engaging.
src/chatbot_v1/prompts/upcoming_earnings.txt ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##### Task
2
+ Search for **upcoming critical earnings announcements** in the stock market.
3
+
4
+ ###### Include
5
+ - **Ticker**
6
+ - **Company name**
7
+ - **Earnings date & time**
8
+ - **Expected EPS & revenue consensus**
9
+ - **Last quarter’s actual EPS & revenue**
10
+ - **Implied volatility trend ahead of earnings**
11
+
12
+ ###### Requirements / Guidelines
13
+ - Focus on **high‑impact names** (large cap, high volume, sector leaders)
14
+ - Include **earnings expected within the next 7 calendar days**
15
+ - Use **primary/authoritative sources** for earnings dates and estimates (e.g., exchange calendars, Bloomberg/Refinitiv/Estimize)
16
+ - Show **timestamped data** (UTC)
17
+
18
+ ###### Fallback
19
+ - If no critical earnings are found in the next 7 days, state:
20
+ **“No upcoming critical earnings announcements found within the specified period.”**
21
+ - If consensus estimates are unavailable, list the earnings date/time and note missing metrics.
22
+
23
+ ###### Output Style
24
+ - Structured list sorted by **earnings date**
25
+ - Use clear bullet points or short paragraphs
26
+ - Provide **sources** for each item
27
+ - Use color and emoji to make it more engaging.
src/chatbot_v1/trace_config.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # trace_config.py
2
+ import openai
3
+ from langsmith.wrappers import wrap_openai
4
+ import os
5
+
6
+ print("🔌 APPLYING LANGSMITH TRACE PATCH...")
7
+
8
+ # 1. Save original classes
9
+ _OriginalOpenAI = openai.OpenAI
10
+ _OriginalAsyncOpenAI = openai.AsyncOpenAI
11
+
12
+ # 2. Define the shim
13
+ def PatchedOpenAI(*args, **kwargs):
14
+ print("✨ Creating Wrapped OpenAI Client (Sync)") # Debug print
15
+ client = _OriginalOpenAI(*args, **kwargs)
16
+ return wrap_openai(client)
17
+
18
+ def PatchedAsyncOpenAI(*args, **kwargs):
19
+ print("✨ Creating Wrapped OpenAI Client (Async)") # Debug print
20
+ client = _OriginalAsyncOpenAI(*args, **kwargs)
21
+ return wrap_openai(client)
22
+
23
+ # 3. Apply patch
24
+ openai.OpenAI = PatchedOpenAI
25
+ openai.AsyncOpenAI = PatchedAsyncOpenAI
26
+
27
+ from langsmith import traceable
28
+
29
+ # You can't decorate the class directly with @traceable,
30
+ # but you can use this helper to wrap all methods:
31
+
32
+ def instrument_class(cls):
33
+ for attr_name, attr_value in cls.__dict__.items():
34
+ if callable(attr_value) and not attr_name.startswith("__"):
35
+ setattr(cls, attr_name, traceable(attr_value, run_type="tool"))
36
+ return cls
37
+
uv.lock CHANGED
@@ -15,6 +15,10 @@ dependencies = [
15
  { name = "autogen-agentchat" },
16
  { name = "autogen-ext", extra = ["grpc", "mcp", "openai"] },
17
  { name = "azure-identity" },
 
 
 
 
18
  { name = "beautifulsoup4" },
19
  { name = "chromadb" },
20
  { name = "datasets" },
@@ -61,11 +65,13 @@ dependencies = [
61
  { name = "opentelemetry-api" },
62
  { name = "opentelemetry-exporter-otlp" },
63
  { name = "opentelemetry-sdk" },
 
64
  { name = "pillow" },
65
  { name = "playwright" },
66
  { name = "plotly" },
67
  { name = "polygon-api-client" },
68
  { name = "psutil" },
 
69
  { name = "pymupdf" },
70
  { name = "pypdf" },
71
  { name = "pypdf2" },
@@ -103,6 +109,10 @@ requires-dist = [
103
  { name = "autogen-agentchat", specifier = "==0.4.7" },
104
  { name = "autogen-ext", extras = ["grpc", "mcp", "ollama", "openai"], specifier = "==0.4.7" },
105
  { name = "azure-identity", specifier = ">=1.25.1" },
 
 
 
 
106
  { name = "beautifulsoup4", specifier = ">=4.12.3" },
107
  { name = "chromadb", specifier = ">=0.4.0" },
108
  { name = "datasets", specifier = ">=4.4.1" },
@@ -149,11 +159,13 @@ requires-dist = [
149
  { name = "opentelemetry-api", specifier = ">=1.20.0" },
150
  { name = "opentelemetry-exporter-otlp", specifier = ">=1.20.0" },
151
  { name = "opentelemetry-sdk", specifier = ">=1.20.0" },
 
152
  { name = "pillow" },
153
  { name = "playwright", specifier = ">=1.51.0" },
154
  { name = "plotly", specifier = ">=6.5.0" },
155
  { name = "polygon-api-client", specifier = ">=1.16.3" },
156
  { name = "psutil", specifier = ">=7.0.0" },
 
157
  { name = "pymupdf" },
158
  { name = "pypdf", specifier = ">=6.3.0" },
159
  { name = "pypdf2", specifier = ">=3.0.1" },
@@ -446,6 +458,15 @@ openai = [
446
  { name = "tiktoken" },
447
  ]
448
 
 
 
 
 
 
 
 
 
 
449
  [[package]]
450
  name = "azure-core"
451
  version = "1.38.0"
@@ -475,6 +496,75 @@ wheels = [
475
  { url = "https://files.pythonhosted.org/packages/83/7b/5652771e24fff12da9dde4c20ecf4682e606b104f26419d139758cc935a6/azure_identity-1.25.1-py3-none-any.whl", hash = "sha256:e9edd720af03dff020223cd269fa3a61e8f345ea75443858273bcb44844ab651", size = 191317, upload-time = "2025-10-06T20:30:04.251Z" },
476
  ]
477
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  [[package]]
479
  name = "backoff"
480
  version = "2.2.1"
@@ -1632,6 +1722,15 @@ wheels = [
1632
  { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
1633
  ]
1634
 
 
 
 
 
 
 
 
 
 
1635
  [[package]]
1636
  name = "jedi"
1637
  version = "0.19.2"
@@ -3594,6 +3693,28 @@ wheels = [
3594
  { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" },
3595
  ]
3596
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3597
  [[package]]
3598
  name = "pillow"
3599
  version = "12.1.0"
@@ -3971,6 +4092,22 @@ wheels = [
3971
  { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" },
3972
  ]
3973
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3974
  [[package]]
3975
  name = "pygments"
3976
  version = "2.19.2"
@@ -4009,6 +4146,29 @@ wheels = [
4009
  { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952, upload-time = "2025-12-11T21:48:02.947Z" },
4010
  ]
4011
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4012
  [[package]]
4013
  name = "pyparsing"
4014
  version = "3.3.2"
@@ -4744,6 +4904,24 @@ wheels = [
4744
  { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
4745
  ]
4746
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4747
  [[package]]
4748
  name = "torch"
4749
  version = "2.10.0"
@@ -4775,6 +4953,7 @@ dependencies = [
4775
  { name = "typing-extensions" },
4776
  ]
4777
  wheels = [
 
4778
  { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" },
4779
  { url = "https://files.pythonhosted.org/packages/23/8e/3c74db5e53bff7ed9e34c8123e6a8bfef718b2450c35eefab85bb4a7e270/torch-2.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb", size = 915711952, upload-time = "2026-01-21T16:23:53.503Z" },
4780
  { url = "https://files.pythonhosted.org/packages/6e/01/624c4324ca01f66ae4c7cd1b74eb16fb52596dce66dbe51eff95ef9e7a4c/torch-2.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547", size = 113757972, upload-time = "2026-01-21T16:24:39.516Z" },
 
15
  { name = "autogen-agentchat" },
16
  { name = "autogen-ext", extra = ["grpc", "mcp", "openai"] },
17
  { name = "azure-identity" },
18
+ { name = "azure-mgmt-compute" },
19
+ { name = "azure-mgmt-monitor" },
20
+ { name = "azure-mgmt-resource" },
21
+ { name = "azure-monitor-query" },
22
  { name = "beautifulsoup4" },
23
  { name = "chromadb" },
24
  { name = "datasets" },
 
65
  { name = "opentelemetry-api" },
66
  { name = "opentelemetry-exporter-otlp" },
67
  { name = "opentelemetry-sdk" },
68
+ { name = "phidata" },
69
  { name = "pillow" },
70
  { name = "playwright" },
71
  { name = "plotly" },
72
  { name = "polygon-api-client" },
73
  { name = "psutil" },
74
+ { name = "pygithub" },
75
  { name = "pymupdf" },
76
  { name = "pypdf" },
77
  { name = "pypdf2" },
 
109
  { name = "autogen-agentchat", specifier = "==0.4.7" },
110
  { name = "autogen-ext", extras = ["grpc", "mcp", "ollama", "openai"], specifier = "==0.4.7" },
111
  { name = "azure-identity", specifier = ">=1.25.1" },
112
+ { name = "azure-mgmt-compute", specifier = ">=30.3.0" },
113
+ { name = "azure-mgmt-monitor", specifier = ">=6.0.2" },
114
+ { name = "azure-mgmt-resource", specifier = ">=23.0.1" },
115
+ { name = "azure-monitor-query", specifier = ">=1.2.0" },
116
  { name = "beautifulsoup4", specifier = ">=4.12.3" },
117
  { name = "chromadb", specifier = ">=0.4.0" },
118
  { name = "datasets", specifier = ">=4.4.1" },
 
159
  { name = "opentelemetry-api", specifier = ">=1.20.0" },
160
  { name = "opentelemetry-exporter-otlp", specifier = ">=1.20.0" },
161
  { name = "opentelemetry-sdk", specifier = ">=1.20.0" },
162
+ { name = "phidata", specifier = ">=2.0.0" },
163
  { name = "pillow" },
164
  { name = "playwright", specifier = ">=1.51.0" },
165
  { name = "plotly", specifier = ">=6.5.0" },
166
  { name = "polygon-api-client", specifier = ">=1.16.3" },
167
  { name = "psutil", specifier = ">=7.0.0" },
168
+ { name = "pygithub", specifier = ">=2.1.1" },
169
  { name = "pymupdf" },
170
  { name = "pypdf", specifier = ">=6.3.0" },
171
  { name = "pypdf2", specifier = ">=3.0.1" },
 
458
  { name = "tiktoken" },
459
  ]
460
 
461
+ [[package]]
462
+ name = "azure-common"
463
+ version = "1.1.28"
464
+ source = { registry = "https://pypi.org/simple" }
465
+ sdist = { url = "https://files.pythonhosted.org/packages/3e/71/f6f71a276e2e69264a97ad39ef850dca0a04fce67b12570730cb38d0ccac/azure-common-1.1.28.zip", hash = "sha256:4ac0cd3214e36b6a1b6a442686722a5d8cc449603aa833f3f0f40bda836704a3", size = 20914, upload-time = "2022-02-03T19:39:44.373Z" }
466
+ wheels = [
467
+ { url = "https://files.pythonhosted.org/packages/62/55/7f118b9c1b23ec15ca05d15a578d8207aa1706bc6f7c87218efffbbf875d/azure_common-1.1.28-py2.py3-none-any.whl", hash = "sha256:5c12d3dcf4ec20599ca6b0d3e09e86e146353d443e7fcc050c9a19c1f9df20ad", size = 14462, upload-time = "2022-02-03T19:39:42.417Z" },
468
+ ]
469
+
470
  [[package]]
471
  name = "azure-core"
472
  version = "1.38.0"
 
496
  { url = "https://files.pythonhosted.org/packages/83/7b/5652771e24fff12da9dde4c20ecf4682e606b104f26419d139758cc935a6/azure_identity-1.25.1-py3-none-any.whl", hash = "sha256:e9edd720af03dff020223cd269fa3a61e8f345ea75443858273bcb44844ab651", size = 191317, upload-time = "2025-10-06T20:30:04.251Z" },
497
  ]
498
 
499
+ [[package]]
500
+ name = "azure-mgmt-compute"
501
+ version = "37.2.0"
502
+ source = { registry = "https://pypi.org/simple" }
503
+ dependencies = [
504
+ { name = "azure-mgmt-core" },
505
+ { name = "isodate" },
506
+ { name = "typing-extensions" },
507
+ ]
508
+ sdist = { url = "https://files.pythonhosted.org/packages/e2/e3/c887e27260754014dc63fc33bf612f1c7f1751f74e80d1aaa32491af3ffa/azure_mgmt_compute-37.2.0.tar.gz", hash = "sha256:23499d4d5ad2b2bf40a4c59df2684cc4c9cef0f9672a4e842bb9a1cf6b62f628", size = 534068, upload-time = "2026-01-27T06:39:05.39Z" }
509
+ wheels = [
510
+ { url = "https://files.pythonhosted.org/packages/be/78/8dcdb92dd9f716d08a3ac6b31c31a12cfcf8c430b2c312cbf9cc6e4695e8/azure_mgmt_compute-37.2.0-py3-none-any.whl", hash = "sha256:70741c26ac94c30408a3b20f4fdfe93e6481e308b3c14a6dbefdfd4794028616", size = 686212, upload-time = "2026-01-27T06:39:07.016Z" },
511
+ ]
512
+
513
+ [[package]]
514
+ name = "azure-mgmt-core"
515
+ version = "1.6.0"
516
+ source = { registry = "https://pypi.org/simple" }
517
+ dependencies = [
518
+ { name = "azure-core" },
519
+ ]
520
+ sdist = { url = "https://files.pythonhosted.org/packages/3e/99/fa9e7551313d8c7099c89ebf3b03cd31beb12e1b498d575aa19bb59a5d04/azure_mgmt_core-1.6.0.tar.gz", hash = "sha256:b26232af857b021e61d813d9f4ae530465255cb10b3dde945ad3743f7a58e79c", size = 30818, upload-time = "2025-07-03T02:02:24.093Z" }
521
+ wheels = [
522
+ { url = "https://files.pythonhosted.org/packages/a0/26/c79f962fd3172b577b6f38685724de58b6b4337a51d3aad316a43a4558c6/azure_mgmt_core-1.6.0-py3-none-any.whl", hash = "sha256:0460d11e85c408b71c727ee1981f74432bc641bb25dfcf1bb4e90a49e776dbc4", size = 29310, upload-time = "2025-07-03T02:02:25.203Z" },
523
+ ]
524
+
525
+ [[package]]
526
+ name = "azure-mgmt-monitor"
527
+ version = "7.0.0"
528
+ source = { registry = "https://pypi.org/simple" }
529
+ dependencies = [
530
+ { name = "azure-common" },
531
+ { name = "azure-mgmt-core" },
532
+ { name = "isodate" },
533
+ { name = "typing-extensions" },
534
+ ]
535
+ sdist = { url = "https://files.pythonhosted.org/packages/0e/12/25874f6b894e972646244f570a23298969b58f57cfb7a188e2740017b43a/azure_mgmt_monitor-7.0.0.tar.gz", hash = "sha256:b75f536441d430f69ff873a1646e5f5dbcb3080a10768a59d0adc01541623816", size = 195496, upload-time = "2025-07-28T07:46:17.031Z" }
536
+ wheels = [
537
+ { url = "https://files.pythonhosted.org/packages/c6/d1/f6ea4731edfa02c14756770d7c3d5202b40c5c72744f15142c0d89b6d957/azure_mgmt_monitor-7.0.0-py3-none-any.whl", hash = "sha256:ad63b5d187e21d2d34366271ade6abbeea1fcf76e313ff0f83d394d9c124aa1b", size = 245243, upload-time = "2025-07-28T07:46:18.594Z" },
538
+ ]
539
+
540
+ [[package]]
541
+ name = "azure-mgmt-resource"
542
+ version = "25.0.0"
543
+ source = { registry = "https://pypi.org/simple" }
544
+ dependencies = [
545
+ { name = "azure-mgmt-core" },
546
+ { name = "isodate" },
547
+ { name = "typing-extensions" },
548
+ ]
549
+ sdist = { url = "https://files.pythonhosted.org/packages/d7/7e/b3f9d544a94782be9c5ab8123d2fa7fb20cbdf3f5a16b883f308865e1406/azure_mgmt_resource-25.0.0.tar.gz", hash = "sha256:dc123a9f6509c37299d7716c9090cff0a9d73309b228cc094ea950ce3cca3603", size = 92837, upload-time = "2026-02-06T06:00:39.699Z" }
550
+ wheels = [
551
+ { url = "https://files.pythonhosted.org/packages/92/41/ce12546aa2a20c4f37d061bfa7df3bf8fa72ff01e7557ec330929c72ec7d/azure_mgmt_resource-25.0.0-py3-none-any.whl", hash = "sha256:f6f17b2305abe9bf6ec6c92a9410af21a2b0d805cc98e94d80c07220924a045b", size = 83670, upload-time = "2026-02-06T06:00:41.317Z" },
552
+ ]
553
+
554
+ [[package]]
555
+ name = "azure-monitor-query"
556
+ version = "2.0.0"
557
+ source = { registry = "https://pypi.org/simple" }
558
+ dependencies = [
559
+ { name = "azure-core" },
560
+ { name = "isodate" },
561
+ { name = "typing-extensions" },
562
+ ]
563
+ sdist = { url = "https://files.pythonhosted.org/packages/04/c0/e5c760f38224575f1eba35c319842f2be30fab599854ba9bd0b19d39c261/azure_monitor_query-2.0.0.tar.gz", hash = "sha256:7b05f2fcac4fb67fc9f77a7d4c5d98a0f3099fb73b57c69ec1b080773994671b", size = 86658, upload-time = "2025-07-30T22:23:41.534Z" }
564
+ wheels = [
565
+ { url = "https://files.pythonhosted.org/packages/52/0c/6b08a5a1e5f0bd97cefa13c53bf47f281a9a11732d19a94a86709acbc6bd/azure_monitor_query-2.0.0-py3-none-any.whl", hash = "sha256:8f52d581271d785e12f49cd5aaa144b8910fb843db2373855a7ef94c7fc462ea", size = 71102, upload-time = "2025-07-30T22:23:43.056Z" },
566
+ ]
567
+
568
  [[package]]
569
  name = "backoff"
570
  version = "2.2.1"
 
1722
  { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
1723
  ]
1724
 
1725
+ [[package]]
1726
+ name = "isodate"
1727
+ version = "0.7.2"
1728
+ source = { registry = "https://pypi.org/simple" }
1729
+ sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705, upload-time = "2024-10-08T23:04:11.5Z" }
1730
+ wheels = [
1731
+ { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320, upload-time = "2024-10-08T23:04:09.501Z" },
1732
+ ]
1733
+
1734
  [[package]]
1735
  name = "jedi"
1736
  version = "0.19.2"
 
3693
  { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" },
3694
  ]
3695
 
3696
+ [[package]]
3697
+ name = "phidata"
3698
+ version = "2.7.10"
3699
+ source = { registry = "https://pypi.org/simple" }
3700
+ dependencies = [
3701
+ { name = "docstring-parser" },
3702
+ { name = "gitpython" },
3703
+ { name = "httpx" },
3704
+ { name = "pydantic" },
3705
+ { name = "pydantic-settings" },
3706
+ { name = "python-dotenv" },
3707
+ { name = "pyyaml" },
3708
+ { name = "rich" },
3709
+ { name = "tomli" },
3710
+ { name = "typer" },
3711
+ { name = "typing-extensions" },
3712
+ ]
3713
+ sdist = { url = "https://files.pythonhosted.org/packages/5c/bc/808d8f82c1be723d51c945bbedca62c68950b3cb294716f309428a9d3be7/phidata-2.7.10.tar.gz", hash = "sha256:d8d01e5e3841bf0df659f57d84a5eb5a8e5271fdf2f2899f6037f54839463482", size = 500479, upload-time = "2025-01-27T14:27:54.142Z" }
3714
+ wheels = [
3715
+ { url = "https://files.pythonhosted.org/packages/90/de/814e0bc3532a9a0ad45c7164ac3a43abfcaac1253e61ad852ae344badc55/phidata-2.7.10-py3-none-any.whl", hash = "sha256:9cb3b2bf790440d644c5443cd20e0ab27dea98e5b7cfed4676a615e1583e2501", size = 716942, upload-time = "2025-01-27T14:27:50.415Z" },
3716
+ ]
3717
+
3718
  [[package]]
3719
  name = "pillow"
3720
  version = "12.1.0"
 
4092
  { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" },
4093
  ]
4094
 
4095
+ [[package]]
4096
+ name = "pygithub"
4097
+ version = "2.8.1"
4098
+ source = { registry = "https://pypi.org/simple" }
4099
+ dependencies = [
4100
+ { name = "pyjwt", extra = ["crypto"] },
4101
+ { name = "pynacl" },
4102
+ { name = "requests" },
4103
+ { name = "typing-extensions" },
4104
+ { name = "urllib3" },
4105
+ ]
4106
+ sdist = { url = "https://files.pythonhosted.org/packages/c1/74/e560bdeffea72ecb26cff27f0fad548bbff5ecc51d6a155311ea7f9e4c4c/pygithub-2.8.1.tar.gz", hash = "sha256:341b7c78521cb07324ff670afd1baa2bf5c286f8d9fd302c1798ba594a5400c9", size = 2246994, upload-time = "2025-09-02T17:41:54.674Z" }
4107
+ wheels = [
4108
+ { url = "https://files.pythonhosted.org/packages/07/ba/7049ce39f653f6140aac4beb53a5aaf08b4407b6a3019aae394c1c5244ff/pygithub-2.8.1-py3-none-any.whl", hash = "sha256:23a0a5bca93baef082e03411bf0ce27204c32be8bfa7abc92fe4a3e132936df0", size = 432709, upload-time = "2025-09-02T17:41:52.947Z" },
4109
+ ]
4110
+
4111
  [[package]]
4112
  name = "pygments"
4113
  version = "2.19.2"
 
4146
  { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952, upload-time = "2025-12-11T21:48:02.947Z" },
4147
  ]
4148
 
4149
+ [[package]]
4150
+ name = "pynacl"
4151
+ version = "1.6.2"
4152
+ source = { registry = "https://pypi.org/simple" }
4153
+ dependencies = [
4154
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
4155
+ ]
4156
+ sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" }
4157
+ wheels = [
4158
+ { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" },
4159
+ { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" },
4160
+ { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" },
4161
+ { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" },
4162
+ { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" },
4163
+ { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" },
4164
+ { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" },
4165
+ { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" },
4166
+ { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" },
4167
+ { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" },
4168
+ { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" },
4169
+ { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" },
4170
+ ]
4171
+
4172
  [[package]]
4173
  name = "pyparsing"
4174
  version = "3.3.2"
 
4904
  { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
4905
  ]
4906
 
4907
+ [[package]]
4908
+ name = "tomli"
4909
+ version = "2.4.0"
4910
+ source = { registry = "https://pypi.org/simple" }
4911
+ sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" }
4912
+ wheels = [
4913
+ { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" },
4914
+ { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" },
4915
+ { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" },
4916
+ { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" },
4917
+ { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" },
4918
+ { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" },
4919
+ { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" },
4920
+ { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" },
4921
+ { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" },
4922
+ { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
4923
+ ]
4924
+
4925
  [[package]]
4926
  name = "torch"
4927
  version = "2.10.0"
 
4953
  { name = "typing-extensions" },
4954
  ]
4955
  wheels = [
4956
+ { url = "https://files.pythonhosted.org/packages/c9/2f/0b295dd8d199ef71e6f176f576473d645d41357b7b8aa978cc6b042575df/torch-2.10.0-1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:6abb224c2b6e9e27b592a1c0015c33a504b00a0e0938f1499f7f514e9b7bfb5c", size = 79498197, upload-time = "2026-02-06T17:37:27.627Z" },
4957
  { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" },
4958
  { url = "https://files.pythonhosted.org/packages/23/8e/3c74db5e53bff7ed9e34c8123e6a8bfef718b2450c35eefab85bb4a7e270/torch-2.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb", size = 915711952, upload-time = "2026-01-21T16:23:53.503Z" },
4959
  { url = "https://files.pythonhosted.org/packages/6e/01/624c4324ca01f66ae4c7cd1b74eb16fb52596dce66dbe51eff95ef9e7a4c/torch-2.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547", size = 113757972, upload-time = "2026-01-21T16:24:39.516Z" },