mishrabp commited on
Commit
716048e
·
verified ·
1 Parent(s): 8e5962b

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/ ./src/chatbot/
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", "--port", "7860"]
 
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
 
33
  EXPOSE 7860
34
 
35
+ CMD ["python", "run.py", "chatbot_v2", "--port", "7860"]
pyproject.toml CHANGED
@@ -33,6 +33,16 @@ dependencies = [
33
  "html2text>=2025.4.15",
34
  "traceloop-sdk>=0.33.0",
35
 
 
 
 
 
 
 
 
 
 
 
36
  # =======================
37
  # VECTOR DB / INDEXING
38
  # =======================
@@ -94,6 +104,11 @@ dependencies = [
94
  "reportlab>=4.4.5",
95
  "fastapi",
96
  "Pillow",
 
 
 
 
 
97
 
98
  # =======================
99
  # AUDIO / VIDEO
 
33
  "html2text>=2025.4.15",
34
  "traceloop-sdk>=0.33.0",
35
 
36
+ # =======================
37
+ # MICROSOFT AGENT FRAMEWORK
38
+ # =======================
39
+ #"agent-framework==1.0.0b251204",
40
+ #"agent-framework-azure-ai==1.0.0b251204",
41
+ #"azure-ai-projects",
42
+ #"azure-ai-agents",
43
+ #"azure-ai-agents>=1.2.0b5",
44
+ #"agent-framework-azure-ai",
45
+
46
  # =======================
47
  # VECTOR DB / INDEXING
48
  # =======================
 
104
  "reportlab>=4.4.5",
105
  "fastapi",
106
  "Pillow",
107
+ "python-docx",
108
+ "matplotlib",
109
+ "fpdf",
110
+ "extra-streamlit-components",
111
+ "nest_asyncio",
112
 
113
  # =======================
114
  # AUDIO / VIDEO
run.py CHANGED
@@ -58,6 +58,11 @@ APP_REGISTRY: Dict[str, Dict[str, str]] = {
58
  "entry": "app.py",
59
  "description": "General Chatbot - Multi-purpose conversational AI"
60
  },
 
 
 
 
 
61
  "accessibility": {
62
  "path": "src/accessibility",
63
  "entry": "app.py",
@@ -77,6 +82,11 @@ APP_REGISTRY: Dict[str, Dict[str, str]] = {
77
  "path": "src/image-generator",
78
  "entry": "app.py",
79
  "description": "Image Generator - Multi-agent image generation tool"
 
 
 
 
 
80
  }
81
  }
82
 
 
58
  "entry": "app.py",
59
  "description": "General Chatbot - Multi-purpose conversational AI"
60
  },
61
+ "chatbot_v2": {
62
+ "path": "src/chatbot_v2",
63
+ "entry": "app.py",
64
+ "description": "Layered Chatbot (ReAct) - Advanced Architecture"
65
+ },
66
  "accessibility": {
67
  "path": "src/accessibility",
68
  "entry": "app.py",
 
82
  "path": "src/image-generator",
83
  "entry": "app.py",
84
  "description": "Image Generator - Multi-agent image generation tool"
85
+ },
86
+ "interview-assistant": {
87
+ "path": "src/interview-assistant",
88
+ "entry": "app.py",
89
+ "description": "Interview Assistant - Multi-agent interview tool"
90
  }
91
  }
92
 
src/chatbot_v2/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_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 && \
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_v2", "--port", "7860"]
src/chatbot_v2/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_v2/app.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ import uuid
4
+ import asyncio
5
+ import logging
6
+ import streamlit as st
7
+
8
+ # Import the new Orchestrator Pattern
9
+ from src.chatbot_v2.patterns.orchestrator import ChatbotOrchestrator
10
+
11
+ # -----------------------------
12
+ # Configuration & Utils
13
+ # -----------------------------
14
+ st.set_page_config(
15
+ page_title="Layered AI Assistant",
16
+ layout="wide",
17
+ page_icon="🧠"
18
+ )
19
+
20
+ def load_prompts(folder="prompts"):
21
+ prompts = []
22
+ prompt_labels = []
23
+ if os.path.exists(folder):
24
+ for file_path in glob.glob(os.path.join(folder, "*.txt")):
25
+ with open(file_path, "r", encoding="utf-8") as f:
26
+ content = f.read().strip()
27
+ if content:
28
+ prompts.append(content)
29
+
30
+ prompt_labels.append(os.path.basename(file_path).replace("_", " ").replace(".txt", "").title())
31
+ return prompts, prompt_labels
32
+
33
+ prompts, prompt_labels = load_prompts()
34
+
35
+ # -----------------------------
36
+ # Session State
37
+ # -----------------------------
38
+ if "messages" not in st.session_state:
39
+ st.session_state.messages = []
40
+
41
+ # Initialize the Agent
42
+ if "agent" not in st.session_state:
43
+ st.session_state.agent = ChatbotOrchestrator()
44
+
45
+ # -----------------------------
46
+ # Premium Styling
47
+ # -----------------------------
48
+ st.markdown("""
49
+ <style>
50
+ /* ---------------------------------------------------------------------
51
+ 1. GLOBAL & RESET
52
+ --------------------------------------------------------------------- */
53
+ * {
54
+ box-sizing: border-box;
55
+ }
56
+
57
+ .stApp, [data-testid="stAppViewContainer"] {
58
+ /* Standard Streamlit background */
59
+ background-color: #f8f9fa;
60
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
61
+ }
62
+
63
+ html {
64
+ -webkit-text-size-adjust: 100%; /* Prevent iOS font boosting */
65
+ }
66
+
67
+ /* ---------------------------------------------------------------------
68
+ 2. LAYOUT & HERO BANNER
69
+ --------------------------------------------------------------------- */
70
+
71
+ /* Mobile font optimization */
72
+ @media (max-width: 768px) {
73
+ /* Target all markdown text specifically */
74
+ .stMarkdown p, .stMarkdown li, .stChatMessage p, .message-content, .stDataFrame, .stTable {
75
+ font-size: 16px !important;
76
+ line-height: 1.6 !important;
77
+ color: #1a1a1a !important;
78
+ }
79
+
80
+ h1, h2, h3, h4, h5, h6 {
81
+ color: #1a1a1a !important;
82
+ }
83
+ }
84
+
85
+ /* Desktop Layout */
86
+ @media (min-width: 769px) {
87
+ .block-container {
88
+ padding-top: 0 !important;
89
+ padding-bottom: 2rem !important;
90
+ padding-left: 5rem !important;
91
+ padding-right: 5rem !important;
92
+ max-width: 100% !important;
93
+ }
94
+
95
+ .hero-container {
96
+ margin-top: -3rem;
97
+ margin-left: -5rem;
98
+ margin-right: -5rem;
99
+ /* Simple negative margins to pull edge-to-edge */
100
+ padding: 2.5rem 1rem 2rem 1rem; /* Compact desktop padding */
101
+ }
102
+ }
103
+
104
+ /* Mobile Layout */
105
+ @media (max-width: 768px) {
106
+ .block-container {
107
+ padding-left: 1rem !important;
108
+ padding-right: 1rem !important;
109
+ padding-top: 0 !important;
110
+ padding-bottom: 0rem !important;
111
+ }
112
+
113
+ .hero-container {
114
+ margin-top: -2rem;
115
+ margin-left: -1rem;
116
+ margin-right: -1rem;
117
+ /* Break out of the 1rem padding */
118
+ padding: 2rem 1rem 1.5rem 1rem; /* Compact mobile padding */
119
+ border-radius: 0 0 12px 12px;
120
+ }
121
+ }
122
+
123
+ /* Hero Styling */
124
+ .hero-container {
125
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
126
+ color: white;
127
+ text-align: center;
128
+ border-radius: 0 0 16px 16px;
129
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
130
+ margin-bottom: 2rem;
131
+ }
132
+
133
+ .hero-title {
134
+ font-size: 2rem; /* Slightly smaller */
135
+ font-weight: 700;
136
+ margin-bottom: 0.25rem;
137
+ color: white !important;
138
+ }
139
+ .hero-subtitle {
140
+ font-size: 1rem;
141
+ opacity: 0.95;
142
+ font-weight: 400;
143
+ color: rgba(255,255,255,0.95) !important;
144
+ }
145
+
146
+ /* Remove Header Decoration */
147
+ header[data-testid="stHeader"] {
148
+ background-color: transparent !important;
149
+ height: 0 !important;
150
+ z-index: 100;
151
+ }
152
+ div[data-testid="stDecoration"] { display: none; }
153
+
154
+ /* ---------------------------------------------------------------------
155
+ 3. COMPONENT STYLING (Healthcare-like)
156
+ --------------------------------------------------------------------- */
157
+
158
+ /* Chat Bubbles - Clean & Readable */
159
+ .stChatMessage {
160
+ background-color: white;
161
+ border-radius: 12px;
162
+ border: 1px solid #e5e5e5;
163
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05);
164
+ padding: 1rem;
165
+ }
166
+
167
+ .stChatMessage[data-testid="stChatMessage"]:nth-of-type(odd) {
168
+ background-color: #f8f9fa;
169
+ }
170
+
171
+ /* Input Fields */
172
+ .stTextInput input {
173
+ border-radius: 20px; /* Matching healthcare-assistant roundness */
174
+ border: 1px solid #ddd;
175
+ padding: 0.75rem 1rem;
176
+ }
177
+
178
+ /* Buttons */
179
+ .stButton button {
180
+ border-radius: 20px; /* Matching healthcare-assistant */
181
+ min-height: 48px;
182
+ font-weight: 500;
183
+ }
184
+
185
+ /* Sidebar */
186
+ section[data-testid="stSidebar"] {
187
+ background-color: #ffffff;
188
+ border-right: 1px solid #eaeaea;
189
+ }
190
+
191
+ /* Minimize Sidebar Top Padding */
192
+ section[data-testid="stSidebar"] .block-container {
193
+ padding-top: 0rem !important;
194
+ padding-bottom: 0rem !important;
195
+ }
196
+ </style>
197
+ """, unsafe_allow_html=True)
198
+
199
+ # -----------------------------
200
+ # Logic
201
+ # -----------------------------
202
+ async def get_ai_response(prompt: str) -> str:
203
+ try:
204
+ agent: ChatbotOrchestrator = st.session_state.agent
205
+
206
+ # We pass the *previous* history (messages excluding the latest one which we just appended)
207
+ # Actually, st.session_state.messages ALREADY has the new user message appended below.
208
+ # So we pass messages[:-1] as "history"
209
+ history = st.session_state.messages[:-1]
210
+
211
+ result = await agent.run(user_input=prompt, external_history=history)
212
+ return result
213
+ except Exception as e:
214
+ return f"❌ **Error**: {str(e)}"
215
+
216
+ # -----------------------------
217
+ # Sidebar - Quick Actions
218
+ # -----------------------------
219
+ with st.sidebar:
220
+ st.markdown("### ⚡ Quick Starters")
221
+ st.markdown("Select a prompt to start:")
222
+
223
+ # We use a trick with st.button to act as input triggers
224
+ # If a button is clicked, we'll handle it in the main loop logic
225
+ selected_prompt = None
226
+ for idx, prompt_text in enumerate(prompts):
227
+ label = prompt_labels[idx] if idx < len(prompt_labels) else f"Prompt {idx+1}"
228
+ if st.button(label, key=f"sidebar_btn_{idx}", use_container_width=True):
229
+ # Reset conversation
230
+ st.session_state.messages = []
231
+ st.session_state.agent = ChatbotOrchestrator() # Reset agent memory too
232
+ selected_prompt = prompt_text
233
+
234
+ st.markdown("---")
235
+ if st.button("🗑️ Clear Conversation", use_container_width=True):
236
+ st.session_state.messages = []
237
+ st.session_state.agent = ChatbotOrchestrator()
238
+ st.rerun()
239
+
240
+ # -----------------------------
241
+ # Main Content
242
+ # -----------------------------
243
+
244
+ # Hero Banner (Always visible & Sticky)
245
+ st.markdown("""
246
+ <div class="hero-container" role="banner">
247
+ <div class="hero-title">🧠 Layered AI Agent</div>
248
+ <div class="hero-subtitle">Architecture: Perception ➜ Cognition ➜ Action</div>
249
+ </div>
250
+ """, unsafe_allow_html=True)
251
+
252
+ # Display Chat History
253
+ for message in st.session_state.messages:
254
+ with st.chat_message(message["role"]):
255
+ st.markdown(message["content"], unsafe_allow_html=True)
256
+
257
+ # Chat Input Handling
258
+ # We handle both the chat input widget and the sidebar selection here
259
+ if prompt := (st.chat_input("Type your message...") or selected_prompt):
260
+ # User Message
261
+ st.session_state.messages.append({"role": "user", "content": prompt})
262
+ with st.chat_message("user"):
263
+ st.markdown(prompt)
264
+
265
+ # Assistant Response
266
+ with st.chat_message("assistant"):
267
+ with st.spinner("🧠 Thinking (Layers Active)..."):
268
+ response_text = asyncio.run(get_ai_response(prompt))
269
+ st.markdown(response_text, unsafe_allow_html=True)
270
+
271
+ st.session_state.messages.append({"role": "assistant", "content": response_text})
272
+
273
+ if selected_prompt:
274
+ st.rerun()
src/chatbot_v2/core/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+
2
+ from .model import get_model_client
3
+
4
+ __all__ = ["get_model_client"]
src/chatbot_v2/core/model.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from common.utility.openai_model_factory import OpenAIModelFactory
2
+
3
+ def get_model_client(provider:str = "openai"):
4
+ if provider.lower() == "google":
5
+ return OpenAIModelFactory.get_model(
6
+ provider="google",
7
+ model_name="gemini-2.5-flash",
8
+ temperature=0
9
+ )
10
+ elif provider.lower() == "openai":
11
+ return OpenAIModelFactory.get_model(
12
+ provider="openai",
13
+ model_name="gpt-4o-mini",
14
+ temperature=0
15
+ )
16
+ elif provider.lower() == "azure":
17
+ return OpenAIModelFactory.get_model(
18
+ provider="azure",
19
+ model_name="gpt-4o-mini",
20
+ temperature=0
21
+ )
22
+ elif provider.lower() == "groq":
23
+ return OpenAIModelFactory.get_model(
24
+ provider="groq",
25
+ model_name="gpt-4o-mini",
26
+ temperature=0
27
+ )
28
+ elif provider.lower() == "ollama":
29
+ return OpenAIModelFactory.get_model(
30
+ provider="ollama",
31
+ model_name="gpt-4o-mini",
32
+ temperature=0
33
+ )
34
+ else:
35
+ raise ValueError(f"Unsupported provider: {provider}")
36
+
src/chatbot_v2/layers/__init__.py ADDED
File without changes
src/chatbot_v2/layers/action.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ from typing import Any, Dict, List
3
+ from agents import Runner
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
+
8
+ class ActionLayer:
9
+ """
10
+ The 'Hands' of the agent.
11
+ Responsibility: Execute specific, well-defined tools or side-effects.
12
+ Does NOT reason about 'why'.
13
+ """
14
+
15
+ def __init__(self):
16
+ # Register available tools
17
+ self.tools = {
18
+ "web_search": self._tool_web_search,
19
+ "financial_data": self._tool_financial_data,
20
+ "news_search": self._tool_news_search,
21
+ "broadcast_research": self._tool_broadcast_research
22
+ }
23
+
24
+ async def execute(self, tool_name: str, args: Dict[str, Any]) -> str:
25
+ if tool_name not in self.tools:
26
+ return f"Error: Tool '{tool_name}' not found."
27
+
28
+ print(f"[Action] Executing tool: {tool_name} with args: {args}")
29
+ try:
30
+ return await self.tools[tool_name](**args)
31
+ except Exception as e:
32
+ return f"Error executing {tool_name}: {str(e)}"
33
+
34
+ async def _tool_web_search(self, query: str) -> str:
35
+ result = await Runner.run(search_agent, query)
36
+ return f"Web Search Result:\n{result.final_output}"
37
+
38
+ async def _tool_financial_data(self, query: str) -> str:
39
+ result = await Runner.run(yf_agent, query)
40
+ return f"Financial Data:\n{result.final_output}"
41
+
42
+ async def _tool_news_search(self, query: str) -> str:
43
+ result = await Runner.run(news_agent, query)
44
+ return f"News Result:\n{result.final_output}"
45
+
46
+ async def _tool_broadcast_research(self, query: str, include_finance: bool = True, include_news: bool = True, include_search: bool = True) -> str:
47
+ """
48
+ Broadcasts the search query to selected specialized agents in parallel and aggregates their responses.
49
+ """
50
+ active_agents = []
51
+ if include_finance: active_agents.append(("YahooFinanceAgent", Runner.run(yf_agent, query)))
52
+ if include_news: active_agents.append(("NewsAgent", Runner.run(news_agent, query)))
53
+ if include_search: active_agents.append(("WebSearchAgent", Runner.run(search_agent, query)))
54
+
55
+ if not active_agents:
56
+ return "No agents were selected for this query."
57
+
58
+ # Run in parallel
59
+ agent_names = [name for name, _ in active_agents]
60
+ coroutines = [coro for _, coro in active_agents]
61
+
62
+ results = await asyncio.gather(*coroutines, return_exceptions=True)
63
+
64
+ outputs = []
65
+ for name, res in zip(agent_names, results):
66
+ if isinstance(res, Exception):
67
+ outputs.append(f"❌ {name} Error: {str(res)}")
68
+ else:
69
+ outputs.append(f"✅ {name} Report:\n{res.final_output}")
70
+
71
+ return "\n--- START OF AGENT REPORTS ---\n\n" + "\n\n-----------------------------------\n\n".join(outputs) + "\n\n--- END OF AGENT REPORTS ---"
src/chatbot_v2/layers/cognition.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from typing import List, Dict, Optional
4
+ from common.utility.openai_model_factory import OpenAIModelFactory
5
+ from openai import OpenAI, AsyncOpenAI
6
+
7
+ class CognitiveOutput:
8
+ def __init__(self, thought: str, action: Optional[str] = None, action_input: Optional[Dict] = None, final_answer: Optional[str] = None):
9
+ self.thought = thought
10
+ self.action = action
11
+ self.action_input = action_input
12
+ self.final_answer = final_answer
13
+
14
+ class CognitionLayer:
15
+ """
16
+ The 'Brain' of the agent.
17
+ Uses OpenAI GPT-4o (via OpenAIModelFactory) to reason and decide which tools to use.
18
+ """
19
+
20
+
21
+ def __init__(self):
22
+ # Direct OpenAI client usage for maximum compatibility
23
+ # We circumvent the factory wrapper to access the raw client directly for JSON mode
24
+ api_key = os.environ.get("OPENAI_API_KEY")
25
+ self.client = OpenAI(api_key=api_key) if api_key else None
26
+
27
+ # If we wanted to use the factory strictly, we'd need to know the exact internal attribute
28
+ # self.model_wrapper = OpenAIModelFactory.get_model(...)
29
+ # self.client = self.model_wrapper.client # guessing 'client' vs 'openai_client'
30
+ # But to be safe and fix the user's error immediately:
31
+ from openai import AsyncOpenAI
32
+ self.client = AsyncOpenAI(api_key=api_key)
33
+
34
+ self.model_name = "gpt-4o"
35
+
36
+ self.system_prompt = """
37
+ You are the **AI Chat Orchestrator**.
38
+ Your goal is to provide a comprehensive, multi-perspective answer by synthesizing data from specialized sub-agents.
39
+
40
+ **Available Tools**:
41
+ 1. `broadcast_research(query: str, include_finance: bool, include_news: bool, include_search: bool)`:
42
+ Broadcasts the query to specialized agents (Finance, News, Web Search). Use this for complex queries needing external info.
43
+ 2. `web_search(query: str)`: Single web search.
44
+ 3. `financial_data(query: str)`: Single financial check.
45
+ 4. `news_search(query: str)`: Single news check.
46
+
47
+ **Workflow**:
48
+ 1. **Analyze Request**: Understand the user's question.
49
+ 2. **Determine Needs**: Decide calls are needed.
50
+ * **Finance**: For stock prices, market trends, company financials.
51
+ * **News**: For recent events, headlines.
52
+ * **Web Search**: For general knowledge, history.
53
+ 3. **Action**:
54
+ If you need external info, PREFER `broadcast_research` to query multiple sources in parallel.
55
+ If it's a simple greeting or general chat not requiring data, just answer.
56
+ 4. **Synthesize Results**:
57
+ When you receive tool outputs ("Agent Reports"), combine them into a clear, professional summary.
58
+ Do NOT simply paste the reports. Synthesize them.
59
+
60
+ **Output Format**:
61
+ You must output valid JSON only:
62
+ {
63
+ "thought": "Reasoning...",
64
+ "action": "tool_name_or_null",
65
+ "action_input": { "arg": "value" } or null,
66
+ "final_answer": "Final output to user" or null
67
+ }
68
+ """
69
+
70
+ async def decide(self, history: List[Dict[str, str]]) -> CognitiveOutput:
71
+ # 1. Construct Messages
72
+ messages = [{"role": "system", "content": self.system_prompt}]
73
+
74
+ for entry in history:
75
+ role = entry['role']
76
+ content = entry['content']
77
+
78
+ # Map roles. 'system' in our history layer usually means tool output.
79
+ if role == 'user':
80
+ messages.append({"role": "user", "content": content})
81
+ elif role == 'assistant':
82
+ messages.append({"role": "assistant", "content": content})
83
+ elif role == 'system':
84
+ messages.append({"role": "user", "content": f"Observation/Tool Output: {content}"})
85
+
86
+ # 2. Call LLM (Async)
87
+ try:
88
+ completion = await self.client.chat.completions.create(
89
+ model=self.model_name,
90
+ messages=messages,
91
+ response_format={"type": "json_object"}
92
+ )
93
+
94
+ response_text = completion.choices[0].message.content
95
+ if response_text.startswith("```"):
96
+ response_text = response_text.strip("`").replace("json", "").strip()
97
+
98
+ data = json.loads(response_text)
99
+
100
+ return CognitiveOutput(
101
+ thought=data.get("thought", ""),
102
+ action=data.get("action"),
103
+ action_input=data.get("action_input"),
104
+ final_answer=data.get("final_answer")
105
+ )
106
+
107
+ except Exception as e:
108
+ return CognitiveOutput(
109
+ thought=f"Error: {str(e)}",
110
+ final_answer="I encountered an error processing your request."
111
+ )
src/chatbot_v2/layers/memory.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Dict
2
+
3
+ class MemoryLayer:
4
+ """
5
+ The 'Memory' of the agent.
6
+ Responsibility: Store and retrieve conversation history.
7
+ """
8
+
9
+ def __init__(self):
10
+ self.history: List[Dict[str, str]] = []
11
+
12
+ def add_entry(self, role: str, content: str):
13
+ self.history.append({"role": role, "content": content})
14
+
15
+ def get_history(self) -> List[Dict[str, str]]:
16
+ return self.history
17
+
18
+ def set_history(self, messages: List[Dict[str, str]]):
19
+ """Allows initializing/overwriting memory from external source (e.g. Streamlit session)"""
20
+ self.history = messages
src/chatbot_v2/layers/perception.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import datetime
4
+ from dataclasses import dataclass
5
+ from openai import OpenAI
6
+
7
+ @dataclass
8
+ class EnvironmentState:
9
+ user_input: str
10
+ timestamp: str
11
+ source: str
12
+
13
+ class PerceptionLayer:
14
+ """
15
+ The 'Sensors' of the agent.
16
+ Responsibility: Accept raw data, clean it, validate it (Guardrails), and package it.
17
+ """
18
+
19
+ def __init__(self):
20
+ api_key = os.environ.get("OPENAI_API_KEY")
21
+ self.client = OpenAI(api_key=api_key) if api_key else None
22
+ self.model_name = "gpt-4o"
23
+
24
+ def perceive(self, raw_text: str, source: str = "user_input") -> EnvironmentState:
25
+ # 1. Basic Cleaning
26
+ clean_text = raw_text.strip()
27
+
28
+ # 2. Guardrail Check (Input Validation)
29
+ # We run this BEFORE accepting the input into the system state.
30
+ if self.client and clean_text:
31
+ validation = self._run_guardrail(clean_text)
32
+ if not validation["is_valid"]:
33
+ raise ValueError(f"Guardrail tripped: {validation['reasoning']}")
34
+
35
+ return EnvironmentState(
36
+ user_input=clean_text,
37
+ timestamp=datetime.datetime.now().isoformat(),
38
+ source=source
39
+ )
40
+
41
+ def _run_guardrail(self, text: str) -> dict:
42
+ """
43
+ Validates if logic contains unparliamentary language.
44
+ """
45
+ system_prompt = """
46
+ You are a highly efficient Guardrail Agent.
47
+
48
+ **Goal**: Validate that the user input is safe and polite.
49
+
50
+ **PASS / VALID Criteria**:
51
+ - The input is technical, professional, or casual.
52
+ - The input contains complex instructions, code features, or formatting instructions.
53
+ - The input is a valid request for information or action.
54
+
55
+ **FAIL / INVALID Criteria**:
56
+ - The input contains HATE SPEECH, EXPLICIT PROFANITY, or THREATS.
57
+ - The input is aggressive, insulting, or unparliamentary.
58
+
59
+ **Output Format**:
60
+ Return JSON only: { "is_valid": boolean, "reasoning": string }
61
+
62
+ If unsure, lean towards VALID.
63
+ """
64
+
65
+ try:
66
+ response = self.client.chat.completions.create(
67
+ model=self.model_name,
68
+ messages=[
69
+ {"role": "system", "content": system_prompt},
70
+ {"role": "user", "content": text}
71
+ ],
72
+ response_format={"type": "json_object"}
73
+ )
74
+ content = response.choices[0].message.content
75
+ return json.loads(content)
76
+ except Exception as e:
77
+ # On failure, fail open or closed? Let's log and allow for now to prevent blocking on API errors.
78
+ print(f"Guardrail check failed: {e}")
79
+ return {"is_valid": True, "reasoning": "Guardrail check failed, allowing input."}
src/chatbot_v2/patterns/__init__.py ADDED
File without changes
src/chatbot_v2/patterns/orchestrator.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.chatbot_v2.layers.perception import PerceptionLayer
2
+ from src.chatbot_v2.layers.cognition import CognitionLayer, CognitiveOutput
3
+ from src.chatbot_v2.layers.action import ActionLayer
4
+ from src.chatbot_v2.layers.memory import MemoryLayer
5
+ from typing import List, Dict
6
+
7
+ class ChatbotOrchestrator:
8
+ """
9
+ DESIGN PATTERN: ReAct (Reason + Act) - Orchestrator
10
+
11
+ Structure:
12
+ 1. Loop:
13
+ - Update Perception
14
+ - Consult Cognition (Reasoning)
15
+ - If Action needed -> Call Action Layer -> Loop
16
+ - If Final Answer -> Return
17
+ """
18
+
19
+ def __init__(self):
20
+ # Initialize the 'Organs' (Layers)
21
+ self.perception = PerceptionLayer()
22
+ self.brain = CognitionLayer()
23
+ self.hands = ActionLayer()
24
+ self.memory = MemoryLayer()
25
+
26
+ async def run(self, user_input: str, external_history: List[Dict[str, str]] = None):
27
+ """
28
+ Runs the agent loop.
29
+ Args:
30
+ user_input: The new message from the user.
31
+ external_history: Existing chat history (e.g. from Streamlit).
32
+ """
33
+ # 1. Sync Memory
34
+ if external_history:
35
+ self.memory.set_history(list(external_history)) # Copy
36
+
37
+ # 2. Perception Layer (Input)
38
+ env_state = self.perception.perceive(user_input)
39
+ self.memory.add_entry("user", env_state.user_input)
40
+
41
+ # Max steps to prevent infinite loops
42
+ for step in range(5):
43
+ print(f"\n--- Step {step+1} (ReAct Loop) ---")
44
+
45
+ # 3. Cognition Layer (Reasoning)
46
+ history = self.memory.get_history()
47
+ decision: CognitiveOutput = await self.brain.decide(history)
48
+
49
+ print(f"[Think]: {decision.thought}")
50
+
51
+ # 4. Handling Decision
52
+ if decision.final_answer:
53
+ print(f"[Final Answer]: {decision.final_answer}")
54
+ self.memory.add_entry("assistant", decision.final_answer)
55
+ return decision.final_answer
56
+
57
+ if decision.action:
58
+ # 5. Action Layer (Execution)
59
+ print(f"[Action Needed]: Call {decision.action} with {decision.action_input}")
60
+ tool_result = await self.hands.execute(decision.action, decision.action_input or {})
61
+
62
+ # 6. Feedback Loop
63
+ print(f"[Observation]: {tool_result}")
64
+ self.memory.add_entry("system", f"Tool {decision.action} returned: {tool_result}")
65
+
66
+ return "I apologize, but I got stuck in a loop trying to answer your request."
src/chatbot_v2/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_v2/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_v2/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_v2/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_v2/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_v2/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_v2/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_v2/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_v2/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
The diff for this file is too large to render. See raw diff