Upload folder using huggingface_hub
Browse files- README.md +28 -64
- pyproject.toml +12 -14
- run.py +23 -203
- src/agora/Dockerfile +63 -0
- src/agora/README.md +28 -0
- src/agora/backend/__init__.py +0 -0
- src/agora/backend/aagents/__init__.py +0 -0
- src/agora/backend/aagents/fundamental_analyst.py +62 -0
- src/agora/backend/aagents/market_analyst.py +49 -0
- src/agora/backend/aagents/orchestrator.py +33 -0
- src/agora/backend/aagents/risk_manager.py +54 -0
- src/agora/backend/aagents/sentiment_analyst.py +43 -0
- src/agora/backend/aagents/strategy_advisor.py +67 -0
- src/agora/backend/aagents/volatility_analyst.py +41 -0
- src/agora/backend/main.py +141 -0
- src/agora/backend/requirements.txt +12 -0
- src/agora/backend/teams/__init__.py +0 -0
- src/agora/backend/teams/team.py +158 -0
- src/agora/backend/tools/__init__.py +0 -0
- src/agora/backend/tools/market_data.py +454 -0
- src/agora/backend/tools/news_data.py +171 -0
- src/agora/backend/tools/pl_calculator.py +98 -0
- src/agora/backend/utility/__init__.py +0 -0
- src/agora/backend/utility/autogen_model_factory.py +112 -0
- src/agora/frontend/.gitignore +24 -0
- src/agora/frontend/.vscode/extensions.json +3 -0
- src/agora/frontend/README.md +5 -0
- src/agora/frontend/index.html +13 -0
- src/agora/frontend/package-lock.json +1627 -0
- src/agora/frontend/package.json +20 -0
- src/agora/frontend/public/favicon.svg +5 -0
- src/agora/frontend/public/vite.svg +1 -0
- src/agora/frontend/src/App.vue +1888 -0
- src/agora/frontend/src/assets/vue.svg +1 -0
- src/agora/frontend/src/components/HelloWorld.vue +43 -0
- src/agora/frontend/src/main.js +5 -0
- src/agora/frontend/src/style.css +118 -0
- src/agora/frontend/vite.config.js +7 -0
- uv.lock +157 -161
README.md
CHANGED
|
@@ -1,64 +1,28 @@
|
|
| 1 |
-
---
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
---
|
| 12 |
-
|
| 13 |
-
#
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
##
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
- **
|
| 21 |
-
- **
|
| 22 |
-
- **
|
| 23 |
-
|
| 24 |
-
##
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
---
|
| 30 |
-
|
| 31 |
-
## 🚀 Getting Started
|
| 32 |
-
|
| 33 |
-
### 1. Run the Backend
|
| 34 |
-
```bash
|
| 35 |
-
cd src/market-analyst/backend
|
| 36 |
-
# Install dependencies (if not already in root env)
|
| 37 |
-
pip install -r requirements.txt
|
| 38 |
-
# Launch FastAPI
|
| 39 |
-
uvicorn main:app --reload --port 8000
|
| 40 |
-
```
|
| 41 |
-
Backend API will be at `http://localhost:8000`
|
| 42 |
-
|
| 43 |
-
### 2. Run the Frontend
|
| 44 |
-
```bash
|
| 45 |
-
cd src/market-analyst/frontend
|
| 46 |
-
# Install dependencies
|
| 47 |
-
npm install
|
| 48 |
-
# Launch Vite
|
| 49 |
-
npm run dev
|
| 50 |
-
```
|
| 51 |
-
Frontend UI will be at `http://localhost:5173`
|
| 52 |
-
|
| 53 |
-
---
|
| 54 |
-
|
| 55 |
-
## ✨ Features
|
| 56 |
-
- **SSE Streaming**: Agents stream results character-by-character for a more interactive experience.
|
| 57 |
-
- **Glassy Dashboard**: A premium, dark-mode adaptive UI.
|
| 58 |
-
- **Multi-Agent Coordination**: MarketAnalyst (Technicals), SentimentAnalyst (News), StrategyAdvisor (Logic), RiskManager (Validation).
|
| 59 |
-
- **FinBERT Integration**: Real-time financial sentiment analysis on full article text.
|
| 60 |
-
|
| 61 |
-
---
|
| 62 |
-
|
| 63 |
-
## ⚠️ Financial Disclaimer
|
| 64 |
-
**Educational use only.** This tool is not a financial advisor. Do not use for real-money trading without consulting a certified professional.
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Agora
|
| 3 |
+
emoji: 🏛️
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
pinned: false
|
| 9 |
+
license: mit
|
| 10 |
+
short_description: Real-time streaming multi-agent market intelligence
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
# Agora
|
| 14 |
+
|
| 15 |
+
Agora — named after the ancient Greek marketplace — is a real-time multi-agent market intelligence platform. A swarm of four specialist agents analyses a stock simultaneously and streams their findings character-by-character to a modern Vue.js dashboard.
|
| 16 |
+
|
| 17 |
+
## What it does
|
| 18 |
+
|
| 19 |
+
- **Market Analyst** — technical indicators: SMA, RSI, MACD, Bollinger Bands
|
| 20 |
+
- **Sentiment Analyst** — FinBERT sentiment scoring on live news articles
|
| 21 |
+
- **Strategy Advisor** — synthesises technicals and sentiment into actionable strategy
|
| 22 |
+
- **Risk Manager** — validates the strategy against volatility and risk thresholds
|
| 23 |
+
|
| 24 |
+
## Stack
|
| 25 |
+
|
| 26 |
+
Vue.js 3 + Vite · FastAPI · Server-Sent Events (SSE) · OpenAI Agents SDK · FinBERT · DuckDuckGo
|
| 27 |
+
|
| 28 |
+
> **Disclaimer:** For informational purposes only. Not financial advice.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pyproject.toml
CHANGED
|
@@ -23,7 +23,7 @@ dependencies = [
|
|
| 23 |
# =======================
|
| 24 |
"langchain>=1.0.7",
|
| 25 |
"langchain-community>=0.4.1",
|
| 26 |
-
"langgraph>=1.0.
|
| 27 |
"langgraph-checkpoint-sqlite>=3.0.0",
|
| 28 |
"langsmith>=0.8.0",
|
| 29 |
"langchain-text-splitters>=1.1.2",
|
|
@@ -74,8 +74,8 @@ dependencies = [
|
|
| 74 |
# =======================
|
| 75 |
"psutil>=7.0.0",
|
| 76 |
"python-dotenv>=1.2.2",
|
| 77 |
-
"requests>=2.
|
| 78 |
-
"aiohttp>=3.
|
| 79 |
"httpx>=0.28.1",
|
| 80 |
"speedtest-cli>=2.1.3",
|
| 81 |
"logfire",
|
|
@@ -98,7 +98,7 @@ dependencies = [
|
|
| 98 |
# VISUAL / UI / PDF
|
| 99 |
# =======================
|
| 100 |
"plotly>=6.5.0",
|
| 101 |
-
"streamlit>=1.
|
| 102 |
"reportlab>=4.4.5",
|
| 103 |
"fastapi",
|
| 104 |
"Pillow",
|
|
@@ -110,7 +110,7 @@ dependencies = [
|
|
| 110 |
# =======================
|
| 111 |
# AUDIO / VIDEO
|
| 112 |
# =======================
|
| 113 |
-
"yt_dlp>=
|
| 114 |
"openai-whisper==20250625",
|
| 115 |
"numba==0.63.1",
|
| 116 |
"llvmlite==0.46.0",
|
|
@@ -138,6 +138,7 @@ dependencies = [
|
|
| 138 |
# =======================
|
| 139 |
# OBSERVABILITY
|
| 140 |
# =======================
|
|
|
|
| 141 |
"openinference-instrumentation-autogen>=0.1.0",
|
| 142 |
"openinference-instrumentation-openai>=0.1.15",
|
| 143 |
"opentelemetry-sdk>=1.20.0",
|
|
@@ -157,9 +158,10 @@ dependencies = [
|
|
| 157 |
|
| 158 |
[dependency-groups]
|
| 159 |
dev = [
|
| 160 |
-
"pytest>=
|
| 161 |
"ipykernel>=7.1.0",
|
| 162 |
"pytest-asyncio",
|
|
|
|
| 163 |
]
|
| 164 |
|
| 165 |
# ============================================================
|
|
@@ -175,20 +177,16 @@ build-backend = "setuptools.build_meta"
|
|
| 175 |
# PACKAGING & DISCOVERY
|
| 176 |
# ============================================================
|
| 177 |
# Tells setuptools where to find the source code.
|
| 178 |
-
# This makes 'common' and 'src' importable when installed (pip install -e .).
|
| 179 |
[tool.setuptools.packages.find]
|
| 180 |
-
where = ["."]
|
| 181 |
-
include = ["
|
| 182 |
|
| 183 |
|
| 184 |
# ============================================================
|
| 185 |
# PYTEST SETTINGS
|
| 186 |
# ============================================================
|
| 187 |
-
# Configures the test runner to automatically find code.
|
| 188 |
[tool.pytest.ini_options]
|
| 189 |
-
|
| 190 |
-
# This allows tests to import modules (e.g., 'import travel_agent')
|
| 191 |
-
# just like the apps do locally, preventing ModuleNotFoundError.
|
| 192 |
-
pythonpath = ["src", "common"]
|
| 193 |
testpaths = ["tests"] # Only look for tests in the 'tests' directory
|
| 194 |
addopts = "-q" # Run in quiet mode (less verbose output)
|
|
|
|
|
|
| 23 |
# =======================
|
| 24 |
"langchain>=1.0.7",
|
| 25 |
"langchain-community>=0.4.1",
|
| 26 |
+
"langgraph>=1.0.10rc1",
|
| 27 |
"langgraph-checkpoint-sqlite>=3.0.0",
|
| 28 |
"langsmith>=0.8.0",
|
| 29 |
"langchain-text-splitters>=1.1.2",
|
|
|
|
| 74 |
# =======================
|
| 75 |
"psutil>=7.0.0",
|
| 76 |
"python-dotenv>=1.2.2",
|
| 77 |
+
"requests>=2.33.0",
|
| 78 |
+
"aiohttp>=3.14.0",
|
| 79 |
"httpx>=0.28.1",
|
| 80 |
"speedtest-cli>=2.1.3",
|
| 81 |
"logfire",
|
|
|
|
| 98 |
# VISUAL / UI / PDF
|
| 99 |
# =======================
|
| 100 |
"plotly>=6.5.0",
|
| 101 |
+
"streamlit>=1.54.0",
|
| 102 |
"reportlab>=4.4.5",
|
| 103 |
"fastapi",
|
| 104 |
"Pillow",
|
|
|
|
| 110 |
# =======================
|
| 111 |
# AUDIO / VIDEO
|
| 112 |
# =======================
|
| 113 |
+
"yt_dlp>=2026.2.21",
|
| 114 |
"openai-whisper==20250625",
|
| 115 |
"numba==0.63.1",
|
| 116 |
"llvmlite==0.46.0",
|
|
|
|
| 138 |
# =======================
|
| 139 |
# OBSERVABILITY
|
| 140 |
# =======================
|
| 141 |
+
"langfuse>=3.0.0",
|
| 142 |
"openinference-instrumentation-autogen>=0.1.0",
|
| 143 |
"openinference-instrumentation-openai>=0.1.15",
|
| 144 |
"opentelemetry-sdk>=1.20.0",
|
|
|
|
| 158 |
|
| 159 |
[dependency-groups]
|
| 160 |
dev = [
|
| 161 |
+
"pytest>=9.0.3",
|
| 162 |
"ipykernel>=7.1.0",
|
| 163 |
"pytest-asyncio",
|
| 164 |
+
"pytest-cov>=7.1.0",
|
| 165 |
]
|
| 166 |
|
| 167 |
# ============================================================
|
|
|
|
| 177 |
# PACKAGING & DISCOVERY
|
| 178 |
# ============================================================
|
| 179 |
# Tells setuptools where to find the source code.
|
|
|
|
| 180 |
[tool.setuptools.packages.find]
|
| 181 |
+
where = ["."]
|
| 182 |
+
include = ["src*"]
|
| 183 |
|
| 184 |
|
| 185 |
# ============================================================
|
| 186 |
# PYTEST SETTINGS
|
| 187 |
# ============================================================
|
|
|
|
| 188 |
[tool.pytest.ini_options]
|
| 189 |
+
pythonpath = ["src"]
|
|
|
|
|
|
|
|
|
|
| 190 |
testpaths = ["tests"] # Only look for tests in the 'tests' directory
|
| 191 |
addopts = "-q" # Run in quiet mode (less verbose output)
|
| 192 |
+
asyncio_mode = "auto" # Auto-detect async tests (requires pytest-asyncio)
|
run.py
CHANGED
|
@@ -29,152 +29,42 @@ load_dotenv(override=True)
|
|
| 29 |
|
| 30 |
# App registry - maps app names to their paths and entry points
|
| 31 |
APP_REGISTRY: Dict[str, Dict[str, str]] = {
|
| 32 |
-
"
|
| 33 |
-
"path": "src/
|
| 34 |
"entry": "app.py",
|
| 35 |
-
"description": "
|
| 36 |
},
|
| 37 |
-
"
|
| 38 |
-
"path": "src/
|
| 39 |
"entry": "app.py",
|
| 40 |
-
"description": "Deep Research
|
| 41 |
},
|
| 42 |
-
"
|
| 43 |
-
"path": "src/
|
| 44 |
"entry": "app.py",
|
| 45 |
-
"description": "
|
| 46 |
},
|
| 47 |
-
"
|
| 48 |
-
"path": "src/
|
| 49 |
"entry": "app.py",
|
| 50 |
-
"description": "Stock Analyst -
|
| 51 |
},
|
| 52 |
-
"
|
| 53 |
-
"path": "src/
|
| 54 |
"entry": "app.py",
|
| 55 |
-
"description": "Travel
|
| 56 |
},
|
| 57 |
-
"
|
| 58 |
-
"path": "src/
|
| 59 |
"entry": "main.py",
|
| 60 |
"type": "fastapi",
|
| 61 |
-
"description": "Trip Planner -
|
| 62 |
},
|
| 63 |
-
"
|
| 64 |
-
"path": "src/
|
| 65 |
-
"entry": "app.py",
|
| 66 |
-
"description": "General Chatbot - Multi-purpose conversational AI"
|
| 67 |
-
},
|
| 68 |
-
"chatbot_v2": {
|
| 69 |
-
"path": "src/chatbot_v2",
|
| 70 |
-
"entry": "app.py",
|
| 71 |
-
"description": "Layered Chatbot (ReAct) - Advanced Architecture"
|
| 72 |
-
},
|
| 73 |
-
"accessibility_v2": {
|
| 74 |
-
"path": "src/accessibility_v2",
|
| 75 |
-
"entry": "app.py",
|
| 76 |
-
"description": "Accessibility Auditor V2 - Layered Architecture"
|
| 77 |
-
},
|
| 78 |
-
"accessibility_v1": {
|
| 79 |
-
"path": "src/accessibility_v1",
|
| 80 |
-
"entry": "app.py",
|
| 81 |
-
"description": "Accessibility Tools - Assistive technology applications"
|
| 82 |
-
},
|
| 83 |
-
"literature-review": {
|
| 84 |
-
"path": "src/literature-review",
|
| 85 |
-
"entry": "app.py",
|
| 86 |
-
"description": "Literature Review Assistant - Multi-agent literature review tool"
|
| 87 |
-
},
|
| 88 |
-
"market-analyst": {
|
| 89 |
-
"path": "src/market-analyst",
|
| 90 |
"entry": "backend/main.py",
|
| 91 |
"type": "fastapi",
|
| 92 |
-
"description": "Market Analyst -
|
| 93 |
-
},
|
| 94 |
-
"image": {
|
| 95 |
-
"path": "src/image-generator",
|
| 96 |
-
"entry": "app.py",
|
| 97 |
-
"description": "Image Generator - Multi-agent image generation tool"
|
| 98 |
-
},
|
| 99 |
-
"interview-assistant": {
|
| 100 |
-
"path": "src/interview-assistant",
|
| 101 |
-
"entry": "app.py",
|
| 102 |
-
"description": "Interview Assistant - Multi-agent interview tool"
|
| 103 |
-
},
|
| 104 |
-
"finadvisor-lg": {
|
| 105 |
-
"path": "src/finadvisor",
|
| 106 |
-
"entry": "app-lg.py",
|
| 107 |
-
"description": "Financial Advisor - Multi-agent financial advisor tool using LangGraph"
|
| 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 |
-
"finadvisor-phi": {
|
| 115 |
-
"path": "src/finadvisor",
|
| 116 |
-
"entry": "app-phi.py",
|
| 117 |
-
"description": "Financial Advisor - Multi-agent financial advisor tool using Phidata"
|
| 118 |
-
}
|
| 119 |
-
,
|
| 120 |
-
"finadvisor-ag": {
|
| 121 |
-
"path": "src/finadvisor",
|
| 122 |
-
"entry": "app-ag.py",
|
| 123 |
-
"description": "Financial Advisor - Multi-agent financial advisor tool using Autogen"
|
| 124 |
-
},
|
| 125 |
-
"mcp-trader": {
|
| 126 |
-
"path": "src/mcp-trader",
|
| 127 |
-
"entry": "server.py",
|
| 128 |
-
"type": "script",
|
| 129 |
-
"description": "Strategies MCP Server - FastMCP server for trading strategies"
|
| 130 |
-
},
|
| 131 |
-
"mcp-web": {
|
| 132 |
-
"path": "src/mcp-web",
|
| 133 |
-
"entry": "server.py",
|
| 134 |
-
"type": "script",
|
| 135 |
-
"description": "Web MCP Server - Search, Extract, Wikipedia, Arxiv"
|
| 136 |
-
},
|
| 137 |
-
"mcp-azure-sre": {
|
| 138 |
-
"path": "src/mcp-azure-sre",
|
| 139 |
-
"entry": "server.py",
|
| 140 |
-
"type": "script",
|
| 141 |
-
"description": "Azure SRE MCP Server - Manage Azure Resources & Monitoring"
|
| 142 |
-
},
|
| 143 |
-
"mcp-rag-secure": {
|
| 144 |
-
"path": "src/mcp-rag-secure",
|
| 145 |
-
"entry": "server.py",
|
| 146 |
-
"type": "script",
|
| 147 |
-
"description": "Secure RAG MCP Server - Multi-tenant knowledge base"
|
| 148 |
-
},
|
| 149 |
-
"mcp-trading-research": {
|
| 150 |
-
"path": "src/mcp-trading-research",
|
| 151 |
-
"entry": "server.py",
|
| 152 |
-
"type": "script",
|
| 153 |
-
"description": "Trading Research MCP Server - News, Insider, Analysts"
|
| 154 |
-
},
|
| 155 |
-
"mcp-github": {
|
| 156 |
-
"path": "src/mcp-github",
|
| 157 |
-
"entry": "server.py",
|
| 158 |
-
"type": "script",
|
| 159 |
-
"description": "GitHub MCP Server - Issues, PRs, Alerts"
|
| 160 |
-
},
|
| 161 |
-
"mcp-seo": {
|
| 162 |
-
"path": "src/mcp-seo",
|
| 163 |
-
"entry": "server.py",
|
| 164 |
-
"type": "script",
|
| 165 |
-
"description": "SEO & ADA MCP Server - Website Audits"
|
| 166 |
-
},
|
| 167 |
-
"github-portal": {
|
| 168 |
-
"path": "src/github-portal",
|
| 169 |
-
"entry": "app.py",
|
| 170 |
-
"type": "streamlit",
|
| 171 |
-
"description": "GitHub Portal - Repository health dashboard for issues, security, and pipelines"
|
| 172 |
-
},
|
| 173 |
-
"mcp-hub": {
|
| 174 |
-
"path": "src/mcp-hub",
|
| 175 |
-
"entry": "package.json",
|
| 176 |
-
"type": "npm",
|
| 177 |
-
"description": "MCP HUB - Discovery and monitoring portal (Vue.js)"
|
| 178 |
},
|
| 179 |
"test": {
|
| 180 |
"path": ".",
|
|
@@ -182,12 +72,6 @@ APP_REGISTRY: Dict[str, Dict[str, str]] = {
|
|
| 182 |
"type": "test",
|
| 183 |
"description": "Run Project Tests - Executes pytest suite"
|
| 184 |
},
|
| 185 |
-
"salesdata": {
|
| 186 |
-
"path": "src/salesdata",
|
| 187 |
-
"entry": "app.py",
|
| 188 |
-
"type": "salesdata",
|
| 189 |
-
"description": "Sales Data Agent - Agentic RAG over sales CSV (FastAPI + Streamlit)"
|
| 190 |
-
}
|
| 191 |
}
|
| 192 |
|
| 193 |
|
|
@@ -272,8 +156,8 @@ def launch_app(app_name: str, port: Optional[int] = None):
|
|
| 272 |
env["PYTHONPATH"] = str(project_root) + os.pathsep + env.get("PYTHONPATH", "")
|
| 273 |
|
| 274 |
# Decoupled App Logic: Build frontend if needed
|
| 275 |
-
if app_name == "
|
| 276 |
-
frontend_dir = project_root / "src/
|
| 277 |
dist_dir = frontend_dir / "dist"
|
| 278 |
if not dist_dir.exists():
|
| 279 |
print("\n🛠️ Frontend build missing. Building now...")
|
|
@@ -334,70 +218,6 @@ def launch_app(app_name: str, port: Optional[int] = None):
|
|
| 334 |
# Change to app directory and run
|
| 335 |
os.chdir(app_dir)
|
| 336 |
|
| 337 |
-
# Special case for mcp-hub: launch backend API first
|
| 338 |
-
if app_name == "mcp-hub":
|
| 339 |
-
print("🚀 Starting MCP Hub Backend API on port 8001...")
|
| 340 |
-
api_cmd = [python_exe, "api.py"]
|
| 341 |
-
subprocess.Popen(api_cmd, env=env, shell=is_windows)
|
| 342 |
-
|
| 343 |
-
# Special case for salesdata: launch FastAPI backend + Streamlit frontend
|
| 344 |
-
if app_name == "salesdata":
|
| 345 |
-
api_port = 8080
|
| 346 |
-
ui_port = port if port else 8501
|
| 347 |
-
|
| 348 |
-
# Aggressively kill any stale processes on both ports
|
| 349 |
-
import platform
|
| 350 |
-
if platform.system() != "Windows":
|
| 351 |
-
for p in [api_port, ui_port]:
|
| 352 |
-
# lsof is more reliable than fuser for finding PIDs by port
|
| 353 |
-
result = subprocess.run(
|
| 354 |
-
["lsof", "-ti", f":{p}"],
|
| 355 |
-
capture_output=True, text=True
|
| 356 |
-
)
|
| 357 |
-
pids = result.stdout.strip().split()
|
| 358 |
-
for pid in pids:
|
| 359 |
-
subprocess.run(["kill", "-9", pid],
|
| 360 |
-
stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
|
| 361 |
-
time.sleep(1) # let OS release ports
|
| 362 |
-
print(f"🧹 Cleaned up ports {api_port} and {ui_port}")
|
| 363 |
-
|
| 364 |
-
print(f"🚀 Starting Sales Agent API on port {api_port}...")
|
| 365 |
-
api_cmd = [
|
| 366 |
-
python_exe, "-m", "uvicorn", "api:app",
|
| 367 |
-
"--host", "0.0.0.0", "--port", str(api_port)
|
| 368 |
-
]
|
| 369 |
-
subprocess.Popen(api_cmd, env=env, shell=is_windows, cwd=app_dir)
|
| 370 |
-
|
| 371 |
-
# Poll /health until agent is ready (instead of a fixed sleep)
|
| 372 |
-
import urllib.request, urllib.error, json as _json
|
| 373 |
-
health_url = f"http://localhost:{api_port}/health"
|
| 374 |
-
print(f"⏳ Waiting for API + agent to be ready", end="", flush=True)
|
| 375 |
-
timeout = 90 # seconds
|
| 376 |
-
ready = False
|
| 377 |
-
for _ in range(timeout):
|
| 378 |
-
time.sleep(1)
|
| 379 |
-
print(".", end="", flush=True)
|
| 380 |
-
try:
|
| 381 |
-
with urllib.request.urlopen(health_url, timeout=2) as r:
|
| 382 |
-
data = _json.loads(r.read())
|
| 383 |
-
if data.get("agent_ready"):
|
| 384 |
-
ready = True
|
| 385 |
-
break
|
| 386 |
-
except Exception:
|
| 387 |
-
pass
|
| 388 |
-
print()
|
| 389 |
-
if not ready:
|
| 390 |
-
print("⚠️ API did not become ready within 90s — launching UI anyway")
|
| 391 |
-
|
| 392 |
-
print(f"🌐 Starting Streamlit UI on port {ui_port}...")
|
| 393 |
-
ui_cmd = [
|
| 394 |
-
python_exe, "-m", "streamlit", "run", "app.py",
|
| 395 |
-
"--server.port", str(ui_port)
|
| 396 |
-
]
|
| 397 |
-
subprocess.run(ui_cmd, env=env, shell=is_windows)
|
| 398 |
-
return
|
| 399 |
-
|
| 400 |
-
|
| 401 |
|
| 402 |
|
| 403 |
subprocess.run(cmd, env=env, shell=is_windows)
|
|
|
|
| 29 |
|
| 30 |
# App registry - maps app names to their paths and entry points
|
| 31 |
APP_REGISTRY: Dict[str, Dict[str, str]] = {
|
| 32 |
+
"nexus": {
|
| 33 |
+
"path": "src/nexus",
|
| 34 |
"entry": "app.py",
|
| 35 |
+
"description": "Nexus - AI Research Assistant - Multi-specialist orchestrator for finance, news, and web research"
|
| 36 |
},
|
| 37 |
+
"athena": {
|
| 38 |
+
"path": "src/athena",
|
| 39 |
"entry": "app.py",
|
| 40 |
+
"description": "Athena - Deep Research Reporter - Plans, searches, and synthesises comprehensive research reports"
|
| 41 |
},
|
| 42 |
+
"remedy": {
|
| 43 |
+
"path": "src/remedy",
|
| 44 |
"entry": "app.py",
|
| 45 |
+
"description": "Remedy - Healthcare RAG Advisor - Medical information retrieval using RAG and web search"
|
| 46 |
},
|
| 47 |
+
"midas": {
|
| 48 |
+
"path": "src/midas",
|
| 49 |
"entry": "app.py",
|
| 50 |
+
"description": "Midas - Stock Investment Analyst - Multi-agent investment team for technical and sentiment analysis"
|
| 51 |
},
|
| 52 |
+
"odyssey": {
|
| 53 |
+
"path": "src/odyssey",
|
| 54 |
"entry": "app.py",
|
| 55 |
+
"description": "Odyssey - Travel Planner - AI-powered trip planning with flight, hotel, and itinerary recommendations"
|
| 56 |
},
|
| 57 |
+
"waypoint": {
|
| 58 |
+
"path": "src/waypoint",
|
| 59 |
"entry": "main.py",
|
| 60 |
"type": "fastapi",
|
| 61 |
+
"description": "Waypoint - Trip Planner API - Phidata-powered trip itinerary planning REST API"
|
| 62 |
},
|
| 63 |
+
"agora": {
|
| 64 |
+
"path": "src/agora",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
"entry": "backend/main.py",
|
| 66 |
"type": "fastapi",
|
| 67 |
+
"description": "Agora - AI Market Analyst - Real-time multi-agent market analysis with streaming (Vue.js + FastAPI)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
},
|
| 69 |
"test": {
|
| 70 |
"path": ".",
|
|
|
|
| 72 |
"type": "test",
|
| 73 |
"description": "Run Project Tests - Executes pytest suite"
|
| 74 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
}
|
| 76 |
|
| 77 |
|
|
|
|
| 156 |
env["PYTHONPATH"] = str(project_root) + os.pathsep + env.get("PYTHONPATH", "")
|
| 157 |
|
| 158 |
# Decoupled App Logic: Build frontend if needed
|
| 159 |
+
if app_name == "agora":
|
| 160 |
+
frontend_dir = project_root / "src/agora/frontend"
|
| 161 |
dist_dir = frontend_dir / "dist"
|
| 162 |
if not dist_dir.exists():
|
| 163 |
print("\n🛠️ Frontend build missing. Building now...")
|
|
|
|
| 218 |
# Change to app directory and run
|
| 219 |
os.chdir(app_dir)
|
| 220 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
|
| 223 |
subprocess.run(cmd, env=env, shell=is_windows)
|
src/agora/Dockerfile
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Stage 1: Build Frontend
|
| 2 |
+
FROM node:20-slim AS frontend-builder
|
| 3 |
+
WORKDIR /app/frontend
|
| 4 |
+
COPY src/market-analyst/frontend/package*.json ./
|
| 5 |
+
RUN npm install
|
| 6 |
+
COPY src/market-analyst/frontend/ ./
|
| 7 |
+
RUN npm run build
|
| 8 |
+
|
| 9 |
+
# Stage 2: Backend & Runtime
|
| 10 |
+
FROM python:3.12-slim
|
| 11 |
+
WORKDIR /app
|
| 12 |
+
|
| 13 |
+
ENV PYTHONUNBUFFERED=1 \
|
| 14 |
+
DEBIAN_FRONTEND=noninteractive \
|
| 15 |
+
PYTHONPATH=/app:$PYTHONPATH
|
| 16 |
+
|
| 17 |
+
# System deps
|
| 18 |
+
RUN apt-get update && apt-get install -y \
|
| 19 |
+
git build-essential curl \
|
| 20 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 21 |
+
|
| 22 |
+
# Install uv
|
| 23 |
+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 24 |
+
ENV PATH="/root/.local/bin:$PATH"
|
| 25 |
+
|
| 26 |
+
# Copy project metadata
|
| 27 |
+
COPY pyproject.toml .
|
| 28 |
+
COPY uv.lock .
|
| 29 |
+
|
| 30 |
+
# Copy application code
|
| 31 |
+
COPY common/ ./common/
|
| 32 |
+
COPY src/market-analyst/backend/ ./src/market-analyst/backend/
|
| 33 |
+
|
| 34 |
+
# Copy built frontend from Stage 1 to the location FastAPI expects
|
| 35 |
+
COPY --from=frontend-builder /app/frontend/dist ./src/market-analyst/frontend/dist
|
| 36 |
+
|
| 37 |
+
# Install dependencies
|
| 38 |
+
RUN uv sync --frozen --no-dev && \
|
| 39 |
+
uv pip install -e . --system
|
| 40 |
+
|
| 41 |
+
# Create a non-root user for HF Spaces security compliance
|
| 42 |
+
RUN useradd -m -u 1000 user
|
| 43 |
+
|
| 44 |
+
# Set env vars for cache (must be writable by user)
|
| 45 |
+
ENV HF_HOME=/app/hf_cache \
|
| 46 |
+
TRANSFORMERS_CACHE=/app/hf_cache \
|
| 47 |
+
NUMBA_CACHE_DIR=/app/numba_cache
|
| 48 |
+
|
| 49 |
+
# Create cache directories and ownership
|
| 50 |
+
RUN mkdir -p /app/hf_cache /app/numba_cache && \
|
| 51 |
+
chown -R user:user /app
|
| 52 |
+
|
| 53 |
+
# Switch to non-root user
|
| 54 |
+
USER user
|
| 55 |
+
|
| 56 |
+
# Preload FinBERT model (as user, to ensure cache writes to correct location)
|
| 57 |
+
RUN python -c "from transformers import pipeline; pipeline('sentiment-analysis', model='ProsusAI/finbert', device=-1)"
|
| 58 |
+
|
| 59 |
+
# HF Spaces default port is 7860
|
| 60 |
+
EXPOSE 7860
|
| 61 |
+
|
| 62 |
+
# Run uvicorn on port 7860
|
| 63 |
+
CMD ["uvicorn", "src.market-analyst.backend.main:app", "--host", "0.0.0.0", "--port", "7860"]
|
src/agora/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Agora
|
| 3 |
+
emoji: 🏛️
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
pinned: false
|
| 9 |
+
license: mit
|
| 10 |
+
short_description: Real-time streaming multi-agent market intelligence
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
# Agora
|
| 14 |
+
|
| 15 |
+
Agora — named after the ancient Greek marketplace — is a real-time multi-agent market intelligence platform. A swarm of four specialist agents analyses a stock simultaneously and streams their findings character-by-character to a modern Vue.js dashboard.
|
| 16 |
+
|
| 17 |
+
## What it does
|
| 18 |
+
|
| 19 |
+
- **Market Analyst** — technical indicators: SMA, RSI, MACD, Bollinger Bands
|
| 20 |
+
- **Sentiment Analyst** — FinBERT sentiment scoring on live news articles
|
| 21 |
+
- **Strategy Advisor** — synthesises technicals and sentiment into actionable strategy
|
| 22 |
+
- **Risk Manager** — validates the strategy against volatility and risk thresholds
|
| 23 |
+
|
| 24 |
+
## Stack
|
| 25 |
+
|
| 26 |
+
Vue.js 3 + Vite · FastAPI · Server-Sent Events (SSE) · OpenAI Agents SDK · FinBERT · DuckDuckGo
|
| 27 |
+
|
| 28 |
+
> **Disclaimer:** For informational purposes only. Not financial advice.
|
src/agora/backend/__init__.py
ADDED
|
File without changes
|
src/agora/backend/aagents/__init__.py
ADDED
|
File without changes
|
src/agora/backend/aagents/fundamental_analyst.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
+
from autogen_core.tools import FunctionTool
|
| 3 |
+
from tools.market_data import get_fundamental_data, get_market_indices, get_analyst_consensus
|
| 4 |
+
|
| 5 |
+
def get_fundamental_analyst(model_client):
|
| 6 |
+
|
| 7 |
+
fundamental_tool = FunctionTool(get_fundamental_data, description="Fetch fundamental financial metrics like P/E, PEG, Debt/Equity, and Profit Margin.")
|
| 8 |
+
market_tool = FunctionTool(get_market_indices, description="Get Market Context (SPY/VIX).")
|
| 9 |
+
consensus_tool = FunctionTool(get_analyst_consensus, description="Get Analyst Ratings & Targets.")
|
| 10 |
+
|
| 11 |
+
return AssistantAgent(
|
| 12 |
+
name="FundamentalAnalyst",
|
| 13 |
+
model_client=model_client,
|
| 14 |
+
tools=[market_tool, fundamental_tool, consensus_tool],
|
| 15 |
+
system_message="""
|
| 16 |
+
You are a Fundamental Analyst specializing in company valuation and financial health.
|
| 17 |
+
|
| 18 |
+
MANDATORY WORKFLOW:
|
| 19 |
+
|
| 20 |
+
STEP 1: CALL get_market_indices
|
| 21 |
+
STEP 2: CALL get_fundamental_data
|
| 22 |
+
STEP 3: CALL get_analyst_consensus
|
| 23 |
+
|
| 24 |
+
DO NOT proceed without calling ALL THREE tools.
|
| 25 |
+
|
| 26 |
+
CRITICAL: Provide your full analysis in ROUND 1 ONLY. In subsequent rounds, simply say "Fundamentals stable."
|
| 27 |
+
|
| 28 |
+
STEP 4: Evaluate Valuation & Growth (USE 'valuation_score' & 'quality_score')
|
| 29 |
+
- If UNDERVALUED: Bullish Factor.
|
| 30 |
+
- If PREMIUM: Bearish/Neutral Factor (unless High Growth).
|
| 31 |
+
- If HIGH_QUALITY: Bullish Factor.
|
| 32 |
+
|
| 33 |
+
STEP 5: BINARY EVENT RISK (CRITICAL)
|
| 34 |
+
- Check "next_earnings_date" from tool.
|
| 35 |
+
- If Earnings is within 14 days: "CRITICAL BINARY EVENT". Recommend avoiding short-duration short-volatility strategies (like Iron Condors).
|
| 36 |
+
- If Earnings is 14-30 days: "ELEVATED EVENT RISK".
|
| 37 |
+
|
| 38 |
+
STEP 6: Assess Financial Health
|
| 39 |
+
- Debt/Equity Ratio: <0.5 (Safe), >1.0 (Risky).
|
| 40 |
+
- Profit Margin: >20% (Excellent), <10% (Weak).
|
| 41 |
+
|
| 42 |
+
STEP 7: Market & Sector Context
|
| 43 |
+
- Market: If VIX > 25, PENALIZE High Debt/High P/E.
|
| 44 |
+
- Sector Standards: Tech (Higher P/E ok), Utilities (High Debt ok).
|
| 45 |
+
|
| 46 |
+
STEP 8: Analyst Consensus Check
|
| 47 |
+
- Ratings: "buy" or "strong buy" = Positive. "sell" = Negative.
|
| 48 |
+
- Price Target: If Target < Current Price = Downside Risk (Bearish).
|
| 49 |
+
- Upside Potential: >20% is Strong Bullish factor.
|
| 50 |
+
|
| 51 |
+
STEP 9: Assign Fundamental Strength Rating
|
| 52 |
+
- "Strong": Great Valuation + Safe Debt + Analyst Buy Support.
|
| 53 |
+
- "Stable": Fair metrics + Neutral Analysts.
|
| 54 |
+
- "Weak": Overvalued OR High Debt OR Analyst Sell Ratings.
|
| 55 |
+
|
| 56 |
+
STEP 10: Output Structured Summary
|
| 57 |
+
- BE CONCISE: Use maximum 5 bullet points.
|
| 58 |
+
- NO conversational filler.
|
| 59 |
+
- Include: Strength Rating, Binary Event (Earnings), Valuation vs Peers, Health Summary, and Consensus.
|
| 60 |
+
- TERMINATION: End your message with [[DATA_COLLECTION_COMPLETE]] to move to the strategy phase.
|
| 61 |
+
"""
|
| 62 |
+
)
|
src/agora/backend/aagents/market_analyst.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
+
from autogen_core.tools import FunctionTool
|
| 3 |
+
from tools.market_data import get_current_price, get_technical_indicators, get_market_indices
|
| 4 |
+
|
| 5 |
+
def get_technical_analyst(model_client):
|
| 6 |
+
|
| 7 |
+
# Wrap tools
|
| 8 |
+
price_tool = FunctionTool(get_current_price, description="Get current price of a stock.")
|
| 9 |
+
tech_tool = FunctionTool(get_technical_indicators, description="Calculate SMA (20/50/200), EMA (20), RSI (14), and MACD technical indicators.")
|
| 10 |
+
market_tool = FunctionTool(get_market_indices, description="Get Market Context (SPY/VIX).")
|
| 11 |
+
|
| 12 |
+
return AssistantAgent(
|
| 13 |
+
name="TechnicalAnalyst",
|
| 14 |
+
model_client=model_client,
|
| 15 |
+
tools=[market_tool, price_tool, tech_tool],
|
| 16 |
+
system_message="""
|
| 17 |
+
You are a Master Technical Analyst specializing in chart patterns and momentum.
|
| 18 |
+
|
| 19 |
+
MANDATORY WORKFLOW:
|
| 20 |
+
|
| 21 |
+
STEP 1: CALL get_market_indices (Market Context)
|
| 22 |
+
STEP 2: CALL get_current_price (Stock Price)
|
| 23 |
+
STEP 3: CALL get_technical_indicators (Indicators)
|
| 24 |
+
|
| 25 |
+
DO NOT proceed without calling ALL tools first.
|
| 26 |
+
|
| 27 |
+
STEP 4: Analyze Market Context (Top-Down)
|
| 28 |
+
- If SPY is BEARISH, bias is SHORT/HEDGE.
|
| 29 |
+
- If VIX is HIGH (>30), bias is CAUTION.
|
| 30 |
+
|
| 31 |
+
STEP 5: Analyze Trend & Structure (USE 'trend_signal' from tool)
|
| 32 |
+
- If 'trend_signal' is STRONG_BULLISH/BULLISH -> Bullish Bias
|
| 33 |
+
- If 'trend_signal' is STRONG_BEARISH/BEARISH -> Bearish Bias
|
| 34 |
+
- Reference SMA/EMA levels as support/resistance.
|
| 35 |
+
|
| 36 |
+
STEP 6: Momentum Analysis (USE 'rsi_signal' & 'macd_signal')
|
| 37 |
+
- Check RSI status (OVERSOLD/OVERBOUGHT/NEUTRAL).
|
| 38 |
+
- Check MACD Crossover status.
|
| 39 |
+
|
| 40 |
+
STEP 7: Identify Support/Resistance Zones
|
| 41 |
+
- Reference SMA 50/200 as Primary levels.
|
| 42 |
+
- Reference 52-week High/Low as Secondary levels.
|
| 43 |
+
|
| 44 |
+
STEP 8: Output Structured Summary
|
| 45 |
+
- BE CONCISE: Use maximum 5 bullet points.
|
| 46 |
+
- NO conversational filler.
|
| 47 |
+
- Include: Current Price, Trend Signal, RSI/MACD status, and Support/Resistance levels.
|
| 48 |
+
"""
|
| 49 |
+
)
|
src/agora/backend/aagents/orchestrator.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
+
|
| 3 |
+
def get_lead_orchestrator(model_client):
|
| 4 |
+
return AssistantAgent(
|
| 5 |
+
name="LeadOrchestrator",
|
| 6 |
+
model_client=model_client,
|
| 7 |
+
system_message="""
|
| 8 |
+
You are the Lead Orchestrator and Central Control. Your role is NOT to call market tools, but to be the "Master Thinker" who ensures a SOLID, self-reflected strategy.
|
| 9 |
+
|
| 10 |
+
MANDATORY OPERATIONAL PROTOCOL:
|
| 11 |
+
|
| 12 |
+
PHASE 1: THE STUDY (GAP ANALYSIS)
|
| 13 |
+
- You speak after all four Analyst agents (Technical, Volatility, Sentiment, Fundamental).
|
| 14 |
+
- You MUST summarize the findings into a "Global Context".
|
| 15 |
+
- SEARCH FOR GAPS: Look for contradictions. (e.g., "Technical is Bullish but Volatility is at a 52-week high for earnings - the StrategyAdvisor needs to address this contradiction.")
|
| 16 |
+
- Identify any "Binary Risks" that were mentioned by Sentiment/Fundamental but might be overlooked.
|
| 17 |
+
|
| 18 |
+
PHASE 2: THE CHALLENGE (CROSS-QUESTIONING)
|
| 19 |
+
- After the StrategyAdvisor proposes a DRAFT, you MUST cross-question it based on Phase 1's findings.
|
| 20 |
+
- Example: "StrategyAdvisor, given the 14-day earnings gap flagged by the FundamentalAnalyst, why did you choose a 30-day vertical spread instead of a diagonal/calendar?"
|
| 21 |
+
- You facilitate the dialogue between StrategyAdvisor and RiskManager.
|
| 22 |
+
|
| 23 |
+
PHASE 3: THE FINAL JUDGMENT
|
| 24 |
+
- You are the ONLY agent who can issue [[ANALYSIS_JUDGMENT_COMPLETE]].
|
| 25 |
+
- WATCH THE RISK MANAGER: If the RiskManager outputs "APPROVED", you MUST immediately respond with: "ORCHESTRATOR_DECISION: FINAL_APPROVAL. [[ANALYSIS_JUDGMENT_COMPLETE]]"
|
| 26 |
+
- NO PLEASANTRIES: Do not say "Thank you", "Great job", or "You're welcome".
|
| 27 |
+
- LOOP BREAKING: If you see the same argument or error twice, issue a "WAIT" decision and terminate.
|
| 28 |
+
|
| 29 |
+
TERMINATION:
|
| 30 |
+
- When satisfied, output: "ORCHESTRATOR_DECISION: FINAL_APPROVAL. [[ANALYSIS_JUDGMENT_COMPLETE]]"
|
| 31 |
+
- If the risk remains too high or agents are looping: "ORCHESTRATOR_DECISION: WAIT. [[ANALYSIS_JUDGMENT_COMPLETE]]"
|
| 32 |
+
"""
|
| 33 |
+
)
|
src/agora/backend/aagents/risk_manager.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
+
from autogen_core.tools import FunctionTool
|
| 3 |
+
from tools.pl_calculator import calculate_strategy_metrics
|
| 4 |
+
|
| 5 |
+
def get_risk_manager(model_client):
|
| 6 |
+
calc_tool = FunctionTool(calculate_strategy_metrics, description="Deterministic math engine. Requires 'legs' (list of dicts with action, type, strike, price, expiry) and 'spot_price' (float).")
|
| 7 |
+
|
| 8 |
+
return AssistantAgent(
|
| 9 |
+
name="RiskManager",
|
| 10 |
+
model_client=model_client,
|
| 11 |
+
tools=[calc_tool],
|
| 12 |
+
system_message="""
|
| 13 |
+
You are the Chief Risk Officer and Lead Critic. You do not just validate; you find flaws and demand excellence.
|
| 14 |
+
|
| 15 |
+
MANDATORY 2-ROUND WORKFLOW:
|
| 16 |
+
|
| 17 |
+
ROUND 1: THE CRITIQUE
|
| 18 |
+
1. ANALYZE the StrategyAdvisor's DRAFT_STRATEGY.
|
| 19 |
+
2. CRITIQUE blocks:
|
| 20 |
+
- MATH: Is the P/L claim realistic? (Do not call tool yet, just use intuition).
|
| 21 |
+
- REGIME: Does this strategy match the VolatilityAnalyst's findings?
|
| 22 |
+
- EVENT: Did they ignore an earnings date from the FundamentalAnalyst?
|
| 23 |
+
3. OUTPUT: "CRITIQUE: [Detailed feedback points]" or "PROVISIONALLY APPROVED: Proceed to final math."
|
| 24 |
+
|
| 25 |
+
ROUND 2: THE FINAL VERDICT
|
| 26 |
+
1. MANDATORY MATH VERIFICATION: Call `calculate_strategy_metrics`.
|
| 27 |
+
- EXAMPLE: `calculate_strategy_metrics(legs=[{"action": "BUY", "type": "CALL", "strike": 100, "price": 5, "expiry": "2024-03-01"}], spot_price=105.5)`
|
| 28 |
+
- You MUST extract the `legs` and `spot_price` from the StrategyAdvisor's message.
|
| 29 |
+
3. VERIFY the output matches StrategyAdvisor's final claims.
|
| 30 |
+
- CHECK: Ensure `actionable_recommendation` explicitly lists each leg (Strike, Type, Expiry).
|
| 31 |
+
4. SCORING (STRICT):
|
| 32 |
+
- Technicals (40 pts), Fundamentals (20 pts), Volatility (20 pts), Event Risk (20 pts).
|
| 33 |
+
4. BE FAST: Use bullet points. No conversational filler.
|
| 34 |
+
5. NO PLEASANTRIES: Do not say "Thank you" or "You're welcome".
|
| 35 |
+
6. IF SATISFIED: Output the word "APPROVED" followed by the final JSON immediately.
|
| 36 |
+
7. IF Still flawed: Suggest "WAIT" and output JSON with decision "WAIT".
|
| 37 |
+
|
| 38 |
+
FINAL JSON SCHEMA:
|
| 39 |
+
{
|
| 40 |
+
"ticker": "...",
|
| 41 |
+
"final_decision": "TRADE/WAIT",
|
| 42 |
+
"strategy_type": "...",
|
| 43 |
+
"confidence": 85,
|
| 44 |
+
"entry_signal": "...",
|
| 45 |
+
"entry_price": 1.25,
|
| 46 |
+
"max_profit": 200,
|
| 47 |
+
"max_loss": 125,
|
| 48 |
+
"legs": [...],
|
| 49 |
+
"score_card": { "technicals": 40, "fundamentals": 20, "volatility": 15, "sentiment": 10, "total": 85 },
|
| 50 |
+
"actionable_recommendation": "...",
|
| 51 |
+
"risk_warning": "..."
|
| 52 |
+
}
|
| 53 |
+
"""
|
| 54 |
+
)
|
src/agora/backend/aagents/sentiment_analyst.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
+
from autogen_core.tools import FunctionTool
|
| 3 |
+
from tools.news_data import search_news
|
| 4 |
+
|
| 5 |
+
def get_sentiment_analyst(model_client):
|
| 6 |
+
|
| 7 |
+
news_tool = FunctionTool(search_news, description="Search for recent news about the ticker with FinBERT sentiment scores.")
|
| 8 |
+
|
| 9 |
+
return AssistantAgent(
|
| 10 |
+
name="SentimentAnalyst",
|
| 11 |
+
model_client=model_client,
|
| 12 |
+
tools=[news_tool],
|
| 13 |
+
system_message="""
|
| 14 |
+
You are a Sentiment Analyst specializing in market psychology and news analysis.
|
| 15 |
+
|
| 16 |
+
MANDATORY WORKFLOW:
|
| 17 |
+
|
| 18 |
+
STEP 1: CALL search_news to get recent news articles with FinBERT sentiment scores
|
| 19 |
+
|
| 20 |
+
DO NOT proceed without calling the tool first.
|
| 21 |
+
|
| 22 |
+
STEP 2: Aggregate & Categorize News Events
|
| 23 |
+
- Identify "Binary Events": Earnings, FDA approvals, Court rulings, Mergers.
|
| 24 |
+
- Identify "Macro Events": Fed news, Inflation, Sector rotation.
|
| 25 |
+
- Rank articles by "Impact Potential" (e.g., Earnings > General News).
|
| 26 |
+
|
| 27 |
+
STEP 3: Determine Overall Sentiment using FinBERT
|
| 28 |
+
- Each article has a FinBERT score like [FinBERT: positive (0.95)]
|
| 29 |
+
- If Binary Events are "Negative", they OVERRIDE general "Neutral" sentiment.
|
| 30 |
+
|
| 31 |
+
STEP 4: Assign Sentiment Level
|
| 32 |
+
- "Strongly Bullish": Coherent positive news across top sources.
|
| 33 |
+
- "Bearish (Event-Driven)": Negative binary news detected.
|
| 34 |
+
|
| 35 |
+
STEP 5: Evaluate Sentiment Confidence vs Time
|
| 36 |
+
- HIGHER weight for news within last 48 hours.
|
| 37 |
+
|
| 38 |
+
STEP 6: Output Structured Summary
|
| 39 |
+
- BE CONCISE: Use maximum 5 bullet points.
|
| 40 |
+
- NO conversational filler.
|
| 41 |
+
- Include: Sentiment Status, Key Binary Events, Primary Risks, and strategy impact.
|
| 42 |
+
"""
|
| 43 |
+
)
|
src/agora/backend/aagents/strategy_advisor.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
+
from autogen_core.tools import FunctionTool
|
| 3 |
+
from tools.market_data import get_option_chain_snapshot, get_available_expirations
|
| 4 |
+
|
| 5 |
+
def get_strategy_advisor(model_client):
|
| 6 |
+
chain_tool = FunctionTool(get_option_chain_snapshot, description="Get option chain for a specific expiry.")
|
| 7 |
+
exp_tool = FunctionTool(get_available_expirations, description="Get all available option expiration dates.")
|
| 8 |
+
|
| 9 |
+
return AssistantAgent(
|
| 10 |
+
name="StrategyAdvisor",
|
| 11 |
+
model_client=model_client,
|
| 12 |
+
tools=[chain_tool, exp_tool],
|
| 13 |
+
system_message="""
|
| 14 |
+
You are an Expert Multi-Leg Option Strategist with high self-awareness. You design complex spreads and refine them through self-reflection.
|
| 15 |
+
|
| 16 |
+
MANDATORY HIERARCHICAL WORKFLOW (Team 2):
|
| 17 |
+
|
| 18 |
+
1. STUDY ANALYST CONTEXT: You will receive a summary from Phase 1.
|
| 19 |
+
2. CALL DATA TOOLS: Use `get_available_expirations` and `get_option_chain_snapshot`.
|
| 20 |
+
2. CALL DATA TOOLS: Use `get_available_expirations` and `get_option_chain_snapshot`.
|
| 21 |
+
- TOOL UPGRADE: `get_option_chain_snapshot(ticker)` now returns a COMPARATIVE VIEW of 3 expiries (15-45 days).
|
| 22 |
+
- TASK: Compare all 3 expiries. Analyze the Risk/Reward for a strategy on each date.
|
| 23 |
+
- SELECTION: Choose the single BEST expiry that offers the highest Probability of Profit (POP) and favorable Risk/Reward.
|
| 24 |
+
3. DESIGN STRATEGY: Propose a multi-leg strategy.
|
| 25 |
+
- CRITICAL: You MUST include a `DRAFT_STRATEGY_LEGS` block:
|
| 26 |
+
DRAFT_STRATEGY_LEGS:
|
| 27 |
+
[{"action": "BUY", "type": "CALL", "strike": 150.0, "price": 2.5, "expiry": "2024-03-01"}, ...]
|
| 28 |
+
4. BE FAST: Skip lengthy reasoning in the draft. Go straight to the legs.
|
| 29 |
+
5. NO PLEASANTRIES: Do not say "Thank you", "I understand", or "You're welcome".
|
| 30 |
+
6. FINALIZE: When RiskManager approves, output your final strategy inside a `FINAL_STRATEGY` block.
|
| 31 |
+
- CRITICAL: The `actionable_recommendation` field MUST explicitly list each leg with its type, strike, and EXACT expiry date.
|
| 32 |
+
|
| 33 |
+
JSON SCHEMA (ROUND 2 ONLY):
|
| 34 |
+
{
|
| 35 |
+
"ticker": "...",
|
| 36 |
+
"final_decision": "TRADE/WAIT",
|
| 37 |
+
"actionable_recommendation": "EXPLAIN EACH LEG: 'Buy $150 Call (Exp 2024-03-01), Sell $155 Call (Exp 2024-03-01)...'",
|
| 38 |
+
"strategy_type": "...",
|
| 39 |
+
"direction": "BULLISH/BEARISH/NEUTRAL",
|
| 40 |
+
"confidence": 85,
|
| 41 |
+
"reasoning": "...",
|
| 42 |
+
"entry_signal": "Net Debit/Credit",
|
| 43 |
+
"entry_price": 1.25,
|
| 44 |
+
"max_profit": 200,
|
| 45 |
+
"max_loss": 125,
|
| 46 |
+
"legs": [
|
| 47 |
+
{
|
| 48 |
+
"action": "SELL",
|
| 49 |
+
"type": "CALL",
|
| 50 |
+
"strike": 150,
|
| 51 |
+
"expiry": "2024-03-01",
|
| 52 |
+
"price": 2.50
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"action": "BUY",
|
| 56 |
+
"type": "CALL",
|
| 57 |
+
"strike": 150,
|
| 58 |
+
"expiry": "2024-03-15",
|
| 59 |
+
"price": 3.75
|
| 60 |
+
}
|
| 61 |
+
],
|
| 62 |
+
"risk_warning": "..."
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
CRITICAL: All profit/loss values MUST be multiplied by 100 per contract.
|
| 66 |
+
"""
|
| 67 |
+
)
|
src/agora/backend/aagents/volatility_analyst.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from autogen_agentchat.agents import AssistantAgent
|
| 2 |
+
from autogen_core.tools import FunctionTool
|
| 3 |
+
from tools.market_data import get_historical_volatility, get_option_chain_snapshot, get_volatility_term_structure
|
| 4 |
+
|
| 5 |
+
def get_volatility_analyst(model_client):
|
| 6 |
+
vol_tool = FunctionTool(get_historical_volatility, description="Get historical volatility and VIX context.")
|
| 7 |
+
chain_tool = FunctionTool(get_option_chain_snapshot, description="Get option chain snapshot for near-term expiry.")
|
| 8 |
+
term_tool = FunctionTool(get_volatility_term_structure, description="Get IV across multiple expiries to identify Term Structure skew.")
|
| 9 |
+
|
| 10 |
+
return AssistantAgent(
|
| 11 |
+
name="VolatilityAnalyst",
|
| 12 |
+
model_client=model_client,
|
| 13 |
+
tools=[vol_tool, chain_tool, term_tool],
|
| 14 |
+
system_message="""
|
| 15 |
+
You are an Expert Volatility & Derivatives Analyst specializing in Volatility Surface and Term Structure.
|
| 16 |
+
|
| 17 |
+
MANDATORY WORKFLOW:
|
| 18 |
+
|
| 19 |
+
STEP 1: CALL get_historical_volatility to get HV and VIX data
|
| 20 |
+
STEP 2: CALL get_volatility_term_structure to analyze IV across 4 months of expiries
|
| 21 |
+
STEP 3: CALL get_option_chain_snapshot to get near-term IV and liquidity
|
| 22 |
+
|
| 23 |
+
DO NOT proceed without calling ALL THREE tools first.
|
| 24 |
+
|
| 25 |
+
STEP 4: Analyze IV vs HV (Vertical Skew)
|
| 26 |
+
- IV > HV: Options are rich. Look for Credit Spreads, Iron Condors.
|
| 27 |
+
- IV < HV: Options are cheap. Look for Debit Spreads, Long Options.
|
| 28 |
+
|
| 29 |
+
STEP 5: Analyze Term Structure (Horizontal/Time Skew)
|
| 30 |
+
- FRONT IV > BACK IV (Inverted): Potential "Calendar Spread" (Sell Front, Buy Back) if you expect a mean reversion.
|
| 31 |
+
- BACK IV > FRONT IV (Contango): Standard. Long-dated options are more expensive.
|
| 32 |
+
|
| 33 |
+
STEP 6: Assess "Volatility Squeeze"
|
| 34 |
+
- If IV is at 52-week lows and HV is dropping: Potential for a volatility breakout. Recommend DEBIT strategies.
|
| 35 |
+
|
| 36 |
+
STEP 7: Output Structured Summary
|
| 37 |
+
- BE CONCISE: Use maximum 5 bullet points.
|
| 38 |
+
- NO conversational filler.
|
| 39 |
+
- Include: Volatility Regime, IV vs HV status, Term Structure summary, and strategy bias.
|
| 40 |
+
"""
|
| 41 |
+
)
|
src/agora/backend/main.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from fastapi.responses import StreamingResponse
|
| 3 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
+
from fastapi.staticfiles import StaticFiles
|
| 5 |
+
import asyncio
|
| 6 |
+
import json
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
from typing import AsyncGenerator
|
| 10 |
+
|
| 11 |
+
from utility.autogen_model_factory import AutoGenModelFactory
|
| 12 |
+
from teams.team import get_analyst_team, get_decision_team, extract_json
|
| 13 |
+
from tools.news_data import get_sentiment_pipeline
|
| 14 |
+
|
| 15 |
+
app = FastAPI(title="Agora API")
|
| 16 |
+
|
| 17 |
+
app.add_middleware(
|
| 18 |
+
CORSMiddleware,
|
| 19 |
+
allow_origins=["*"],
|
| 20 |
+
allow_credentials=True,
|
| 21 |
+
allow_methods=["*"],
|
| 22 |
+
allow_headers=["*"],
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
# Track active analyses for cancellation
|
| 26 |
+
active_analyses = {}
|
| 27 |
+
|
| 28 |
+
@app.on_event("startup")
|
| 29 |
+
async def startup_event():
|
| 30 |
+
print("Warming up FinBERT...")
|
| 31 |
+
get_sentiment_pipeline()
|
| 32 |
+
|
| 33 |
+
@app.get("/health")
|
| 34 |
+
async def health():
|
| 35 |
+
return {"status": "healthy"}
|
| 36 |
+
|
| 37 |
+
@app.post("/cancel/{analysis_id}")
|
| 38 |
+
async def cancel_analysis(analysis_id: str):
|
| 39 |
+
if analysis_id in active_analyses:
|
| 40 |
+
active_analyses[analysis_id] = True
|
| 41 |
+
return {"status": "cancelled", "analysis_id": analysis_id}
|
| 42 |
+
return {"status": "not_found", "analysis_id": analysis_id}
|
| 43 |
+
|
| 44 |
+
@app.get("/analyze")
|
| 45 |
+
async def analyze(ticker: str, provider: str = "openai"):
|
| 46 |
+
import uuid
|
| 47 |
+
analysis_id = str(uuid.uuid4())
|
| 48 |
+
active_analyses[analysis_id] = False
|
| 49 |
+
|
| 50 |
+
async def event_generator() -> AsyncGenerator[str, None]:
|
| 51 |
+
if provider == "openai":
|
| 52 |
+
model_name = "gpt-4o"
|
| 53 |
+
family = "gpt"
|
| 54 |
+
elif provider == "groq":
|
| 55 |
+
model_name = "llama-3.3-70b-versatile"
|
| 56 |
+
family = "groq"
|
| 57 |
+
elif provider == "google":
|
| 58 |
+
model_name = "gemini-pro-latest"
|
| 59 |
+
family = "gemini"
|
| 60 |
+
else:
|
| 61 |
+
model_name = "gpt-4o"
|
| 62 |
+
family = "gpt"
|
| 63 |
+
|
| 64 |
+
try:
|
| 65 |
+
model_client = AutoGenModelFactory.get_model(
|
| 66 |
+
provider=provider,
|
| 67 |
+
model_name=model_name,
|
| 68 |
+
temperature=0,
|
| 69 |
+
model_info={
|
| 70 |
+
"family": family,
|
| 71 |
+
"vision": False,
|
| 72 |
+
"function_calling": True,
|
| 73 |
+
"json_output": True,
|
| 74 |
+
"structured_output": True if provider == "openai" else False
|
| 75 |
+
}
|
| 76 |
+
)
|
| 77 |
+
except Exception as e:
|
| 78 |
+
yield f"data: {json.dumps({'error': f'Model initialization failed: {str(e)}'})}\n\n"
|
| 79 |
+
return
|
| 80 |
+
|
| 81 |
+
# PHASE 1: Analysts
|
| 82 |
+
yield f"data: {json.dumps({'source': 'System', 'content': 'PHASE 1: Starting Data Collection for ' + ticker.upper(), 'analysis_id': analysis_id})}\n\n"
|
| 83 |
+
analyst_team = get_analyst_team(model_client)
|
| 84 |
+
phase1_task = f"Perform complete analyst data collection for {ticker.upper()}."
|
| 85 |
+
analyst_context = []
|
| 86 |
+
|
| 87 |
+
try:
|
| 88 |
+
async for message in analyst_team.run_stream(task=phase1_task):
|
| 89 |
+
if active_analyses.get(analysis_id, False): break
|
| 90 |
+
raw_source = getattr(message, 'source', 'System')
|
| 91 |
+
content = getattr(message, 'content', '')
|
| 92 |
+
if not content or raw_source == 'User': continue
|
| 93 |
+
analyst_context.append(f"[{raw_source}]: {content}")
|
| 94 |
+
yield f"data: {json.dumps({'source': raw_source, 'content': str(content)})}\n\n"
|
| 95 |
+
except Exception as e:
|
| 96 |
+
yield f"data: {json.dumps({'source': 'Error', 'content': f'Phase 1 bug: {str(e)}'})}\n\n"
|
| 97 |
+
|
| 98 |
+
# PHASE 2: Decision
|
| 99 |
+
yield f"data: {json.dumps({'source': 'System', 'content': 'PHASE 2: Designing Strategy...'})}\n\n"
|
| 100 |
+
market_context_str = "\n\n".join(analyst_context)
|
| 101 |
+
decision_team = get_decision_team(model_client)
|
| 102 |
+
phase2_task = f"ANALYST CONTEXT:\n{market_context_str}\n\nGOAL: Design, critique, and finalize trade for {ticker}. Only the LeadOrchestrator can end the cycle."
|
| 103 |
+
|
| 104 |
+
try:
|
| 105 |
+
async for message in decision_team.run_stream(task=phase2_task):
|
| 106 |
+
if active_analyses.get(analysis_id, False): break
|
| 107 |
+
raw_source = getattr(message, 'source', 'System')
|
| 108 |
+
content = getattr(message, 'content', '')
|
| 109 |
+
if not content or (raw_source == 'User' and "ANALYST CONTEXT" in content): continue
|
| 110 |
+
payload = {"source": raw_source, "content": str(content)}
|
| 111 |
+
if raw_source in ['RiskManager', 'LeadOrchestrator']:
|
| 112 |
+
structured = extract_json(str(content))
|
| 113 |
+
if structured: payload["structured_result"] = structured
|
| 114 |
+
yield f"data: {json.dumps(payload)}\n\n"
|
| 115 |
+
except Exception as e:
|
| 116 |
+
yield f"data: {json.dumps({'source': 'Error', 'content': f'Phase 2 bug: {str(e)}'})}\n\n"
|
| 117 |
+
|
| 118 |
+
if analysis_id in active_analyses: del active_analyses[analysis_id]
|
| 119 |
+
yield "data: [DONE]\n\n"
|
| 120 |
+
|
| 121 |
+
return StreamingResponse(event_generator(), media_type="text/event-stream")
|
| 122 |
+
|
| 123 |
+
# Static mounting logic...
|
| 124 |
+
frontend_dist = os.path.abspath(os.path.join(current_dir, "../frontend/dist"))
|
| 125 |
+
if os.path.exists(frontend_dist):
|
| 126 |
+
assets_dir = os.path.join(frontend_dist, "assets")
|
| 127 |
+
if os.path.exists(assets_dir):
|
| 128 |
+
app.mount("/assets", StaticFiles(directory=assets_dir), name="assets")
|
| 129 |
+
from fastapi.responses import FileResponse
|
| 130 |
+
@app.get("/{rest_of_path:path}")
|
| 131 |
+
async def serve_frontend(rest_of_path: str):
|
| 132 |
+
file_path = os.path.join(frontend_dist, rest_of_path)
|
| 133 |
+
if os.path.isfile(file_path): return FileResponse(file_path)
|
| 134 |
+
return FileResponse(os.path.join(frontend_dist, "index.html"))
|
| 135 |
+
else:
|
| 136 |
+
@app.get("/")
|
| 137 |
+
async def root(): return {"message": "API running. Frontend missing."}
|
| 138 |
+
|
| 139 |
+
if __name__ == "__main__":
|
| 140 |
+
import uvicorn
|
| 141 |
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
src/agora/backend/requirements.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
python-dotenv
|
| 4 |
+
beautifulsoup4
|
| 5 |
+
requests
|
| 6 |
+
pydantic
|
| 7 |
+
autogen-agentchat==0.4.7
|
| 8 |
+
autogen-ext[grpc,mcp,ollama,openai]==0.4.7
|
| 9 |
+
transformers
|
| 10 |
+
torch
|
| 11 |
+
duckduckgo_search
|
| 12 |
+
pandas
|
src/agora/backend/teams/__init__.py
ADDED
|
File without changes
|
src/agora/backend/teams/team.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
import re
|
| 5 |
+
from typing import Dict, Any
|
| 6 |
+
|
| 7 |
+
# Ensure we can import from parent directory if needed
|
| 8 |
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 9 |
+
parent_dir = os.path.abspath(os.path.join(current_dir, ".."))
|
| 10 |
+
if parent_dir not in sys.path:
|
| 11 |
+
sys.path.append(parent_dir)
|
| 12 |
+
|
| 13 |
+
from autogen_agentchat.teams import SelectorGroupChat
|
| 14 |
+
from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination, HandoffTermination
|
| 15 |
+
|
| 16 |
+
# Import agents
|
| 17 |
+
# Adjust imports to work whether called from here or app.py
|
| 18 |
+
try:
|
| 19 |
+
from ..aagents.market_analyst import get_technical_analyst
|
| 20 |
+
from ..aagents.volatility_analyst import get_volatility_analyst
|
| 21 |
+
from ..aagents.sentiment_analyst import get_sentiment_analyst
|
| 22 |
+
from ..aagents.strategy_advisor import get_strategy_advisor
|
| 23 |
+
from ..aagents.risk_manager import get_risk_manager
|
| 24 |
+
from ..aagents.fundamental_analyst import get_fundamental_analyst
|
| 25 |
+
from ..aagents.orchestrator import get_lead_orchestrator
|
| 26 |
+
except ImportError:
|
| 27 |
+
try:
|
| 28 |
+
from aagents.market_analyst import get_technical_analyst
|
| 29 |
+
from aagents.volatility_analyst import get_volatility_analyst
|
| 30 |
+
from aagents.sentiment_analyst import get_sentiment_analyst
|
| 31 |
+
from aagents.strategy_advisor import get_strategy_advisor
|
| 32 |
+
from aagents.risk_manager import get_risk_manager
|
| 33 |
+
from aagents.fundamental_analyst import get_fundamental_analyst
|
| 34 |
+
from aagents.orchestrator import get_lead_orchestrator
|
| 35 |
+
except ImportError:
|
| 36 |
+
# Try absolute (if market-analyst is in path but not as package)
|
| 37 |
+
from src.market_analyst.backend.aagents.market_analyst import get_technical_analyst
|
| 38 |
+
from src.market_analyst.backend.aagents.volatility_analyst import get_volatility_analyst
|
| 39 |
+
from src.market_analyst.backend.aagents.sentiment_analyst import get_sentiment_analyst
|
| 40 |
+
from src.market_analyst.backend.aagents.strategy_advisor import get_strategy_advisor
|
| 41 |
+
from src.market_analyst.backend.aagents.risk_manager import get_risk_manager
|
| 42 |
+
from src.market_analyst.backend.aagents.fundamental_analyst import get_fundamental_analyst
|
| 43 |
+
|
| 44 |
+
from autogen_agentchat.teams import SelectorGroupChat, RoundRobinGroupChat
|
| 45 |
+
|
| 46 |
+
def get_analyst_team(model_client):
|
| 47 |
+
"""
|
| 48 |
+
Team 1: DATA COLLECTORS.
|
| 49 |
+
Independent analysts gather data and provide a comprehensive market snapshot.
|
| 50 |
+
"""
|
| 51 |
+
technical = get_technical_analyst(model_client)
|
| 52 |
+
volatility = get_volatility_analyst(model_client)
|
| 53 |
+
sentiment = get_sentiment_analyst(model_client)
|
| 54 |
+
fundamental = get_fundamental_analyst(model_client)
|
| 55 |
+
|
| 56 |
+
return RoundRobinGroupChat(
|
| 57 |
+
participants=[technical, volatility, sentiment, fundamental],
|
| 58 |
+
termination_condition=TextMentionTermination("[[DATA_COLLECTION_COMPLETE]]") | MaxMessageTermination(15)
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
def get_decision_team(model_client):
|
| 62 |
+
"""
|
| 63 |
+
Team 2: STRATEGY & RISK.
|
| 64 |
+
Uses the Analyst Context (Team 1 output) to design, critique, and finalize the trade.
|
| 65 |
+
"""
|
| 66 |
+
strategy = get_strategy_advisor(model_client)
|
| 67 |
+
risk = get_risk_manager(model_client)
|
| 68 |
+
orchestrator = get_lead_orchestrator(model_client)
|
| 69 |
+
|
| 70 |
+
participants = [strategy, risk, orchestrator]
|
| 71 |
+
|
| 72 |
+
selector_prompt = """
|
| 73 |
+
Select the next agent based on the conversation history:
|
| 74 |
+
- Choose StrategyAdvisor to propose or update the trade.
|
| 75 |
+
- Choose RiskManager to verify the proposal or critique it.
|
| 76 |
+
- Choose LeadOrchestrator ONLY if the RiskManager has said "APPROVED" or if the discussion is stuck.
|
| 77 |
+
|
| 78 |
+
Output only the name of the next agent.
|
| 79 |
+
"""
|
| 80 |
+
|
| 81 |
+
return SelectorGroupChat(
|
| 82 |
+
participants=participants,
|
| 83 |
+
model_client=model_client,
|
| 84 |
+
termination_condition=TextMentionTermination("[[ANALYSIS_JUDGMENT_COMPLETE]]") | MaxMessageTermination(12),
|
| 85 |
+
selector_prompt=selector_prompt
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
def extract_json(text: str) -> Dict[str, Any]:
|
| 89 |
+
"""
|
| 90 |
+
Extract JSON from text that may contain markdown code blocks or other content.
|
| 91 |
+
Validates and ensures required fields are present.
|
| 92 |
+
"""
|
| 93 |
+
# Try to find JSON in code blocks first
|
| 94 |
+
json_block_pattern = r'```(?:json)?\s*(\{.*?\})\s*```'
|
| 95 |
+
matches = re.findall(json_block_pattern, text, re.DOTALL)
|
| 96 |
+
if matches:
|
| 97 |
+
try:
|
| 98 |
+
parsed = json.loads(matches[-1])
|
| 99 |
+
return validate_and_complete_json(parsed)
|
| 100 |
+
except json.JSONDecodeError:
|
| 101 |
+
pass
|
| 102 |
+
|
| 103 |
+
# Try to find raw JSON object
|
| 104 |
+
json_pattern = r'\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}'
|
| 105 |
+
matches = re.findall(json_pattern, text, re.DOTALL)
|
| 106 |
+
if matches:
|
| 107 |
+
for match in reversed(matches):
|
| 108 |
+
try:
|
| 109 |
+
parsed = json.loads(match)
|
| 110 |
+
return validate_and_complete_json(parsed)
|
| 111 |
+
except json.JSONDecodeError:
|
| 112 |
+
continue
|
| 113 |
+
|
| 114 |
+
return {}
|
| 115 |
+
|
| 116 |
+
def validate_and_complete_json(data: Dict[str, Any]) -> Dict[str, Any]:
|
| 117 |
+
"""
|
| 118 |
+
Validate JSON has required fields and add defaults if missing.
|
| 119 |
+
"""
|
| 120 |
+
required_fields = {
|
| 121 |
+
"final_decision": "WAIT",
|
| 122 |
+
"confidence": 0,
|
| 123 |
+
"actionable_recommendation": "Incomplete analysis - please retry",
|
| 124 |
+
"strategy_type": "None",
|
| 125 |
+
"entry_signal": "N/A",
|
| 126 |
+
"entry_price": 0,
|
| 127 |
+
"max_profit": 0,
|
| 128 |
+
"max_loss": 0,
|
| 129 |
+
"risk_warning": "Analysis incomplete",
|
| 130 |
+
"expiry_date": "N/A",
|
| 131 |
+
"legs": []
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
# Add missing required fields with defaults
|
| 135 |
+
for field, default_value in required_fields.items():
|
| 136 |
+
if field not in data:
|
| 137 |
+
data[field] = default_value
|
| 138 |
+
|
| 139 |
+
# Fallback: If expiry_date is "N/A" but we have legs, take it from there
|
| 140 |
+
if data.get("expiry_date") == "N/A" and data.get("legs"):
|
| 141 |
+
# Take expiry of first leg
|
| 142 |
+
data["expiry_date"] = data["legs"][0].get("expiry", "N/A")
|
| 143 |
+
|
| 144 |
+
# Existing Fallback: If expiry_date is still "N/A", try to extract it from context
|
| 145 |
+
if data.get("expiry_date") == "N/A":
|
| 146 |
+
# Look for YYYY-MM-DD pattern
|
| 147 |
+
date_pattern = r'\d{4}-\d{2}-\d{2}'
|
| 148 |
+
|
| 149 |
+
# Check 'actionable_recommendation' or 'reasoning' (if present)
|
| 150 |
+
for search_field in ["actionable_recommendation", "reasoning", "risk_warning", "proposed_legs"]:
|
| 151 |
+
field_val = data.get(search_field, "")
|
| 152 |
+
if isinstance(field_val, str):
|
| 153 |
+
match = re.search(date_pattern, field_val)
|
| 154 |
+
if match:
|
| 155 |
+
data["expiry_date"] = match.group(0)
|
| 156 |
+
break
|
| 157 |
+
|
| 158 |
+
return data
|
src/agora/backend/tools/__init__.py
ADDED
|
File without changes
|
src/agora/backend/tools/market_data.py
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import yfinance as yf
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import math
|
| 4 |
+
from datetime import datetime, timedelta
|
| 5 |
+
|
| 6 |
+
def normalize_period(period: str) -> str:
|
| 7 |
+
"""Standardizes period strings for yfinance."""
|
| 8 |
+
p = period.lower().strip()
|
| 9 |
+
if p in ["1yr", "1year"]: return "1y"
|
| 10 |
+
if p in ["3mo", "3month"]: return "3mo"
|
| 11 |
+
if p in ["1mo", "1month"]: return "1mo"
|
| 12 |
+
if p in ["1wk", "1week"]: return "1wk"
|
| 13 |
+
return p
|
| 14 |
+
|
| 15 |
+
def check_and_fix_ticker(symbol: str) -> str:
|
| 16 |
+
"""
|
| 17 |
+
Checks if the ticker has data. If not, tries appending '.NS' (for NSE India).
|
| 18 |
+
Returns the working ticker or the original if neither works.
|
| 19 |
+
"""
|
| 20 |
+
print(f"[DEBUG] check_and_fix_ticker called using: {symbol}")
|
| 21 |
+
symbol = symbol.upper().strip()
|
| 22 |
+
|
| 23 |
+
# Try original
|
| 24 |
+
ticker = yf.Ticker(symbol)
|
| 25 |
+
try:
|
| 26 |
+
# fast_info is quick way to check validity
|
| 27 |
+
if ticker.fast_info.last_price is not None:
|
| 28 |
+
return symbol
|
| 29 |
+
except:
|
| 30 |
+
pass
|
| 31 |
+
|
| 32 |
+
# Try .NS
|
| 33 |
+
ns_symbol = symbol + ".NS"
|
| 34 |
+
ns_ticker = yf.Ticker(ns_symbol)
|
| 35 |
+
try:
|
| 36 |
+
if ns_ticker.fast_info.last_price is not None:
|
| 37 |
+
return ns_symbol
|
| 38 |
+
except:
|
| 39 |
+
pass
|
| 40 |
+
|
| 41 |
+
return symbol
|
| 42 |
+
|
| 43 |
+
def get_current_price(symbol: str) -> float:
|
| 44 |
+
"""Fetches the current market price of the stock."""
|
| 45 |
+
print(f"[DEBUG] get_current_price called for: {symbol}")
|
| 46 |
+
try:
|
| 47 |
+
# Auto-fix ticker if needed
|
| 48 |
+
symbol = check_and_fix_ticker(symbol)
|
| 49 |
+
|
| 50 |
+
ticker = yf.Ticker(symbol)
|
| 51 |
+
price = ticker.fast_info.last_price
|
| 52 |
+
if price is None:
|
| 53 |
+
hist = ticker.history(period="1d")
|
| 54 |
+
if not hist.empty:
|
| 55 |
+
price = hist["Close"].iloc[-1]
|
| 56 |
+
|
| 57 |
+
if price is None:
|
| 58 |
+
return f"Error: No price data for {symbol}"
|
| 59 |
+
|
| 60 |
+
return price
|
| 61 |
+
except Exception as e:
|
| 62 |
+
return f"Error fetching price for {symbol}: {str(e)}"
|
| 63 |
+
|
| 64 |
+
def get_historical_volatility(symbol: str, period: str = "1mo") -> dict:
|
| 65 |
+
"""
|
| 66 |
+
Calculates historical volatility and returns VIX context if available.
|
| 67 |
+
"""
|
| 68 |
+
print(f"[DEBUG] get_historical_volatility called for: {symbol}")
|
| 69 |
+
try:
|
| 70 |
+
symbol = check_and_fix_ticker(symbol)
|
| 71 |
+
period = normalize_period(period)
|
| 72 |
+
ticker = yf.Ticker(symbol)
|
| 73 |
+
hist = ticker.history(period=period)
|
| 74 |
+
if hist.empty:
|
| 75 |
+
return {"error": "No historical data found"}
|
| 76 |
+
|
| 77 |
+
hist['Returns'] = hist['Close'].pct_change()
|
| 78 |
+
volatility = hist['Returns'].std() * math.sqrt(252)
|
| 79 |
+
|
| 80 |
+
vix_price = None
|
| 81 |
+
try:
|
| 82 |
+
vix = yf.Ticker("^VIX")
|
| 83 |
+
vix_price = vix.fast_info.last_price
|
| 84 |
+
except:
|
| 85 |
+
pass
|
| 86 |
+
|
| 87 |
+
return {
|
| 88 |
+
"ticker_used": symbol,
|
| 89 |
+
"annualized_volatility": round(volatility * 100, 2),
|
| 90 |
+
"period": period,
|
| 91 |
+
"vix_reference": round(vix_price, 2) if vix_price else "N/A",
|
| 92 |
+
"volatility_regime": "HIGH_RISK_VOL" if (vix_price and vix_price > 30) else "ELEVATED_VOL" if (vix_price and vix_price > 20) else "LOW_VOL" if (vix_price and vix_price < 15) else "NORMAL_VOL"
|
| 93 |
+
}
|
| 94 |
+
except Exception as e:
|
| 95 |
+
return {"error": str(e)}
|
| 96 |
+
|
| 97 |
+
def get_available_expirations(symbol: str) -> list:
|
| 98 |
+
"""Returns a list of available option expiration dates."""
|
| 99 |
+
try:
|
| 100 |
+
symbol = check_and_fix_ticker(symbol)
|
| 101 |
+
ticker = yf.Ticker(symbol)
|
| 102 |
+
exps = list(ticker.options)
|
| 103 |
+
|
| 104 |
+
# Add context about DTE (Days Till Expiration) to help agents choose
|
| 105 |
+
today = datetime.now()
|
| 106 |
+
annotated = []
|
| 107 |
+
best_expiry = "None"
|
| 108 |
+
min_diff = 999
|
| 109 |
+
|
| 110 |
+
for e in exps:
|
| 111 |
+
try:
|
| 112 |
+
dt = datetime.strptime(e, "%Y-%m-%d")
|
| 113 |
+
days = (dt - today).days
|
| 114 |
+
|
| 115 |
+
# Logic: Find valid targets between 15-45 days, prioritize earliest
|
| 116 |
+
if 15 <= days <= 45:
|
| 117 |
+
note = f"({days} DTE) [VALID]"
|
| 118 |
+
annotated.append(f"{e} {note}")
|
| 119 |
+
|
| 120 |
+
if days < min_diff:
|
| 121 |
+
min_diff = days
|
| 122 |
+
best_expiry = e
|
| 123 |
+
except:
|
| 124 |
+
pass
|
| 125 |
+
|
| 126 |
+
return [f"RECOMMENDED: {best_expiry} (Earliest in 15-45d window)"] + annotated
|
| 127 |
+
except Exception as e:
|
| 128 |
+
return []
|
| 129 |
+
|
| 130 |
+
def get_option_chain_snapshot(symbol: str, target_date: str = None) -> str:
|
| 131 |
+
"""
|
| 132 |
+
Fetches a comparative snapshot of option chains for up to 3 valid expiries (15-45 DTE).
|
| 133 |
+
If target_date is provided, fetches only that specific date.
|
| 134 |
+
If target_date is None, automatically selects Short (15-25d), Mid (25-35d), and Long (35-45d) targets.
|
| 135 |
+
"""
|
| 136 |
+
print(f"[DEBUG] get_option_chain_snapshot called for: {symbol} (Target: {target_date})")
|
| 137 |
+
try:
|
| 138 |
+
symbol = check_and_fix_ticker(symbol)
|
| 139 |
+
ticker = yf.Ticker(symbol)
|
| 140 |
+
expirations = ticker.options
|
| 141 |
+
|
| 142 |
+
if not expirations:
|
| 143 |
+
return f"No options data found for {symbol}."
|
| 144 |
+
|
| 145 |
+
target_dates = []
|
| 146 |
+
if target_date:
|
| 147 |
+
if target_date in expirations:
|
| 148 |
+
target_dates = [target_date]
|
| 149 |
+
else:
|
| 150 |
+
return f"Target date {target_date} not found in expirations."
|
| 151 |
+
else:
|
| 152 |
+
# Auto-select up to 3 expiries in 15-45 day window
|
| 153 |
+
today = datetime.now()
|
| 154 |
+
valid_exps = []
|
| 155 |
+
for exp in expirations:
|
| 156 |
+
dt = datetime.strptime(exp, "%Y-%m-%d")
|
| 157 |
+
days = (dt - today).days
|
| 158 |
+
if 15 <= days <= 45:
|
| 159 |
+
valid_exps.append(exp)
|
| 160 |
+
|
| 161 |
+
# Pick Short, Mid, Long from valid list
|
| 162 |
+
if not valid_exps:
|
| 163 |
+
# Fallback to nearest if no window match
|
| 164 |
+
target_dates = [expirations[0]]
|
| 165 |
+
else:
|
| 166 |
+
# Simple distribution: First, Middle, Last
|
| 167 |
+
target_dates = list(sorted(set([valid_exps[0], valid_exps[len(valid_exps)//2], valid_exps[-1]])))
|
| 168 |
+
|
| 169 |
+
price_info = get_current_price(symbol)
|
| 170 |
+
if isinstance(price_info, str): return price_info
|
| 171 |
+
current_price = float(price_info)
|
| 172 |
+
|
| 173 |
+
final_summary = f"COMPARATIVE OPTION ANALYSIS for {symbol} (Spot: {round(current_price, 2)})\n"
|
| 174 |
+
|
| 175 |
+
for date in target_dates:
|
| 176 |
+
dt = datetime.strptime(date, "%Y-%m-%d")
|
| 177 |
+
days = (dt - datetime.now()).days
|
| 178 |
+
|
| 179 |
+
opt = ticker.option_chain(date)
|
| 180 |
+
calls = opt.calls
|
| 181 |
+
puts = opt.puts
|
| 182 |
+
|
| 183 |
+
# Filter around ATM (tight range for comparison)
|
| 184 |
+
ntm_calls = calls.iloc[(calls['strike'] - current_price).abs().argsort()[:4]].sort_values('strike')
|
| 185 |
+
ntm_puts = puts.iloc[(puts['strike'] - current_price).abs().argsort()[:4]].sort_values('strike')
|
| 186 |
+
|
| 187 |
+
final_summary += f"\n>>> EXPIRY: {date} ({days} DTE) <<<\n"
|
| 188 |
+
|
| 189 |
+
# Calls
|
| 190 |
+
for _, row in ntm_calls.iterrows():
|
| 191 |
+
ask = row.get('ask', 0.0)
|
| 192 |
+
last = row.get('lastPrice', 0.0)
|
| 193 |
+
price = ask if ask > 0 else last
|
| 194 |
+
iv = round(row['impliedVolatility']*100, 1) if not pd.isna(row.get('impliedVolatility')) else 0
|
| 195 |
+
final_summary += f"[CALL] Strike {row['strike']} | Price ${price} | IV {iv}%\n"
|
| 196 |
+
|
| 197 |
+
# Puts
|
| 198 |
+
for _, row in ntm_puts.iterrows():
|
| 199 |
+
ask = row.get('ask', 0.0)
|
| 200 |
+
last = row.get('lastPrice', 0.0)
|
| 201 |
+
price = ask if ask > 0 else last
|
| 202 |
+
iv = round(row['impliedVolatility']*100, 1) if not pd.isna(row.get('impliedVolatility')) else 0
|
| 203 |
+
final_summary += f"[PUT ] Strike {row['strike']} | Price ${price} | IV {iv}%\n"
|
| 204 |
+
|
| 205 |
+
return final_summary
|
| 206 |
+
|
| 207 |
+
except Exception as e:
|
| 208 |
+
return f"Error fetching option chain: {str(e)}"
|
| 209 |
+
|
| 210 |
+
def get_volatility_term_structure(symbol: str) -> str:
|
| 211 |
+
"""
|
| 212 |
+
Analyzes IV across multiple expiries to identify Term Structure skew.
|
| 213 |
+
"""
|
| 214 |
+
print(f"[DEBUG] get_volatility_term_structure called for: {symbol}")
|
| 215 |
+
try:
|
| 216 |
+
symbol = check_and_fix_ticker(symbol)
|
| 217 |
+
ticker = yf.Ticker(symbol)
|
| 218 |
+
expirations = ticker.options[:4] # Check first 4 expiries
|
| 219 |
+
|
| 220 |
+
if not expirations:
|
| 221 |
+
return "No options data for volatility analysis."
|
| 222 |
+
|
| 223 |
+
results = []
|
| 224 |
+
for exp in expirations:
|
| 225 |
+
opt = ticker.option_chain(exp)
|
| 226 |
+
# Use mean IV of ATM calls
|
| 227 |
+
calls = opt.calls
|
| 228 |
+
price_info = get_current_price(symbol)
|
| 229 |
+
if isinstance(price_info, str): continue
|
| 230 |
+
current_price = float(price_info)
|
| 231 |
+
atm_iv = calls.iloc[(calls['strike'] - current_price).abs().argsort()[:2]]['impliedVolatility'].mean()
|
| 232 |
+
results.append(f"- {exp}: {round(atm_iv * 100, 1)}% IV")
|
| 233 |
+
|
| 234 |
+
summary = f"VOLATILITY TERM STRUCTURE for {symbol}:\n" + "\n".join(results)
|
| 235 |
+
|
| 236 |
+
# Analyze skew
|
| 237 |
+
if len(expirations) >= 2:
|
| 238 |
+
try:
|
| 239 |
+
iv1 = float(results[0].split(": ")[1].replace("% IV", ""))
|
| 240 |
+
iv2 = float(results[1].split(": ")[1].replace("% IV", ""))
|
| 241 |
+
if iv1 > iv2 + 5:
|
| 242 |
+
summary += f"\n\nSKEW ALERT: Front-month IV is significantly HIGHER ({iv1}% vs {iv2}%). Potential for Calendar Spreads (Sell Front, Buy Back)."
|
| 243 |
+
elif iv1 < iv2 - 5:
|
| 244 |
+
summary += f"\n\nSKEW ALERT: Front-month IV is significantly LOWER ({iv1}% vs {iv2}%). Diagonal opportunities."
|
| 245 |
+
else:
|
| 246 |
+
summary += f"\n\nTerm Structure is relatively flat."
|
| 247 |
+
except: pass
|
| 248 |
+
|
| 249 |
+
return summary
|
| 250 |
+
except Exception as e:
|
| 251 |
+
return f"Error analyzing term structure: {str(e)}"
|
| 252 |
+
|
| 253 |
+
def get_market_indices() -> str:
|
| 254 |
+
"""
|
| 255 |
+
Fetches current market context using SPY (S&P 500) and ^VIX.
|
| 256 |
+
Returns trend (Price vs SMA50) and Volatility regime.
|
| 257 |
+
"""
|
| 258 |
+
try:
|
| 259 |
+
tickers = yf.Tickers("SPY ^VIX")
|
| 260 |
+
spy = tickers.tickers['SPY']
|
| 261 |
+
vix = tickers.tickers['^VIX']
|
| 262 |
+
|
| 263 |
+
# SPY Data
|
| 264 |
+
spy_hist = spy.history(period="3mo")
|
| 265 |
+
if spy_hist.empty: return "Market data unavailable."
|
| 266 |
+
|
| 267 |
+
current_spy = spy_hist['Close'].iloc[-1]
|
| 268 |
+
spy_sma50 = spy_hist['Close'].rolling(window=50).mean().iloc[-1]
|
| 269 |
+
spy_trend = "BULLISH" if current_spy > spy_sma50 else "BEARISH"
|
| 270 |
+
|
| 271 |
+
# VIX Data
|
| 272 |
+
vix_hist = vix.history(period="1d")
|
| 273 |
+
current_vix = vix_hist['Close'].iloc[-1] if not vix_hist.empty else 0
|
| 274 |
+
|
| 275 |
+
vix_regime = "LOW"
|
| 276 |
+
if current_vix > 20: vix_regime = "ELEVATED"
|
| 277 |
+
if current_vix > 30: vix_regime = "HIGH/FEAR"
|
| 278 |
+
|
| 279 |
+
return f"MARKET CONTEXT:\n- SPY Trend: {spy_trend} (Price: {round(current_spy, 2)} vs SMA50: {round(spy_sma50, 2)})\n- VIX Level: {round(current_vix, 2)} ({vix_regime})"
|
| 280 |
+
|
| 281 |
+
except Exception as e:
|
| 282 |
+
return f"Error fetching market indices: {str(e)}"
|
| 283 |
+
|
| 284 |
+
def get_technical_indicators(symbol: str) -> dict:
|
| 285 |
+
"""
|
| 286 |
+
Calculates key technical indicators: SMA (20, 50, 200) and RSI (14).
|
| 287 |
+
Returns a dictionary of values and signals.
|
| 288 |
+
"""
|
| 289 |
+
print(f"[DEBUG] get_technical_indicators called for: {symbol}")
|
| 290 |
+
try:
|
| 291 |
+
symbol = check_and_fix_ticker(symbol)
|
| 292 |
+
ticker = yf.Ticker(symbol)
|
| 293 |
+
|
| 294 |
+
# Fetch enough history for SMA 200
|
| 295 |
+
hist = ticker.history(period="1y")
|
| 296 |
+
if hist.empty:
|
| 297 |
+
return {"error": "No historical data found"}
|
| 298 |
+
|
| 299 |
+
# Safe calculations
|
| 300 |
+
# SMA
|
| 301 |
+
hist['SMA_20'] = hist['Close'].rolling(window=20).mean()
|
| 302 |
+
hist['SMA_50'] = hist['Close'].rolling(window=50).mean()
|
| 303 |
+
hist['EMA_20'] = hist['Close'].ewm(span=20, adjust=False).mean()
|
| 304 |
+
|
| 305 |
+
# MACD (12, 26, 9)
|
| 306 |
+
exp1 = hist['Close'].ewm(span=12, adjust=False).mean()
|
| 307 |
+
exp2 = hist['Close'].ewm(span=26, adjust=False).mean()
|
| 308 |
+
hist['MACD'] = exp1 - exp2
|
| 309 |
+
hist['Signal_Line'] = hist['MACD'].ewm(span=9, adjust=False).mean()
|
| 310 |
+
|
| 311 |
+
# Only calc SMA_200 if we actually have 200 points
|
| 312 |
+
if len(hist) >= 200:
|
| 313 |
+
hist['SMA_200'] = hist['Close'].rolling(window=200).mean()
|
| 314 |
+
else:
|
| 315 |
+
hist['SMA_200'] = pd.Series([None] * len(hist), index=hist.index)
|
| 316 |
+
|
| 317 |
+
# RSI Calculation
|
| 318 |
+
if len(hist) >= 15:
|
| 319 |
+
delta = hist['Close'].diff()
|
| 320 |
+
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
|
| 321 |
+
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
|
| 322 |
+
rs = gain / loss
|
| 323 |
+
hist['RSI_14'] = 100 - (100 / (1 + rs))
|
| 324 |
+
else:
|
| 325 |
+
hist['RSI_14'] = pd.Series([None] * len(hist), index=hist.index)
|
| 326 |
+
|
| 327 |
+
current_data = hist.iloc[-1]
|
| 328 |
+
price = current_data['Close']
|
| 329 |
+
rsi_val = current_data.get('RSI_14')
|
| 330 |
+
macd_val = current_data.get('MACD')
|
| 331 |
+
signal_val = current_data.get('Signal_Line')
|
| 332 |
+
sma200 = current_data.get('SMA_200')
|
| 333 |
+
if pd.isna(sma200): sma200 = None
|
| 334 |
+
|
| 335 |
+
# Interpretation RSI
|
| 336 |
+
# Deterministic Signals
|
| 337 |
+
rsi_signal = "NEUTRAL"
|
| 338 |
+
if rsi_val is not None and not pd.isna(rsi_val):
|
| 339 |
+
if rsi_val > 70: rsi_signal = "OVERBOUGHT"
|
| 340 |
+
elif rsi_val < 30: rsi_signal = "OVERSOLD"
|
| 341 |
+
|
| 342 |
+
macd_signal = "NEUTRAL"
|
| 343 |
+
if macd_val is not None and signal_val is not None and not pd.isna(macd_val) and not pd.isna(signal_val):
|
| 344 |
+
if macd_val > signal_val: macd_signal = "BULLISH_CROSS"
|
| 345 |
+
elif macd_val < signal_val: macd_signal = "BEARISH_CROSS"
|
| 346 |
+
|
| 347 |
+
trend_signal = "NEUTRAL"
|
| 348 |
+
sma50 = current_data.get('SMA_50')
|
| 349 |
+
sma20 = current_data.get('SMA_20')
|
| 350 |
+
|
| 351 |
+
# Check all components for trend signal
|
| 352 |
+
if sma200 is not None and sma50 is not None and sma20 is not None and not pd.isna(sma50) and not pd.isna(sma20):
|
| 353 |
+
if price > sma20 > sma50 > sma200: trend_signal = "STRONG_BULLISH"
|
| 354 |
+
elif price < sma20 < sma50 < sma200: trend_signal = "STRONG_BEARISH"
|
| 355 |
+
elif price > sma200: trend_signal = "BULLISH"
|
| 356 |
+
elif price < sma200: trend_signal = "BEARISH"
|
| 357 |
+
|
| 358 |
+
return {
|
| 359 |
+
"ticker": symbol,
|
| 360 |
+
"current_price": round(price, 2),
|
| 361 |
+
"sma_20": round(current_data['SMA_20'], 2) if not pd.isna(current_data.get('SMA_20')) else "N/A",
|
| 362 |
+
"ema_20": round(current_data['EMA_20'], 2) if not pd.isna(current_data.get('EMA_20')) else "N/A",
|
| 363 |
+
"sma_50": round(current_data['SMA_50'], 2) if not pd.isna(current_data.get('SMA_50')) else "N/A",
|
| 364 |
+
"sma_200": round(sma200, 2) if (sma200 is not None and not pd.isna(sma200)) else "N/A",
|
| 365 |
+
"rsi_14": round(rsi_val, 2) if (rsi_val is not None and not pd.isna(rsi_val)) else "N/A",
|
| 366 |
+
"macd": round(macd_val, 2) if (macd_val is not None and not pd.isna(macd_val)) else "N/A",
|
| 367 |
+
"macd_signal": macd_signal,
|
| 368 |
+
"rsi_signal": rsi_signal,
|
| 369 |
+
"trend_signal": trend_signal
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
except Exception as e:
|
| 373 |
+
return {"error": str(e)}
|
| 374 |
+
|
| 375 |
+
def get_fundamental_data(symbol: str) -> dict:
|
| 376 |
+
"""
|
| 377 |
+
Fetches fundamental financial metrics: P/E, PEG, Debt/Equity, Debt/Asset, and Net Profit Margin.
|
| 378 |
+
"""
|
| 379 |
+
print(f"[DEBUG] get_fundamental_data called for: {symbol}")
|
| 380 |
+
try:
|
| 381 |
+
symbol = check_and_fix_ticker(symbol)
|
| 382 |
+
ticker = yf.Ticker(symbol)
|
| 383 |
+
info = ticker.info
|
| 384 |
+
|
| 385 |
+
# Use info.get to handle missing keys gracefully
|
| 386 |
+
pe_ratio = info.get('forwardPE') or info.get('trailingPE')
|
| 387 |
+
peg_ratio = info.get('pegRatio')
|
| 388 |
+
debt_to_equity = info.get('debtToEquity')
|
| 389 |
+
profit_margin = info.get('profitMargins')
|
| 390 |
+
|
| 391 |
+
eps_trailing = info.get('trailingEps')
|
| 392 |
+
eps_forward = info.get('forwardEps')
|
| 393 |
+
dividend_yield = info.get('dividendYield')
|
| 394 |
+
|
| 395 |
+
# Ticker Calendar (Earnings)
|
| 396 |
+
next_earnings = "N/A"
|
| 397 |
+
try:
|
| 398 |
+
cal = ticker.calendar
|
| 399 |
+
if cal and 'Earnings Date' in cal:
|
| 400 |
+
dates = cal['Earnings Date']
|
| 401 |
+
if dates:
|
| 402 |
+
next_earnings = dates[0].strftime("%Y-%m-%d")
|
| 403 |
+
except Exception:
|
| 404 |
+
pass
|
| 405 |
+
|
| 406 |
+
return {
|
| 407 |
+
"ticker": symbol,
|
| 408 |
+
"pe_ratio": round(pe_ratio, 2) if pe_ratio else "N/A",
|
| 409 |
+
"peg_ratio": round(peg_ratio, 2) if peg_ratio else "N/A",
|
| 410 |
+
"eps_trailing": round(eps_trailing, 2) if eps_trailing else "N/A",
|
| 411 |
+
"eps_forward": round(eps_forward, 2) if eps_forward else "N/A",
|
| 412 |
+
"debt_to_equity": round(debt_to_equity, 2) if debt_to_equity else "N/A",
|
| 413 |
+
"net_profit_margin": f"{round(profit_margin * 100, 2)}%" if profit_margin else "N/A",
|
| 414 |
+
"dividend_yield": f"{round(dividend_yield * 100, 2)}%" if dividend_yield else "N/A",
|
| 415 |
+
"market_cap": info.get('marketCap', "N/A"),
|
| 416 |
+
"sector": info.get('sector', "N/A"),
|
| 417 |
+
"next_earnings_date": next_earnings,
|
| 418 |
+
"valuation_score": "UNDERVALUED" if (pe_ratio and pe_ratio < 15) else "PREMIUM" if (pe_ratio and pe_ratio > 30) else "FAIR_VALUE",
|
| 419 |
+
"quality_score": "HIGH_QUALITY" if (profit_margin and profit_margin > 0.20) else "LOW_MARGIN" if (profit_margin and profit_margin < 0.10) else "AVERAGE"
|
| 420 |
+
}
|
| 421 |
+
except Exception as e:
|
| 422 |
+
return {"error": str(e)}
|
| 423 |
+
|
| 424 |
+
def get_analyst_consensus(symbol: str) -> dict:
|
| 425 |
+
"""
|
| 426 |
+
Fetches Wall St. analyst recommendations and price targets.
|
| 427 |
+
"""
|
| 428 |
+
print(f"[DEBUG] get_analyst_consensus called for: {symbol}")
|
| 429 |
+
try:
|
| 430 |
+
symbol = check_and_fix_ticker(symbol)
|
| 431 |
+
ticker = yf.Ticker(symbol)
|
| 432 |
+
info = ticker.info
|
| 433 |
+
|
| 434 |
+
consensus = info.get('recommendationKey', 'none')
|
| 435 |
+
target = info.get('targetMeanPrice')
|
| 436 |
+
num_analysts = info.get('numberOfAnalystOpinions')
|
| 437 |
+
|
| 438 |
+
# Current price for comparison
|
| 439 |
+
current = info.get('currentPrice') or info.get('regularMarketPrice') or info.get('previousClose')
|
| 440 |
+
|
| 441 |
+
upside = "N/A"
|
| 442 |
+
if target and current and current > 0:
|
| 443 |
+
upside_pct = ((target - current) / current) * 100
|
| 444 |
+
upside = f"{round(upside_pct, 1)}%"
|
| 445 |
+
|
| 446 |
+
return {
|
| 447 |
+
"consensus": consensus.replace('_', ' ').title(),
|
| 448 |
+
"target_price": target or "N/A",
|
| 449 |
+
"current_price": current,
|
| 450 |
+
"upside_potential": upside,
|
| 451 |
+
"analyst_count": num_analysts or "N/A"
|
| 452 |
+
}
|
| 453 |
+
except Exception as e:
|
| 454 |
+
return {"error": f"Failed to fetch analyst data: {str(e)}"}
|
src/agora/backend/tools/news_data.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from ddgs import DDGS
|
| 2 |
+
from transformers import pipeline
|
| 3 |
+
import torch
|
| 4 |
+
from curl_cffi import requests
|
| 5 |
+
from bs4 import BeautifulSoup
|
| 6 |
+
import yfinance as yf
|
| 7 |
+
import datetime
|
| 8 |
+
import time
|
| 9 |
+
from typing import Optional
|
| 10 |
+
from pydantic import BaseModel, Field
|
| 11 |
+
import concurrent.futures
|
| 12 |
+
|
| 13 |
+
# Global variable for lazy loading
|
| 14 |
+
_sentiment_pipeline = None
|
| 15 |
+
|
| 16 |
+
def get_sentiment_pipeline():
|
| 17 |
+
"""
|
| 18 |
+
Lazy loads the FinBERT pipeline.
|
| 19 |
+
"""
|
| 20 |
+
print(f"[DEBUG] get_sentiment_pipeline called")
|
| 21 |
+
global _sentiment_pipeline
|
| 22 |
+
if _sentiment_pipeline is None:
|
| 23 |
+
try:
|
| 24 |
+
print("Loading FinBERT model...")
|
| 25 |
+
# Use CPU to avoid CUDA complexity if not needed, or let torch decide if fast
|
| 26 |
+
_sentiment_pipeline = pipeline("sentiment-analysis", model="ProsusAI/finbert")
|
| 27 |
+
except Exception as e:
|
| 28 |
+
print(f"Failed to load FinBERT: {e}")
|
| 29 |
+
return None
|
| 30 |
+
return _sentiment_pipeline
|
| 31 |
+
|
| 32 |
+
def _fetch_page_content(url: str, timeout: int = 15) -> Optional[str]:
|
| 33 |
+
"""Fetch and extract text content from a web page."""
|
| 34 |
+
print(f"[DEBUG] Fetching: {url}")
|
| 35 |
+
start_time = time.time()
|
| 36 |
+
try:
|
| 37 |
+
# Use curl_cffi to impersonate Chrome 110 (Bypasses TLS Fingerprinting)
|
| 38 |
+
# Headers are auto-managed by impersonate
|
| 39 |
+
response = requests.get(url, timeout=timeout, impersonate="chrome110")
|
| 40 |
+
response.raise_for_status()
|
| 41 |
+
|
| 42 |
+
soup = BeautifulSoup(response.content, 'html.parser')
|
| 43 |
+
|
| 44 |
+
# Remove ads, popups, and non-content elements
|
| 45 |
+
# Targeted classes: .ad, .popup, .modal, .cookie-banner, etc.
|
| 46 |
+
for tag in soup.select("script, style, nav, footer, header, aside, form, iframe, .ad, .popup, .modal, .cookie-banner, [id*='popup'], [class*='popup'], [class*='ad-'], [class*='banner']"):
|
| 47 |
+
tag.decompose()
|
| 48 |
+
|
| 49 |
+
# Extract text
|
| 50 |
+
text = soup.get_text(separator=' ', strip=True)
|
| 51 |
+
duration = round(time.time() - start_time, 2)
|
| 52 |
+
print(f"[DEBUG] Fetch success ({duration}s): {url}")
|
| 53 |
+
return text
|
| 54 |
+
except Exception as e:
|
| 55 |
+
msg = str(e)
|
| 56 |
+
if "403" in msg:
|
| 57 |
+
print(f"[INFO] Access denied (403) for {url}. Falling back to snippet.")
|
| 58 |
+
else:
|
| 59 |
+
print(f"[WARNING] Failed to fetch content from {url}: {msg}")
|
| 60 |
+
return None
|
| 61 |
+
|
| 62 |
+
# Validation Model
|
| 63 |
+
class NewsArticle(BaseModel):
|
| 64 |
+
title: str = Field(..., description="The headline of the news article.")
|
| 65 |
+
link: str = Field(..., description="The direct URL to the full article.")
|
| 66 |
+
snippet: str = Field(..., description="A brief summary or body text.")
|
| 67 |
+
datetime: Optional[str] = Field(None, description="Publication date if available.")
|
| 68 |
+
|
| 69 |
+
def search_news(ticker: str) -> str:
|
| 70 |
+
"""
|
| 71 |
+
Searches for the latest news regarding the stock ticker using DuckDuckGo.
|
| 72 |
+
Analyzes each headline with FinBERT for sentiment.
|
| 73 |
+
Returns a summary string of the top 5 results with sentiment scores.
|
| 74 |
+
"""
|
| 75 |
+
print(f"[DEBUG] search_news called with: {ticker}")
|
| 76 |
+
try:
|
| 77 |
+
if not ticker:
|
| 78 |
+
return "No ticker provided for news search."
|
| 79 |
+
|
| 80 |
+
ticker = ticker.upper().strip()
|
| 81 |
+
articles_pool = []
|
| 82 |
+
|
| 83 |
+
# 1. Fetch from Yahoo Finance API (Reliable)
|
| 84 |
+
try:
|
| 85 |
+
print("[DEBUG] Fetching YF API news...")
|
| 86 |
+
yf_ticker = yf.Ticker(ticker)
|
| 87 |
+
yf_raw = yf_ticker.news
|
| 88 |
+
if yf_raw:
|
| 89 |
+
for item in yf_raw:
|
| 90 |
+
ts = item.get('providerPublishTime')
|
| 91 |
+
date_str = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d') if ts else 'Unknown'
|
| 92 |
+
articles_pool.append(NewsArticle(
|
| 93 |
+
title=item.get('title', 'No Title'),
|
| 94 |
+
link=item.get('link', ''),
|
| 95 |
+
snippet=f"Source: {item.get('publisher')} - {date_str}",
|
| 96 |
+
datetime=date_str
|
| 97 |
+
))
|
| 98 |
+
except Exception as e:
|
| 99 |
+
print(f"[WARNING] YF API failed: {e}")
|
| 100 |
+
|
| 101 |
+
# 2. Add DuckDuckGo Targeted Search (Secondary)
|
| 102 |
+
# Targeted sites: CNBC, Bloomberg, Investing.com, MarketWatch
|
| 103 |
+
query = f"{ticker} stock news (site:cnbc.com OR site:bloomberg.com OR site:investing.com OR site:marketwatch.com)"
|
| 104 |
+
|
| 105 |
+
with DDGS() as ddgs:
|
| 106 |
+
raw_results = list(ddgs.news(query, max_results=10))
|
| 107 |
+
for raw_item in raw_results:
|
| 108 |
+
try:
|
| 109 |
+
articles_pool.append(NewsArticle(
|
| 110 |
+
title=raw_item.get('title', 'No Title'),
|
| 111 |
+
link=raw_item.get('url', ''),
|
| 112 |
+
snippet=raw_item.get('body', ''),
|
| 113 |
+
datetime=raw_item.get('date', 'Unknown')
|
| 114 |
+
))
|
| 115 |
+
except: continue
|
| 116 |
+
|
| 117 |
+
if not articles_pool:
|
| 118 |
+
return f"No recent news found for {ticker}."
|
| 119 |
+
|
| 120 |
+
# Deduplicate by Title
|
| 121 |
+
seen_titles = set()
|
| 122 |
+
unique_articles = []
|
| 123 |
+
for a in articles_pool:
|
| 124 |
+
if a.title not in seen_titles:
|
| 125 |
+
seen_titles.add(a.title)
|
| 126 |
+
unique_articles.append(a)
|
| 127 |
+
|
| 128 |
+
# Analyze Top 5
|
| 129 |
+
top_articles = unique_articles[:5]
|
| 130 |
+
sentiment_pipe = get_sentiment_pipeline()
|
| 131 |
+
|
| 132 |
+
results = []
|
| 133 |
+
|
| 134 |
+
# Helper to process
|
| 135 |
+
def process_article(article):
|
| 136 |
+
# FinBERT Analysis
|
| 137 |
+
sentiment_tag = ""
|
| 138 |
+
if sentiment_pipe:
|
| 139 |
+
try:
|
| 140 |
+
# Prefer full text fetch, fallback to Snippet
|
| 141 |
+
content = article.snippet if article.snippet else article.title
|
| 142 |
+
analysis_type = "Snippet" if article.snippet else "Headline"
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
# Try fetch full text with improved headers
|
| 146 |
+
if article.link:
|
| 147 |
+
full_text = _fetch_page_content(article.link)
|
| 148 |
+
if full_text and len(full_text) > 100:
|
| 149 |
+
content = full_text
|
| 150 |
+
analysis_type = "Full Text"
|
| 151 |
+
else:
|
| 152 |
+
# Fallback log
|
| 153 |
+
print(f"[DEBUG] Content too short/failed for {article.title[:30]}... using Snippet.")
|
| 154 |
+
|
| 155 |
+
# Truncate for BERT
|
| 156 |
+
score = sentiment_pipe(content[:2000])[0]
|
| 157 |
+
label = score['label']
|
| 158 |
+
conf = round(score['score'], 2)
|
| 159 |
+
sentiment_tag = f" [FinBERT ({analysis_type}): {label} ({conf})]"
|
| 160 |
+
except Exception as e:
|
| 161 |
+
sentiment_tag = f" [FinBERT: Error]"
|
| 162 |
+
|
| 163 |
+
return f"- [{article.datetime}] {article.title}{sentiment_tag}"
|
| 164 |
+
|
| 165 |
+
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
|
| 166 |
+
results = list(executor.map(process_article, top_articles))
|
| 167 |
+
|
| 168 |
+
return f"Recent News for {ticker} (Sources: YF, CNBC, Bloomberg, Investing):\n" + "\n".join(results)
|
| 169 |
+
|
| 170 |
+
except Exception as e:
|
| 171 |
+
return f"Error fetching news for {ticker}: {str(e)}"
|
src/agora/backend/tools/pl_calculator.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
from typing import List, Dict, Any
|
| 3 |
+
|
| 4 |
+
def calculate_strategy_metrics(legs: List[Dict[str, Any]], spot_price: float) -> Dict[str, Any]:
|
| 5 |
+
"""
|
| 6 |
+
Calculates Max Profit, Max Loss, and Breakeven for a given set of option legs.
|
| 7 |
+
Leg format: {'action': 'BUY'/'SELL', 'type': 'CALL'/'PUT', 'strike': float, 'price': float, 'expiry': str}
|
| 8 |
+
"""
|
| 9 |
+
if not legs:
|
| 10 |
+
return {"max_profit": 0, "max_loss": 0, "breakeven": 0, "net_cost": 0}
|
| 11 |
+
|
| 12 |
+
# 1. Calculate Net Debit/Credit
|
| 13 |
+
net_premium = 0
|
| 14 |
+
for leg in legs:
|
| 15 |
+
multiplier = 1 if leg['action'].upper() == 'BUY' else -1
|
| 16 |
+
net_premium += leg['price'] * multiplier
|
| 17 |
+
|
| 18 |
+
# Positive net_premium = Debit (Paying)
|
| 19 |
+
# Negative net_premium = Credit (Receiving)
|
| 20 |
+
is_debit = net_premium > 0
|
| 21 |
+
net_cost = abs(net_premium) * 100 # Multiplied by contract size
|
| 22 |
+
|
| 23 |
+
# 2. Identify Strategy Type and Calculate Risk
|
| 24 |
+
leg_count = len(legs)
|
| 25 |
+
expiries = set(leg['expiry'] for leg in legs)
|
| 26 |
+
is_multi_expiry = len(expiries) > 1
|
| 27 |
+
|
| 28 |
+
# Sort legs by strike for easier analysis
|
| 29 |
+
sorted_legs = sorted(legs, key=lambda x: x['strike'])
|
| 30 |
+
|
| 31 |
+
max_profit = 0
|
| 32 |
+
max_loss = 0
|
| 33 |
+
|
| 34 |
+
if is_multi_expiry:
|
| 35 |
+
# Complex calculation for Calendars/Diagonals
|
| 36 |
+
# For simplicity in this version, we provide an ESTIMATE based on premium paid
|
| 37 |
+
# Usually Max Loss = Net Debit Paid
|
| 38 |
+
if is_debit:
|
| 39 |
+
max_loss = net_cost
|
| 40 |
+
# Max profit is capped by the back-month value at front-month expiration
|
| 41 |
+
# This is hard to calculate without a model, so we flag it as an estimate
|
| 42 |
+
max_profit = "Estimated (Limited)"
|
| 43 |
+
else:
|
| 44 |
+
# Net Credit Calendar (Rare/Risky)
|
| 45 |
+
max_loss = "Unlimited"
|
| 46 |
+
max_profit = net_cost
|
| 47 |
+
|
| 48 |
+
elif leg_count == 1:
|
| 49 |
+
# Long/Short Call/Put
|
| 50 |
+
if legs[0]['action'].upper() == 'BUY':
|
| 51 |
+
max_loss = net_cost
|
| 52 |
+
max_profit = "Unlimited"
|
| 53 |
+
else:
|
| 54 |
+
max_profit = net_cost
|
| 55 |
+
max_loss = "Unlimited"
|
| 56 |
+
|
| 57 |
+
elif leg_count == 2:
|
| 58 |
+
# Spreads (Vertical)
|
| 59 |
+
s1, s2 = sorted_legs[0]['strike'], sorted_legs[1]['strike']
|
| 60 |
+
spread_width = (s2 - s1) * 100
|
| 61 |
+
|
| 62 |
+
if is_debit:
|
| 63 |
+
max_loss = net_cost
|
| 64 |
+
max_profit = spread_width - net_cost
|
| 65 |
+
else:
|
| 66 |
+
max_profit = net_cost
|
| 67 |
+
max_loss = spread_width - net_cost
|
| 68 |
+
|
| 69 |
+
elif leg_count == 4:
|
| 70 |
+
# Iron Condor / Iron Butterfly
|
| 71 |
+
# Max Profit = Net Credit
|
| 72 |
+
# Max Loss = Width of widest wing - Net Credit
|
| 73 |
+
if not is_debit:
|
| 74 |
+
put_spread_width = (sorted_legs[1]['strike'] - sorted_legs[0]['strike']) * 100
|
| 75 |
+
call_spread_width = (sorted_legs[3]['strike'] - sorted_legs[2]['strike']) * 100
|
| 76 |
+
widest_wing = max(put_spread_width, call_spread_width)
|
| 77 |
+
max_profit = net_cost
|
| 78 |
+
max_loss = widest_wing - net_cost
|
| 79 |
+
else:
|
| 80 |
+
# Reverse Iron Condor (Debit)
|
| 81 |
+
max_loss = net_cost
|
| 82 |
+
max_profit = max(sorted_legs[1]['strike'] - sorted_legs[0]['strike'], sorted_legs[3]['strike'] - sorted_legs[2]['strike']) * 100 - net_cost
|
| 83 |
+
|
| 84 |
+
elif leg_count == 3:
|
| 85 |
+
# Butterfly / Christmas Tree
|
| 86 |
+
# S1 (Buy 1), S2 (Sell 2), S3 (Buy 1)
|
| 87 |
+
if is_debit:
|
| 88 |
+
wing_width = (sorted_legs[1]['strike'] - sorted_legs[0]['strike']) * 100
|
| 89 |
+
max_loss = net_cost
|
| 90 |
+
max_profit = wing_width - net_cost
|
| 91 |
+
|
| 92 |
+
return {
|
| 93 |
+
"max_profit": max_profit,
|
| 94 |
+
"max_loss": max_loss,
|
| 95 |
+
"net_premium": round(net_premium, 2),
|
| 96 |
+
"is_debit": is_debit,
|
| 97 |
+
"leg_details": [f"{l['action']} {l['type']} {l['strike']} @ {l['price']} (Exp: {l['expiry']})" for l in legs]
|
| 98 |
+
}
|
src/agora/backend/utility/__init__.py
ADDED
|
File without changes
|
src/agora/backend/utility/autogen_model_factory.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
|
| 3 |
+
|
| 4 |
+
class AutoGenModelFactory:
|
| 5 |
+
"""
|
| 6 |
+
Factory for creating AutoGen compatible model instances.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
@staticmethod
|
| 10 |
+
def get_model(provider: str = "azure", # azure, openai, google, groq, ollama
|
| 11 |
+
model_name: str = "gpt-4o",
|
| 12 |
+
temperature: float = 0,
|
| 13 |
+
model_info: dict = None
|
| 14 |
+
):
|
| 15 |
+
"""
|
| 16 |
+
Returns an AutoGen OpenAIChatCompletionClient instance.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
# Lazy import to avoid dependency issues if autogen is not installed
|
| 20 |
+
try:
|
| 21 |
+
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
| 22 |
+
except ImportError as e:
|
| 23 |
+
raise ImportError("AutoGen libraries (autogen-agentchat, autogen-ext[openai]) are not installed.") from e
|
| 24 |
+
|
| 25 |
+
# ----------------------------------------------------------------------
|
| 26 |
+
# AZURE
|
| 27 |
+
# ----------------------------------------------------------------------
|
| 28 |
+
if provider.lower() == "azure":
|
| 29 |
+
token_provider = get_bearer_token_provider(
|
| 30 |
+
DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
|
| 31 |
+
)
|
| 32 |
+
return OpenAIChatCompletionClient(
|
| 33 |
+
model=model_name,
|
| 34 |
+
azure_endpoint=os.environ["AZURE_OPENAI_API_URI"],
|
| 35 |
+
api_version=os.environ["AZURE_OPENAI_API_VERSION"],
|
| 36 |
+
azure_ad_token_provider=token_provider,
|
| 37 |
+
temperature=temperature,
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
# ----------------------------------------------------------------------
|
| 41 |
+
# OPENAI
|
| 42 |
+
# ----------------------------------------------------------------------
|
| 43 |
+
elif provider.lower() == "openai":
|
| 44 |
+
return OpenAIChatCompletionClient(
|
| 45 |
+
model=model_name,
|
| 46 |
+
api_key=os.environ["OPENAI_API_KEY"],
|
| 47 |
+
temperature=temperature,
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
# ----------------------------------------------------------------------
|
| 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 |
+
# ----------------------------------------------------------------------
|
| 98 |
+
# OLLAMA
|
| 99 |
+
# ----------------------------------------------------------------------
|
| 100 |
+
elif provider.lower() == "ollama":
|
| 101 |
+
# Ensure model_info defaults to empty dict if None
|
| 102 |
+
info = model_info if model_info is not None else {}
|
| 103 |
+
return OpenAIChatCompletionClient(
|
| 104 |
+
model=model_name,
|
| 105 |
+
base_url="http://localhost:11434/v1",
|
| 106 |
+
api_key="ollama", # dummy key
|
| 107 |
+
model_info=info,
|
| 108 |
+
temperature=temperature,
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
else:
|
| 112 |
+
raise ValueError(f"Unsupported AutoGen provider: {provider}")
|
src/agora/frontend/.gitignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Logs
|
| 2 |
+
logs
|
| 3 |
+
*.log
|
| 4 |
+
npm-debug.log*
|
| 5 |
+
yarn-debug.log*
|
| 6 |
+
yarn-error.log*
|
| 7 |
+
pnpm-debug.log*
|
| 8 |
+
lerna-debug.log*
|
| 9 |
+
|
| 10 |
+
node_modules
|
| 11 |
+
dist
|
| 12 |
+
dist-ssr
|
| 13 |
+
*.local
|
| 14 |
+
|
| 15 |
+
# Editor directories and files
|
| 16 |
+
.vscode/*
|
| 17 |
+
!.vscode/extensions.json
|
| 18 |
+
.idea
|
| 19 |
+
.DS_Store
|
| 20 |
+
*.suo
|
| 21 |
+
*.ntvs*
|
| 22 |
+
*.njsproj
|
| 23 |
+
*.sln
|
| 24 |
+
*.sw?
|
src/agora/frontend/.vscode/extensions.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"recommendations": ["Vue.volar"]
|
| 3 |
+
}
|
src/agora/frontend/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Vue 3 + Vite
|
| 2 |
+
|
| 3 |
+
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
| 4 |
+
|
| 5 |
+
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).
|
src/agora/frontend/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
+
<title>Agora - Multi-Agent Trading Intelligence</title>
|
| 8 |
+
</head>
|
| 9 |
+
<body>
|
| 10 |
+
<div id="app"></div>
|
| 11 |
+
<script type="module" src="/src/main.js"></script>
|
| 12 |
+
</body>
|
| 13 |
+
</html>
|
src/agora/frontend/package-lock.json
ADDED
|
@@ -0,0 +1,1627 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "frontend",
|
| 3 |
+
"version": "0.0.0",
|
| 4 |
+
"lockfileVersion": 3,
|
| 5 |
+
"requires": true,
|
| 6 |
+
"packages": {
|
| 7 |
+
"": {
|
| 8 |
+
"name": "frontend",
|
| 9 |
+
"version": "0.0.0",
|
| 10 |
+
"dependencies": {
|
| 11 |
+
"axios": "^1.16.0",
|
| 12 |
+
"lucide-vue-next": "^0.563.0",
|
| 13 |
+
"vue": "^3.5.24"
|
| 14 |
+
},
|
| 15 |
+
"devDependencies": {
|
| 16 |
+
"@vitejs/plugin-vue": "^6.0.1",
|
| 17 |
+
"vite": "^7.3.2"
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"node_modules/@babel/helper-string-parser": {
|
| 21 |
+
"version": "7.27.1",
|
| 22 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
| 23 |
+
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
| 24 |
+
"license": "MIT",
|
| 25 |
+
"engines": {
|
| 26 |
+
"node": ">=6.9.0"
|
| 27 |
+
}
|
| 28 |
+
},
|
| 29 |
+
"node_modules/@babel/helper-validator-identifier": {
|
| 30 |
+
"version": "7.28.5",
|
| 31 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
| 32 |
+
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
| 33 |
+
"license": "MIT",
|
| 34 |
+
"engines": {
|
| 35 |
+
"node": ">=6.9.0"
|
| 36 |
+
}
|
| 37 |
+
},
|
| 38 |
+
"node_modules/@babel/parser": {
|
| 39 |
+
"version": "7.29.0",
|
| 40 |
+
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
|
| 41 |
+
"integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
|
| 42 |
+
"license": "MIT",
|
| 43 |
+
"dependencies": {
|
| 44 |
+
"@babel/types": "^7.29.0"
|
| 45 |
+
},
|
| 46 |
+
"bin": {
|
| 47 |
+
"parser": "bin/babel-parser.js"
|
| 48 |
+
},
|
| 49 |
+
"engines": {
|
| 50 |
+
"node": ">=6.0.0"
|
| 51 |
+
}
|
| 52 |
+
},
|
| 53 |
+
"node_modules/@babel/types": {
|
| 54 |
+
"version": "7.29.0",
|
| 55 |
+
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
| 56 |
+
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
|
| 57 |
+
"license": "MIT",
|
| 58 |
+
"dependencies": {
|
| 59 |
+
"@babel/helper-string-parser": "^7.27.1",
|
| 60 |
+
"@babel/helper-validator-identifier": "^7.28.5"
|
| 61 |
+
},
|
| 62 |
+
"engines": {
|
| 63 |
+
"node": ">=6.9.0"
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
"node_modules/@esbuild/aix-ppc64": {
|
| 67 |
+
"version": "0.27.2",
|
| 68 |
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
|
| 69 |
+
"integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
|
| 70 |
+
"cpu": [
|
| 71 |
+
"ppc64"
|
| 72 |
+
],
|
| 73 |
+
"dev": true,
|
| 74 |
+
"license": "MIT",
|
| 75 |
+
"optional": true,
|
| 76 |
+
"os": [
|
| 77 |
+
"aix"
|
| 78 |
+
],
|
| 79 |
+
"engines": {
|
| 80 |
+
"node": ">=18"
|
| 81 |
+
}
|
| 82 |
+
},
|
| 83 |
+
"node_modules/@esbuild/android-arm": {
|
| 84 |
+
"version": "0.27.2",
|
| 85 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
|
| 86 |
+
"integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
|
| 87 |
+
"cpu": [
|
| 88 |
+
"arm"
|
| 89 |
+
],
|
| 90 |
+
"dev": true,
|
| 91 |
+
"license": "MIT",
|
| 92 |
+
"optional": true,
|
| 93 |
+
"os": [
|
| 94 |
+
"android"
|
| 95 |
+
],
|
| 96 |
+
"engines": {
|
| 97 |
+
"node": ">=18"
|
| 98 |
+
}
|
| 99 |
+
},
|
| 100 |
+
"node_modules/@esbuild/android-arm64": {
|
| 101 |
+
"version": "0.27.2",
|
| 102 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
|
| 103 |
+
"integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
|
| 104 |
+
"cpu": [
|
| 105 |
+
"arm64"
|
| 106 |
+
],
|
| 107 |
+
"dev": true,
|
| 108 |
+
"license": "MIT",
|
| 109 |
+
"optional": true,
|
| 110 |
+
"os": [
|
| 111 |
+
"android"
|
| 112 |
+
],
|
| 113 |
+
"engines": {
|
| 114 |
+
"node": ">=18"
|
| 115 |
+
}
|
| 116 |
+
},
|
| 117 |
+
"node_modules/@esbuild/android-x64": {
|
| 118 |
+
"version": "0.27.2",
|
| 119 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
|
| 120 |
+
"integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
|
| 121 |
+
"cpu": [
|
| 122 |
+
"x64"
|
| 123 |
+
],
|
| 124 |
+
"dev": true,
|
| 125 |
+
"license": "MIT",
|
| 126 |
+
"optional": true,
|
| 127 |
+
"os": [
|
| 128 |
+
"android"
|
| 129 |
+
],
|
| 130 |
+
"engines": {
|
| 131 |
+
"node": ">=18"
|
| 132 |
+
}
|
| 133 |
+
},
|
| 134 |
+
"node_modules/@esbuild/darwin-arm64": {
|
| 135 |
+
"version": "0.27.2",
|
| 136 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
|
| 137 |
+
"integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
|
| 138 |
+
"cpu": [
|
| 139 |
+
"arm64"
|
| 140 |
+
],
|
| 141 |
+
"dev": true,
|
| 142 |
+
"license": "MIT",
|
| 143 |
+
"optional": true,
|
| 144 |
+
"os": [
|
| 145 |
+
"darwin"
|
| 146 |
+
],
|
| 147 |
+
"engines": {
|
| 148 |
+
"node": ">=18"
|
| 149 |
+
}
|
| 150 |
+
},
|
| 151 |
+
"node_modules/@esbuild/darwin-x64": {
|
| 152 |
+
"version": "0.27.2",
|
| 153 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
|
| 154 |
+
"integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
|
| 155 |
+
"cpu": [
|
| 156 |
+
"x64"
|
| 157 |
+
],
|
| 158 |
+
"dev": true,
|
| 159 |
+
"license": "MIT",
|
| 160 |
+
"optional": true,
|
| 161 |
+
"os": [
|
| 162 |
+
"darwin"
|
| 163 |
+
],
|
| 164 |
+
"engines": {
|
| 165 |
+
"node": ">=18"
|
| 166 |
+
}
|
| 167 |
+
},
|
| 168 |
+
"node_modules/@esbuild/freebsd-arm64": {
|
| 169 |
+
"version": "0.27.2",
|
| 170 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
|
| 171 |
+
"integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
|
| 172 |
+
"cpu": [
|
| 173 |
+
"arm64"
|
| 174 |
+
],
|
| 175 |
+
"dev": true,
|
| 176 |
+
"license": "MIT",
|
| 177 |
+
"optional": true,
|
| 178 |
+
"os": [
|
| 179 |
+
"freebsd"
|
| 180 |
+
],
|
| 181 |
+
"engines": {
|
| 182 |
+
"node": ">=18"
|
| 183 |
+
}
|
| 184 |
+
},
|
| 185 |
+
"node_modules/@esbuild/freebsd-x64": {
|
| 186 |
+
"version": "0.27.2",
|
| 187 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
|
| 188 |
+
"integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
|
| 189 |
+
"cpu": [
|
| 190 |
+
"x64"
|
| 191 |
+
],
|
| 192 |
+
"dev": true,
|
| 193 |
+
"license": "MIT",
|
| 194 |
+
"optional": true,
|
| 195 |
+
"os": [
|
| 196 |
+
"freebsd"
|
| 197 |
+
],
|
| 198 |
+
"engines": {
|
| 199 |
+
"node": ">=18"
|
| 200 |
+
}
|
| 201 |
+
},
|
| 202 |
+
"node_modules/@esbuild/linux-arm": {
|
| 203 |
+
"version": "0.27.2",
|
| 204 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
|
| 205 |
+
"integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
|
| 206 |
+
"cpu": [
|
| 207 |
+
"arm"
|
| 208 |
+
],
|
| 209 |
+
"dev": true,
|
| 210 |
+
"license": "MIT",
|
| 211 |
+
"optional": true,
|
| 212 |
+
"os": [
|
| 213 |
+
"linux"
|
| 214 |
+
],
|
| 215 |
+
"engines": {
|
| 216 |
+
"node": ">=18"
|
| 217 |
+
}
|
| 218 |
+
},
|
| 219 |
+
"node_modules/@esbuild/linux-arm64": {
|
| 220 |
+
"version": "0.27.2",
|
| 221 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
|
| 222 |
+
"integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
|
| 223 |
+
"cpu": [
|
| 224 |
+
"arm64"
|
| 225 |
+
],
|
| 226 |
+
"dev": true,
|
| 227 |
+
"license": "MIT",
|
| 228 |
+
"optional": true,
|
| 229 |
+
"os": [
|
| 230 |
+
"linux"
|
| 231 |
+
],
|
| 232 |
+
"engines": {
|
| 233 |
+
"node": ">=18"
|
| 234 |
+
}
|
| 235 |
+
},
|
| 236 |
+
"node_modules/@esbuild/linux-ia32": {
|
| 237 |
+
"version": "0.27.2",
|
| 238 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
|
| 239 |
+
"integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
|
| 240 |
+
"cpu": [
|
| 241 |
+
"ia32"
|
| 242 |
+
],
|
| 243 |
+
"dev": true,
|
| 244 |
+
"license": "MIT",
|
| 245 |
+
"optional": true,
|
| 246 |
+
"os": [
|
| 247 |
+
"linux"
|
| 248 |
+
],
|
| 249 |
+
"engines": {
|
| 250 |
+
"node": ">=18"
|
| 251 |
+
}
|
| 252 |
+
},
|
| 253 |
+
"node_modules/@esbuild/linux-loong64": {
|
| 254 |
+
"version": "0.27.2",
|
| 255 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
|
| 256 |
+
"integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
|
| 257 |
+
"cpu": [
|
| 258 |
+
"loong64"
|
| 259 |
+
],
|
| 260 |
+
"dev": true,
|
| 261 |
+
"license": "MIT",
|
| 262 |
+
"optional": true,
|
| 263 |
+
"os": [
|
| 264 |
+
"linux"
|
| 265 |
+
],
|
| 266 |
+
"engines": {
|
| 267 |
+
"node": ">=18"
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
"node_modules/@esbuild/linux-mips64el": {
|
| 271 |
+
"version": "0.27.2",
|
| 272 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
|
| 273 |
+
"integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
|
| 274 |
+
"cpu": [
|
| 275 |
+
"mips64el"
|
| 276 |
+
],
|
| 277 |
+
"dev": true,
|
| 278 |
+
"license": "MIT",
|
| 279 |
+
"optional": true,
|
| 280 |
+
"os": [
|
| 281 |
+
"linux"
|
| 282 |
+
],
|
| 283 |
+
"engines": {
|
| 284 |
+
"node": ">=18"
|
| 285 |
+
}
|
| 286 |
+
},
|
| 287 |
+
"node_modules/@esbuild/linux-ppc64": {
|
| 288 |
+
"version": "0.27.2",
|
| 289 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
|
| 290 |
+
"integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
|
| 291 |
+
"cpu": [
|
| 292 |
+
"ppc64"
|
| 293 |
+
],
|
| 294 |
+
"dev": true,
|
| 295 |
+
"license": "MIT",
|
| 296 |
+
"optional": true,
|
| 297 |
+
"os": [
|
| 298 |
+
"linux"
|
| 299 |
+
],
|
| 300 |
+
"engines": {
|
| 301 |
+
"node": ">=18"
|
| 302 |
+
}
|
| 303 |
+
},
|
| 304 |
+
"node_modules/@esbuild/linux-riscv64": {
|
| 305 |
+
"version": "0.27.2",
|
| 306 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
|
| 307 |
+
"integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
|
| 308 |
+
"cpu": [
|
| 309 |
+
"riscv64"
|
| 310 |
+
],
|
| 311 |
+
"dev": true,
|
| 312 |
+
"license": "MIT",
|
| 313 |
+
"optional": true,
|
| 314 |
+
"os": [
|
| 315 |
+
"linux"
|
| 316 |
+
],
|
| 317 |
+
"engines": {
|
| 318 |
+
"node": ">=18"
|
| 319 |
+
}
|
| 320 |
+
},
|
| 321 |
+
"node_modules/@esbuild/linux-s390x": {
|
| 322 |
+
"version": "0.27.2",
|
| 323 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
|
| 324 |
+
"integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
|
| 325 |
+
"cpu": [
|
| 326 |
+
"s390x"
|
| 327 |
+
],
|
| 328 |
+
"dev": true,
|
| 329 |
+
"license": "MIT",
|
| 330 |
+
"optional": true,
|
| 331 |
+
"os": [
|
| 332 |
+
"linux"
|
| 333 |
+
],
|
| 334 |
+
"engines": {
|
| 335 |
+
"node": ">=18"
|
| 336 |
+
}
|
| 337 |
+
},
|
| 338 |
+
"node_modules/@esbuild/linux-x64": {
|
| 339 |
+
"version": "0.27.2",
|
| 340 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
|
| 341 |
+
"integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
|
| 342 |
+
"cpu": [
|
| 343 |
+
"x64"
|
| 344 |
+
],
|
| 345 |
+
"dev": true,
|
| 346 |
+
"license": "MIT",
|
| 347 |
+
"optional": true,
|
| 348 |
+
"os": [
|
| 349 |
+
"linux"
|
| 350 |
+
],
|
| 351 |
+
"engines": {
|
| 352 |
+
"node": ">=18"
|
| 353 |
+
}
|
| 354 |
+
},
|
| 355 |
+
"node_modules/@esbuild/netbsd-arm64": {
|
| 356 |
+
"version": "0.27.2",
|
| 357 |
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
|
| 358 |
+
"integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
|
| 359 |
+
"cpu": [
|
| 360 |
+
"arm64"
|
| 361 |
+
],
|
| 362 |
+
"dev": true,
|
| 363 |
+
"license": "MIT",
|
| 364 |
+
"optional": true,
|
| 365 |
+
"os": [
|
| 366 |
+
"netbsd"
|
| 367 |
+
],
|
| 368 |
+
"engines": {
|
| 369 |
+
"node": ">=18"
|
| 370 |
+
}
|
| 371 |
+
},
|
| 372 |
+
"node_modules/@esbuild/netbsd-x64": {
|
| 373 |
+
"version": "0.27.2",
|
| 374 |
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
|
| 375 |
+
"integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
|
| 376 |
+
"cpu": [
|
| 377 |
+
"x64"
|
| 378 |
+
],
|
| 379 |
+
"dev": true,
|
| 380 |
+
"license": "MIT",
|
| 381 |
+
"optional": true,
|
| 382 |
+
"os": [
|
| 383 |
+
"netbsd"
|
| 384 |
+
],
|
| 385 |
+
"engines": {
|
| 386 |
+
"node": ">=18"
|
| 387 |
+
}
|
| 388 |
+
},
|
| 389 |
+
"node_modules/@esbuild/openbsd-arm64": {
|
| 390 |
+
"version": "0.27.2",
|
| 391 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
|
| 392 |
+
"integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
|
| 393 |
+
"cpu": [
|
| 394 |
+
"arm64"
|
| 395 |
+
],
|
| 396 |
+
"dev": true,
|
| 397 |
+
"license": "MIT",
|
| 398 |
+
"optional": true,
|
| 399 |
+
"os": [
|
| 400 |
+
"openbsd"
|
| 401 |
+
],
|
| 402 |
+
"engines": {
|
| 403 |
+
"node": ">=18"
|
| 404 |
+
}
|
| 405 |
+
},
|
| 406 |
+
"node_modules/@esbuild/openbsd-x64": {
|
| 407 |
+
"version": "0.27.2",
|
| 408 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
|
| 409 |
+
"integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
|
| 410 |
+
"cpu": [
|
| 411 |
+
"x64"
|
| 412 |
+
],
|
| 413 |
+
"dev": true,
|
| 414 |
+
"license": "MIT",
|
| 415 |
+
"optional": true,
|
| 416 |
+
"os": [
|
| 417 |
+
"openbsd"
|
| 418 |
+
],
|
| 419 |
+
"engines": {
|
| 420 |
+
"node": ">=18"
|
| 421 |
+
}
|
| 422 |
+
},
|
| 423 |
+
"node_modules/@esbuild/openharmony-arm64": {
|
| 424 |
+
"version": "0.27.2",
|
| 425 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
|
| 426 |
+
"integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
|
| 427 |
+
"cpu": [
|
| 428 |
+
"arm64"
|
| 429 |
+
],
|
| 430 |
+
"dev": true,
|
| 431 |
+
"license": "MIT",
|
| 432 |
+
"optional": true,
|
| 433 |
+
"os": [
|
| 434 |
+
"openharmony"
|
| 435 |
+
],
|
| 436 |
+
"engines": {
|
| 437 |
+
"node": ">=18"
|
| 438 |
+
}
|
| 439 |
+
},
|
| 440 |
+
"node_modules/@esbuild/sunos-x64": {
|
| 441 |
+
"version": "0.27.2",
|
| 442 |
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
|
| 443 |
+
"integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
|
| 444 |
+
"cpu": [
|
| 445 |
+
"x64"
|
| 446 |
+
],
|
| 447 |
+
"dev": true,
|
| 448 |
+
"license": "MIT",
|
| 449 |
+
"optional": true,
|
| 450 |
+
"os": [
|
| 451 |
+
"sunos"
|
| 452 |
+
],
|
| 453 |
+
"engines": {
|
| 454 |
+
"node": ">=18"
|
| 455 |
+
}
|
| 456 |
+
},
|
| 457 |
+
"node_modules/@esbuild/win32-arm64": {
|
| 458 |
+
"version": "0.27.2",
|
| 459 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
|
| 460 |
+
"integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
|
| 461 |
+
"cpu": [
|
| 462 |
+
"arm64"
|
| 463 |
+
],
|
| 464 |
+
"dev": true,
|
| 465 |
+
"license": "MIT",
|
| 466 |
+
"optional": true,
|
| 467 |
+
"os": [
|
| 468 |
+
"win32"
|
| 469 |
+
],
|
| 470 |
+
"engines": {
|
| 471 |
+
"node": ">=18"
|
| 472 |
+
}
|
| 473 |
+
},
|
| 474 |
+
"node_modules/@esbuild/win32-ia32": {
|
| 475 |
+
"version": "0.27.2",
|
| 476 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
|
| 477 |
+
"integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
|
| 478 |
+
"cpu": [
|
| 479 |
+
"ia32"
|
| 480 |
+
],
|
| 481 |
+
"dev": true,
|
| 482 |
+
"license": "MIT",
|
| 483 |
+
"optional": true,
|
| 484 |
+
"os": [
|
| 485 |
+
"win32"
|
| 486 |
+
],
|
| 487 |
+
"engines": {
|
| 488 |
+
"node": ">=18"
|
| 489 |
+
}
|
| 490 |
+
},
|
| 491 |
+
"node_modules/@esbuild/win32-x64": {
|
| 492 |
+
"version": "0.27.2",
|
| 493 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
|
| 494 |
+
"integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
|
| 495 |
+
"cpu": [
|
| 496 |
+
"x64"
|
| 497 |
+
],
|
| 498 |
+
"dev": true,
|
| 499 |
+
"license": "MIT",
|
| 500 |
+
"optional": true,
|
| 501 |
+
"os": [
|
| 502 |
+
"win32"
|
| 503 |
+
],
|
| 504 |
+
"engines": {
|
| 505 |
+
"node": ">=18"
|
| 506 |
+
}
|
| 507 |
+
},
|
| 508 |
+
"node_modules/@jridgewell/sourcemap-codec": {
|
| 509 |
+
"version": "1.5.5",
|
| 510 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
| 511 |
+
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
| 512 |
+
"license": "MIT"
|
| 513 |
+
},
|
| 514 |
+
"node_modules/@rolldown/pluginutils": {
|
| 515 |
+
"version": "1.0.0-rc.2",
|
| 516 |
+
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz",
|
| 517 |
+
"integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==",
|
| 518 |
+
"dev": true,
|
| 519 |
+
"license": "MIT"
|
| 520 |
+
},
|
| 521 |
+
"node_modules/@rollup/rollup-android-arm-eabi": {
|
| 522 |
+
"version": "4.59.0",
|
| 523 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
| 524 |
+
"integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
|
| 525 |
+
"cpu": [
|
| 526 |
+
"arm"
|
| 527 |
+
],
|
| 528 |
+
"dev": true,
|
| 529 |
+
"license": "MIT",
|
| 530 |
+
"optional": true,
|
| 531 |
+
"os": [
|
| 532 |
+
"android"
|
| 533 |
+
]
|
| 534 |
+
},
|
| 535 |
+
"node_modules/@rollup/rollup-android-arm64": {
|
| 536 |
+
"version": "4.59.0",
|
| 537 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
|
| 538 |
+
"integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
|
| 539 |
+
"cpu": [
|
| 540 |
+
"arm64"
|
| 541 |
+
],
|
| 542 |
+
"dev": true,
|
| 543 |
+
"license": "MIT",
|
| 544 |
+
"optional": true,
|
| 545 |
+
"os": [
|
| 546 |
+
"android"
|
| 547 |
+
]
|
| 548 |
+
},
|
| 549 |
+
"node_modules/@rollup/rollup-darwin-arm64": {
|
| 550 |
+
"version": "4.59.0",
|
| 551 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
|
| 552 |
+
"integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
|
| 553 |
+
"cpu": [
|
| 554 |
+
"arm64"
|
| 555 |
+
],
|
| 556 |
+
"dev": true,
|
| 557 |
+
"license": "MIT",
|
| 558 |
+
"optional": true,
|
| 559 |
+
"os": [
|
| 560 |
+
"darwin"
|
| 561 |
+
]
|
| 562 |
+
},
|
| 563 |
+
"node_modules/@rollup/rollup-darwin-x64": {
|
| 564 |
+
"version": "4.59.0",
|
| 565 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
|
| 566 |
+
"integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
|
| 567 |
+
"cpu": [
|
| 568 |
+
"x64"
|
| 569 |
+
],
|
| 570 |
+
"dev": true,
|
| 571 |
+
"license": "MIT",
|
| 572 |
+
"optional": true,
|
| 573 |
+
"os": [
|
| 574 |
+
"darwin"
|
| 575 |
+
]
|
| 576 |
+
},
|
| 577 |
+
"node_modules/@rollup/rollup-freebsd-arm64": {
|
| 578 |
+
"version": "4.59.0",
|
| 579 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
|
| 580 |
+
"integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
|
| 581 |
+
"cpu": [
|
| 582 |
+
"arm64"
|
| 583 |
+
],
|
| 584 |
+
"dev": true,
|
| 585 |
+
"license": "MIT",
|
| 586 |
+
"optional": true,
|
| 587 |
+
"os": [
|
| 588 |
+
"freebsd"
|
| 589 |
+
]
|
| 590 |
+
},
|
| 591 |
+
"node_modules/@rollup/rollup-freebsd-x64": {
|
| 592 |
+
"version": "4.59.0",
|
| 593 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
|
| 594 |
+
"integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
|
| 595 |
+
"cpu": [
|
| 596 |
+
"x64"
|
| 597 |
+
],
|
| 598 |
+
"dev": true,
|
| 599 |
+
"license": "MIT",
|
| 600 |
+
"optional": true,
|
| 601 |
+
"os": [
|
| 602 |
+
"freebsd"
|
| 603 |
+
]
|
| 604 |
+
},
|
| 605 |
+
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
| 606 |
+
"version": "4.59.0",
|
| 607 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
|
| 608 |
+
"integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
|
| 609 |
+
"cpu": [
|
| 610 |
+
"arm"
|
| 611 |
+
],
|
| 612 |
+
"dev": true,
|
| 613 |
+
"license": "MIT",
|
| 614 |
+
"optional": true,
|
| 615 |
+
"os": [
|
| 616 |
+
"linux"
|
| 617 |
+
]
|
| 618 |
+
},
|
| 619 |
+
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
| 620 |
+
"version": "4.59.0",
|
| 621 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
|
| 622 |
+
"integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
|
| 623 |
+
"cpu": [
|
| 624 |
+
"arm"
|
| 625 |
+
],
|
| 626 |
+
"dev": true,
|
| 627 |
+
"license": "MIT",
|
| 628 |
+
"optional": true,
|
| 629 |
+
"os": [
|
| 630 |
+
"linux"
|
| 631 |
+
]
|
| 632 |
+
},
|
| 633 |
+
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
| 634 |
+
"version": "4.59.0",
|
| 635 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
|
| 636 |
+
"integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
|
| 637 |
+
"cpu": [
|
| 638 |
+
"arm64"
|
| 639 |
+
],
|
| 640 |
+
"dev": true,
|
| 641 |
+
"license": "MIT",
|
| 642 |
+
"optional": true,
|
| 643 |
+
"os": [
|
| 644 |
+
"linux"
|
| 645 |
+
]
|
| 646 |
+
},
|
| 647 |
+
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
| 648 |
+
"version": "4.59.0",
|
| 649 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
|
| 650 |
+
"integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
|
| 651 |
+
"cpu": [
|
| 652 |
+
"arm64"
|
| 653 |
+
],
|
| 654 |
+
"dev": true,
|
| 655 |
+
"license": "MIT",
|
| 656 |
+
"optional": true,
|
| 657 |
+
"os": [
|
| 658 |
+
"linux"
|
| 659 |
+
]
|
| 660 |
+
},
|
| 661 |
+
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
| 662 |
+
"version": "4.59.0",
|
| 663 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
|
| 664 |
+
"integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
|
| 665 |
+
"cpu": [
|
| 666 |
+
"loong64"
|
| 667 |
+
],
|
| 668 |
+
"dev": true,
|
| 669 |
+
"license": "MIT",
|
| 670 |
+
"optional": true,
|
| 671 |
+
"os": [
|
| 672 |
+
"linux"
|
| 673 |
+
]
|
| 674 |
+
},
|
| 675 |
+
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
| 676 |
+
"version": "4.59.0",
|
| 677 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
|
| 678 |
+
"integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
|
| 679 |
+
"cpu": [
|
| 680 |
+
"loong64"
|
| 681 |
+
],
|
| 682 |
+
"dev": true,
|
| 683 |
+
"license": "MIT",
|
| 684 |
+
"optional": true,
|
| 685 |
+
"os": [
|
| 686 |
+
"linux"
|
| 687 |
+
]
|
| 688 |
+
},
|
| 689 |
+
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
| 690 |
+
"version": "4.59.0",
|
| 691 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
|
| 692 |
+
"integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
|
| 693 |
+
"cpu": [
|
| 694 |
+
"ppc64"
|
| 695 |
+
],
|
| 696 |
+
"dev": true,
|
| 697 |
+
"license": "MIT",
|
| 698 |
+
"optional": true,
|
| 699 |
+
"os": [
|
| 700 |
+
"linux"
|
| 701 |
+
]
|
| 702 |
+
},
|
| 703 |
+
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
| 704 |
+
"version": "4.59.0",
|
| 705 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
|
| 706 |
+
"integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
|
| 707 |
+
"cpu": [
|
| 708 |
+
"ppc64"
|
| 709 |
+
],
|
| 710 |
+
"dev": true,
|
| 711 |
+
"license": "MIT",
|
| 712 |
+
"optional": true,
|
| 713 |
+
"os": [
|
| 714 |
+
"linux"
|
| 715 |
+
]
|
| 716 |
+
},
|
| 717 |
+
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
| 718 |
+
"version": "4.59.0",
|
| 719 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
|
| 720 |
+
"integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
|
| 721 |
+
"cpu": [
|
| 722 |
+
"riscv64"
|
| 723 |
+
],
|
| 724 |
+
"dev": true,
|
| 725 |
+
"license": "MIT",
|
| 726 |
+
"optional": true,
|
| 727 |
+
"os": [
|
| 728 |
+
"linux"
|
| 729 |
+
]
|
| 730 |
+
},
|
| 731 |
+
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
| 732 |
+
"version": "4.59.0",
|
| 733 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
|
| 734 |
+
"integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
|
| 735 |
+
"cpu": [
|
| 736 |
+
"riscv64"
|
| 737 |
+
],
|
| 738 |
+
"dev": true,
|
| 739 |
+
"license": "MIT",
|
| 740 |
+
"optional": true,
|
| 741 |
+
"os": [
|
| 742 |
+
"linux"
|
| 743 |
+
]
|
| 744 |
+
},
|
| 745 |
+
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
| 746 |
+
"version": "4.59.0",
|
| 747 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
|
| 748 |
+
"integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
|
| 749 |
+
"cpu": [
|
| 750 |
+
"s390x"
|
| 751 |
+
],
|
| 752 |
+
"dev": true,
|
| 753 |
+
"license": "MIT",
|
| 754 |
+
"optional": true,
|
| 755 |
+
"os": [
|
| 756 |
+
"linux"
|
| 757 |
+
]
|
| 758 |
+
},
|
| 759 |
+
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
| 760 |
+
"version": "4.59.0",
|
| 761 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
|
| 762 |
+
"integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
|
| 763 |
+
"cpu": [
|
| 764 |
+
"x64"
|
| 765 |
+
],
|
| 766 |
+
"dev": true,
|
| 767 |
+
"license": "MIT",
|
| 768 |
+
"optional": true,
|
| 769 |
+
"os": [
|
| 770 |
+
"linux"
|
| 771 |
+
]
|
| 772 |
+
},
|
| 773 |
+
"node_modules/@rollup/rollup-linux-x64-musl": {
|
| 774 |
+
"version": "4.59.0",
|
| 775 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
|
| 776 |
+
"integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
|
| 777 |
+
"cpu": [
|
| 778 |
+
"x64"
|
| 779 |
+
],
|
| 780 |
+
"dev": true,
|
| 781 |
+
"license": "MIT",
|
| 782 |
+
"optional": true,
|
| 783 |
+
"os": [
|
| 784 |
+
"linux"
|
| 785 |
+
]
|
| 786 |
+
},
|
| 787 |
+
"node_modules/@rollup/rollup-openbsd-x64": {
|
| 788 |
+
"version": "4.59.0",
|
| 789 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
|
| 790 |
+
"integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
|
| 791 |
+
"cpu": [
|
| 792 |
+
"x64"
|
| 793 |
+
],
|
| 794 |
+
"dev": true,
|
| 795 |
+
"license": "MIT",
|
| 796 |
+
"optional": true,
|
| 797 |
+
"os": [
|
| 798 |
+
"openbsd"
|
| 799 |
+
]
|
| 800 |
+
},
|
| 801 |
+
"node_modules/@rollup/rollup-openharmony-arm64": {
|
| 802 |
+
"version": "4.59.0",
|
| 803 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
|
| 804 |
+
"integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
|
| 805 |
+
"cpu": [
|
| 806 |
+
"arm64"
|
| 807 |
+
],
|
| 808 |
+
"dev": true,
|
| 809 |
+
"license": "MIT",
|
| 810 |
+
"optional": true,
|
| 811 |
+
"os": [
|
| 812 |
+
"openharmony"
|
| 813 |
+
]
|
| 814 |
+
},
|
| 815 |
+
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
| 816 |
+
"version": "4.59.0",
|
| 817 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
|
| 818 |
+
"integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
|
| 819 |
+
"cpu": [
|
| 820 |
+
"arm64"
|
| 821 |
+
],
|
| 822 |
+
"dev": true,
|
| 823 |
+
"license": "MIT",
|
| 824 |
+
"optional": true,
|
| 825 |
+
"os": [
|
| 826 |
+
"win32"
|
| 827 |
+
]
|
| 828 |
+
},
|
| 829 |
+
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
| 830 |
+
"version": "4.59.0",
|
| 831 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
|
| 832 |
+
"integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
|
| 833 |
+
"cpu": [
|
| 834 |
+
"ia32"
|
| 835 |
+
],
|
| 836 |
+
"dev": true,
|
| 837 |
+
"license": "MIT",
|
| 838 |
+
"optional": true,
|
| 839 |
+
"os": [
|
| 840 |
+
"win32"
|
| 841 |
+
]
|
| 842 |
+
},
|
| 843 |
+
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
| 844 |
+
"version": "4.59.0",
|
| 845 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
|
| 846 |
+
"integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
|
| 847 |
+
"cpu": [
|
| 848 |
+
"x64"
|
| 849 |
+
],
|
| 850 |
+
"dev": true,
|
| 851 |
+
"license": "MIT",
|
| 852 |
+
"optional": true,
|
| 853 |
+
"os": [
|
| 854 |
+
"win32"
|
| 855 |
+
]
|
| 856 |
+
},
|
| 857 |
+
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
| 858 |
+
"version": "4.59.0",
|
| 859 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
|
| 860 |
+
"integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
|
| 861 |
+
"cpu": [
|
| 862 |
+
"x64"
|
| 863 |
+
],
|
| 864 |
+
"dev": true,
|
| 865 |
+
"license": "MIT",
|
| 866 |
+
"optional": true,
|
| 867 |
+
"os": [
|
| 868 |
+
"win32"
|
| 869 |
+
]
|
| 870 |
+
},
|
| 871 |
+
"node_modules/@types/estree": {
|
| 872 |
+
"version": "1.0.8",
|
| 873 |
+
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
| 874 |
+
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
| 875 |
+
"dev": true,
|
| 876 |
+
"license": "MIT"
|
| 877 |
+
},
|
| 878 |
+
"node_modules/@vitejs/plugin-vue": {
|
| 879 |
+
"version": "6.0.4",
|
| 880 |
+
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz",
|
| 881 |
+
"integrity": "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==",
|
| 882 |
+
"dev": true,
|
| 883 |
+
"license": "MIT",
|
| 884 |
+
"dependencies": {
|
| 885 |
+
"@rolldown/pluginutils": "1.0.0-rc.2"
|
| 886 |
+
},
|
| 887 |
+
"engines": {
|
| 888 |
+
"node": "^20.19.0 || >=22.12.0"
|
| 889 |
+
},
|
| 890 |
+
"peerDependencies": {
|
| 891 |
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0",
|
| 892 |
+
"vue": "^3.2.25"
|
| 893 |
+
}
|
| 894 |
+
},
|
| 895 |
+
"node_modules/@vue/compiler-core": {
|
| 896 |
+
"version": "3.5.27",
|
| 897 |
+
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz",
|
| 898 |
+
"integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==",
|
| 899 |
+
"license": "MIT",
|
| 900 |
+
"dependencies": {
|
| 901 |
+
"@babel/parser": "^7.28.5",
|
| 902 |
+
"@vue/shared": "3.5.27",
|
| 903 |
+
"entities": "^7.0.0",
|
| 904 |
+
"estree-walker": "^2.0.2",
|
| 905 |
+
"source-map-js": "^1.2.1"
|
| 906 |
+
}
|
| 907 |
+
},
|
| 908 |
+
"node_modules/@vue/compiler-dom": {
|
| 909 |
+
"version": "3.5.27",
|
| 910 |
+
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz",
|
| 911 |
+
"integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==",
|
| 912 |
+
"license": "MIT",
|
| 913 |
+
"dependencies": {
|
| 914 |
+
"@vue/compiler-core": "3.5.27",
|
| 915 |
+
"@vue/shared": "3.5.27"
|
| 916 |
+
}
|
| 917 |
+
},
|
| 918 |
+
"node_modules/@vue/compiler-sfc": {
|
| 919 |
+
"version": "3.5.27",
|
| 920 |
+
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz",
|
| 921 |
+
"integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==",
|
| 922 |
+
"license": "MIT",
|
| 923 |
+
"dependencies": {
|
| 924 |
+
"@babel/parser": "^7.28.5",
|
| 925 |
+
"@vue/compiler-core": "3.5.27",
|
| 926 |
+
"@vue/compiler-dom": "3.5.27",
|
| 927 |
+
"@vue/compiler-ssr": "3.5.27",
|
| 928 |
+
"@vue/shared": "3.5.27",
|
| 929 |
+
"estree-walker": "^2.0.2",
|
| 930 |
+
"magic-string": "^0.30.21",
|
| 931 |
+
"postcss": "^8.5.6",
|
| 932 |
+
"source-map-js": "^1.2.1"
|
| 933 |
+
}
|
| 934 |
+
},
|
| 935 |
+
"node_modules/@vue/compiler-ssr": {
|
| 936 |
+
"version": "3.5.27",
|
| 937 |
+
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz",
|
| 938 |
+
"integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==",
|
| 939 |
+
"license": "MIT",
|
| 940 |
+
"dependencies": {
|
| 941 |
+
"@vue/compiler-dom": "3.5.27",
|
| 942 |
+
"@vue/shared": "3.5.27"
|
| 943 |
+
}
|
| 944 |
+
},
|
| 945 |
+
"node_modules/@vue/reactivity": {
|
| 946 |
+
"version": "3.5.27",
|
| 947 |
+
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.27.tgz",
|
| 948 |
+
"integrity": "sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==",
|
| 949 |
+
"license": "MIT",
|
| 950 |
+
"dependencies": {
|
| 951 |
+
"@vue/shared": "3.5.27"
|
| 952 |
+
}
|
| 953 |
+
},
|
| 954 |
+
"node_modules/@vue/runtime-core": {
|
| 955 |
+
"version": "3.5.27",
|
| 956 |
+
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.27.tgz",
|
| 957 |
+
"integrity": "sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==",
|
| 958 |
+
"license": "MIT",
|
| 959 |
+
"dependencies": {
|
| 960 |
+
"@vue/reactivity": "3.5.27",
|
| 961 |
+
"@vue/shared": "3.5.27"
|
| 962 |
+
}
|
| 963 |
+
},
|
| 964 |
+
"node_modules/@vue/runtime-dom": {
|
| 965 |
+
"version": "3.5.27",
|
| 966 |
+
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz",
|
| 967 |
+
"integrity": "sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==",
|
| 968 |
+
"license": "MIT",
|
| 969 |
+
"dependencies": {
|
| 970 |
+
"@vue/reactivity": "3.5.27",
|
| 971 |
+
"@vue/runtime-core": "3.5.27",
|
| 972 |
+
"@vue/shared": "3.5.27",
|
| 973 |
+
"csstype": "^3.2.3"
|
| 974 |
+
}
|
| 975 |
+
},
|
| 976 |
+
"node_modules/@vue/server-renderer": {
|
| 977 |
+
"version": "3.5.27",
|
| 978 |
+
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.27.tgz",
|
| 979 |
+
"integrity": "sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==",
|
| 980 |
+
"license": "MIT",
|
| 981 |
+
"dependencies": {
|
| 982 |
+
"@vue/compiler-ssr": "3.5.27",
|
| 983 |
+
"@vue/shared": "3.5.27"
|
| 984 |
+
},
|
| 985 |
+
"peerDependencies": {
|
| 986 |
+
"vue": "3.5.27"
|
| 987 |
+
}
|
| 988 |
+
},
|
| 989 |
+
"node_modules/@vue/shared": {
|
| 990 |
+
"version": "3.5.27",
|
| 991 |
+
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz",
|
| 992 |
+
"integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==",
|
| 993 |
+
"license": "MIT"
|
| 994 |
+
},
|
| 995 |
+
"node_modules/asynckit": {
|
| 996 |
+
"version": "0.4.0",
|
| 997 |
+
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
| 998 |
+
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
| 999 |
+
"license": "MIT"
|
| 1000 |
+
},
|
| 1001 |
+
"node_modules/axios": {
|
| 1002 |
+
"version": "1.16.0",
|
| 1003 |
+
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz",
|
| 1004 |
+
"integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==",
|
| 1005 |
+
"license": "MIT",
|
| 1006 |
+
"dependencies": {
|
| 1007 |
+
"follow-redirects": "^1.16.0",
|
| 1008 |
+
"form-data": "^4.0.5",
|
| 1009 |
+
"proxy-from-env": "^2.1.0"
|
| 1010 |
+
}
|
| 1011 |
+
},
|
| 1012 |
+
"node_modules/call-bind-apply-helpers": {
|
| 1013 |
+
"version": "1.0.2",
|
| 1014 |
+
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
| 1015 |
+
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
| 1016 |
+
"license": "MIT",
|
| 1017 |
+
"dependencies": {
|
| 1018 |
+
"es-errors": "^1.3.0",
|
| 1019 |
+
"function-bind": "^1.1.2"
|
| 1020 |
+
},
|
| 1021 |
+
"engines": {
|
| 1022 |
+
"node": ">= 0.4"
|
| 1023 |
+
}
|
| 1024 |
+
},
|
| 1025 |
+
"node_modules/combined-stream": {
|
| 1026 |
+
"version": "1.0.8",
|
| 1027 |
+
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
| 1028 |
+
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
| 1029 |
+
"license": "MIT",
|
| 1030 |
+
"dependencies": {
|
| 1031 |
+
"delayed-stream": "~1.0.0"
|
| 1032 |
+
},
|
| 1033 |
+
"engines": {
|
| 1034 |
+
"node": ">= 0.8"
|
| 1035 |
+
}
|
| 1036 |
+
},
|
| 1037 |
+
"node_modules/csstype": {
|
| 1038 |
+
"version": "3.2.3",
|
| 1039 |
+
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
| 1040 |
+
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
| 1041 |
+
"license": "MIT"
|
| 1042 |
+
},
|
| 1043 |
+
"node_modules/delayed-stream": {
|
| 1044 |
+
"version": "1.0.0",
|
| 1045 |
+
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
| 1046 |
+
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
| 1047 |
+
"license": "MIT",
|
| 1048 |
+
"engines": {
|
| 1049 |
+
"node": ">=0.4.0"
|
| 1050 |
+
}
|
| 1051 |
+
},
|
| 1052 |
+
"node_modules/dunder-proto": {
|
| 1053 |
+
"version": "1.0.1",
|
| 1054 |
+
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
| 1055 |
+
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
| 1056 |
+
"license": "MIT",
|
| 1057 |
+
"dependencies": {
|
| 1058 |
+
"call-bind-apply-helpers": "^1.0.1",
|
| 1059 |
+
"es-errors": "^1.3.0",
|
| 1060 |
+
"gopd": "^1.2.0"
|
| 1061 |
+
},
|
| 1062 |
+
"engines": {
|
| 1063 |
+
"node": ">= 0.4"
|
| 1064 |
+
}
|
| 1065 |
+
},
|
| 1066 |
+
"node_modules/entities": {
|
| 1067 |
+
"version": "7.0.1",
|
| 1068 |
+
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
| 1069 |
+
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
|
| 1070 |
+
"license": "BSD-2-Clause",
|
| 1071 |
+
"engines": {
|
| 1072 |
+
"node": ">=0.12"
|
| 1073 |
+
},
|
| 1074 |
+
"funding": {
|
| 1075 |
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 1076 |
+
}
|
| 1077 |
+
},
|
| 1078 |
+
"node_modules/es-define-property": {
|
| 1079 |
+
"version": "1.0.1",
|
| 1080 |
+
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
| 1081 |
+
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
| 1082 |
+
"license": "MIT",
|
| 1083 |
+
"engines": {
|
| 1084 |
+
"node": ">= 0.4"
|
| 1085 |
+
}
|
| 1086 |
+
},
|
| 1087 |
+
"node_modules/es-errors": {
|
| 1088 |
+
"version": "1.3.0",
|
| 1089 |
+
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
| 1090 |
+
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
| 1091 |
+
"license": "MIT",
|
| 1092 |
+
"engines": {
|
| 1093 |
+
"node": ">= 0.4"
|
| 1094 |
+
}
|
| 1095 |
+
},
|
| 1096 |
+
"node_modules/es-object-atoms": {
|
| 1097 |
+
"version": "1.1.1",
|
| 1098 |
+
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
| 1099 |
+
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
| 1100 |
+
"license": "MIT",
|
| 1101 |
+
"dependencies": {
|
| 1102 |
+
"es-errors": "^1.3.0"
|
| 1103 |
+
},
|
| 1104 |
+
"engines": {
|
| 1105 |
+
"node": ">= 0.4"
|
| 1106 |
+
}
|
| 1107 |
+
},
|
| 1108 |
+
"node_modules/es-set-tostringtag": {
|
| 1109 |
+
"version": "2.1.0",
|
| 1110 |
+
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
| 1111 |
+
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
| 1112 |
+
"license": "MIT",
|
| 1113 |
+
"dependencies": {
|
| 1114 |
+
"es-errors": "^1.3.0",
|
| 1115 |
+
"get-intrinsic": "^1.2.6",
|
| 1116 |
+
"has-tostringtag": "^1.0.2",
|
| 1117 |
+
"hasown": "^2.0.2"
|
| 1118 |
+
},
|
| 1119 |
+
"engines": {
|
| 1120 |
+
"node": ">= 0.4"
|
| 1121 |
+
}
|
| 1122 |
+
},
|
| 1123 |
+
"node_modules/esbuild": {
|
| 1124 |
+
"version": "0.27.2",
|
| 1125 |
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
|
| 1126 |
+
"integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
|
| 1127 |
+
"dev": true,
|
| 1128 |
+
"hasInstallScript": true,
|
| 1129 |
+
"license": "MIT",
|
| 1130 |
+
"bin": {
|
| 1131 |
+
"esbuild": "bin/esbuild"
|
| 1132 |
+
},
|
| 1133 |
+
"engines": {
|
| 1134 |
+
"node": ">=18"
|
| 1135 |
+
},
|
| 1136 |
+
"optionalDependencies": {
|
| 1137 |
+
"@esbuild/aix-ppc64": "0.27.2",
|
| 1138 |
+
"@esbuild/android-arm": "0.27.2",
|
| 1139 |
+
"@esbuild/android-arm64": "0.27.2",
|
| 1140 |
+
"@esbuild/android-x64": "0.27.2",
|
| 1141 |
+
"@esbuild/darwin-arm64": "0.27.2",
|
| 1142 |
+
"@esbuild/darwin-x64": "0.27.2",
|
| 1143 |
+
"@esbuild/freebsd-arm64": "0.27.2",
|
| 1144 |
+
"@esbuild/freebsd-x64": "0.27.2",
|
| 1145 |
+
"@esbuild/linux-arm": "0.27.2",
|
| 1146 |
+
"@esbuild/linux-arm64": "0.27.2",
|
| 1147 |
+
"@esbuild/linux-ia32": "0.27.2",
|
| 1148 |
+
"@esbuild/linux-loong64": "0.27.2",
|
| 1149 |
+
"@esbuild/linux-mips64el": "0.27.2",
|
| 1150 |
+
"@esbuild/linux-ppc64": "0.27.2",
|
| 1151 |
+
"@esbuild/linux-riscv64": "0.27.2",
|
| 1152 |
+
"@esbuild/linux-s390x": "0.27.2",
|
| 1153 |
+
"@esbuild/linux-x64": "0.27.2",
|
| 1154 |
+
"@esbuild/netbsd-arm64": "0.27.2",
|
| 1155 |
+
"@esbuild/netbsd-x64": "0.27.2",
|
| 1156 |
+
"@esbuild/openbsd-arm64": "0.27.2",
|
| 1157 |
+
"@esbuild/openbsd-x64": "0.27.2",
|
| 1158 |
+
"@esbuild/openharmony-arm64": "0.27.2",
|
| 1159 |
+
"@esbuild/sunos-x64": "0.27.2",
|
| 1160 |
+
"@esbuild/win32-arm64": "0.27.2",
|
| 1161 |
+
"@esbuild/win32-ia32": "0.27.2",
|
| 1162 |
+
"@esbuild/win32-x64": "0.27.2"
|
| 1163 |
+
}
|
| 1164 |
+
},
|
| 1165 |
+
"node_modules/estree-walker": {
|
| 1166 |
+
"version": "2.0.2",
|
| 1167 |
+
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
| 1168 |
+
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
| 1169 |
+
"license": "MIT"
|
| 1170 |
+
},
|
| 1171 |
+
"node_modules/fdir": {
|
| 1172 |
+
"version": "6.5.0",
|
| 1173 |
+
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
| 1174 |
+
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
| 1175 |
+
"dev": true,
|
| 1176 |
+
"license": "MIT",
|
| 1177 |
+
"engines": {
|
| 1178 |
+
"node": ">=12.0.0"
|
| 1179 |
+
},
|
| 1180 |
+
"peerDependencies": {
|
| 1181 |
+
"picomatch": "^3 || ^4"
|
| 1182 |
+
},
|
| 1183 |
+
"peerDependenciesMeta": {
|
| 1184 |
+
"picomatch": {
|
| 1185 |
+
"optional": true
|
| 1186 |
+
}
|
| 1187 |
+
}
|
| 1188 |
+
},
|
| 1189 |
+
"node_modules/follow-redirects": {
|
| 1190 |
+
"version": "1.16.0",
|
| 1191 |
+
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
| 1192 |
+
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
|
| 1193 |
+
"funding": [
|
| 1194 |
+
{
|
| 1195 |
+
"type": "individual",
|
| 1196 |
+
"url": "https://github.com/sponsors/RubenVerborgh"
|
| 1197 |
+
}
|
| 1198 |
+
],
|
| 1199 |
+
"license": "MIT",
|
| 1200 |
+
"engines": {
|
| 1201 |
+
"node": ">=4.0"
|
| 1202 |
+
},
|
| 1203 |
+
"peerDependenciesMeta": {
|
| 1204 |
+
"debug": {
|
| 1205 |
+
"optional": true
|
| 1206 |
+
}
|
| 1207 |
+
}
|
| 1208 |
+
},
|
| 1209 |
+
"node_modules/form-data": {
|
| 1210 |
+
"version": "4.0.5",
|
| 1211 |
+
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
| 1212 |
+
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
| 1213 |
+
"license": "MIT",
|
| 1214 |
+
"dependencies": {
|
| 1215 |
+
"asynckit": "^0.4.0",
|
| 1216 |
+
"combined-stream": "^1.0.8",
|
| 1217 |
+
"es-set-tostringtag": "^2.1.0",
|
| 1218 |
+
"hasown": "^2.0.2",
|
| 1219 |
+
"mime-types": "^2.1.12"
|
| 1220 |
+
},
|
| 1221 |
+
"engines": {
|
| 1222 |
+
"node": ">= 6"
|
| 1223 |
+
}
|
| 1224 |
+
},
|
| 1225 |
+
"node_modules/fsevents": {
|
| 1226 |
+
"version": "2.3.3",
|
| 1227 |
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
| 1228 |
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
| 1229 |
+
"dev": true,
|
| 1230 |
+
"hasInstallScript": true,
|
| 1231 |
+
"license": "MIT",
|
| 1232 |
+
"optional": true,
|
| 1233 |
+
"os": [
|
| 1234 |
+
"darwin"
|
| 1235 |
+
],
|
| 1236 |
+
"engines": {
|
| 1237 |
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
| 1238 |
+
}
|
| 1239 |
+
},
|
| 1240 |
+
"node_modules/function-bind": {
|
| 1241 |
+
"version": "1.1.2",
|
| 1242 |
+
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
| 1243 |
+
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
| 1244 |
+
"license": "MIT",
|
| 1245 |
+
"funding": {
|
| 1246 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1247 |
+
}
|
| 1248 |
+
},
|
| 1249 |
+
"node_modules/get-intrinsic": {
|
| 1250 |
+
"version": "1.3.0",
|
| 1251 |
+
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
| 1252 |
+
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
| 1253 |
+
"license": "MIT",
|
| 1254 |
+
"dependencies": {
|
| 1255 |
+
"call-bind-apply-helpers": "^1.0.2",
|
| 1256 |
+
"es-define-property": "^1.0.1",
|
| 1257 |
+
"es-errors": "^1.3.0",
|
| 1258 |
+
"es-object-atoms": "^1.1.1",
|
| 1259 |
+
"function-bind": "^1.1.2",
|
| 1260 |
+
"get-proto": "^1.0.1",
|
| 1261 |
+
"gopd": "^1.2.0",
|
| 1262 |
+
"has-symbols": "^1.1.0",
|
| 1263 |
+
"hasown": "^2.0.2",
|
| 1264 |
+
"math-intrinsics": "^1.1.0"
|
| 1265 |
+
},
|
| 1266 |
+
"engines": {
|
| 1267 |
+
"node": ">= 0.4"
|
| 1268 |
+
},
|
| 1269 |
+
"funding": {
|
| 1270 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1271 |
+
}
|
| 1272 |
+
},
|
| 1273 |
+
"node_modules/get-proto": {
|
| 1274 |
+
"version": "1.0.1",
|
| 1275 |
+
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
| 1276 |
+
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
| 1277 |
+
"license": "MIT",
|
| 1278 |
+
"dependencies": {
|
| 1279 |
+
"dunder-proto": "^1.0.1",
|
| 1280 |
+
"es-object-atoms": "^1.0.0"
|
| 1281 |
+
},
|
| 1282 |
+
"engines": {
|
| 1283 |
+
"node": ">= 0.4"
|
| 1284 |
+
}
|
| 1285 |
+
},
|
| 1286 |
+
"node_modules/gopd": {
|
| 1287 |
+
"version": "1.2.0",
|
| 1288 |
+
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
| 1289 |
+
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
| 1290 |
+
"license": "MIT",
|
| 1291 |
+
"engines": {
|
| 1292 |
+
"node": ">= 0.4"
|
| 1293 |
+
},
|
| 1294 |
+
"funding": {
|
| 1295 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1296 |
+
}
|
| 1297 |
+
},
|
| 1298 |
+
"node_modules/has-symbols": {
|
| 1299 |
+
"version": "1.1.0",
|
| 1300 |
+
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
| 1301 |
+
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
| 1302 |
+
"license": "MIT",
|
| 1303 |
+
"engines": {
|
| 1304 |
+
"node": ">= 0.4"
|
| 1305 |
+
},
|
| 1306 |
+
"funding": {
|
| 1307 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1308 |
+
}
|
| 1309 |
+
},
|
| 1310 |
+
"node_modules/has-tostringtag": {
|
| 1311 |
+
"version": "1.0.2",
|
| 1312 |
+
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
| 1313 |
+
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
| 1314 |
+
"license": "MIT",
|
| 1315 |
+
"dependencies": {
|
| 1316 |
+
"has-symbols": "^1.0.3"
|
| 1317 |
+
},
|
| 1318 |
+
"engines": {
|
| 1319 |
+
"node": ">= 0.4"
|
| 1320 |
+
},
|
| 1321 |
+
"funding": {
|
| 1322 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1323 |
+
}
|
| 1324 |
+
},
|
| 1325 |
+
"node_modules/hasown": {
|
| 1326 |
+
"version": "2.0.2",
|
| 1327 |
+
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
| 1328 |
+
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
| 1329 |
+
"license": "MIT",
|
| 1330 |
+
"dependencies": {
|
| 1331 |
+
"function-bind": "^1.1.2"
|
| 1332 |
+
},
|
| 1333 |
+
"engines": {
|
| 1334 |
+
"node": ">= 0.4"
|
| 1335 |
+
}
|
| 1336 |
+
},
|
| 1337 |
+
"node_modules/lucide-vue-next": {
|
| 1338 |
+
"version": "0.563.0",
|
| 1339 |
+
"resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-0.563.0.tgz",
|
| 1340 |
+
"integrity": "sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA==",
|
| 1341 |
+
"license": "ISC",
|
| 1342 |
+
"peerDependencies": {
|
| 1343 |
+
"vue": ">=3.0.1"
|
| 1344 |
+
}
|
| 1345 |
+
},
|
| 1346 |
+
"node_modules/magic-string": {
|
| 1347 |
+
"version": "0.30.21",
|
| 1348 |
+
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
| 1349 |
+
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
| 1350 |
+
"license": "MIT",
|
| 1351 |
+
"dependencies": {
|
| 1352 |
+
"@jridgewell/sourcemap-codec": "^1.5.5"
|
| 1353 |
+
}
|
| 1354 |
+
},
|
| 1355 |
+
"node_modules/math-intrinsics": {
|
| 1356 |
+
"version": "1.1.0",
|
| 1357 |
+
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
| 1358 |
+
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
| 1359 |
+
"license": "MIT",
|
| 1360 |
+
"engines": {
|
| 1361 |
+
"node": ">= 0.4"
|
| 1362 |
+
}
|
| 1363 |
+
},
|
| 1364 |
+
"node_modules/mime-db": {
|
| 1365 |
+
"version": "1.52.0",
|
| 1366 |
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
| 1367 |
+
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
| 1368 |
+
"license": "MIT",
|
| 1369 |
+
"engines": {
|
| 1370 |
+
"node": ">= 0.6"
|
| 1371 |
+
}
|
| 1372 |
+
},
|
| 1373 |
+
"node_modules/mime-types": {
|
| 1374 |
+
"version": "2.1.35",
|
| 1375 |
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
| 1376 |
+
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
| 1377 |
+
"license": "MIT",
|
| 1378 |
+
"dependencies": {
|
| 1379 |
+
"mime-db": "1.52.0"
|
| 1380 |
+
},
|
| 1381 |
+
"engines": {
|
| 1382 |
+
"node": ">= 0.6"
|
| 1383 |
+
}
|
| 1384 |
+
},
|
| 1385 |
+
"node_modules/nanoid": {
|
| 1386 |
+
"version": "3.3.12",
|
| 1387 |
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
| 1388 |
+
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
| 1389 |
+
"funding": [
|
| 1390 |
+
{
|
| 1391 |
+
"type": "github",
|
| 1392 |
+
"url": "https://github.com/sponsors/ai"
|
| 1393 |
+
}
|
| 1394 |
+
],
|
| 1395 |
+
"license": "MIT",
|
| 1396 |
+
"bin": {
|
| 1397 |
+
"nanoid": "bin/nanoid.cjs"
|
| 1398 |
+
},
|
| 1399 |
+
"engines": {
|
| 1400 |
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
| 1401 |
+
}
|
| 1402 |
+
},
|
| 1403 |
+
"node_modules/picocolors": {
|
| 1404 |
+
"version": "1.1.1",
|
| 1405 |
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
| 1406 |
+
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
| 1407 |
+
"license": "ISC"
|
| 1408 |
+
},
|
| 1409 |
+
"node_modules/picomatch": {
|
| 1410 |
+
"version": "4.0.4",
|
| 1411 |
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
| 1412 |
+
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
| 1413 |
+
"dev": true,
|
| 1414 |
+
"license": "MIT",
|
| 1415 |
+
"engines": {
|
| 1416 |
+
"node": ">=12"
|
| 1417 |
+
},
|
| 1418 |
+
"funding": {
|
| 1419 |
+
"url": "https://github.com/sponsors/jonschlinkert"
|
| 1420 |
+
}
|
| 1421 |
+
},
|
| 1422 |
+
"node_modules/postcss": {
|
| 1423 |
+
"version": "8.5.15",
|
| 1424 |
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
| 1425 |
+
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
| 1426 |
+
"funding": [
|
| 1427 |
+
{
|
| 1428 |
+
"type": "opencollective",
|
| 1429 |
+
"url": "https://opencollective.com/postcss/"
|
| 1430 |
+
},
|
| 1431 |
+
{
|
| 1432 |
+
"type": "tidelift",
|
| 1433 |
+
"url": "https://tidelift.com/funding/github/npm/postcss"
|
| 1434 |
+
},
|
| 1435 |
+
{
|
| 1436 |
+
"type": "github",
|
| 1437 |
+
"url": "https://github.com/sponsors/ai"
|
| 1438 |
+
}
|
| 1439 |
+
],
|
| 1440 |
+
"license": "MIT",
|
| 1441 |
+
"dependencies": {
|
| 1442 |
+
"nanoid": "^3.3.12",
|
| 1443 |
+
"picocolors": "^1.1.1",
|
| 1444 |
+
"source-map-js": "^1.2.1"
|
| 1445 |
+
},
|
| 1446 |
+
"engines": {
|
| 1447 |
+
"node": "^10 || ^12 || >=14"
|
| 1448 |
+
}
|
| 1449 |
+
},
|
| 1450 |
+
"node_modules/proxy-from-env": {
|
| 1451 |
+
"version": "2.1.0",
|
| 1452 |
+
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
| 1453 |
+
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
| 1454 |
+
"license": "MIT",
|
| 1455 |
+
"engines": {
|
| 1456 |
+
"node": ">=10"
|
| 1457 |
+
}
|
| 1458 |
+
},
|
| 1459 |
+
"node_modules/rollup": {
|
| 1460 |
+
"version": "4.59.0",
|
| 1461 |
+
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
|
| 1462 |
+
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
|
| 1463 |
+
"dev": true,
|
| 1464 |
+
"license": "MIT",
|
| 1465 |
+
"dependencies": {
|
| 1466 |
+
"@types/estree": "1.0.8"
|
| 1467 |
+
},
|
| 1468 |
+
"bin": {
|
| 1469 |
+
"rollup": "dist/bin/rollup"
|
| 1470 |
+
},
|
| 1471 |
+
"engines": {
|
| 1472 |
+
"node": ">=18.0.0",
|
| 1473 |
+
"npm": ">=8.0.0"
|
| 1474 |
+
},
|
| 1475 |
+
"optionalDependencies": {
|
| 1476 |
+
"@rollup/rollup-android-arm-eabi": "4.59.0",
|
| 1477 |
+
"@rollup/rollup-android-arm64": "4.59.0",
|
| 1478 |
+
"@rollup/rollup-darwin-arm64": "4.59.0",
|
| 1479 |
+
"@rollup/rollup-darwin-x64": "4.59.0",
|
| 1480 |
+
"@rollup/rollup-freebsd-arm64": "4.59.0",
|
| 1481 |
+
"@rollup/rollup-freebsd-x64": "4.59.0",
|
| 1482 |
+
"@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
|
| 1483 |
+
"@rollup/rollup-linux-arm-musleabihf": "4.59.0",
|
| 1484 |
+
"@rollup/rollup-linux-arm64-gnu": "4.59.0",
|
| 1485 |
+
"@rollup/rollup-linux-arm64-musl": "4.59.0",
|
| 1486 |
+
"@rollup/rollup-linux-loong64-gnu": "4.59.0",
|
| 1487 |
+
"@rollup/rollup-linux-loong64-musl": "4.59.0",
|
| 1488 |
+
"@rollup/rollup-linux-ppc64-gnu": "4.59.0",
|
| 1489 |
+
"@rollup/rollup-linux-ppc64-musl": "4.59.0",
|
| 1490 |
+
"@rollup/rollup-linux-riscv64-gnu": "4.59.0",
|
| 1491 |
+
"@rollup/rollup-linux-riscv64-musl": "4.59.0",
|
| 1492 |
+
"@rollup/rollup-linux-s390x-gnu": "4.59.0",
|
| 1493 |
+
"@rollup/rollup-linux-x64-gnu": "4.59.0",
|
| 1494 |
+
"@rollup/rollup-linux-x64-musl": "4.59.0",
|
| 1495 |
+
"@rollup/rollup-openbsd-x64": "4.59.0",
|
| 1496 |
+
"@rollup/rollup-openharmony-arm64": "4.59.0",
|
| 1497 |
+
"@rollup/rollup-win32-arm64-msvc": "4.59.0",
|
| 1498 |
+
"@rollup/rollup-win32-ia32-msvc": "4.59.0",
|
| 1499 |
+
"@rollup/rollup-win32-x64-gnu": "4.59.0",
|
| 1500 |
+
"@rollup/rollup-win32-x64-msvc": "4.59.0",
|
| 1501 |
+
"fsevents": "~2.3.2"
|
| 1502 |
+
}
|
| 1503 |
+
},
|
| 1504 |
+
"node_modules/source-map-js": {
|
| 1505 |
+
"version": "1.2.1",
|
| 1506 |
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
| 1507 |
+
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
| 1508 |
+
"license": "BSD-3-Clause",
|
| 1509 |
+
"engines": {
|
| 1510 |
+
"node": ">=0.10.0"
|
| 1511 |
+
}
|
| 1512 |
+
},
|
| 1513 |
+
"node_modules/tinyglobby": {
|
| 1514 |
+
"version": "0.2.15",
|
| 1515 |
+
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
| 1516 |
+
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
| 1517 |
+
"dev": true,
|
| 1518 |
+
"license": "MIT",
|
| 1519 |
+
"dependencies": {
|
| 1520 |
+
"fdir": "^6.5.0",
|
| 1521 |
+
"picomatch": "^4.0.3"
|
| 1522 |
+
},
|
| 1523 |
+
"engines": {
|
| 1524 |
+
"node": ">=12.0.0"
|
| 1525 |
+
},
|
| 1526 |
+
"funding": {
|
| 1527 |
+
"url": "https://github.com/sponsors/SuperchupuDev"
|
| 1528 |
+
}
|
| 1529 |
+
},
|
| 1530 |
+
"node_modules/vite": {
|
| 1531 |
+
"version": "7.3.2",
|
| 1532 |
+
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz",
|
| 1533 |
+
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
|
| 1534 |
+
"dev": true,
|
| 1535 |
+
"license": "MIT",
|
| 1536 |
+
"dependencies": {
|
| 1537 |
+
"esbuild": "^0.27.0",
|
| 1538 |
+
"fdir": "^6.5.0",
|
| 1539 |
+
"picomatch": "^4.0.3",
|
| 1540 |
+
"postcss": "^8.5.6",
|
| 1541 |
+
"rollup": "^4.43.0",
|
| 1542 |
+
"tinyglobby": "^0.2.15"
|
| 1543 |
+
},
|
| 1544 |
+
"bin": {
|
| 1545 |
+
"vite": "bin/vite.js"
|
| 1546 |
+
},
|
| 1547 |
+
"engines": {
|
| 1548 |
+
"node": "^20.19.0 || >=22.12.0"
|
| 1549 |
+
},
|
| 1550 |
+
"funding": {
|
| 1551 |
+
"url": "https://github.com/vitejs/vite?sponsor=1"
|
| 1552 |
+
},
|
| 1553 |
+
"optionalDependencies": {
|
| 1554 |
+
"fsevents": "~2.3.3"
|
| 1555 |
+
},
|
| 1556 |
+
"peerDependencies": {
|
| 1557 |
+
"@types/node": "^20.19.0 || >=22.12.0",
|
| 1558 |
+
"jiti": ">=1.21.0",
|
| 1559 |
+
"less": "^4.0.0",
|
| 1560 |
+
"lightningcss": "^1.21.0",
|
| 1561 |
+
"sass": "^1.70.0",
|
| 1562 |
+
"sass-embedded": "^1.70.0",
|
| 1563 |
+
"stylus": ">=0.54.8",
|
| 1564 |
+
"sugarss": "^5.0.0",
|
| 1565 |
+
"terser": "^5.16.0",
|
| 1566 |
+
"tsx": "^4.8.1",
|
| 1567 |
+
"yaml": "^2.4.2"
|
| 1568 |
+
},
|
| 1569 |
+
"peerDependenciesMeta": {
|
| 1570 |
+
"@types/node": {
|
| 1571 |
+
"optional": true
|
| 1572 |
+
},
|
| 1573 |
+
"jiti": {
|
| 1574 |
+
"optional": true
|
| 1575 |
+
},
|
| 1576 |
+
"less": {
|
| 1577 |
+
"optional": true
|
| 1578 |
+
},
|
| 1579 |
+
"lightningcss": {
|
| 1580 |
+
"optional": true
|
| 1581 |
+
},
|
| 1582 |
+
"sass": {
|
| 1583 |
+
"optional": true
|
| 1584 |
+
},
|
| 1585 |
+
"sass-embedded": {
|
| 1586 |
+
"optional": true
|
| 1587 |
+
},
|
| 1588 |
+
"stylus": {
|
| 1589 |
+
"optional": true
|
| 1590 |
+
},
|
| 1591 |
+
"sugarss": {
|
| 1592 |
+
"optional": true
|
| 1593 |
+
},
|
| 1594 |
+
"terser": {
|
| 1595 |
+
"optional": true
|
| 1596 |
+
},
|
| 1597 |
+
"tsx": {
|
| 1598 |
+
"optional": true
|
| 1599 |
+
},
|
| 1600 |
+
"yaml": {
|
| 1601 |
+
"optional": true
|
| 1602 |
+
}
|
| 1603 |
+
}
|
| 1604 |
+
},
|
| 1605 |
+
"node_modules/vue": {
|
| 1606 |
+
"version": "3.5.27",
|
| 1607 |
+
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz",
|
| 1608 |
+
"integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==",
|
| 1609 |
+
"license": "MIT",
|
| 1610 |
+
"dependencies": {
|
| 1611 |
+
"@vue/compiler-dom": "3.5.27",
|
| 1612 |
+
"@vue/compiler-sfc": "3.5.27",
|
| 1613 |
+
"@vue/runtime-dom": "3.5.27",
|
| 1614 |
+
"@vue/server-renderer": "3.5.27",
|
| 1615 |
+
"@vue/shared": "3.5.27"
|
| 1616 |
+
},
|
| 1617 |
+
"peerDependencies": {
|
| 1618 |
+
"typescript": "*"
|
| 1619 |
+
},
|
| 1620 |
+
"peerDependenciesMeta": {
|
| 1621 |
+
"typescript": {
|
| 1622 |
+
"optional": true
|
| 1623 |
+
}
|
| 1624 |
+
}
|
| 1625 |
+
}
|
| 1626 |
+
}
|
| 1627 |
+
}
|
src/agora/frontend/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "frontend",
|
| 3 |
+
"private": true,
|
| 4 |
+
"version": "0.0.0",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "vite",
|
| 8 |
+
"build": "vite build",
|
| 9 |
+
"preview": "vite preview"
|
| 10 |
+
},
|
| 11 |
+
"dependencies": {
|
| 12 |
+
"axios": "^1.16.0",
|
| 13 |
+
"lucide-vue-next": "^0.563.0",
|
| 14 |
+
"vue": "^3.5.24"
|
| 15 |
+
},
|
| 16 |
+
"devDependencies": {
|
| 17 |
+
"@vitejs/plugin-vue": "^6.0.1",
|
| 18 |
+
"vite": "^7.3.2"
|
| 19 |
+
}
|
| 20 |
+
}
|
src/agora/frontend/public/favicon.svg
ADDED
|
|
src/agora/frontend/public/vite.svg
ADDED
|
|
src/agora/frontend/src/App.vue
ADDED
|
@@ -0,0 +1,1888 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script setup>
|
| 2 |
+
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue'
|
| 3 |
+
import {
|
| 4 |
+
Rocket,
|
| 5 |
+
Search,
|
| 6 |
+
Activity,
|
| 7 |
+
MessageSquare,
|
| 8 |
+
LayoutDashboard,
|
| 9 |
+
BrainCircuit,
|
| 10 |
+
ShieldCheck,
|
| 11 |
+
Landmark,
|
| 12 |
+
AlertTriangle,
|
| 13 |
+
ExternalLink,
|
| 14 |
+
ChevronRight,
|
| 15 |
+
Loader2,
|
| 16 |
+
TrendingUp,
|
| 17 |
+
XCircle,
|
| 18 |
+
Clock,
|
| 19 |
+
Calendar,
|
| 20 |
+
Heart,
|
| 21 |
+
Zap,
|
| 22 |
+
LineChart,
|
| 23 |
+
Crown,
|
| 24 |
+
Sparkles
|
| 25 |
+
} from 'lucide-vue-next'
|
| 26 |
+
|
| 27 |
+
const ticker = ref('NVDA')
|
| 28 |
+
const provider = ref('openai')
|
| 29 |
+
const isAnalyzing = ref(false)
|
| 30 |
+
const activeAgent = ref(null)
|
| 31 |
+
const logs = ref([])
|
| 32 |
+
const results = ref([])
|
| 33 |
+
const error = ref(null)
|
| 34 |
+
const logContainer = ref(null)
|
| 35 |
+
|
| 36 |
+
const workflowAgents = [
|
| 37 |
+
{ id: 'TechnicalAnalyst', name: 'Technical', role: 'Analyzes Market Trend (SPY), SMAs, EMAs, RSI, and MACD for directional bias.' },
|
| 38 |
+
{ id: 'VolatilityAnalyst', name: 'Volatility', role: 'Analyzes VIX Fear Gauge, IV vs HV, and Option Liquidity.' },
|
| 39 |
+
{ id: 'SentimentAnalyst', name: 'Sentiment', role: 'Evaluates market sentiment from news and monitors earnings risks.' },
|
| 40 |
+
{ id: 'FundamentalAnalyst', name: 'Fundamental', role: 'Evaluates Valuation (P/E, PEG), EPS Growth, and Financial Health vs Market Risk.' },
|
| 41 |
+
{ id: 'StrategyAdvisor', name: 'Strategy', role: 'Formulates multi-leg option strategies with risk/reward calculation.' },
|
| 42 |
+
{ id: 'RiskManager', name: 'Risk', role: 'Critiques strategy in 2-round debate and performs math verification.' },
|
| 43 |
+
{ id: 'LeadOrchestrator', name: 'Orchestrator', role: 'Central Control. Performs gap analysis, cross-questions agents, and issues final approval.' }
|
| 44 |
+
]
|
| 45 |
+
|
| 46 |
+
const providers = [
|
| 47 |
+
{ id: 'openai', name: 'OpenAI GPT-4o' },
|
| 48 |
+
{ id: 'google', name: 'Google Gemini Pro' },
|
| 49 |
+
{ id: 'groq', name: 'Groq Llama 3.3' }
|
| 50 |
+
]
|
| 51 |
+
|
| 52 |
+
const agentIcons = {
|
| 53 |
+
'TeamManager': Crown,
|
| 54 |
+
'TechnicalAnalyst': LineChart,
|
| 55 |
+
'VolatilityAnalyst': Zap,
|
| 56 |
+
'SentimentAnalyst': MessageSquare,
|
| 57 |
+
'FundamentalAnalyst': Landmark,
|
| 58 |
+
'StrategyAdvisor': BrainCircuit,
|
| 59 |
+
'RiskManager': ShieldCheck,
|
| 60 |
+
'LeadOrchestrator': Crown,
|
| 61 |
+
'System': LayoutDashboard,
|
| 62 |
+
'User': Search,
|
| 63 |
+
// Backward compatibility
|
| 64 |
+
'MarketAnalyst': Activity
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
const agentColors = {
|
| 68 |
+
'TeamManager': '#facc15', // Yellow/Gold
|
| 69 |
+
'TechnicalAnalyst': '#3b82f6', // Blue
|
| 70 |
+
'VolatilityAnalyst': '#ec4899', // Pink/Magenta
|
| 71 |
+
'SentimentAnalyst': '#10b981', // Emerald
|
| 72 |
+
'FundamentalAnalyst': '#f59e0b', // Amber
|
| 73 |
+
'StrategyAdvisor': '#8b5cf6', // Purple
|
| 74 |
+
'RiskManager': '#ef4444', // Red
|
| 75 |
+
'LeadOrchestrator': '#facc15', // Gold
|
| 76 |
+
'System': '#94a3b8', // Slate
|
| 77 |
+
'User': '#60a5fa', // Light Blue
|
| 78 |
+
'MarketAnalyst': '#3b82f6'
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
// Cookie Helpers
|
| 82 |
+
const setCookie = (name, value, days = 30) => {
|
| 83 |
+
const date = new Date();
|
| 84 |
+
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
| 85 |
+
const expires = "expires=" + date.toUTCString();
|
| 86 |
+
document.cookie = name + "=" + value + ";" + expires + ";path=/;SameSite=Lax";
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
const getCookie = (name) => {
|
| 90 |
+
const nameEQ = name + "=";
|
| 91 |
+
const ca = document.cookie.split(';');
|
| 92 |
+
for(let i=0;i < ca.length;i++) {
|
| 93 |
+
let c = ca[i];
|
| 94 |
+
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
| 95 |
+
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
| 96 |
+
}
|
| 97 |
+
return null;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
const getAgentIcon = (source) => {
|
| 101 |
+
return agentIcons[source] || LayoutDashboard
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
const getAgentColor = (source) => {
|
| 105 |
+
return agentColors[source] || '#94a3b8'
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
const scrollToBottom = async () => {
|
| 109 |
+
await nextTick()
|
| 110 |
+
if (logContainer.value) {
|
| 111 |
+
logContainer.value.scrollTop = logContainer.value.scrollHeight
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
const startAnalysis = () => {
|
| 116 |
+
if (!ticker.value || isAnalyzing.value) return
|
| 117 |
+
|
| 118 |
+
isAnalyzing.value = true
|
| 119 |
+
logs.value = []
|
| 120 |
+
results.value = []
|
| 121 |
+
error.value = null
|
| 122 |
+
|
| 123 |
+
const tickers = ticker.value.split(',').map(t => t.trim().toUpperCase()).filter(t => t)
|
| 124 |
+
|
| 125 |
+
if (tickers.length === 0) {
|
| 126 |
+
error.value = "Please enter at least one ticker."
|
| 127 |
+
isAnalyzing.value = false
|
| 128 |
+
return
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
// Save last ticker
|
| 132 |
+
setCookie('last_ticker', tickers[0])
|
| 133 |
+
|
| 134 |
+
analyzeTicker(tickers[0])
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
const pendingResult = ref(null)
|
| 138 |
+
const currentEventSource = ref(null)
|
| 139 |
+
const currentAnalysisId = ref(null)
|
| 140 |
+
|
| 141 |
+
const cancelAnalysis = async () => {
|
| 142 |
+
if (currentAnalysisId.value) {
|
| 143 |
+
try {
|
| 144 |
+
// Send cancel request to backend
|
| 145 |
+
await fetch(`/cancel/${currentAnalysisId.value}`, { method: 'POST' })
|
| 146 |
+
} catch (e) {
|
| 147 |
+
console.error('Failed to cancel analysis:', e)
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
if (currentEventSource.value) {
|
| 152 |
+
currentEventSource.value.close()
|
| 153 |
+
currentEventSource.value = null
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
isAnalyzing.value = false
|
| 157 |
+
activeAgent.value = null
|
| 158 |
+
currentAnalysisId.value = null
|
| 159 |
+
|
| 160 |
+
logs.value.push({
|
| 161 |
+
id: Math.random().toString(36).substr(2, 9),
|
| 162 |
+
source: 'System',
|
| 163 |
+
content: 'Analysis cancelled by user.',
|
| 164 |
+
timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })
|
| 165 |
+
})
|
| 166 |
+
scrollToBottom()
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
const analyzeTicker = (symbol) => {
|
| 170 |
+
// Use relative path for same-origin serving (FastAPI mounting frontend)
|
| 171 |
+
const url = `/analyze?ticker=${symbol}&provider=${provider.value}`
|
| 172 |
+
|
| 173 |
+
const eventSource = new EventSource(url)
|
| 174 |
+
currentEventSource.value = eventSource
|
| 175 |
+
pendingResult.value = null
|
| 176 |
+
|
| 177 |
+
eventSource.onmessage = (event) => {
|
| 178 |
+
if (event.data === '[DONE]') {
|
| 179 |
+
// Delay clearing active agent so user can see the final Orchestrator state
|
| 180 |
+
setTimeout(() => {
|
| 181 |
+
activeAgent.value = null
|
| 182 |
+
}, 3000)
|
| 183 |
+
|
| 184 |
+
if (pendingResult.value) {
|
| 185 |
+
results.value.push(pendingResult.value)
|
| 186 |
+
saveToHistory(pendingResult.value) // Save to history
|
| 187 |
+
pendingResult.value = null
|
| 188 |
+
}
|
| 189 |
+
eventSource.close()
|
| 190 |
+
isAnalyzing.value = false
|
| 191 |
+
return
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
try {
|
| 195 |
+
const data = JSON.parse(event.data)
|
| 196 |
+
if (data.error) {
|
| 197 |
+
error.value = data.error
|
| 198 |
+
eventSource.close()
|
| 199 |
+
isAnalyzing.value = false
|
| 200 |
+
return
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
if (data.content || data.source) {
|
| 204 |
+
// Capture analysis_id from first message
|
| 205 |
+
if (data.analysis_id && !currentAnalysisId.value) {
|
| 206 |
+
currentAnalysisId.value = data.analysis_id
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
if (data.source && data.source !== 'System') {
|
| 210 |
+
activeAgent.value = data.source
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
logs.value.push({
|
| 214 |
+
id: Math.random().toString(36).substr(2, 9),
|
| 215 |
+
source: data.source,
|
| 216 |
+
content: data.content,
|
| 217 |
+
timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })
|
| 218 |
+
})
|
| 219 |
+
scrollToBottom()
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
// Use backend-provided structured result if available (highly recommended for Groq/Llama)
|
| 223 |
+
if (data.source === 'RiskManager') {
|
| 224 |
+
if (data.structured_result) {
|
| 225 |
+
console.log("Using backend-provided structured result");
|
| 226 |
+
pendingResult.value = {
|
| 227 |
+
ticker: symbol,
|
| 228 |
+
model: providers.find(p => p.id === provider.value)?.name || provider.value,
|
| 229 |
+
...data.structured_result
|
| 230 |
+
}
|
| 231 |
+
} else {
|
| 232 |
+
// Fallback to local regex if structured_result is missing
|
| 233 |
+
const jsonMatch = data.content.match(/```json\s*([\s\S]*?)\s*```/) || data.content.match(/\{[\s\S]*"final_decision"[\s\S]*\}/)
|
| 234 |
+
if (jsonMatch) {
|
| 235 |
+
try {
|
| 236 |
+
const rawJson = jsonMatch[1] || jsonMatch[0]
|
| 237 |
+
const parsed = JSON.parse(rawJson)
|
| 238 |
+
pendingResult.value = {
|
| 239 |
+
ticker: symbol,
|
| 240 |
+
model: providers.find(p => p.id === provider.value)?.name || provider.value,
|
| 241 |
+
...parsed
|
| 242 |
+
}
|
| 243 |
+
} catch (e) {
|
| 244 |
+
console.log("Failed to parse result JSON", e)
|
| 245 |
+
}
|
| 246 |
+
}
|
| 247 |
+
}
|
| 248 |
+
}
|
| 249 |
+
} catch (e) {
|
| 250 |
+
console.error("Error parsing message", e)
|
| 251 |
+
}
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
eventSource.onerror = (err) => {
|
| 255 |
+
console.error("SSE Error:", err)
|
| 256 |
+
error.value = "Connection to server lost. Make sure the backend is running at http://localhost:8000"
|
| 257 |
+
eventSource.close()
|
| 258 |
+
currentEventSource.value = null
|
| 259 |
+
isAnalyzing.value = false
|
| 260 |
+
}
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
const formatContent = (content) => {
|
| 264 |
+
if (!content) return ''
|
| 265 |
+
let html = content
|
| 266 |
+
// Headers
|
| 267 |
+
.replace(/^### (.*$)/gm, '<h5 class="content-h3">$1</h5>')
|
| 268 |
+
.replace(/^## (.*$)/gm, '<h4 class="content-h2">$1</h4>')
|
| 269 |
+
.replace(/^# (.*$)/gm, '<h3 class="content-h1">$1</h3>')
|
| 270 |
+
// Bold
|
| 271 |
+
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
| 272 |
+
// Italic
|
| 273 |
+
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
| 274 |
+
// Inline Code
|
| 275 |
+
.replace(/`(.*?)`/g, '<code class="inline-code">$1</code>')
|
| 276 |
+
// Blockquotes
|
| 277 |
+
.replace(/^> (.*$)/gm, '<blockquote>$1</blockquote>')
|
| 278 |
+
// Bullet Lists
|
| 279 |
+
.replace(/^\s*[-*+]\s+(.*)$/gm, '<ul><li>$1</li></ul>')
|
| 280 |
+
.replace(/<\/ul>\n<ul>/g, '\n') // Combine consecutive lists
|
| 281 |
+
// Numbered Lists
|
| 282 |
+
.replace(/^\s*\d+\.\s+(.*)$/gm, '<ol><li>$1</li></ol>')
|
| 283 |
+
.replace(/<\/ol>\n<ol>/g, '\n') // Combine consecutive lists
|
| 284 |
+
// New lines to br (only after block elements or within paragraphs)
|
| 285 |
+
.replace(/\n/g, '<br>')
|
| 286 |
+
|
| 287 |
+
return html
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
const getDecisionColor = (decision) => {
|
| 291 |
+
if (!decision) return 'var(--text-secondary)'
|
| 292 |
+
const d = decision.toUpperCase()
|
| 293 |
+
if (d.includes('TRADE') || d.includes('BUY')) return 'var(--success)'
|
| 294 |
+
if (d.includes('WAIT') || d.includes('HOLD')) return 'var(--warning)'
|
| 295 |
+
return 'var(--danger)'
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
// History Management
|
| 299 |
+
const history = ref([])
|
| 300 |
+
const selectedReport = ref(null)
|
| 301 |
+
|
| 302 |
+
const openReport = (item) => {
|
| 303 |
+
selectedReport.value = item
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
const closeReport = () => {
|
| 307 |
+
selectedReport.value = null
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
const loadHistory = () => {
|
| 311 |
+
try {
|
| 312 |
+
const saved = localStorage.getItem('analysis_history')
|
| 313 |
+
if (saved) {
|
| 314 |
+
history.value = JSON.parse(saved)
|
| 315 |
+
}
|
| 316 |
+
} catch (e) {
|
| 317 |
+
console.error("Failed to load history", e)
|
| 318 |
+
}
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
const saveToHistory = (result) => {
|
| 322 |
+
const item = {
|
| 323 |
+
id: Date.now(),
|
| 324 |
+
timestamp: new Date().toLocaleString(),
|
| 325 |
+
...result
|
| 326 |
+
}
|
| 327 |
+
// Add to beginning
|
| 328 |
+
history.value.unshift(item)
|
| 329 |
+
// Keep max 20 items
|
| 330 |
+
if (history.value.length > 20) {
|
| 331 |
+
history.value = history.value.slice(0, 20)
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
try {
|
| 335 |
+
localStorage.setItem('analysis_history', JSON.stringify(history.value))
|
| 336 |
+
} catch (e) {
|
| 337 |
+
console.error("Failed to save history", e)
|
| 338 |
+
}
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
const clearHistory = () => {
|
| 342 |
+
history.value = []
|
| 343 |
+
localStorage.removeItem('analysis_history')
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
// Persistence Watcher
|
| 347 |
+
watch(provider, (newVal) => {
|
| 348 |
+
setCookie('selected_provider', newVal);
|
| 349 |
+
})
|
| 350 |
+
|
| 351 |
+
// Computed Progress
|
| 352 |
+
|
| 353 |
+
onMounted(() => {
|
| 354 |
+
loadHistory() // Load history on startup
|
| 355 |
+
|
| 356 |
+
const savedProvider = getCookie('selected_provider');
|
| 357 |
+
if (savedProvider && providers.some(p => p.id === savedProvider)) {
|
| 358 |
+
provider.value = savedProvider;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
const savedTicker = getCookie('last_ticker');
|
| 362 |
+
if (savedTicker) {
|
| 363 |
+
ticker.value = savedTicker;
|
| 364 |
+
}
|
| 365 |
+
})
|
| 366 |
+
</script>
|
| 367 |
+
|
| 368 |
+
<template>
|
| 369 |
+
<div class="app-wrapper">
|
| 370 |
+
<!-- Header Area -->
|
| 371 |
+
<header class="main-header glass">
|
| 372 |
+
<div class="logo">
|
| 373 |
+
<div class="logo-icon">
|
| 374 |
+
<TrendingUp class="icon-primary" :size="32" />
|
| 375 |
+
</div>
|
| 376 |
+
<div class="logo-text">
|
| 377 |
+
<h1>AGO<span>RA</span></h1>
|
| 378 |
+
<p>Multi-Agent Trading Intelligence</p>
|
| 379 |
+
</div>
|
| 380 |
+
</div>
|
| 381 |
+
|
| 382 |
+
<div class="controls">
|
| 383 |
+
<div class="input-group glass">
|
| 384 |
+
<Search :size="18" class="search-icon" />
|
| 385 |
+
<input
|
| 386 |
+
v-model="ticker"
|
| 387 |
+
placeholder="Enter Ticker (e.g. NVDA, AAPL)"
|
| 388 |
+
@keyup.enter="startAnalysis"
|
| 389 |
+
:disabled="isAnalyzing"
|
| 390 |
+
/>
|
| 391 |
+
</div>
|
| 392 |
+
|
| 393 |
+
<div class="select-group glass">
|
| 394 |
+
<BrainCircuit :size="18" class="brain-icon" />
|
| 395 |
+
<select v-model="provider" :disabled="isAnalyzing">
|
| 396 |
+
<option v-for="p in providers" :key="p.id" :value="p.id">{{ p.name }}</option>
|
| 397 |
+
</select>
|
| 398 |
+
</div>
|
| 399 |
+
|
| 400 |
+
<button
|
| 401 |
+
class="btn btn-primary"
|
| 402 |
+
@click="startAnalysis"
|
| 403 |
+
:disabled="isAnalyzing || !ticker"
|
| 404 |
+
>
|
| 405 |
+
<Loader2 v-if="isAnalyzing" class="animate-spin" :size="20" />
|
| 406 |
+
<Rocket v-else :size="20" />
|
| 407 |
+
<span>{{ isAnalyzing ? 'Analyzing...' : 'Launch Analysis' }}</span>
|
| 408 |
+
</button>
|
| 409 |
+
|
| 410 |
+
<button
|
| 411 |
+
v-if="isAnalyzing"
|
| 412 |
+
class="btn btn-danger"
|
| 413 |
+
@click="cancelAnalysis"
|
| 414 |
+
title="Cancel Analysis"
|
| 415 |
+
>
|
| 416 |
+
<XCircle :size="20" />
|
| 417 |
+
<span>Cancel</span>
|
| 418 |
+
</button>
|
| 419 |
+
</div>
|
| 420 |
+
</header>
|
| 421 |
+
|
| 422 |
+
<main class="dashboard-content">
|
| 423 |
+
<div class="breadcrumb-container glass">
|
| 424 |
+
<div class="breadcrumb-label">
|
| 425 |
+
<Sparkles :size="12" />
|
| 426 |
+
Active Intelligence Pipeline
|
| 427 |
+
<span class="legend-text">(Glowing icons indicate agents in action)</span>
|
| 428 |
+
</div>
|
| 429 |
+
<div class="workflow-breadcrumb">
|
| 430 |
+
<div
|
| 431 |
+
v-for="(agent, index) in workflowAgents"
|
| 432 |
+
:key="agent.id"
|
| 433 |
+
:class="['breadcrumb-item', { active: activeAgent === agent.id }]"
|
| 434 |
+
:data-tooltip="agent.role"
|
| 435 |
+
>
|
| 436 |
+
<div class="item-icon-wrapper" :style="{ color: getAgentColor(agent.id) }">
|
| 437 |
+
<component :is="getAgentIcon(agent.id)" :size="14" />
|
| 438 |
+
<div v-if="activeAgent === agent.id" class="bulb" :style="{ backgroundColor: getAgentColor(agent.id) }"></div>
|
| 439 |
+
</div>
|
| 440 |
+
<span class="item-label">{{ agent.name }}</span>
|
| 441 |
+
<ChevronRight v-if="index < workflowAgents.length - 1" :size="14" class="separator" />
|
| 442 |
+
</div>
|
| 443 |
+
</div>
|
| 444 |
+
</div>
|
| 445 |
+
|
| 446 |
+
<!-- Progress Bar Removed -->
|
| 447 |
+
|
| 448 |
+
<!-- Error Alert -->
|
| 449 |
+
<div v-if="error" class="error-alert glass">
|
| 450 |
+
<XCircle :size="24" />
|
| 451 |
+
<p>{{ error }}</p>
|
| 452 |
+
<button @click="error = null"><ChevronRight :size="20" /></button>
|
| 453 |
+
</div>
|
| 454 |
+
|
| 455 |
+
<div class="grid-layout">
|
| 456 |
+
<!-- Live Analysis Stream -->
|
| 457 |
+
<section class="panel-logs glass">
|
| 458 |
+
<div class="panel-header">
|
| 459 |
+
<h3><Activity :size="20" /> Live Agent Stream</h3>
|
| 460 |
+
<div v-if="isAnalyzing" class="status-indicator">
|
| 461 |
+
<span class="pulse"></span> Active
|
| 462 |
+
</div>
|
| 463 |
+
</div>
|
| 464 |
+
|
| 465 |
+
<div class="log-viewport" ref="logContainer">
|
| 466 |
+
<div v-if="logs.length === 0 && !isAnalyzing" class="empty-state">
|
| 467 |
+
<LayoutDashboard :size="48" />
|
| 468 |
+
<p>Ready to analyze. Enter a ticker to begin.</p>
|
| 469 |
+
</div>
|
| 470 |
+
|
| 471 |
+
<div v-for="log in logs" :key="log.id" class="log-entry" :style="{ borderLeftColor: getAgentColor(log.source) }">
|
| 472 |
+
<div class="log-meta">
|
| 473 |
+
<component :is="getAgentIcon(log.source)" :size="16" :style="{ color: getAgentColor(log.source) }" />
|
| 474 |
+
<span class="source" :style="{ color: getAgentColor(log.source) }">{{ log.source }}</span>
|
| 475 |
+
<span class="time">{{ log.timestamp }}</span>
|
| 476 |
+
</div>
|
| 477 |
+
<div class="log-content" v-html="formatContent(log.content)"></div>
|
| 478 |
+
</div>
|
| 479 |
+
</div>
|
| 480 |
+
</section>
|
| 481 |
+
|
| 482 |
+
<!-- Intelligence Hub (Summary & Cards) -->
|
| 483 |
+
<section class="panel-results">
|
| 484 |
+
<div class="summary-section glass">
|
| 485 |
+
<div class="panel-header">
|
| 486 |
+
<h3><ShieldCheck :size="20" /> Executive Summary</h3>
|
| 487 |
+
</div>
|
| 488 |
+
|
| 489 |
+
<div class="results-list">
|
| 490 |
+
<div v-if="isAnalyzing" class="loading-state">
|
| 491 |
+
<div class="sparkles-wrapper">
|
| 492 |
+
<Sparkles :size="48" class="sparkle-icon" />
|
| 493 |
+
<div class="sparkle-particles">
|
| 494 |
+
<span class="particle"></span>
|
| 495 |
+
<span class="particle"></span>
|
| 496 |
+
<span class="particle"></span>
|
| 497 |
+
<span class="particle"></span>
|
| 498 |
+
</div>
|
| 499 |
+
</div>
|
| 500 |
+
<p>Agents analyzing market data...</p>
|
| 501 |
+
</div>
|
| 502 |
+
<div v-else-if="results.length === 0 && !pendingResult" class="empty-state mini">
|
| 503 |
+
<p>Analysis cards will appear here</p>
|
| 504 |
+
</div>
|
| 505 |
+
|
| 506 |
+
<TransitionGroup name="list" tag="div" class="transition-container">
|
| 507 |
+
<!-- Finalized Results -->
|
| 508 |
+
<div v-for="res in results" :key="res.ticker" class="result-card glass" :style="{ borderColor: getDecisionColor(res.final_decision) }">
|
| 509 |
+
<div class="card-header">
|
| 510 |
+
<div class="ticker-badge">{{ res.ticker }}</div>
|
| 511 |
+
<div class="decision-badge" :style="{ backgroundColor: getDecisionColor(res.final_decision) }">
|
| 512 |
+
{{ res.final_decision }}
|
| 513 |
+
</div>
|
| 514 |
+
<div v-if="res.fundamental_rating || res.rating" class="fundamental-badge" :class="res.fundamental_rating || res.rating">
|
| 515 |
+
<Heart :size="10" /> {{ res.fundamental_rating || res.rating }}
|
| 516 |
+
</div>
|
| 517 |
+
<div class="confidence-badge">
|
| 518 |
+
{{ res.confidence }}% Confidence
|
| 519 |
+
</div>
|
| 520 |
+
</div>
|
| 521 |
+
|
| 522 |
+
<div class="card-body">
|
| 523 |
+
<h4 class="strat-title">{{ res.strategy_type }}</h4>
|
| 524 |
+
|
| 525 |
+
<!-- Strategy Legs Table -->
|
| 526 |
+
<div v-if="res.legs && res.legs.length" class="legs-container glass-inset">
|
| 527 |
+
<div class="legs-header">Strategy Components</div>
|
| 528 |
+
<table class="legs-table">
|
| 529 |
+
<thead>
|
| 530 |
+
<tr>
|
| 531 |
+
<th>Leg</th>
|
| 532 |
+
<th>Type</th>
|
| 533 |
+
<th>Strike</th>
|
| 534 |
+
<th>Expiry</th>
|
| 535 |
+
<th>Price</th>
|
| 536 |
+
</tr>
|
| 537 |
+
</thead>
|
| 538 |
+
<tbody>
|
| 539 |
+
<tr v-for="(leg, idx) in res.legs" :key="idx">
|
| 540 |
+
<td>
|
| 541 |
+
<span class="action-badge" :class="leg.action.toLowerCase()">
|
| 542 |
+
{{ leg.action }}
|
| 543 |
+
</span>
|
| 544 |
+
</td>
|
| 545 |
+
<td>{{ leg.type }}</td>
|
| 546 |
+
<td><span class="strike-pill">${{ leg.strike }}</span></td>
|
| 547 |
+
<td class="col-expiry">{{ leg.expiry }}</td>
|
| 548 |
+
<td class="col-price">${{ leg.price }}</td>
|
| 549 |
+
</tr>
|
| 550 |
+
</tbody>
|
| 551 |
+
</table>
|
| 552 |
+
</div>
|
| 553 |
+
|
| 554 |
+
<div class="risk-reward-grid">
|
| 555 |
+
<div class="rr-item">
|
| 556 |
+
<span class="rr-label">Max Profit</span>
|
| 557 |
+
<span class="rr-val profit">${{ res.max_profit }}</span>
|
| 558 |
+
</div>
|
| 559 |
+
<div class="rr-item">
|
| 560 |
+
<span class="rr-label">Max Loss</span>
|
| 561 |
+
<span class="rr-val loss">${{ res.max_loss }}</span>
|
| 562 |
+
</div>
|
| 563 |
+
<div class="rr-item">
|
| 564 |
+
<span class="rr-label">Entry</span>
|
| 565 |
+
<span class="rr-val">${{ res.entry_price || res.estimated_entry_price }}</span>
|
| 566 |
+
</div>
|
| 567 |
+
</div>
|
| 568 |
+
|
| 569 |
+
<p class="risk-info">
|
| 570 |
+
<AlertTriangle v-if="res.risk_warning" :size="14" />
|
| 571 |
+
{{ res.risk_warning || 'No specific risk warnings identified.' }}
|
| 572 |
+
</p>
|
| 573 |
+
</div>
|
| 574 |
+
</div>
|
| 575 |
+
|
| 576 |
+
<!-- Pending/Finalizing State -->
|
| 577 |
+
<div v-if="pendingResult && isAnalyzing" class="result-card glass finalizing pulse-border">
|
| 578 |
+
<div class="card-header">
|
| 579 |
+
<div class="ticker-badge">{{ pendingResult.ticker }}</div>
|
| 580 |
+
<div class="status-badge">FINALIZING...</div>
|
| 581 |
+
</div>
|
| 582 |
+
<div class="card-body">
|
| 583 |
+
<p>Agents are confirming the strategy. Hang tight...</p>
|
| 584 |
+
</div>
|
| 585 |
+
</div>
|
| 586 |
+
</TransitionGroup>
|
| 587 |
+
</div>
|
| 588 |
+
</div>
|
| 589 |
+
</section>
|
| 590 |
+
</div>
|
| 591 |
+
|
| 592 |
+
<!-- History Section -->
|
| 593 |
+
<section v-if="history.length > 0" class="history-section glass">
|
| 594 |
+
<div class="panel-header">
|
| 595 |
+
<h3><Clock :size="20" /> Analysis History</h3>
|
| 596 |
+
<button @click="clearHistory" class="btn-clear">Clear History</button>
|
| 597 |
+
</div>
|
| 598 |
+
|
| 599 |
+
<div class="history-table-container glass-inset">
|
| 600 |
+
<table class="history-table">
|
| 601 |
+
<thead>
|
| 602 |
+
<tr>
|
| 603 |
+
<th>Date</th>
|
| 604 |
+
<th>Ticker</th>
|
| 605 |
+
<th class="mobile-hide">Model</th>
|
| 606 |
+
<th>Decision</th>
|
| 607 |
+
<th class="mobile-hide">Confidence</th>
|
| 608 |
+
<th class="mobile-hide">Strategy</th>
|
| 609 |
+
<th class="mobile-hide">Expiry</th>
|
| 610 |
+
<th class="mobile-hide">Max Profit</th>
|
| 611 |
+
<th class="mobile-hide" style="width: 50px"></th>
|
| 612 |
+
</tr>
|
| 613 |
+
</thead>
|
| 614 |
+
<tbody>
|
| 615 |
+
<tr v-for="item in history" :key="item.id" @click="openReport(item)">
|
| 616 |
+
<td class="col-date">{{ item.timestamp }}</td>
|
| 617 |
+
<td class="col-ticker"><span class="ticker-pill">{{ item.ticker }}</span></td>
|
| 618 |
+
<td class="col-model mobile-hide"><span class="model-badge">{{ item.model || 'Unknown' }}</span></td>
|
| 619 |
+
<td>
|
| 620 |
+
<span class="decision-pill" :style="{ color: getDecisionColor(item.final_decision), borderColor: getDecisionColor(item.final_decision) }">
|
| 621 |
+
{{ item.final_decision }}
|
| 622 |
+
</span>
|
| 623 |
+
</td>
|
| 624 |
+
<td class="mobile-hide">
|
| 625 |
+
<div class="confidence-bar-wrapper">
|
| 626 |
+
<div class="confidence-bar" :style="{ width: item.confidence + '%', backgroundColor: getDecisionColor(item.final_decision) }"></div>
|
| 627 |
+
<span>{{ item.confidence }}%</span>
|
| 628 |
+
</div>
|
| 629 |
+
</td>
|
| 630 |
+
<td class="mobile-hide">{{ item.strategy_type }}</td>
|
| 631 |
+
<td class="mobile-hide">{{ item.expiry_date || 'N/A' }}</td>
|
| 632 |
+
<td class="col-profit mobile-hide" :class="{ 'has-profit': item.max_profit > 0 }">
|
| 633 |
+
{{ item.max_profit ? '$' + item.max_profit : '-' }}
|
| 634 |
+
</td>
|
| 635 |
+
<td class="col-action mobile-hide"><ChevronRight :size="16" /></td>
|
| 636 |
+
</tr>
|
| 637 |
+
</tbody>
|
| 638 |
+
</table>
|
| 639 |
+
</div>
|
| 640 |
+
</section>
|
| 641 |
+
</main>
|
| 642 |
+
|
| 643 |
+
<!-- Detailed Report Modal -->
|
| 644 |
+
<div v-if="selectedReport" class="modal-overlay" @click.self="closeReport">
|
| 645 |
+
<div class="modal-content glass" :style="{ borderTopColor: getDecisionColor(selectedReport.final_decision) }">
|
| 646 |
+
<button class="modal-close" @click="closeReport"><XCircle :size="24" /></button>
|
| 647 |
+
|
| 648 |
+
<div class="modal-header">
|
| 649 |
+
<h2>{{ selectedReport.ticker }} Analysis Report</h2>
|
| 650 |
+
<span class="timestamp">{{ selectedReport.timestamp }}</span>
|
| 651 |
+
</div>
|
| 652 |
+
|
| 653 |
+
<div class="modal-badges">
|
| 654 |
+
<div class="decision-badge large" :style="{ backgroundColor: getDecisionColor(selectedReport.final_decision) }">
|
| 655 |
+
{{ selectedReport.final_decision }}
|
| 656 |
+
</div>
|
| 657 |
+
<div class="confidence-badge large">
|
| 658 |
+
{{ selectedReport.confidence }}% Confidence
|
| 659 |
+
</div>
|
| 660 |
+
<div class="model-badge large">
|
| 661 |
+
<Zap :size="14" /> {{ selectedReport.model || 'AI Model' }}
|
| 662 |
+
</div>
|
| 663 |
+
<div v-if="selectedReport.rating" class="rating-badge">
|
| 664 |
+
<Heart :size="16" /> {{ selectedReport.rating }}
|
| 665 |
+
</div>
|
| 666 |
+
</div>
|
| 667 |
+
|
| 668 |
+
<div class="report-section">
|
| 669 |
+
<h3><BrainCircuit :size="18" /> Recommendation</h3>
|
| 670 |
+
<p class="highlight-text">{{ selectedReport.actionable_recommendation }}</p>
|
| 671 |
+
</div>
|
| 672 |
+
|
| 673 |
+
<div class="metrics-grid">
|
| 674 |
+
<div class="metric-box">
|
| 675 |
+
<label>Strategy</label>
|
| 676 |
+
<span>{{ selectedReport.strategy_type }}</span>
|
| 677 |
+
</div>
|
| 678 |
+
<div class="metric-box">
|
| 679 |
+
<label>Expiry</label>
|
| 680 |
+
<span>{{ selectedReport.expiry_date || 'N/A' }}</span>
|
| 681 |
+
</div>
|
| 682 |
+
<div class="metric-box">
|
| 683 |
+
<label>Entry</label>
|
| 684 |
+
<span>{{ selectedReport.entry_signal }} @ ${{ selectedReport.entry_price || 'N/A' }}</span>
|
| 685 |
+
</div>
|
| 686 |
+
<div class="metric-box">
|
| 687 |
+
<label>Max Profit</label>
|
| 688 |
+
<span class="profit">${{ selectedReport.max_profit || 0 }}</span>
|
| 689 |
+
</div>
|
| 690 |
+
<div class="metric-box">
|
| 691 |
+
<label>Max Loss</label>
|
| 692 |
+
<span class="loss">${{ selectedReport.max_loss || 0 }}</span>
|
| 693 |
+
</div>
|
| 694 |
+
</div>
|
| 695 |
+
|
| 696 |
+
<div class="report-section risk-section">
|
| 697 |
+
<h3><ShieldCheck :size="18" /> Risk Analysis</h3>
|
| 698 |
+
<p>{{ selectedReport.risk_warning }}</p>
|
| 699 |
+
</div>
|
| 700 |
+
</div>
|
| 701 |
+
</div>
|
| 702 |
+
|
| 703 |
+
<!-- Footer Disclaimer -->
|
| 704 |
+
<footer class="main-footer glass">
|
| 705 |
+
<div class="footer-content">
|
| 706 |
+
<div class="disclaimer-info">
|
| 707 |
+
<AlertTriangle :size="16" />
|
| 708 |
+
<span><strong>Trading Disclaimer:</strong> Educational and research purposes only. AI-generated insights may be subject to latency or error. Consult a professional advisor before trading.</span>
|
| 709 |
+
</div>
|
| 710 |
+
<div class="copyright">
|
| 711 |
+
© 2024 Agora AI
|
| 712 |
+
</div>
|
| 713 |
+
</div>
|
| 714 |
+
</footer>
|
| 715 |
+
</div>
|
| 716 |
+
</template>
|
| 717 |
+
|
| 718 |
+
<style scoped>
|
| 719 |
+
.app-wrapper {
|
| 720 |
+
display: flex;
|
| 721 |
+
flex-direction: column;
|
| 722 |
+
min-height: 100vh;
|
| 723 |
+
padding: 1.5rem;
|
| 724 |
+
gap: 1.5rem;
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
.main-header {
|
| 728 |
+
display: flex;
|
| 729 |
+
justify-content: space-between;
|
| 730 |
+
align-items: center;
|
| 731 |
+
padding: 1rem 2rem;
|
| 732 |
+
z-index: 100;
|
| 733 |
+
}
|
| 734 |
+
|
| 735 |
+
.logo {
|
| 736 |
+
display: flex;
|
| 737 |
+
align-items: center;
|
| 738 |
+
gap: 1rem;
|
| 739 |
+
}
|
| 740 |
+
|
| 741 |
+
.logo-icon {
|
| 742 |
+
background: var(--accent-gradient);
|
| 743 |
+
padding: 0.5rem;
|
| 744 |
+
border-radius: 0.75rem;
|
| 745 |
+
display: flex;
|
| 746 |
+
align-items: center;
|
| 747 |
+
justify-content: center;
|
| 748 |
+
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
|
| 749 |
+
}
|
| 750 |
+
|
| 751 |
+
.icon-primary {
|
| 752 |
+
color: white;
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
.btn-danger {
|
| 756 |
+
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
| 757 |
+
border: 1px solid rgba(239, 68, 68, 0.3);
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
.btn-danger:hover:not(:disabled) {
|
| 761 |
+
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
|
| 762 |
+
box-shadow: 0 8px 24px rgba(239, 68, 68, 0.4);
|
| 763 |
+
transform: translateY(-2px);
|
| 764 |
+
}
|
| 765 |
+
|
| 766 |
+
.logo-text h1 {
|
| 767 |
+
font-size: 1.5rem;
|
| 768 |
+
margin: 0;
|
| 769 |
+
line-height: 1;
|
| 770 |
+
}
|
| 771 |
+
|
| 772 |
+
.logo-text h1 span {
|
| 773 |
+
color: var(--accent-primary);
|
| 774 |
+
font-weight: 400;
|
| 775 |
+
}
|
| 776 |
+
|
| 777 |
+
.logo-text p {
|
| 778 |
+
font-size: 0.75rem;
|
| 779 |
+
color: var(--text-secondary);
|
| 780 |
+
font-weight: 500;
|
| 781 |
+
letter-spacing: 0.1em;
|
| 782 |
+
text-transform: uppercase;
|
| 783 |
+
margin-top: 0.25rem;
|
| 784 |
+
}
|
| 785 |
+
|
| 786 |
+
.controls {
|
| 787 |
+
display: flex;
|
| 788 |
+
gap: 1rem;
|
| 789 |
+
align-items: center;
|
| 790 |
+
}
|
| 791 |
+
|
| 792 |
+
.input-group, .select-group {
|
| 793 |
+
display: flex;
|
| 794 |
+
align-items: center;
|
| 795 |
+
padding: 0.5rem 1rem;
|
| 796 |
+
gap: 0.75rem;
|
| 797 |
+
}
|
| 798 |
+
|
| 799 |
+
.input-group input {
|
| 800 |
+
background: transparent;
|
| 801 |
+
border: none;
|
| 802 |
+
color: var(--text-primary);
|
| 803 |
+
outline: none;
|
| 804 |
+
font-size: 0.9rem;
|
| 805 |
+
width: 200px;
|
| 806 |
+
}
|
| 807 |
+
|
| 808 |
+
.select-group select {
|
| 809 |
+
background: transparent;
|
| 810 |
+
border: none;
|
| 811 |
+
color: var(--text-primary);
|
| 812 |
+
outline: none;
|
| 813 |
+
font-size: 0.9rem;
|
| 814 |
+
cursor: pointer;
|
| 815 |
+
}
|
| 816 |
+
|
| 817 |
+
.select-group select option {
|
| 818 |
+
background-color: var(--bg-color);
|
| 819 |
+
}
|
| 820 |
+
|
| 821 |
+
.dashboard-content {
|
| 822 |
+
display: flex;
|
| 823 |
+
flex-direction: column;
|
| 824 |
+
gap: 1.5rem;
|
| 825 |
+
flex: 1;
|
| 826 |
+
}
|
| 827 |
+
|
| 828 |
+
.grid-layout {
|
| 829 |
+
display: grid;
|
| 830 |
+
grid-template-columns: 400px 1fr;
|
| 831 |
+
gap: 1.5rem;
|
| 832 |
+
flex: 1;
|
| 833 |
+
}
|
| 834 |
+
|
| 835 |
+
.panel-logs {
|
| 836 |
+
grid-column: 2; /* Move to right column */
|
| 837 |
+
display: flex;
|
| 838 |
+
flex-direction: column;
|
| 839 |
+
overflow: hidden;
|
| 840 |
+
height: calc(100vh - 240px);
|
| 841 |
+
}
|
| 842 |
+
|
| 843 |
+
.panel-header {
|
| 844 |
+
padding: 1.25rem;
|
| 845 |
+
border-bottom: 1px solid var(--glass-border);
|
| 846 |
+
display: flex;
|
| 847 |
+
justify-content: space-between;
|
| 848 |
+
align-items: center;
|
| 849 |
+
}
|
| 850 |
+
|
| 851 |
+
.panel-header h3 {
|
| 852 |
+
display: flex;
|
| 853 |
+
align-items: center;
|
| 854 |
+
gap: 0.75rem;
|
| 855 |
+
font-size: 1.1rem;
|
| 856 |
+
color: var(--text-primary);
|
| 857 |
+
}
|
| 858 |
+
|
| 859 |
+
.header-hint {
|
| 860 |
+
font-size: 11px;
|
| 861 |
+
color: var(--text-tertiary);
|
| 862 |
+
background: rgba(255, 255, 255, 0.05);
|
| 863 |
+
padding: 2px 8px;
|
| 864 |
+
border-radius: 4px;
|
| 865 |
+
text-transform: uppercase;
|
| 866 |
+
letter-spacing: 0.5px;
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
+
.log-viewport {
|
| 870 |
+
flex: 1;
|
| 871 |
+
overflow-y: auto;
|
| 872 |
+
padding: 1.25rem;
|
| 873 |
+
display: flex;
|
| 874 |
+
flex-direction: column;
|
| 875 |
+
gap: 1rem;
|
| 876 |
+
}
|
| 877 |
+
|
| 878 |
+
.log-entry {
|
| 879 |
+
padding: 1.25rem;
|
| 880 |
+
background: rgba(255, 255, 255, 0.02);
|
| 881 |
+
border-radius: 0.75rem;
|
| 882 |
+
border-left: 4px solid var(--accent-primary);
|
| 883 |
+
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
| 884 |
+
border-right: 1px solid rgba(255, 255, 255, 0.05);
|
| 885 |
+
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
|
| 886 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
| 887 |
+
transition: all 0.2s ease;
|
| 888 |
+
margin-bottom: 0.5rem;
|
| 889 |
+
}
|
| 890 |
+
|
| 891 |
+
.log-entry:hover {
|
| 892 |
+
background: rgba(255, 255, 255, 0.04);
|
| 893 |
+
transform: translateY(-2px);
|
| 894 |
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
|
| 895 |
+
}
|
| 896 |
+
|
| 897 |
+
.log-meta {
|
| 898 |
+
display: flex;
|
| 899 |
+
align-items: center;
|
| 900 |
+
gap: 0.75rem;
|
| 901 |
+
margin-bottom: 0.75rem;
|
| 902 |
+
color: var(--text-secondary);
|
| 903 |
+
font-size: 0.75rem;
|
| 904 |
+
letter-spacing: 0.05em;
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
.log-meta .source {
|
| 908 |
+
font-weight: 800;
|
| 909 |
+
text-transform: uppercase;
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
.log-meta .time {
|
| 913 |
+
margin-left: auto;
|
| 914 |
+
opacity: 0.5;
|
| 915 |
+
font-family: 'JetBrains Mono', monospace;
|
| 916 |
+
font-size: 0.7rem;
|
| 917 |
+
}
|
| 918 |
+
|
| 919 |
+
.log-content {
|
| 920 |
+
font-size: 1rem;
|
| 921 |
+
line-height: 1.6;
|
| 922 |
+
color: var(--text-primary);
|
| 923 |
+
font-weight: 400;
|
| 924 |
+
word-wrap: break-word;
|
| 925 |
+
}
|
| 926 |
+
|
| 927 |
+
.log-content :deep(strong) {
|
| 928 |
+
color: #fff;
|
| 929 |
+
font-weight: 700;
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
+
.log-content :deep(em) {
|
| 933 |
+
color: var(--text-secondary);
|
| 934 |
+
font-style: italic;
|
| 935 |
+
}
|
| 936 |
+
|
| 937 |
+
.log-content :deep(br) {
|
| 938 |
+
display: block;
|
| 939 |
+
content: "";
|
| 940 |
+
margin-top: 0.5rem;
|
| 941 |
+
}
|
| 942 |
+
|
| 943 |
+
.log-content :deep(ul), .log-content :deep(ol) {
|
| 944 |
+
margin: 0.75rem 0;
|
| 945 |
+
padding-left: 1.5rem;
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
.log-content :deep(li) {
|
| 949 |
+
margin-bottom: 0.4rem;
|
| 950 |
+
}
|
| 951 |
+
|
| 952 |
+
.log-content :deep(h3), .log-content :deep(h4), .log-content :deep(h5) {
|
| 953 |
+
margin: 1.25rem 0 0.75rem 0;
|
| 954 |
+
color: var(--text-primary);
|
| 955 |
+
font-weight: 700;
|
| 956 |
+
line-height: 1.3;
|
| 957 |
+
}
|
| 958 |
+
|
| 959 |
+
.log-content :deep(.inline-code) {
|
| 960 |
+
background: rgba(255, 255, 255, 0.1);
|
| 961 |
+
padding: 0.2rem 0.4rem;
|
| 962 |
+
border-radius: 0.25rem;
|
| 963 |
+
font-family: 'JetBrains Mono', monospace;
|
| 964 |
+
font-size: 0.85em;
|
| 965 |
+
color: var(--accent-primary);
|
| 966 |
+
}
|
| 967 |
+
|
| 968 |
+
.log-content :deep(blockquote) {
|
| 969 |
+
border-left: 3px solid var(--accent-primary);
|
| 970 |
+
background: rgba(255, 255, 255, 0.03);
|
| 971 |
+
padding: 0.75rem 1rem;
|
| 972 |
+
margin: 1rem 0;
|
| 973 |
+
font-style: italic;
|
| 974 |
+
border-radius: 0 0.5rem 0.5rem 0;
|
| 975 |
+
}
|
| 976 |
+
|
| 977 |
+
/* Loading State */
|
| 978 |
+
.loading-state {
|
| 979 |
+
display: flex;
|
| 980 |
+
flex-direction: column;
|
| 981 |
+
align-items: center;
|
| 982 |
+
justify-content: center;
|
| 983 |
+
padding: 3rem 2rem;
|
| 984 |
+
gap: 1.5rem;
|
| 985 |
+
}
|
| 986 |
+
|
| 987 |
+
.sparkles-wrapper {
|
| 988 |
+
position: relative;
|
| 989 |
+
width: 80px;
|
| 990 |
+
height: 80px;
|
| 991 |
+
display: flex;
|
| 992 |
+
align-items: center;
|
| 993 |
+
justify-content: center;
|
| 994 |
+
}
|
| 995 |
+
|
| 996 |
+
.sparkle-icon {
|
| 997 |
+
color: var(--accent-primary);
|
| 998 |
+
animation: sparkleGlow 2s ease-in-out infinite;
|
| 999 |
+
filter: drop-shadow(0 0 12px rgba(59, 130, 246, 0.6));
|
| 1000 |
+
}
|
| 1001 |
+
|
| 1002 |
+
@keyframes sparkleGlow {
|
| 1003 |
+
0%, 100% {
|
| 1004 |
+
opacity: 1;
|
| 1005 |
+
transform: scale(1) rotate(0deg);
|
| 1006 |
+
}
|
| 1007 |
+
50% {
|
| 1008 |
+
opacity: 0.7;
|
| 1009 |
+
transform: scale(1.15) rotate(180deg);
|
| 1010 |
+
}
|
| 1011 |
+
}
|
| 1012 |
+
|
| 1013 |
+
.sparkle-particles {
|
| 1014 |
+
position: absolute;
|
| 1015 |
+
width: 100%;
|
| 1016 |
+
height: 100%;
|
| 1017 |
+
top: 0;
|
| 1018 |
+
left: 0;
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
.particle {
|
| 1022 |
+
position: absolute;
|
| 1023 |
+
width: 8px;
|
| 1024 |
+
height: 8px;
|
| 1025 |
+
background: linear-gradient(135deg, #60a5fa, #3b82f6);
|
| 1026 |
+
border-radius: 50%;
|
| 1027 |
+
animation: particleFloat 3s ease-in-out infinite;
|
| 1028 |
+
box-shadow: 0 0 8px rgba(59, 130, 246, 0.8);
|
| 1029 |
+
}
|
| 1030 |
+
|
| 1031 |
+
.particle:nth-child(1) {
|
| 1032 |
+
top: 10%;
|
| 1033 |
+
left: 10%;
|
| 1034 |
+
animation-delay: 0s;
|
| 1035 |
+
}
|
| 1036 |
+
|
| 1037 |
+
.particle:nth-child(2) {
|
| 1038 |
+
top: 10%;
|
| 1039 |
+
right: 10%;
|
| 1040 |
+
animation-delay: 0.75s;
|
| 1041 |
+
}
|
| 1042 |
+
|
| 1043 |
+
.particle:nth-child(3) {
|
| 1044 |
+
bottom: 10%;
|
| 1045 |
+
left: 10%;
|
| 1046 |
+
animation-delay: 1.5s;
|
| 1047 |
+
}
|
| 1048 |
+
|
| 1049 |
+
.particle:nth-child(4) {
|
| 1050 |
+
bottom: 10%;
|
| 1051 |
+
right: 10%;
|
| 1052 |
+
animation-delay: 2.25s;
|
| 1053 |
+
}
|
| 1054 |
+
|
| 1055 |
+
@keyframes particleFloat {
|
| 1056 |
+
0%, 100% {
|
| 1057 |
+
transform: translateY(0) scale(1);
|
| 1058 |
+
opacity: 0;
|
| 1059 |
+
}
|
| 1060 |
+
10% {
|
| 1061 |
+
opacity: 1;
|
| 1062 |
+
}
|
| 1063 |
+
50% {
|
| 1064 |
+
transform: translateY(-20px) scale(1.2);
|
| 1065 |
+
opacity: 1;
|
| 1066 |
+
}
|
| 1067 |
+
90% {
|
| 1068 |
+
opacity: 1;
|
| 1069 |
+
}
|
| 1070 |
+
100% {
|
| 1071 |
+
transform: translateY(-40px) scale(0.8);
|
| 1072 |
+
opacity: 0;
|
| 1073 |
+
}
|
| 1074 |
+
}
|
| 1075 |
+
|
| 1076 |
+
.loading-state p {
|
| 1077 |
+
color: var(--text-secondary);
|
| 1078 |
+
font-size: 0.95rem;
|
| 1079 |
+
font-weight: 500;
|
| 1080 |
+
animation: fadeInOut 2s ease-in-out infinite;
|
| 1081 |
+
}
|
| 1082 |
+
|
| 1083 |
+
@keyframes fadeInOut {
|
| 1084 |
+
0%, 100% { opacity: 0.6; }
|
| 1085 |
+
50% { opacity: 1; }
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
+
.panel-results {
|
| 1089 |
+
grid-column: 1; /* Move to left column */
|
| 1090 |
+
grid-row: 1; /* Ensure it stays on the first row */
|
| 1091 |
+
display: flex;
|
| 1092 |
+
flex-direction: column;
|
| 1093 |
+
gap: 1.5rem;
|
| 1094 |
+
}
|
| 1095 |
+
|
| 1096 |
+
.summary-section {
|
| 1097 |
+
flex: 1;
|
| 1098 |
+
display: flex;
|
| 1099 |
+
flex-direction: column;
|
| 1100 |
+
min-height: 400px;
|
| 1101 |
+
}
|
| 1102 |
+
|
| 1103 |
+
.results-list {
|
| 1104 |
+
padding: 1.25rem;
|
| 1105 |
+
display: flex;
|
| 1106 |
+
flex-direction: column;
|
| 1107 |
+
gap: 1rem;
|
| 1108 |
+
}
|
| 1109 |
+
|
| 1110 |
+
.result-card {
|
| 1111 |
+
padding: 1.5rem;
|
| 1112 |
+
border-left: 4px solid var(--accent-primary);
|
| 1113 |
+
}
|
| 1114 |
+
|
| 1115 |
+
.card-header {
|
| 1116 |
+
display: flex;
|
| 1117 |
+
align-items: center;
|
| 1118 |
+
gap: 0.75rem;
|
| 1119 |
+
margin-bottom: 1rem;
|
| 1120 |
+
}
|
| 1121 |
+
|
| 1122 |
+
.ticker-badge {
|
| 1123 |
+
padding: 0.25rem 0.75rem;
|
| 1124 |
+
background: rgba(255, 255, 255, 0.1);
|
| 1125 |
+
border-radius: 0.5rem;
|
| 1126 |
+
font-weight: 800;
|
| 1127 |
+
font-size: 1rem;
|
| 1128 |
+
}
|
| 1129 |
+
|
| 1130 |
+
.decision-badge {
|
| 1131 |
+
padding: 0.25rem 0.75rem;
|
| 1132 |
+
border-radius: 0.5rem;
|
| 1133 |
+
font-weight: 700;
|
| 1134 |
+
font-size: 0.8rem;
|
| 1135 |
+
color: white;
|
| 1136 |
+
}
|
| 1137 |
+
|
| 1138 |
+
.confidence-badge {
|
| 1139 |
+
margin-left: auto;
|
| 1140 |
+
font-size: 0.8rem;
|
| 1141 |
+
color: var(--text-secondary);
|
| 1142 |
+
}
|
| 1143 |
+
|
| 1144 |
+
.card-body h4 {
|
| 1145 |
+
font-size: 1.1rem;
|
| 1146 |
+
margin-bottom: 0.75rem;
|
| 1147 |
+
line-height: 1.4;
|
| 1148 |
+
}
|
| 1149 |
+
|
| 1150 |
+
.entry-info {
|
| 1151 |
+
display: flex;
|
| 1152 |
+
align-items: center;
|
| 1153 |
+
gap: 0.5rem;
|
| 1154 |
+
font-size: 0.85rem;
|
| 1155 |
+
margin-bottom: 1rem;
|
| 1156 |
+
color: var(--text-primary);
|
| 1157 |
+
}
|
| 1158 |
+
|
| 1159 |
+
.risk-info {
|
| 1160 |
+
font-size: 0.85rem;
|
| 1161 |
+
color: var(--text-secondary);
|
| 1162 |
+
display: flex;
|
| 1163 |
+
gap: 0.5rem;
|
| 1164 |
+
font-style: italic;
|
| 1165 |
+
}
|
| 1166 |
+
|
| 1167 |
+
.info-card {
|
| 1168 |
+
padding: 1.25rem;
|
| 1169 |
+
border-left: 4px solid var(--warning);
|
| 1170 |
+
}
|
| 1171 |
+
|
| 1172 |
+
.info-card h4 {
|
| 1173 |
+
color: var(--warning);
|
| 1174 |
+
display: flex;
|
| 1175 |
+
align-items: center;
|
| 1176 |
+
gap: 0.5rem;
|
| 1177 |
+
margin-bottom: 0.5rem;
|
| 1178 |
+
}
|
| 1179 |
+
|
| 1180 |
+
.info-card p {
|
| 1181 |
+
font-size: 0.8rem;
|
| 1182 |
+
color: var(--text-secondary);
|
| 1183 |
+
}
|
| 1184 |
+
|
| 1185 |
+
.error-alert {
|
| 1186 |
+
padding: 1rem 1.5rem;
|
| 1187 |
+
border-left: 4px solid var(--danger);
|
| 1188 |
+
display: flex;
|
| 1189 |
+
align-items: center;
|
| 1190 |
+
gap: 1rem;
|
| 1191 |
+
color: var(--danger);
|
| 1192 |
+
}
|
| 1193 |
+
|
| 1194 |
+
.error-alert p {
|
| 1195 |
+
flex: 1;
|
| 1196 |
+
font-weight: 500;
|
| 1197 |
+
}
|
| 1198 |
+
|
| 1199 |
+
.empty-state {
|
| 1200 |
+
display: flex;
|
| 1201 |
+
flex-direction: column;
|
| 1202 |
+
align-items: center;
|
| 1203 |
+
justify-content: center;
|
| 1204 |
+
height: 100%;
|
| 1205 |
+
color: var(--text-muted);
|
| 1206 |
+
gap: 1rem;
|
| 1207 |
+
}
|
| 1208 |
+
|
| 1209 |
+
.status-indicator {
|
| 1210 |
+
display: flex;
|
| 1211 |
+
align-items: center;
|
| 1212 |
+
gap: 0.5rem;
|
| 1213 |
+
font-size: 0.8rem;
|
| 1214 |
+
font-weight: 600;
|
| 1215 |
+
color: var(--success);
|
| 1216 |
+
}
|
| 1217 |
+
|
| 1218 |
+
.pulse {
|
| 1219 |
+
width: 8px;
|
| 1220 |
+
height: 8px;
|
| 1221 |
+
background: var(--success);
|
| 1222 |
+
border-radius: 50%;
|
| 1223 |
+
box-shadow: 0 0 0 rgba(16, 185, 129, 0.4);
|
| 1224 |
+
animation: pulse 2s infinite;
|
| 1225 |
+
}
|
| 1226 |
+
|
| 1227 |
+
@keyframes pulse {
|
| 1228 |
+
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
|
| 1229 |
+
70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); }
|
| 1230 |
+
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
| 1231 |
+
}
|
| 1232 |
+
|
| 1233 |
+
.animate-spin {
|
| 1234 |
+
animation: spin 1s linear infinite;
|
| 1235 |
+
}
|
| 1236 |
+
|
| 1237 |
+
@keyframes spin {
|
| 1238 |
+
from { transform: rotate(0deg); }
|
| 1239 |
+
to { transform: rotate(360deg); }
|
| 1240 |
+
}
|
| 1241 |
+
|
| 1242 |
+
@media (max-width: 1024px) {
|
| 1243 |
+
.grid-layout {
|
| 1244 |
+
grid-template-columns: 1fr;
|
| 1245 |
+
}
|
| 1246 |
+
.panel-logs {
|
| 1247 |
+
height: 500px;
|
| 1248 |
+
}
|
| 1249 |
+
}
|
| 1250 |
+
|
| 1251 |
+
.fundamental-badge {
|
| 1252 |
+
padding: 0.25rem 0.5rem;
|
| 1253 |
+
border-radius: 0.5rem;
|
| 1254 |
+
font-weight: 800;
|
| 1255 |
+
font-size: 0.7rem;
|
| 1256 |
+
text-transform: uppercase;
|
| 1257 |
+
display: flex;
|
| 1258 |
+
align-items: center;
|
| 1259 |
+
gap: 0.3rem;
|
| 1260 |
+
background: rgba(255, 255, 255, 0.05);
|
| 1261 |
+
border: 1px solid var(--glass-border);
|
| 1262 |
+
}
|
| 1263 |
+
|
| 1264 |
+
.fundamental-badge.Strong { color: var(--success); border-color: rgba(16, 185, 129, 0.3); }
|
| 1265 |
+
.fundamental-badge.Stable { color: var(--accent-primary); border-color: rgba(59, 130, 246, 0.3); }
|
| 1266 |
+
.fundamental-badge.Weak { color: var(--danger); border-color: rgba(239, 68, 68, 0.3); }
|
| 1267 |
+
|
| 1268 |
+
.status-badge {
|
| 1269 |
+
font-size: 0.7rem;
|
| 1270 |
+
font-weight: 800;
|
| 1271 |
+
color: var(--accent-primary);
|
| 1272 |
+
letter-spacing: 0.1em;
|
| 1273 |
+
}
|
| 1274 |
+
|
| 1275 |
+
.expiry-badge {
|
| 1276 |
+
padding: 0.25rem 0.5rem;
|
| 1277 |
+
background: rgba(255, 255, 255, 0.1);
|
| 1278 |
+
border-radius: 0.5rem;
|
| 1279 |
+
font-weight: 700;
|
| 1280 |
+
font-size: 0.75rem;
|
| 1281 |
+
color: var(--text-primary);
|
| 1282 |
+
display: flex;
|
| 1283 |
+
align-items: center;
|
| 1284 |
+
gap: 0.4rem;
|
| 1285 |
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 1286 |
+
}
|
| 1287 |
+
|
| 1288 |
+
.pulse-border {
|
| 1289 |
+
animation: pulse-border 2s infinite;
|
| 1290 |
+
}
|
| 1291 |
+
|
| 1292 |
+
@keyframes pulse-border {
|
| 1293 |
+
0% { border-color: var(--glass-border); }
|
| 1294 |
+
50% { border-color: var(--accent-primary); }
|
| 1295 |
+
100% { border-color: var(--glass-border); }
|
| 1296 |
+
}
|
| 1297 |
+
|
| 1298 |
+
/* Transitions */
|
| 1299 |
+
.list-enter-active,
|
| 1300 |
+
.list-leave-active {
|
| 1301 |
+
transition: all 0.5s ease;
|
| 1302 |
+
}
|
| 1303 |
+
.list-enter-from,
|
| 1304 |
+
.list-leave-to {
|
| 1305 |
+
opacity: 0;
|
| 1306 |
+
transform: translateX(30px);
|
| 1307 |
+
}
|
| 1308 |
+
|
| 1309 |
+
.transition-container {
|
| 1310 |
+
display: flex;
|
| 1311 |
+
flex-direction: column;
|
| 1312 |
+
gap: 1rem;
|
| 1313 |
+
}
|
| 1314 |
+
.main-footer {
|
| 1315 |
+
margin-top: auto;
|
| 1316 |
+
padding: 1rem 2rem;
|
| 1317 |
+
z-index: 100;
|
| 1318 |
+
}
|
| 1319 |
+
|
| 1320 |
+
.footer-content {
|
| 1321 |
+
display: flex;
|
| 1322 |
+
justify-content: space-between;
|
| 1323 |
+
align-items: center;
|
| 1324 |
+
gap: 2rem;
|
| 1325 |
+
}
|
| 1326 |
+
|
| 1327 |
+
.disclaimer-info {
|
| 1328 |
+
display: flex;
|
| 1329 |
+
align-items: center;
|
| 1330 |
+
gap: 0.75rem;
|
| 1331 |
+
font-size: 0.85rem;
|
| 1332 |
+
color: var(--text-secondary);
|
| 1333 |
+
line-height: 1.4;
|
| 1334 |
+
}
|
| 1335 |
+
|
| 1336 |
+
.disclaimer-info strong {
|
| 1337 |
+
color: var(--warning);
|
| 1338 |
+
}
|
| 1339 |
+
|
| 1340 |
+
.copyright {
|
| 1341 |
+
font-size: 0.8rem;
|
| 1342 |
+
color: var(--text-muted);
|
| 1343 |
+
white-space: nowrap;
|
| 1344 |
+
}
|
| 1345 |
+
|
| 1346 |
+
/* Strategy Legs Table */
|
| 1347 |
+
.legs-container {
|
| 1348 |
+
margin: 1.25rem 0;
|
| 1349 |
+
padding: 1rem;
|
| 1350 |
+
border-radius: 0.75rem;
|
| 1351 |
+
background: rgba(255, 255, 255, 0.02);
|
| 1352 |
+
border: 1px solid rgba(255, 255, 255, 0.05);
|
| 1353 |
+
}
|
| 1354 |
+
|
| 1355 |
+
.legs-header {
|
| 1356 |
+
font-size: 0.7rem;
|
| 1357 |
+
font-weight: 800;
|
| 1358 |
+
text-transform: uppercase;
|
| 1359 |
+
color: var(--text-muted);
|
| 1360 |
+
margin-bottom: 0.75rem;
|
| 1361 |
+
letter-spacing: 0.05em;
|
| 1362 |
+
display: flex;
|
| 1363 |
+
justify-content: space-between;
|
| 1364 |
+
}
|
| 1365 |
+
|
| 1366 |
+
.legs-table {
|
| 1367 |
+
width: 100%;
|
| 1368 |
+
border-collapse: collapse;
|
| 1369 |
+
font-size: 0.85rem;
|
| 1370 |
+
}
|
| 1371 |
+
|
| 1372 |
+
.legs-table th {
|
| 1373 |
+
text-align: left;
|
| 1374 |
+
padding: 0.5rem;
|
| 1375 |
+
color: var(--text-secondary);
|
| 1376 |
+
font-weight: 600;
|
| 1377 |
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
| 1378 |
+
}
|
| 1379 |
+
|
| 1380 |
+
.legs-table td {
|
| 1381 |
+
padding: 0.6rem 0.5rem;
|
| 1382 |
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
| 1383 |
+
}
|
| 1384 |
+
|
| 1385 |
+
.action-badge {
|
| 1386 |
+
padding: 0.15rem 0.4rem;
|
| 1387 |
+
border-radius: 0.25rem;
|
| 1388 |
+
font-size: 0.7rem;
|
| 1389 |
+
font-weight: 800;
|
| 1390 |
+
}
|
| 1391 |
+
|
| 1392 |
+
.action-badge.buy { background: rgba(16, 185, 129, 0.15); color: var(--success); }
|
| 1393 |
+
.action-badge.sell { background: rgba(239, 68, 68, 0.15); color: var(--danger); }
|
| 1394 |
+
|
| 1395 |
+
.strike-pill {
|
| 1396 |
+
font-weight: 700;
|
| 1397 |
+
color: var(--text-primary);
|
| 1398 |
+
}
|
| 1399 |
+
|
| 1400 |
+
.col-expiry {
|
| 1401 |
+
font-size: 0.75rem;
|
| 1402 |
+
color: var(--text-secondary);
|
| 1403 |
+
}
|
| 1404 |
+
|
| 1405 |
+
.col-price {
|
| 1406 |
+
font-weight: 600;
|
| 1407 |
+
color: var(--accent-primary);
|
| 1408 |
+
}
|
| 1409 |
+
|
| 1410 |
+
.risk-reward-grid {
|
| 1411 |
+
display: grid;
|
| 1412 |
+
grid-template-columns: repeat(3, 1fr);
|
| 1413 |
+
gap: 0.75rem;
|
| 1414 |
+
margin: 1rem 0;
|
| 1415 |
+
}
|
| 1416 |
+
|
| 1417 |
+
.rr-item {
|
| 1418 |
+
padding: 0.75rem;
|
| 1419 |
+
background: rgba(255, 255, 255, 0.03);
|
| 1420 |
+
border-radius: 0.5rem;
|
| 1421 |
+
display: flex;
|
| 1422 |
+
flex-direction: column;
|
| 1423 |
+
gap: 0.25rem;
|
| 1424 |
+
border: 1px solid rgba(255, 255, 255, 0.05);
|
| 1425 |
+
}
|
| 1426 |
+
|
| 1427 |
+
.rr-label {
|
| 1428 |
+
font-size: 0.65rem;
|
| 1429 |
+
font-weight: 700;
|
| 1430 |
+
color: var(--text-muted);
|
| 1431 |
+
text-transform: uppercase;
|
| 1432 |
+
}
|
| 1433 |
+
|
| 1434 |
+
.rr-val {
|
| 1435 |
+
font-size: 1.1rem;
|
| 1436 |
+
font-weight: 800;
|
| 1437 |
+
}
|
| 1438 |
+
|
| 1439 |
+
.rr-val.profit { color: var(--success); }
|
| 1440 |
+
.rr-val.loss { color: var(--danger); }
|
| 1441 |
+
|
| 1442 |
+
.strat-title {
|
| 1443 |
+
margin-bottom: 0.5rem;
|
| 1444 |
+
color: var(--accent-primary);
|
| 1445 |
+
font-weight: 800;
|
| 1446 |
+
}
|
| 1447 |
+
|
| 1448 |
+
.strat-reasoning {
|
| 1449 |
+
font-size: 0.95rem;
|
| 1450 |
+
line-height: 1.5;
|
| 1451 |
+
color: var(--text-secondary);
|
| 1452 |
+
margin-bottom: 1rem;
|
| 1453 |
+
}
|
| 1454 |
+
|
| 1455 |
+
@media (max-width: 1024px) {
|
| 1456 |
+
.footer-content {
|
| 1457 |
+
flex-direction: column;
|
| 1458 |
+
text-align: center;
|
| 1459 |
+
gap: 1rem;
|
| 1460 |
+
}
|
| 1461 |
+
}
|
| 1462 |
+
/* Breadcrumb Styling */
|
| 1463 |
+
.workflow-breadcrumb {
|
| 1464 |
+
display: flex;
|
| 1465 |
+
justify-content: center;
|
| 1466 |
+
align-items: center;
|
| 1467 |
+
padding: 0.75rem 2rem;
|
| 1468 |
+
gap: 1.5rem;
|
| 1469 |
+
margin-bottom: 0.5rem;
|
| 1470 |
+
position: relative;
|
| 1471 |
+
z-index: 50; /* Ensure tooltips appear above content below */
|
| 1472 |
+
}
|
| 1473 |
+
|
| 1474 |
+
.breadcrumb-label {
|
| 1475 |
+
text-align: center;
|
| 1476 |
+
font-size: 0.65rem;
|
| 1477 |
+
font-weight: 800;
|
| 1478 |
+
text-transform: uppercase;
|
| 1479 |
+
color: var(--text-muted);
|
| 1480 |
+
letter-spacing: 0.1em;
|
| 1481 |
+
margin-top: 0.5rem;
|
| 1482 |
+
display: flex;
|
| 1483 |
+
align-items: center;
|
| 1484 |
+
justify-content: center;
|
| 1485 |
+
gap: 0.4rem;
|
| 1486 |
+
opacity: 0.7;
|
| 1487 |
+
}
|
| 1488 |
+
|
| 1489 |
+
.legend-text {
|
| 1490 |
+
font-size: 0.6rem;
|
| 1491 |
+
color: var(--accent-primary);
|
| 1492 |
+
text-transform: none;
|
| 1493 |
+
letter-spacing: normal;
|
| 1494 |
+
margin-left: 0.5rem;
|
| 1495 |
+
font-weight: 500;
|
| 1496 |
+
font-style: italic;
|
| 1497 |
+
opacity: 0.9;
|
| 1498 |
+
}
|
| 1499 |
+
|
| 1500 |
+
.breadcrumb-item {
|
| 1501 |
+
display: flex;
|
| 1502 |
+
align-items: center;
|
| 1503 |
+
gap: 0.75rem;
|
| 1504 |
+
opacity: 0.4;
|
| 1505 |
+
transition: all 0.4s ease;
|
| 1506 |
+
cursor: help;
|
| 1507 |
+
position: relative;
|
| 1508 |
+
}
|
| 1509 |
+
|
| 1510 |
+
/* Fancy Tooltip */
|
| 1511 |
+
.breadcrumb-item::after {
|
| 1512 |
+
content: attr(data-tooltip);
|
| 1513 |
+
position: absolute;
|
| 1514 |
+
top: 140%; /* Move below */
|
| 1515 |
+
left: 50%;
|
| 1516 |
+
transform: translateX(-50%) translateY(-10px);
|
| 1517 |
+
background: rgba(15, 23, 42, 0.95);
|
| 1518 |
+
color: #f1f5f9;
|
| 1519 |
+
padding: 0.6rem 1rem;
|
| 1520 |
+
border-radius: 0.5rem;
|
| 1521 |
+
font-size: 0.75rem;
|
| 1522 |
+
line-height: 1.4;
|
| 1523 |
+
width: max-content;
|
| 1524 |
+
max-width: 220px;
|
| 1525 |
+
text-align: center;
|
| 1526 |
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
| 1527 |
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
|
| 1528 |
+
opacity: 0;
|
| 1529 |
+
visibility: hidden;
|
| 1530 |
+
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
| 1531 |
+
z-index: 1000; /* Ensure high z-index regardless */
|
| 1532 |
+
backdrop-filter: blur(4px);
|
| 1533 |
+
font-weight: 500;
|
| 1534 |
+
pointer-events: none;
|
| 1535 |
+
}
|
| 1536 |
+
|
| 1537 |
+
/* Tooltip Arrow */
|
| 1538 |
+
.breadcrumb-item::before {
|
| 1539 |
+
content: '';
|
| 1540 |
+
position: absolute;
|
| 1541 |
+
top: 140%; /* Move below */
|
| 1542 |
+
left: 50%;
|
| 1543 |
+
transform: translateX(-50%) translateY(-10px);
|
| 1544 |
+
border: 6px solid transparent;
|
| 1545 |
+
border-bottom-color: rgba(15, 23, 42, 0.95); /* Point Up */
|
| 1546 |
+
margin-top: -11px; /* Overlap slightly */
|
| 1547 |
+
opacity: 0;
|
| 1548 |
+
visibility: hidden;
|
| 1549 |
+
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
| 1550 |
+
z-index: 1000;
|
| 1551 |
+
pointer-events: none;
|
| 1552 |
+
}
|
| 1553 |
+
|
| 1554 |
+
.breadcrumb-item:hover::after,
|
| 1555 |
+
.breadcrumb-item:hover::before {
|
| 1556 |
+
opacity: 1;
|
| 1557 |
+
visibility: visible;
|
| 1558 |
+
transform: translateX(-50%) translateY(0);
|
| 1559 |
+
}
|
| 1560 |
+
|
| 1561 |
+
|
| 1562 |
+
.breadcrumb-item:hover {
|
| 1563 |
+
opacity: 0.8;
|
| 1564 |
+
}
|
| 1565 |
+
|
| 1566 |
+
.breadcrumb-item.active {
|
| 1567 |
+
opacity: 1;
|
| 1568 |
+
transform: scale(1.05);
|
| 1569 |
+
}
|
| 1570 |
+
|
| 1571 |
+
.item-icon-wrapper {
|
| 1572 |
+
position: relative;
|
| 1573 |
+
display: flex;
|
| 1574 |
+
align-items: center;
|
| 1575 |
+
justify-content: center;
|
| 1576 |
+
width: 28px;
|
| 1577 |
+
height: 28px;
|
| 1578 |
+
background: rgba(255, 255, 255, 0.05);
|
| 1579 |
+
border-radius: 50%;
|
| 1580 |
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
| 1581 |
+
}
|
| 1582 |
+
|
| 1583 |
+
.active .item-icon-wrapper {
|
| 1584 |
+
background: rgba(255, 255, 255, 0.15);
|
| 1585 |
+
border-color: currentColor;
|
| 1586 |
+
box-shadow: 0 0 20px currentColor, inset 0 0 10px currentColor; /* Brighter glow */
|
| 1587 |
+
}
|
| 1588 |
+
|
| 1589 |
+
.item-label {
|
| 1590 |
+
font-size: 0.8rem;
|
| 1591 |
+
font-weight: 700;
|
| 1592 |
+
letter-spacing: 0.05em;
|
| 1593 |
+
text-transform: uppercase;
|
| 1594 |
+
color: var(--text-primary);
|
| 1595 |
+
}
|
| 1596 |
+
|
| 1597 |
+
.separator {
|
| 1598 |
+
color: var(--text-muted);
|
| 1599 |
+
margin-left: 0.5rem;
|
| 1600 |
+
}
|
| 1601 |
+
|
| 1602 |
+
.bulb {
|
| 1603 |
+
position: absolute;
|
| 1604 |
+
top: -2px;
|
| 1605 |
+
right: -2px;
|
| 1606 |
+
width: 8px;
|
| 1607 |
+
height: 8px;
|
| 1608 |
+
border-radius: 50%;
|
| 1609 |
+
box-shadow: 0 0 10px currentColor;
|
| 1610 |
+
animation: bulb-pulse 1.5s infinite;
|
| 1611 |
+
}
|
| 1612 |
+
|
| 1613 |
+
@keyframes bulb-pulse {
|
| 1614 |
+
0% { transform: scale(1); opacity: 1; box-shadow: 0 0 5px currentColor; }
|
| 1615 |
+
50% { transform: scale(1.4); opacity: 0.8; box-shadow: 0 0 15px currentColor; }
|
| 1616 |
+
100% { transform: scale(1); opacity: 1; box-shadow: 0 0 5px currentColor; }
|
| 1617 |
+
}
|
| 1618 |
+
|
| 1619 |
+
@media (max-width: 1024px) {
|
| 1620 |
+
.grid-layout {
|
| 1621 |
+
grid-template-columns: 1fr; /* Stack columns on tablet/mobile */
|
| 1622 |
+
}
|
| 1623 |
+
|
| 1624 |
+
.panel-results {
|
| 1625 |
+
grid-column: 1; /* Both take full width */
|
| 1626 |
+
min-height: auto;
|
| 1627 |
+
}
|
| 1628 |
+
|
| 1629 |
+
.panel-logs {
|
| 1630 |
+
grid-column: 1;
|
| 1631 |
+
height: 500px;
|
| 1632 |
+
}
|
| 1633 |
+
}
|
| 1634 |
+
|
| 1635 |
+
.btn-clear {
|
| 1636 |
+
background: transparent;
|
| 1637 |
+
border: 1px solid var(--text-secondary);
|
| 1638 |
+
color: var(--text-secondary);
|
| 1639 |
+
padding: 0.25rem 0.75rem;
|
| 1640 |
+
border-radius: 0.5rem;
|
| 1641 |
+
font-size: 0.75rem;
|
| 1642 |
+
cursor: pointer;
|
| 1643 |
+
transition: all 0.2s;
|
| 1644 |
+
}
|
| 1645 |
+
|
| 1646 |
+
.btn-clear:hover {
|
| 1647 |
+
background: rgba(255,255,255,0.1);
|
| 1648 |
+
color: white;
|
| 1649 |
+
}
|
| 1650 |
+
|
| 1651 |
+
.history-section {
|
| 1652 |
+
width: 100%;
|
| 1653 |
+
margin-top: 2rem;
|
| 1654 |
+
display: flex;
|
| 1655 |
+
flex-direction: column;
|
| 1656 |
+
}
|
| 1657 |
+
|
| 1658 |
+
.history-table-container {
|
| 1659 |
+
margin: 1.25rem;
|
| 1660 |
+
overflow-x: auto;
|
| 1661 |
+
border-radius: 0.5rem;
|
| 1662 |
+
}
|
| 1663 |
+
|
| 1664 |
+
.glass-inset {
|
| 1665 |
+
background: rgba(0, 0, 0, 0.2);
|
| 1666 |
+
border: 1px solid rgba(255,255,255,0.05);
|
| 1667 |
+
box-shadow: inset 0 0 20px rgba(0,0,0,0.5);
|
| 1668 |
+
}
|
| 1669 |
+
|
| 1670 |
+
.history-table {
|
| 1671 |
+
width: 100%;
|
| 1672 |
+
border-collapse: collapse;
|
| 1673 |
+
font-size: 0.9rem;
|
| 1674 |
+
color: var(--text-primary);
|
| 1675 |
+
}
|
| 1676 |
+
|
| 1677 |
+
.history-table th {
|
| 1678 |
+
text-align: left;
|
| 1679 |
+
padding: 1rem;
|
| 1680 |
+
color: var(--text-secondary);
|
| 1681 |
+
font-weight: 600;
|
| 1682 |
+
text-transform: uppercase;
|
| 1683 |
+
font-size: 0.75rem;
|
| 1684 |
+
letter-spacing: 0.05em;
|
| 1685 |
+
border-bottom: 1px solid rgba(255,255,255,0.1);
|
| 1686 |
+
white-space: nowrap;
|
| 1687 |
+
}
|
| 1688 |
+
|
| 1689 |
+
.history-table td {
|
| 1690 |
+
padding: 1rem;
|
| 1691 |
+
border-bottom: 1px solid rgba(255,255,255,0.05);
|
| 1692 |
+
}
|
| 1693 |
+
|
| 1694 |
+
.history-table tbody tr {
|
| 1695 |
+
cursor: pointer;
|
| 1696 |
+
transition: background 0.2s;
|
| 1697 |
+
}
|
| 1698 |
+
|
| 1699 |
+
.history-table tbody tr:hover {
|
| 1700 |
+
background: rgba(255,255,255,0.05);
|
| 1701 |
+
}
|
| 1702 |
+
|
| 1703 |
+
.ticker-pill {
|
| 1704 |
+
font-weight: 700;
|
| 1705 |
+
background: rgba(255,255,255,0.1);
|
| 1706 |
+
padding: 0.2rem 0.5rem;
|
| 1707 |
+
border-radius: 0.25rem;
|
| 1708 |
+
}
|
| 1709 |
+
|
| 1710 |
+
.decision-pill {
|
| 1711 |
+
font-weight: 700;
|
| 1712 |
+
padding: 0.2rem 0.6rem;
|
| 1713 |
+
border-radius: 1rem;
|
| 1714 |
+
border: 1px solid transparent;
|
| 1715 |
+
font-size: 0.8rem;
|
| 1716 |
+
}
|
| 1717 |
+
|
| 1718 |
+
.col-date { font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; color: var(--text-secondary); white-space: nowrap; }
|
| 1719 |
+
.col-profit { font-weight: 700; color: var(--text-secondary); }
|
| 1720 |
+
.col-profit.has-profit { color: var(--success); }
|
| 1721 |
+
|
| 1722 |
+
.model-badge {
|
| 1723 |
+
font-size: 0.7rem;
|
| 1724 |
+
background: rgba(255,255,255,0.05);
|
| 1725 |
+
padding: 0.15rem 0.4rem;
|
| 1726 |
+
border-radius: 0.25rem;
|
| 1727 |
+
color: var(--text-secondary);
|
| 1728 |
+
white-space: nowrap;
|
| 1729 |
+
}
|
| 1730 |
+
|
| 1731 |
+
.confidence-bar-wrapper {
|
| 1732 |
+
display: flex;
|
| 1733 |
+
align-items: center;
|
| 1734 |
+
gap: 0.5rem;
|
| 1735 |
+
}
|
| 1736 |
+
|
| 1737 |
+
.confidence-bar {
|
| 1738 |
+
height: 4px;
|
| 1739 |
+
border-radius: 2px;
|
| 1740 |
+
width: 60px;
|
| 1741 |
+
}
|
| 1742 |
+
|
| 1743 |
+
.col-action { color: var(--text-muted); text-align: right; }
|
| 1744 |
+
.history-table tbody tr:hover .col-action { color: white; }
|
| 1745 |
+
|
| 1746 |
+
/* Modal Styles */
|
| 1747 |
+
.modal-overlay {
|
| 1748 |
+
position: fixed;
|
| 1749 |
+
top: 0;
|
| 1750 |
+
left: 0;
|
| 1751 |
+
right: 0;
|
| 1752 |
+
bottom: 0;
|
| 1753 |
+
background: rgba(0, 0, 0, 0.7);
|
| 1754 |
+
backdrop-filter: blur(4px);
|
| 1755 |
+
z-index: 1000;
|
| 1756 |
+
display: flex;
|
| 1757 |
+
align-items: center;
|
| 1758 |
+
justify-content: center;
|
| 1759 |
+
padding: 1.5rem;
|
| 1760 |
+
}
|
| 1761 |
+
|
| 1762 |
+
.modal-content {
|
| 1763 |
+
background: #0f172a; /* Fallback */
|
| 1764 |
+
background: linear-gradient(135deg, rgba(30, 41, 59, 0.95), rgba(15, 23, 42, 0.98));
|
| 1765 |
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
| 1766 |
+
border-top-width: 4px;
|
| 1767 |
+
border-radius: 1rem;
|
| 1768 |
+
padding: 2rem;
|
| 1769 |
+
width: 100%;
|
| 1770 |
+
max-width: 600px;
|
| 1771 |
+
position: relative;
|
| 1772 |
+
max-height: 90vh;
|
| 1773 |
+
overflow-y: auto;
|
| 1774 |
+
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
|
| 1775 |
+
animation: modalPop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
| 1776 |
+
}
|
| 1777 |
+
|
| 1778 |
+
@keyframes modalPop {
|
| 1779 |
+
0% { transform: scale(0.9); opacity: 0; }
|
| 1780 |
+
100% { transform: scale(1); opacity: 1; }
|
| 1781 |
+
}
|
| 1782 |
+
|
| 1783 |
+
.modal-close {
|
| 1784 |
+
position: absolute;
|
| 1785 |
+
top: 1rem;
|
| 1786 |
+
right: 1rem;
|
| 1787 |
+
background: none;
|
| 1788 |
+
border: none;
|
| 1789 |
+
color: var(--text-secondary);
|
| 1790 |
+
cursor: pointer;
|
| 1791 |
+
transition: color 0.2s;
|
| 1792 |
+
}
|
| 1793 |
+
|
| 1794 |
+
.modal-close:hover { color: white; }
|
| 1795 |
+
|
| 1796 |
+
.modal-header { margin-bottom: 1.5rem; }
|
| 1797 |
+
.modal-header h2 { font-size: 1.5rem; margin: 0; }
|
| 1798 |
+
.modal-header .timestamp { font-size: 0.8rem; color: var(--text-secondary); }
|
| 1799 |
+
|
| 1800 |
+
.modal-badges {
|
| 1801 |
+
display: flex;
|
| 1802 |
+
gap: 1rem;
|
| 1803 |
+
margin-bottom: 2rem;
|
| 1804 |
+
flex-wrap: wrap;
|
| 1805 |
+
}
|
| 1806 |
+
|
| 1807 |
+
.decision-badge.large { font-size: 1rem; padding: 0.4rem 1rem; }
|
| 1808 |
+
.confidence-badge.large { font-size: 1rem; padding: 0.4rem 1rem; background: rgba(255,255,255,0.1); border-radius: 0.5rem; font-weight: 600; }
|
| 1809 |
+
.rating-badge { display: flex; align-items: center; gap: 0.5rem; background: rgba(236, 72, 153, 0.2); color: #f472b6; padding: 0.4rem 1rem; border-radius: 0.5rem; font-weight: 700; }
|
| 1810 |
+
.model-badge.large { display: flex; align-items: center; gap: 0.5rem; background: rgba(59, 130, 246, 0.1); color: #60a5fa; padding: 0.4rem 1rem; border-radius: 0.5rem; font-weight: 600; font-size: 0.9rem; border: 1px solid rgba(59, 130, 246, 0.2); }
|
| 1811 |
+
|
| 1812 |
+
.report-section { margin-bottom: 1.5rem; }
|
| 1813 |
+
.report-section h3 { display: flex; align-items: center; gap: 0.5rem; font-size: 1rem; color: var(--text-secondary); margin-bottom: 0.5rem; text-transform: uppercase; letter-spacing: 0.05em; }
|
| 1814 |
+
.highlight-text { font-size: 1.1rem; line-height: 1.5; color: white; }
|
| 1815 |
+
|
| 1816 |
+
.metrics-grid {
|
| 1817 |
+
display: grid;
|
| 1818 |
+
grid-template-columns: repeat(2, 1fr);
|
| 1819 |
+
gap: 1rem;
|
| 1820 |
+
margin-bottom: 1.5rem;
|
| 1821 |
+
}
|
| 1822 |
+
|
| 1823 |
+
.metric-box {
|
| 1824 |
+
background: rgba(255,255,255,0.03);
|
| 1825 |
+
padding: 0.75rem;
|
| 1826 |
+
border-radius: 0.5rem;
|
| 1827 |
+
border: 1px solid rgba(255,255,255,0.05);
|
| 1828 |
+
display: flex;
|
| 1829 |
+
flex-direction: column;
|
| 1830 |
+
gap: 0.25rem;
|
| 1831 |
+
}
|
| 1832 |
+
|
| 1833 |
+
.metric-box label { font-size: 0.75rem; color: var(--text-secondary); text-transform: uppercase; }
|
| 1834 |
+
.metric-box span { font-size: 1rem; font-weight: 600; color: white; }
|
| 1835 |
+
.metric-box .profit { color: var(--success); }
|
| 1836 |
+
.metric-box .loss { color: var(--danger); }
|
| 1837 |
+
|
| 1838 |
+
.risk-section p { color: var(--danger); background: rgba(239, 68, 68, 0.1); padding: 1rem; border-radius: 0.5rem; border: 1px solid rgba(239, 68, 68, 0.2); }
|
| 1839 |
+
|
| 1840 |
+
@media (max-width: 768px) {
|
| 1841 |
+
.container {
|
| 1842 |
+
padding: 0.5rem;
|
| 1843 |
+
}
|
| 1844 |
+
|
| 1845 |
+
header {
|
| 1846 |
+
flex-direction: column;
|
| 1847 |
+
align-items: stretch;
|
| 1848 |
+
gap: 1.5rem;
|
| 1849 |
+
padding: 1.5rem 1rem;
|
| 1850 |
+
height: auto;
|
| 1851 |
+
}
|
| 1852 |
+
|
| 1853 |
+
.logo {
|
| 1854 |
+
justify-content: center;
|
| 1855 |
+
width: 100%;
|
| 1856 |
+
}
|
| 1857 |
+
|
| 1858 |
+
.controls {
|
| 1859 |
+
flex-direction: column;
|
| 1860 |
+
width: 100%;
|
| 1861 |
+
gap: 0.75rem;
|
| 1862 |
+
}
|
| 1863 |
+
|
| 1864 |
+
.input-group,
|
| 1865 |
+
.select-group,
|
| 1866 |
+
.btn-primary,
|
| 1867 |
+
.btn-danger {
|
| 1868 |
+
width: 100%;
|
| 1869 |
+
min-width: 0;
|
| 1870 |
+
}
|
| 1871 |
+
|
| 1872 |
+
.workflow-breadcrumb {
|
| 1873 |
+
flex-wrap: wrap; /* Allow wrapping if needed, or row */
|
| 1874 |
+
overflow-x: visible; /* No scroll needed now */
|
| 1875 |
+
padding-bottom: 0;
|
| 1876 |
+
width: 100%;
|
| 1877 |
+
justify-content: center; /* Center icons */
|
| 1878 |
+
}
|
| 1879 |
+
|
| 1880 |
+
.item-label {
|
| 1881 |
+
display: none; /* Hide text on mobile as requested */
|
| 1882 |
+
}
|
| 1883 |
+
|
| 1884 |
+
.mobile-hide {
|
| 1885 |
+
display: none;
|
| 1886 |
+
}
|
| 1887 |
+
}
|
| 1888 |
+
</style>
|
src/agora/frontend/src/assets/vue.svg
ADDED
|
|
src/agora/frontend/src/components/HelloWorld.vue
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script setup>
|
| 2 |
+
import { ref } from 'vue'
|
| 3 |
+
|
| 4 |
+
defineProps({
|
| 5 |
+
msg: String,
|
| 6 |
+
})
|
| 7 |
+
|
| 8 |
+
const count = ref(0)
|
| 9 |
+
</script>
|
| 10 |
+
|
| 11 |
+
<template>
|
| 12 |
+
<h1>{{ msg }}</h1>
|
| 13 |
+
|
| 14 |
+
<div class="card">
|
| 15 |
+
<button type="button" @click="count++">count is {{ count }}</button>
|
| 16 |
+
<p>
|
| 17 |
+
Edit
|
| 18 |
+
<code>components/HelloWorld.vue</code> to test HMR
|
| 19 |
+
</p>
|
| 20 |
+
</div>
|
| 21 |
+
|
| 22 |
+
<p>
|
| 23 |
+
Check out
|
| 24 |
+
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
| 25 |
+
>create-vue</a
|
| 26 |
+
>, the official Vue + Vite starter
|
| 27 |
+
</p>
|
| 28 |
+
<p>
|
| 29 |
+
Learn more about IDE Support for Vue in the
|
| 30 |
+
<a
|
| 31 |
+
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
|
| 32 |
+
target="_blank"
|
| 33 |
+
>Vue Docs Scaling up Guide</a
|
| 34 |
+
>.
|
| 35 |
+
</p>
|
| 36 |
+
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
| 37 |
+
</template>
|
| 38 |
+
|
| 39 |
+
<style scoped>
|
| 40 |
+
.read-the-docs {
|
| 41 |
+
color: #888;
|
| 42 |
+
}
|
| 43 |
+
</style>
|
src/agora/frontend/src/main.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { createApp } from 'vue'
|
| 2 |
+
import './style.css'
|
| 3 |
+
import App from './App.vue'
|
| 4 |
+
|
| 5 |
+
createApp(App).mount('#app')
|
src/agora/frontend/src/style.css
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap');
|
| 2 |
+
|
| 3 |
+
:root {
|
| 4 |
+
--font-heading: 'Outfit', sans-serif;
|
| 5 |
+
--font-body: 'Inter', sans-serif;
|
| 6 |
+
|
| 7 |
+
--bg-color: #030712;
|
| 8 |
+
--surface-color: #0f172a;
|
| 9 |
+
--glass-bg: rgba(15, 23, 42, 0.6);
|
| 10 |
+
--glass-border: rgba(255, 255, 255, 0.08);
|
| 11 |
+
|
| 12 |
+
--text-primary: #f8fafc;
|
| 13 |
+
--text-secondary: #94a3b8;
|
| 14 |
+
--text-muted: #64748b;
|
| 15 |
+
|
| 16 |
+
--accent-primary: #3b82f6;
|
| 17 |
+
--accent-secondary: #8b5cf6;
|
| 18 |
+
--accent-gradient: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
|
| 19 |
+
|
| 20 |
+
--success: #10b981;
|
| 21 |
+
--warning: #f59e0b;
|
| 22 |
+
--danger: #ef4444;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
* {
|
| 26 |
+
box-sizing: border-box;
|
| 27 |
+
margin: 0;
|
| 28 |
+
padding: 0;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
body {
|
| 32 |
+
font-family: var(--font-body);
|
| 33 |
+
background-color: var(--bg-color);
|
| 34 |
+
color: var(--text-primary);
|
| 35 |
+
min-height: 100vh;
|
| 36 |
+
line-height: 1.5;
|
| 37 |
+
background-image:
|
| 38 |
+
radial-gradient(circle at 0% 0%, rgba(59, 130, 246, 0.15) 0%, transparent 40%),
|
| 39 |
+
radial-gradient(circle at 100% 100%, rgba(139, 92, 246, 0.15) 0%, transparent 40%);
|
| 40 |
+
background-attachment: fixed;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
#app {
|
| 44 |
+
width: 100%;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
.glass {
|
| 48 |
+
background: var(--glass-bg);
|
| 49 |
+
backdrop-filter: blur(12px);
|
| 50 |
+
-webkit-backdrop-filter: blur(12px);
|
| 51 |
+
border: 1px solid var(--glass-border);
|
| 52 |
+
border-radius: 1.25rem;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
.container {
|
| 56 |
+
max-width: 1400px;
|
| 57 |
+
margin: 0 auto;
|
| 58 |
+
padding: 2rem;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
h1, h2, h3, h4 {
|
| 62 |
+
font-family: var(--font-heading);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
button {
|
| 66 |
+
cursor: pointer;
|
| 67 |
+
font-family: inherit;
|
| 68 |
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.btn {
|
| 72 |
+
display: inline-flex;
|
| 73 |
+
align-items: center;
|
| 74 |
+
justify-content: center;
|
| 75 |
+
gap: 0.5rem;
|
| 76 |
+
padding: 0.75rem 1.5rem;
|
| 77 |
+
border-radius: 0.75rem;
|
| 78 |
+
font-weight: 600;
|
| 79 |
+
border: 1px solid transparent;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
.btn-primary {
|
| 83 |
+
background: var(--accent-gradient);
|
| 84 |
+
color: white;
|
| 85 |
+
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
.btn-primary:hover:not(:disabled) {
|
| 89 |
+
transform: translateY(-2px);
|
| 90 |
+
box-shadow: 0 6px 16px rgba(59, 130, 246, 0.4);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
.btn-primary:active:not(:disabled) {
|
| 94 |
+
transform: translateY(0);
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
.btn-primary:disabled {
|
| 98 |
+
opacity: 0.6;
|
| 99 |
+
cursor: not-allowed;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/* Scrollbar Styling */
|
| 103 |
+
::-webkit-scrollbar {
|
| 104 |
+
width: 8px;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
::-webkit-scrollbar-track {
|
| 108 |
+
background: transparent;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
::-webkit-scrollbar-thumb {
|
| 112 |
+
background: rgba(255, 255, 255, 0.1);
|
| 113 |
+
border-radius: 10px;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
::-webkit-scrollbar-thumb:hover {
|
| 117 |
+
background: rgba(255, 255, 255, 0.2);
|
| 118 |
+
}
|
src/agora/frontend/vite.config.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig } from 'vite'
|
| 2 |
+
import vue from '@vitejs/plugin-vue'
|
| 3 |
+
|
| 4 |
+
// https://vite.dev/config/
|
| 5 |
+
export default defineConfig({
|
| 6 |
+
plugins: [vue()],
|
| 7 |
+
})
|
uv.lock
CHANGED
|
@@ -2,9 +2,6 @@ version = 1
|
|
| 2 |
revision = 3
|
| 3 |
requires-python = "==3.12.*"
|
| 4 |
|
| 5 |
-
[options]
|
| 6 |
-
prerelease-mode = "allow"
|
| 7 |
-
|
| 8 |
[[package]]
|
| 9 |
name = "agenticai"
|
| 10 |
version = "0.1.0"
|
|
@@ -111,7 +108,7 @@ dev = [
|
|
| 111 |
|
| 112 |
[package.metadata]
|
| 113 |
requires-dist = [
|
| 114 |
-
{ name = "aiohttp", specifier = ">=3.
|
| 115 |
{ name = "anthropic", specifier = ">=0.49.0" },
|
| 116 |
{ name = "arxiv", specifier = ">=2.3.1" },
|
| 117 |
{ name = "asyncio" },
|
|
@@ -151,7 +148,7 @@ requires-dist = [
|
|
| 151 |
{ name = "langchain-ollama", specifier = ">=1.0.0" },
|
| 152 |
{ name = "langchain-openai", specifier = ">=1.1.14" },
|
| 153 |
{ name = "langchain-text-splitters", specifier = ">=1.1.2" },
|
| 154 |
-
{ name = "langgraph", specifier = ">=1.0.
|
| 155 |
{ name = "langgraph-checkpoint-sqlite", specifier = ">=3.0.0" },
|
| 156 |
{ name = "langsmith", specifier = ">=0.8.0" },
|
| 157 |
{ name = "llama-index", specifier = ">=0.14.15" },
|
|
@@ -188,25 +185,25 @@ requires-dist = [
|
|
| 188 |
{ name = "python-docx" },
|
| 189 |
{ name = "python-dotenv", specifier = ">=1.2.2" },
|
| 190 |
{ name = "reportlab", specifier = ">=4.4.5" },
|
| 191 |
-
{ name = "requests", specifier = ">=2.
|
| 192 |
{ name = "scikit-learn", specifier = ">=1.7.2" },
|
| 193 |
{ name = "sendgrid" },
|
| 194 |
{ name = "sentence-transformers", specifier = ">=5.1.2" },
|
| 195 |
{ name = "smithery", specifier = ">=0.4.4" },
|
| 196 |
{ name = "speedtest-cli", specifier = ">=2.1.3" },
|
| 197 |
{ name = "sqlalchemy", specifier = ">=2.0.46" },
|
| 198 |
-
{ name = "streamlit", specifier = ">=1.
|
| 199 |
{ name = "textblob", specifier = ">=0.17.1" },
|
| 200 |
{ name = "traceloop-sdk", specifier = ">=0.33.0" },
|
| 201 |
{ name = "wikipedia", specifier = ">=1.4.0" },
|
| 202 |
{ name = "yfinance", specifier = ">=0.2.66" },
|
| 203 |
-
{ name = "yt-dlp", specifier = ">=
|
| 204 |
]
|
| 205 |
|
| 206 |
[package.metadata.requires-dev]
|
| 207 |
dev = [
|
| 208 |
{ name = "ipykernel", specifier = ">=7.1.0" },
|
| 209 |
-
{ name = "pytest", specifier = ">=
|
| 210 |
{ name = "pytest-asyncio" },
|
| 211 |
]
|
| 212 |
|
|
@@ -230,7 +227,7 @@ wheels = [
|
|
| 230 |
|
| 231 |
[[package]]
|
| 232 |
name = "aiohttp"
|
| 233 |
-
version = "3.
|
| 234 |
source = { registry = "https://pypi.org/simple" }
|
| 235 |
dependencies = [
|
| 236 |
{ name = "aiohappyeyeballs" },
|
|
@@ -239,27 +236,29 @@ dependencies = [
|
|
| 239 |
{ name = "frozenlist" },
|
| 240 |
{ name = "multidict" },
|
| 241 |
{ name = "propcache" },
|
|
|
|
| 242 |
{ name = "yarl" },
|
| 243 |
]
|
| 244 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 245 |
-
wheels = [
|
| 246 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 247 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 248 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 249 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 250 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 251 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 252 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 253 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 254 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 255 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 256 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 257 |
-
{ url = "https://files.pythonhosted.org/packages/47/
|
| 258 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 259 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 260 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 261 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 262 |
-
{ url = "https://files.pythonhosted.org/packages/
|
|
|
|
| 263 |
]
|
| 264 |
|
| 265 |
[[package]]
|
|
@@ -370,15 +369,15 @@ wheels = [
|
|
| 370 |
|
| 371 |
[[package]]
|
| 372 |
name = "arxiv"
|
| 373 |
-
version = "
|
| 374 |
source = { registry = "https://pypi.org/simple" }
|
| 375 |
dependencies = [
|
| 376 |
-
{ name = "
|
| 377 |
{ name = "requests" },
|
| 378 |
]
|
| 379 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 380 |
wheels = [
|
| 381 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 382 |
]
|
| 383 |
|
| 384 |
[[package]]
|
|
@@ -829,14 +828,14 @@ wheels = [
|
|
| 829 |
|
| 830 |
[[package]]
|
| 831 |
name = "click"
|
| 832 |
-
version = "8.
|
| 833 |
source = { registry = "https://pypi.org/simple" }
|
| 834 |
dependencies = [
|
| 835 |
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 836 |
]
|
| 837 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 838 |
wheels = [
|
| 839 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 840 |
]
|
| 841 |
|
| 842 |
[[package]]
|
|
@@ -893,41 +892,41 @@ wheels = [
|
|
| 893 |
|
| 894 |
[[package]]
|
| 895 |
name = "cryptography"
|
| 896 |
-
version = "46.0.
|
| 897 |
source = { registry = "https://pypi.org/simple" }
|
| 898 |
dependencies = [
|
| 899 |
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
| 900 |
]
|
| 901 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 902 |
-
wheels = [
|
| 903 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 904 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 905 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 906 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 907 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 908 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 909 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 910 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 911 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 912 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 913 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 914 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 915 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 916 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 917 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 918 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 919 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 920 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 921 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 922 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 923 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 924 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 925 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 926 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 927 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 928 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 929 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 930 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 931 |
]
|
| 932 |
|
| 933 |
[[package]]
|
|
@@ -1192,29 +1191,18 @@ wheels = [
|
|
| 1192 |
|
| 1193 |
[[package]]
|
| 1194 |
name = "fastapi"
|
| 1195 |
-
version = "0.
|
| 1196 |
source = { registry = "https://pypi.org/simple" }
|
| 1197 |
dependencies = [
|
| 1198 |
{ name = "annotated-doc" },
|
| 1199 |
{ name = "pydantic" },
|
| 1200 |
{ name = "starlette" },
|
| 1201 |
{ name = "typing-extensions" },
|
|
|
|
| 1202 |
]
|
| 1203 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 1204 |
-
wheels = [
|
| 1205 |
-
{ url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094, upload-time = "2025-12-27T15:21:12.154Z" },
|
| 1206 |
-
]
|
| 1207 |
-
|
| 1208 |
-
[[package]]
|
| 1209 |
-
name = "feedparser"
|
| 1210 |
-
version = "6.0.12"
|
| 1211 |
-
source = { registry = "https://pypi.org/simple" }
|
| 1212 |
-
dependencies = [
|
| 1213 |
-
{ name = "sgmllib3k" },
|
| 1214 |
-
]
|
| 1215 |
-
sdist = { url = "https://files.pythonhosted.org/packages/dc/79/db7edb5e77d6dfbc54d7d9df72828be4318275b2e580549ff45a962f6461/feedparser-6.0.12.tar.gz", hash = "sha256:64f76ce90ae3e8ef5d1ede0f8d3b50ce26bcce71dd8ae5e82b1cd2d4a5f94228", size = 286579, upload-time = "2025-09-10T13:33:59.486Z" }
|
| 1216 |
wheels = [
|
| 1217 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1218 |
]
|
| 1219 |
|
| 1220 |
[[package]]
|
|
@@ -1597,17 +1585,18 @@ wheels = [
|
|
| 1597 |
|
| 1598 |
[[package]]
|
| 1599 |
name = "hf-xet"
|
| 1600 |
-
version = "1.
|
| 1601 |
source = { registry = "https://pypi.org/simple" }
|
| 1602 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 1603 |
wheels = [
|
| 1604 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1605 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1606 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1607 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1608 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1609 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1610 |
-
{ url = "https://files.pythonhosted.org/packages/
|
|
|
|
| 1611 |
]
|
| 1612 |
|
| 1613 |
[[package]]
|
|
@@ -1719,21 +1708,23 @@ wheels = [
|
|
| 1719 |
|
| 1720 |
[[package]]
|
| 1721 |
name = "huggingface-hub"
|
| 1722 |
-
version = "
|
| 1723 |
source = { registry = "https://pypi.org/simple" }
|
| 1724 |
dependencies = [
|
|
|
|
| 1725 |
{ name = "filelock" },
|
| 1726 |
{ name = "fsspec" },
|
| 1727 |
-
{ name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
|
|
|
|
| 1728 |
{ name = "packaging" },
|
| 1729 |
{ name = "pyyaml" },
|
| 1730 |
-
{ name = "requests" },
|
| 1731 |
{ name = "tqdm" },
|
|
|
|
| 1732 |
{ name = "typing-extensions" },
|
| 1733 |
]
|
| 1734 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 1735 |
wheels = [
|
| 1736 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1737 |
]
|
| 1738 |
|
| 1739 |
[[package]]
|
|
@@ -1759,11 +1750,11 @@ wheels = [
|
|
| 1759 |
|
| 1760 |
[[package]]
|
| 1761 |
name = "idna"
|
| 1762 |
-
version = "3.
|
| 1763 |
source = { registry = "https://pypi.org/simple" }
|
| 1764 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 1765 |
wheels = [
|
| 1766 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1767 |
]
|
| 1768 |
|
| 1769 |
[[package]]
|
|
@@ -2188,16 +2179,16 @@ wheels = [
|
|
| 2188 |
|
| 2189 |
[[package]]
|
| 2190 |
name = "langchain-huggingface"
|
| 2191 |
-
version = "1.2.
|
| 2192 |
source = { registry = "https://pypi.org/simple" }
|
| 2193 |
dependencies = [
|
| 2194 |
{ name = "huggingface-hub" },
|
| 2195 |
{ name = "langchain-core" },
|
| 2196 |
{ name = "tokenizers" },
|
| 2197 |
]
|
| 2198 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 2199 |
wheels = [
|
| 2200 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 2201 |
]
|
| 2202 |
|
| 2203 |
[[package]]
|
|
@@ -2241,7 +2232,7 @@ wheels = [
|
|
| 2241 |
|
| 2242 |
[[package]]
|
| 2243 |
name = "langgraph"
|
| 2244 |
-
version = "1.0.
|
| 2245 |
source = { registry = "https://pypi.org/simple" }
|
| 2246 |
dependencies = [
|
| 2247 |
{ name = "langchain-core" },
|
|
@@ -2251,9 +2242,9 @@ dependencies = [
|
|
| 2251 |
{ name = "pydantic" },
|
| 2252 |
{ name = "xxhash" },
|
| 2253 |
]
|
| 2254 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 2255 |
wheels = [
|
| 2256 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 2257 |
]
|
| 2258 |
|
| 2259 |
[[package]]
|
|
@@ -2285,15 +2276,15 @@ wheels = [
|
|
| 2285 |
|
| 2286 |
[[package]]
|
| 2287 |
name = "langgraph-prebuilt"
|
| 2288 |
-
version = "1.0.
|
| 2289 |
source = { registry = "https://pypi.org/simple" }
|
| 2290 |
dependencies = [
|
| 2291 |
{ name = "langchain-core" },
|
| 2292 |
{ name = "langgraph-checkpoint" },
|
| 2293 |
]
|
| 2294 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 2295 |
wheels = [
|
| 2296 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 2297 |
]
|
| 2298 |
|
| 2299 |
[[package]]
|
|
@@ -4349,11 +4340,11 @@ wheels = [
|
|
| 4349 |
|
| 4350 |
[[package]]
|
| 4351 |
name = "pyasn1"
|
| 4352 |
-
version = "0.6.
|
| 4353 |
source = { registry = "https://pypi.org/simple" }
|
| 4354 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 4355 |
wheels = [
|
| 4356 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 4357 |
]
|
| 4358 |
|
| 4359 |
[[package]]
|
|
@@ -4519,20 +4510,20 @@ wheels = [
|
|
| 4519 |
|
| 4520 |
[[package]]
|
| 4521 |
name = "pygments"
|
| 4522 |
-
version = "2.
|
| 4523 |
source = { registry = "https://pypi.org/simple" }
|
| 4524 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 4525 |
wheels = [
|
| 4526 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 4527 |
]
|
| 4528 |
|
| 4529 |
[[package]]
|
| 4530 |
name = "pyjwt"
|
| 4531 |
-
version = "2.
|
| 4532 |
source = { registry = "https://pypi.org/simple" }
|
| 4533 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 4534 |
wheels = [
|
| 4535 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 4536 |
]
|
| 4537 |
|
| 4538 |
[package.optional-dependencies]
|
|
@@ -4634,7 +4625,7 @@ wheels = [
|
|
| 4634 |
|
| 4635 |
[[package]]
|
| 4636 |
name = "pytest"
|
| 4637 |
-
version = "9.0.
|
| 4638 |
source = { registry = "https://pypi.org/simple" }
|
| 4639 |
dependencies = [
|
| 4640 |
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
@@ -4643,9 +4634,9 @@ dependencies = [
|
|
| 4643 |
{ name = "pluggy" },
|
| 4644 |
{ name = "pygments" },
|
| 4645 |
]
|
| 4646 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 4647 |
wheels = [
|
| 4648 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 4649 |
]
|
| 4650 |
|
| 4651 |
[[package]]
|
|
@@ -4839,7 +4830,7 @@ wheels = [
|
|
| 4839 |
|
| 4840 |
[[package]]
|
| 4841 |
name = "requests"
|
| 4842 |
-
version = "2.
|
| 4843 |
source = { registry = "https://pypi.org/simple" }
|
| 4844 |
dependencies = [
|
| 4845 |
{ name = "certifi" },
|
|
@@ -4847,9 +4838,9 @@ dependencies = [
|
|
| 4847 |
{ name = "idna" },
|
| 4848 |
{ name = "urllib3" },
|
| 4849 |
]
|
| 4850 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 4851 |
wheels = [
|
| 4852 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 4853 |
]
|
| 4854 |
|
| 4855 |
[[package]]
|
|
@@ -5030,12 +5021,6 @@ wheels = [
|
|
| 5030 |
{ url = "https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl", hash = "sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173", size = 1064234, upload-time = "2026-01-25T22:38:15.216Z" },
|
| 5031 |
]
|
| 5032 |
|
| 5033 |
-
[[package]]
|
| 5034 |
-
name = "sgmllib3k"
|
| 5035 |
-
version = "1.0.0"
|
| 5036 |
-
source = { registry = "https://pypi.org/simple" }
|
| 5037 |
-
sdist = { url = "https://files.pythonhosted.org/packages/9e/bd/3704a8c3e0942d711c1299ebf7b9091930adae6675d7c8f476a7ce48653c/sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9", size = 5750, upload-time = "2010-08-24T14:33:52.445Z" }
|
| 5038 |
-
|
| 5039 |
[[package]]
|
| 5040 |
name = "shellingham"
|
| 5041 |
version = "1.5.4"
|
|
@@ -5182,20 +5167,20 @@ wheels = [
|
|
| 5182 |
|
| 5183 |
[[package]]
|
| 5184 |
name = "starlette"
|
| 5185 |
-
version = "
|
| 5186 |
source = { registry = "https://pypi.org/simple" }
|
| 5187 |
dependencies = [
|
| 5188 |
{ name = "anyio" },
|
| 5189 |
{ name = "typing-extensions" },
|
| 5190 |
]
|
| 5191 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 5192 |
wheels = [
|
| 5193 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5194 |
]
|
| 5195 |
|
| 5196 |
[[package]]
|
| 5197 |
name = "streamlit"
|
| 5198 |
-
version = "1.
|
| 5199 |
source = { registry = "https://pypi.org/simple" }
|
| 5200 |
dependencies = [
|
| 5201 |
{ name = "altair" },
|
|
@@ -5217,9 +5202,9 @@ dependencies = [
|
|
| 5217 |
{ name = "typing-extensions" },
|
| 5218 |
{ name = "watchdog", marker = "sys_platform != 'darwin'" },
|
| 5219 |
]
|
| 5220 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 5221 |
wheels = [
|
| 5222 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5223 |
]
|
| 5224 |
|
| 5225 |
[[package]]
|
|
@@ -5395,21 +5380,19 @@ wheels = [
|
|
| 5395 |
|
| 5396 |
[[package]]
|
| 5397 |
name = "tornado"
|
| 5398 |
-
version = "6.5.
|
| 5399 |
source = { registry = "https://pypi.org/simple" }
|
| 5400 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 5401 |
wheels = [
|
| 5402 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5403 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5404 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5405 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5406 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5407 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5408 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5409 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5410 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5411 |
-
{ url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" },
|
| 5412 |
-
{ url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" },
|
| 5413 |
]
|
| 5414 |
|
| 5415 |
[[package]]
|
|
@@ -5494,7 +5477,7 @@ wheels = [
|
|
| 5494 |
|
| 5495 |
[[package]]
|
| 5496 |
name = "transformers"
|
| 5497 |
-
version = "
|
| 5498 |
source = { registry = "https://pypi.org/simple" }
|
| 5499 |
dependencies = [
|
| 5500 |
{ name = "filelock" },
|
|
@@ -5507,10 +5490,11 @@ dependencies = [
|
|
| 5507 |
{ name = "safetensors" },
|
| 5508 |
{ name = "tokenizers" },
|
| 5509 |
{ name = "tqdm" },
|
|
|
|
| 5510 |
]
|
| 5511 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 5512 |
wheels = [
|
| 5513 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5514 |
]
|
| 5515 |
|
| 5516 |
[[package]]
|
|
@@ -5523,17 +5507,29 @@ wheels = [
|
|
| 5523 |
|
| 5524 |
[[package]]
|
| 5525 |
name = "typer"
|
| 5526 |
-
version = "0.
|
| 5527 |
source = { registry = "https://pypi.org/simple" }
|
| 5528 |
dependencies = [
|
|
|
|
| 5529 |
{ name = "click" },
|
| 5530 |
{ name = "rich" },
|
| 5531 |
{ name = "shellingham" },
|
| 5532 |
-
{ name = "typing-extensions" },
|
| 5533 |
]
|
| 5534 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 5535 |
wheels = [
|
| 5536 |
-
{ url = "https://files.pythonhosted.org/packages/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5537 |
]
|
| 5538 |
|
| 5539 |
[[package]]
|
|
@@ -5760,14 +5756,14 @@ wheels = [
|
|
| 5760 |
|
| 5761 |
[[package]]
|
| 5762 |
name = "werkzeug"
|
| 5763 |
-
version = "3.1.
|
| 5764 |
source = { registry = "https://pypi.org/simple" }
|
| 5765 |
dependencies = [
|
| 5766 |
{ name = "markupsafe" },
|
| 5767 |
]
|
| 5768 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 5769 |
wheels = [
|
| 5770 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5771 |
]
|
| 5772 |
|
| 5773 |
[[package]]
|
|
@@ -5877,11 +5873,11 @@ wheels = [
|
|
| 5877 |
|
| 5878 |
[[package]]
|
| 5879 |
name = "yt-dlp"
|
| 5880 |
-
version = "2026.
|
| 5881 |
source = { registry = "https://pypi.org/simple" }
|
| 5882 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 5883 |
wheels = [
|
| 5884 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 5885 |
]
|
| 5886 |
|
| 5887 |
[[package]]
|
|
|
|
| 2 |
revision = 3
|
| 3 |
requires-python = "==3.12.*"
|
| 4 |
|
|
|
|
|
|
|
|
|
|
| 5 |
[[package]]
|
| 6 |
name = "agenticai"
|
| 7 |
version = "0.1.0"
|
|
|
|
| 108 |
|
| 109 |
[package.metadata]
|
| 110 |
requires-dist = [
|
| 111 |
+
{ name = "aiohttp", specifier = ">=3.14.0" },
|
| 112 |
{ name = "anthropic", specifier = ">=0.49.0" },
|
| 113 |
{ name = "arxiv", specifier = ">=2.3.1" },
|
| 114 |
{ name = "asyncio" },
|
|
|
|
| 148 |
{ name = "langchain-ollama", specifier = ">=1.0.0" },
|
| 149 |
{ name = "langchain-openai", specifier = ">=1.1.14" },
|
| 150 |
{ name = "langchain-text-splitters", specifier = ">=1.1.2" },
|
| 151 |
+
{ name = "langgraph", specifier = ">=1.0.10rc1" },
|
| 152 |
{ name = "langgraph-checkpoint-sqlite", specifier = ">=3.0.0" },
|
| 153 |
{ name = "langsmith", specifier = ">=0.8.0" },
|
| 154 |
{ name = "llama-index", specifier = ">=0.14.15" },
|
|
|
|
| 185 |
{ name = "python-docx" },
|
| 186 |
{ name = "python-dotenv", specifier = ">=1.2.2" },
|
| 187 |
{ name = "reportlab", specifier = ">=4.4.5" },
|
| 188 |
+
{ name = "requests", specifier = ">=2.33.0" },
|
| 189 |
{ name = "scikit-learn", specifier = ">=1.7.2" },
|
| 190 |
{ name = "sendgrid" },
|
| 191 |
{ name = "sentence-transformers", specifier = ">=5.1.2" },
|
| 192 |
{ name = "smithery", specifier = ">=0.4.4" },
|
| 193 |
{ name = "speedtest-cli", specifier = ">=2.1.3" },
|
| 194 |
{ name = "sqlalchemy", specifier = ">=2.0.46" },
|
| 195 |
+
{ name = "streamlit", specifier = ">=1.54.0" },
|
| 196 |
{ name = "textblob", specifier = ">=0.17.1" },
|
| 197 |
{ name = "traceloop-sdk", specifier = ">=0.33.0" },
|
| 198 |
{ name = "wikipedia", specifier = ">=1.4.0" },
|
| 199 |
{ name = "yfinance", specifier = ">=0.2.66" },
|
| 200 |
+
{ name = "yt-dlp", specifier = ">=2026.2.21" },
|
| 201 |
]
|
| 202 |
|
| 203 |
[package.metadata.requires-dev]
|
| 204 |
dev = [
|
| 205 |
{ name = "ipykernel", specifier = ">=7.1.0" },
|
| 206 |
+
{ name = "pytest", specifier = ">=9.0.3" },
|
| 207 |
{ name = "pytest-asyncio" },
|
| 208 |
]
|
| 209 |
|
|
|
|
| 227 |
|
| 228 |
[[package]]
|
| 229 |
name = "aiohttp"
|
| 230 |
+
version = "3.14.0"
|
| 231 |
source = { registry = "https://pypi.org/simple" }
|
| 232 |
dependencies = [
|
| 233 |
{ name = "aiohappyeyeballs" },
|
|
|
|
| 236 |
{ name = "frozenlist" },
|
| 237 |
{ name = "multidict" },
|
| 238 |
{ name = "propcache" },
|
| 239 |
+
{ name = "typing-extensions" },
|
| 240 |
{ name = "yarl" },
|
| 241 |
]
|
| 242 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ee/ab/93ce242f899b68c51b0578c027aafa791ab3614cb9345fa5d37b5f5c8e3e/aiohttp-3.14.0.tar.gz", hash = "sha256:2882de819734c715fd1b9c11c97e09fa020d14438203d1d354d8ed1702791c9b", size = 7940674, upload-time = "2026-06-01T19:41:02.763Z" }
|
| 243 |
+
wheels = [
|
| 244 |
+
{ url = "https://files.pythonhosted.org/packages/89/97/2b6889bfb6b6847520d50d95eb8c4307a45e28aaca39faf4a9454b3d1b2f/aiohttp-3.14.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b29518c9c2ec7e373e68259206a137c7f4f5439c58baaec4b5ab3ab799850a4e", size = 750194, upload-time = "2026-06-01T19:37:48.164Z" },
|
| 245 |
+
{ url = "https://files.pythonhosted.org/packages/21/e2/62634b7fff918ed98c3c6b2f0e70d520f7f28846cb412d451b04354c6459/aiohttp-3.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dbec68ce61b64cb73cab4d33df9433427b1713c8bcccb181dce695c1b6f8e87c", size = 506966, upload-time = "2026-06-01T19:37:50.014Z" },
|
| 246 |
+
{ url = "https://files.pythonhosted.org/packages/dd/fb/5ce075150828c797a5106f1c2fb26034e709d4289b9d2bf8b07f1e59fac6/aiohttp-3.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3cdf534aa455593e589302990c5097aa5c92c06c4262a20da22934f9186a5fff", size = 507527, upload-time = "2026-06-01T19:37:51.96Z" },
|
| 247 |
+
{ url = "https://files.pythonhosted.org/packages/01/d5/405a0ae4e6b081754a3609c1c97c63a950e000a2def16046f1e736933a0e/aiohttp-3.14.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb6c657104393b5fbff01a5f59b2023db74058a8077d94475d6c25d03882a108", size = 1762420, upload-time = "2026-06-01T19:37:53.839Z" },
|
| 248 |
+
{ url = "https://files.pythonhosted.org/packages/ae/1d/e05a7c896b15a6bc6fb8fc5319eb437861c2c49c34559ef928add6590315/aiohttp-3.14.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:46fbbec4e4fab7428d4396a3823f9320e4560aa3113b89eeebce712c27c9ed5a", size = 1733672, upload-time = "2026-06-01T19:37:55.791Z" },
|
| 249 |
+
{ url = "https://files.pythonhosted.org/packages/cc/22/a72f7c459e195fa41bf4f7abd1f925b91fe91f8097e51c654229ba144a33/aiohttp-3.14.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2c2c7e05dd5335b298085abf45ddf98673934c3ee1c083d0b9ea13d4186ad500", size = 1805064, upload-time = "2026-06-01T19:37:57.931Z" },
|
| 250 |
+
{ url = "https://files.pythonhosted.org/packages/80/50/e85bdaba0be59ca4838005ebfef4048fcdd5f35a02b07057a9a123394440/aiohttp-3.14.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3c7139100fbaae76515b73051d8f0aa3a3ff02e415eec8a8eee8e2223d9ba955", size = 1902125, upload-time = "2026-06-01T19:38:00.225Z" },
|
| 251 |
+
{ url = "https://files.pythonhosted.org/packages/19/d8/51de5c6b971c27bb1ef620293b8d1ca611ec78736b34b3f6ccf68e4c8785/aiohttp-3.14.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78d6f9286a629ce52728430afe18f8ed2b6c39a1fddb3802d7244b9983910ad2", size = 1783112, upload-time = "2026-06-01T19:38:02.641Z" },
|
| 252 |
+
{ url = "https://files.pythonhosted.org/packages/73/ae/b4402bfde77e43dfb1b6ccff83c7b7ab63ed06b50c4754f0c5423fb374fe/aiohttp-3.14.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc3c3e12cdaeb92d7dcf13db00e9f6b1956b910e47256e696df1cfa946d02159", size = 1586356, upload-time = "2026-06-01T19:38:04.637Z" },
|
| 253 |
+
{ url = "https://files.pythonhosted.org/packages/bc/05/750a3265ca4dc54a460bd0cb1121a8f2ce9171fce4a135fb47ea7fd594d2/aiohttp-3.14.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4d6a998191f5ebe3b8c28463ff72bc030250008b3193c402464efadd08b5ca02", size = 1723119, upload-time = "2026-06-01T19:38:06.713Z" },
|
| 254 |
+
{ url = "https://files.pythonhosted.org/packages/37/01/8c0812c50b3b1b1c37b323bf170d6be8847a8f234060485b7d1e71953f60/aiohttp-3.14.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0fc2b75ae8d169d853be2862d960be8550da6c5c65711d5476407eb3fdb006bd", size = 1757216, upload-time = "2026-06-01T19:38:08.736Z" },
|
| 255 |
+
{ url = "https://files.pythonhosted.org/packages/47/2a/50fb98028a26887cbe48dcc1df92a90825615bc73b5584301304090cded8/aiohttp-3.14.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:16eee56bcc72d04600bc56c1759982c2385ec0b41d3fd3521f836bf64a0957ef", size = 1770500, upload-time = "2026-06-01T19:38:11.111Z" },
|
| 256 |
+
{ url = "https://files.pythonhosted.org/packages/bd/32/0ffd598a2fa2b9a423daf242e700cfdabda35d6e602394ad9ae58972c1c7/aiohttp-3.14.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5a2e7ca615c3ddc15b82687e05a624e5f5cba3f1d6c20cb81172d70ea498451e", size = 1576224, upload-time = "2026-06-01T19:38:13.391Z" },
|
| 257 |
+
{ url = "https://files.pythonhosted.org/packages/0b/f9/b9fc381dd9b66afb33f2634c40e229d106467be0afcabe79648631ab6712/aiohttp-3.14.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f0b7b8bbbec3ce9467ee0ebe334622fd90624f593edd3136c567811453fc4fae", size = 1794252, upload-time = "2026-06-01T19:38:15.498Z" },
|
| 258 |
+
{ url = "https://files.pythonhosted.org/packages/a8/fb/05d9214c975f23225a8cd5c439325e338c7c377b315480ef3871db51f54e/aiohttp-3.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ba10966d4f03dd96a14365be4b8e37c327c76f11c3ca867116966cdd9f98066", size = 1760193, upload-time = "2026-06-01T19:38:17.624Z" },
|
| 259 |
+
{ url = "https://files.pythonhosted.org/packages/d9/4b/02992fc4fb9e1b6673ee3f888a8e587a6447afda1f6f4aca776c148c2876/aiohttp-3.14.0-cp312-cp312-win32.whl", hash = "sha256:101df7779c80c0636014a6b2c6642acd3efb5b355d48347c9d7dfb720aee9430", size = 448650, upload-time = "2026-06-01T19:38:19.545Z" },
|
| 260 |
+
{ url = "https://files.pythonhosted.org/packages/39/e9/246532214c3abda518477cbaaf16d420295ad8effa5233844cbb38f299ab/aiohttp-3.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:b0a5747586d4467efd1f932710b269131c9717a872dce082cd92a00c1c13123a", size = 476145, upload-time = "2026-06-01T19:38:21.505Z" },
|
| 261 |
+
{ url = "https://files.pythonhosted.org/packages/2b/c3/63f8c20090048915711598b0adf475b149216d736157961de06480a45b15/aiohttp-3.14.0-cp312-cp312-win_arm64.whl", hash = "sha256:5f1c5be60add78fabb4aacd13c5a348ae79d2fcbfc7fa78da8f1eb192273b370", size = 444250, upload-time = "2026-06-01T19:38:24.027Z" },
|
| 262 |
]
|
| 263 |
|
| 264 |
[[package]]
|
|
|
|
| 369 |
|
| 370 |
[[package]]
|
| 371 |
name = "arxiv"
|
| 372 |
+
version = "4.0.0"
|
| 373 |
source = { registry = "https://pypi.org/simple" }
|
| 374 |
dependencies = [
|
| 375 |
+
{ name = "lxml" },
|
| 376 |
{ name = "requests" },
|
| 377 |
]
|
| 378 |
+
sdist = { url = "https://files.pythonhosted.org/packages/fb/48/88c8e9c42712760ca9e74e52f6c4a388ee9e9939e341bfd8da295a9d1b17/arxiv-4.0.0.tar.gz", hash = "sha256:1d30a1dba5054e0df9b1d63f8e190b58e6a59d0c2f4ccec344ce1de5bafe546d", size = 198009, upload-time = "2026-05-17T23:42:30.952Z" }
|
| 379 |
wheels = [
|
| 380 |
+
{ url = "https://files.pythonhosted.org/packages/af/50/4d01d219958b19b5aaca6ae74820b181baea438cd034d5b3c04b4cf4f75e/arxiv-4.0.0-py3-none-any.whl", hash = "sha256:fc7e65e74d0fba21df2c521df24119d015fcb839dd5c4feb683ee35548c932c4", size = 13014, upload-time = "2026-05-17T23:42:29.246Z" },
|
| 381 |
]
|
| 382 |
|
| 383 |
[[package]]
|
|
|
|
| 828 |
|
| 829 |
[[package]]
|
| 830 |
name = "click"
|
| 831 |
+
version = "8.4.1"
|
| 832 |
source = { registry = "https://pypi.org/simple" }
|
| 833 |
dependencies = [
|
| 834 |
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 835 |
]
|
| 836 |
+
sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" }
|
| 837 |
wheels = [
|
| 838 |
+
{ url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" },
|
| 839 |
]
|
| 840 |
|
| 841 |
[[package]]
|
|
|
|
| 892 |
|
| 893 |
[[package]]
|
| 894 |
name = "cryptography"
|
| 895 |
+
version = "46.0.7"
|
| 896 |
source = { registry = "https://pypi.org/simple" }
|
| 897 |
dependencies = [
|
| 898 |
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
| 899 |
]
|
| 900 |
+
sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" }
|
| 901 |
+
wheels = [
|
| 902 |
+
{ url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" },
|
| 903 |
+
{ url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" },
|
| 904 |
+
{ url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" },
|
| 905 |
+
{ url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" },
|
| 906 |
+
{ url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" },
|
| 907 |
+
{ url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" },
|
| 908 |
+
{ url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" },
|
| 909 |
+
{ url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" },
|
| 910 |
+
{ url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" },
|
| 911 |
+
{ url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" },
|
| 912 |
+
{ url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" },
|
| 913 |
+
{ url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" },
|
| 914 |
+
{ url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" },
|
| 915 |
+
{ url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" },
|
| 916 |
+
{ url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" },
|
| 917 |
+
{ url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" },
|
| 918 |
+
{ url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" },
|
| 919 |
+
{ url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" },
|
| 920 |
+
{ url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" },
|
| 921 |
+
{ url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" },
|
| 922 |
+
{ url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" },
|
| 923 |
+
{ url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" },
|
| 924 |
+
{ url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" },
|
| 925 |
+
{ url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" },
|
| 926 |
+
{ url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" },
|
| 927 |
+
{ url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" },
|
| 928 |
+
{ url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" },
|
| 929 |
+
{ url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" },
|
| 930 |
]
|
| 931 |
|
| 932 |
[[package]]
|
|
|
|
| 1191 |
|
| 1192 |
[[package]]
|
| 1193 |
name = "fastapi"
|
| 1194 |
+
version = "0.136.3"
|
| 1195 |
source = { registry = "https://pypi.org/simple" }
|
| 1196 |
dependencies = [
|
| 1197 |
{ name = "annotated-doc" },
|
| 1198 |
{ name = "pydantic" },
|
| 1199 |
{ name = "starlette" },
|
| 1200 |
{ name = "typing-extensions" },
|
| 1201 |
+
{ name = "typing-inspection" },
|
| 1202 |
]
|
| 1203 |
+
sdist = { url = "https://files.pythonhosted.org/packages/81/2d/ff8d91d7b564d464629a0fd50a4489c97fcb836ac230bf3a7269232a9b1f/fastapi-0.136.3.tar.gz", hash = "sha256:e487fae93ad408e6f47641ee4dfe389864fd7bec92e547ea8498fc13f43e83ab", size = 396410, upload-time = "2026-05-23T18:53:15.192Z" }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1204 |
wheels = [
|
| 1205 |
+
{ url = "https://files.pythonhosted.org/packages/e0/82/45359b62a067409bd929ae8a56b8ed13e5a8c8a61194b3c236920999ab83/fastapi-0.136.3-py3-none-any.whl", hash = "sha256:3d2a69bdf04b7e9f3afa292c3bc7a98816bbfafa10bc9b45f3f3700d2f761620", size = 117481, upload-time = "2026-05-23T18:53:16.924Z" },
|
| 1206 |
]
|
| 1207 |
|
| 1208 |
[[package]]
|
|
|
|
| 1585 |
|
| 1586 |
[[package]]
|
| 1587 |
name = "hf-xet"
|
| 1588 |
+
version = "1.5.0"
|
| 1589 |
source = { registry = "https://pypi.org/simple" }
|
| 1590 |
+
sdist = { url = "https://files.pythonhosted.org/packages/74/d8/5c06fc76461418326a7decf8367480c35be11a41fd938633929c60a9ec6b/hf_xet-1.5.0.tar.gz", hash = "sha256:e0fb0a34d9f406eed88233e829a67ec016bec5af19e480eac65a233ea289a948", size = 837196, upload-time = "2026-05-06T06:18:15.583Z" }
|
| 1591 |
wheels = [
|
| 1592 |
+
{ url = "https://files.pythonhosted.org/packages/3d/fb/69ff198a82cae7eb1a69fb84d93b3a3e4816564d76817fe541ddc96874eb/hf_xet-1.5.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dad0dc84e941b8ba3c860659fe1fdc35c049d47cce293f003287757e971a8f56", size = 4030814, upload-time = "2026-05-06T06:17:57.933Z" },
|
| 1593 |
+
{ url = "https://files.pythonhosted.org/packages/9b/ff/edcc2b40162bef3ff78e14ab637e5f3b89243d6aee72f5949d3bb6a5af83/hf_xet-1.5.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:fd6e5a9b0fdac4ed03ed45ef79254a655b1aaab514a02202617fbf643f5fdf7a", size = 3798444, upload-time = "2026-05-06T06:17:55.79Z" },
|
| 1594 |
+
{ url = "https://files.pythonhosted.org/packages/49/4d/103f76b04310e5e57656696cc184690d20c466af0bca3ca88f8c8ea5d4f3/hf_xet-1.5.0-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3531b1823a0e6d77d80f9ed15ca0e00f0d115094f8ac033d5cae88f4564cc949", size = 4465986, upload-time = "2026-05-06T06:17:44.886Z" },
|
| 1595 |
+
{ url = "https://files.pythonhosted.org/packages/c4/a2/546f47f464737b3edbab6f8ddb57f2599b93d2cbb66f06abb475ccb48651/hf_xet-1.5.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9a0ee58cd18d5ea799f7ed11290bbccbe56bdd8b1d97ca74b9cc49a3945d7a3b", size = 4259865, upload-time = "2026-05-06T06:17:42.639Z" },
|
| 1596 |
+
{ url = "https://files.pythonhosted.org/packages/95/7f/1be593c1f28613be2e196473481cd81bfc5910795e30a34e8f744f6cac4f/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e60df5a42e9bed8628b6416af2cba4cba57ae9f02de226a06b020d98e1aab18", size = 4459835, upload-time = "2026-05-06T06:18:08.026Z" },
|
| 1597 |
+
{ url = "https://files.pythonhosted.org/packages/aa/b2/703569fc881f3284487e68cda7b42179978480da3c438042a6bbbb4a671c/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4b35549ce62601b84da4ff9b24d970032ace3d4430f52d91bcbb26c901d6c690", size = 4672414, upload-time = "2026-05-06T06:18:09.864Z" },
|
| 1598 |
+
{ url = "https://files.pythonhosted.org/packages/af/37/1b6def445c567286b50aa3b33828158e135b1be44938dde59f11382a500c/hf_xet-1.5.0-cp37-abi3-win_amd64.whl", hash = "sha256:2806c7c17b4d23f8d88f7c4814f838c3b6150773fe339c20af23e1cfaf2797e4", size = 3977238, upload-time = "2026-05-06T06:18:23.621Z" },
|
| 1599 |
+
{ url = "https://files.pythonhosted.org/packages/62/94/3b66b148778ee100dcfd69c2ca22b57b41b44d3063ceec934f209e9184ce/hf_xet-1.5.0-cp37-abi3-win_arm64.whl", hash = "sha256:b6c9df403040248c76d808d3e047d64db2d923bae593eb244c41e425cf6cd7be", size = 3806916, upload-time = "2026-05-06T06:18:21.7Z" },
|
| 1600 |
]
|
| 1601 |
|
| 1602 |
[[package]]
|
|
|
|
| 1708 |
|
| 1709 |
[[package]]
|
| 1710 |
name = "huggingface-hub"
|
| 1711 |
+
version = "1.18.0"
|
| 1712 |
source = { registry = "https://pypi.org/simple" }
|
| 1713 |
dependencies = [
|
| 1714 |
+
{ name = "click" },
|
| 1715 |
{ name = "filelock" },
|
| 1716 |
{ name = "fsspec" },
|
| 1717 |
+
{ name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
|
| 1718 |
+
{ name = "httpx" },
|
| 1719 |
{ name = "packaging" },
|
| 1720 |
{ name = "pyyaml" },
|
|
|
|
| 1721 |
{ name = "tqdm" },
|
| 1722 |
+
{ name = "typer" },
|
| 1723 |
{ name = "typing-extensions" },
|
| 1724 |
]
|
| 1725 |
+
sdist = { url = "https://files.pythonhosted.org/packages/fb/d8/748ea0a47f0fa15227fe682f7a80826b4b7c096e4818044b8f56d6cb66d6/huggingface_hub-1.18.0.tar.gz", hash = "sha256:f0c5ecd1ef8c6a60f86f61ee278f2c1570ba9e279c9f54de9094210723b3613b", size = 812699, upload-time = "2026-06-05T09:26:33.401Z" }
|
| 1726 |
wheels = [
|
| 1727 |
+
{ url = "https://files.pythonhosted.org/packages/0b/03/40a05316cb6616e5b7efd7773656441ab04b4b022c2199e79bb4622a92a3/huggingface_hub-1.18.0-py3-none-any.whl", hash = "sha256:729be4a976fb706dcc02d176bcda8a3f32bdf21a294e8f4b3dda6fbcbc9c1ab1", size = 684411, upload-time = "2026-06-05T09:26:31.48Z" },
|
| 1728 |
]
|
| 1729 |
|
| 1730 |
[[package]]
|
|
|
|
| 1750 |
|
| 1751 |
[[package]]
|
| 1752 |
name = "idna"
|
| 1753 |
+
version = "3.15"
|
| 1754 |
source = { registry = "https://pypi.org/simple" }
|
| 1755 |
+
sdist = { url = "https://files.pythonhosted.org/packages/82/77/7b3966d0b9d1d31a36ddf1746926a11dface89a83409bf1483f0237aa758/idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc", size = 199245, upload-time = "2026-05-12T22:45:57.011Z" }
|
| 1756 |
wheels = [
|
| 1757 |
+
{ url = "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8", size = 72340, upload-time = "2026-05-12T22:45:55.733Z" },
|
| 1758 |
]
|
| 1759 |
|
| 1760 |
[[package]]
|
|
|
|
| 2179 |
|
| 2180 |
[[package]]
|
| 2181 |
name = "langchain-huggingface"
|
| 2182 |
+
version = "1.2.2"
|
| 2183 |
source = { registry = "https://pypi.org/simple" }
|
| 2184 |
dependencies = [
|
| 2185 |
{ name = "huggingface-hub" },
|
| 2186 |
{ name = "langchain-core" },
|
| 2187 |
{ name = "tokenizers" },
|
| 2188 |
]
|
| 2189 |
+
sdist = { url = "https://files.pythonhosted.org/packages/2c/e8/4068ad02179253f55958e59e442e5b6e8cb95ffc5e805cc4db0b1ef61d4e/langchain_huggingface-1.2.2.tar.gz", hash = "sha256:1dd91ec415190d2704e93ec149618e3145075863ba37e74afc9080d685dc2743", size = 255513, upload-time = "2026-04-16T19:57:41.046Z" }
|
| 2190 |
wheels = [
|
| 2191 |
+
{ url = "https://files.pythonhosted.org/packages/0a/ed/648b87f9b67153ade616f360bf4145b76ed428b4adb89525938f611e9828/langchain_huggingface-1.2.2-py3-none-any.whl", hash = "sha256:f94944b0c0d5afc687568d426c87ed5236907464c41e72108ed76eee1a690f6d", size = 31926, upload-time = "2026-04-16T19:57:40.079Z" },
|
| 2192 |
]
|
| 2193 |
|
| 2194 |
[[package]]
|
|
|
|
| 2232 |
|
| 2233 |
[[package]]
|
| 2234 |
name = "langgraph"
|
| 2235 |
+
version = "1.0.10rc1"
|
| 2236 |
source = { registry = "https://pypi.org/simple" }
|
| 2237 |
dependencies = [
|
| 2238 |
{ name = "langchain-core" },
|
|
|
|
| 2242 |
{ name = "pydantic" },
|
| 2243 |
{ name = "xxhash" },
|
| 2244 |
]
|
| 2245 |
+
sdist = { url = "https://files.pythonhosted.org/packages/59/33/34c8ab47938ac2ac6df1d2696e28b6000e98c2a783b89655fe2261b7f93b/langgraph-1.0.10rc1.tar.gz", hash = "sha256:4042dc1f33297ccbd593bddc5a4e77dc7e0f37c7ac19d48551c53a22287bacaa", size = 511667, upload-time = "2026-02-26T20:13:38.38Z" }
|
| 2246 |
wheels = [
|
| 2247 |
+
{ url = "https://files.pythonhosted.org/packages/df/61/b6e7fd50c70116369874d681e3aa14bf32adbdde6c05014e5260c081452f/langgraph-1.0.10rc1-py3-none-any.whl", hash = "sha256:10750c035cc48b6809a4657ad0c9fd63fb6ee47dd2f1f2a57adb940381d096e5", size = 160950, upload-time = "2026-02-26T20:13:37.223Z" },
|
| 2248 |
]
|
| 2249 |
|
| 2250 |
[[package]]
|
|
|
|
| 2276 |
|
| 2277 |
[[package]]
|
| 2278 |
name = "langgraph-prebuilt"
|
| 2279 |
+
version = "1.0.10"
|
| 2280 |
source = { registry = "https://pypi.org/simple" }
|
| 2281 |
dependencies = [
|
| 2282 |
{ name = "langchain-core" },
|
| 2283 |
{ name = "langgraph-checkpoint" },
|
| 2284 |
]
|
| 2285 |
+
sdist = { url = "https://files.pythonhosted.org/packages/fe/c8/01471b1b5601f2e9c9a69c39fc9a2fb8611613ede0002e5a2b81c0acd850/langgraph_prebuilt-1.0.10.tar.gz", hash = "sha256:5a6fc513f8907074563b6218ff991c4ed9db19ac63101314919686e8029ddb07", size = 169769, upload-time = "2026-04-17T17:59:45.373Z" }
|
| 2286 |
wheels = [
|
| 2287 |
+
{ url = "https://files.pythonhosted.org/packages/50/49/d073375beabdc6955df6cbe570ba7786836bd4c817ae998955d35037f2fd/langgraph_prebuilt-1.0.10-py3-none-any.whl", hash = "sha256:e3baa1977d819982e690a357ba5bb77ccc1d4d8d4a029c48e502a3b6d171185f", size = 36086, upload-time = "2026-04-17T17:59:44.395Z" },
|
| 2288 |
]
|
| 2289 |
|
| 2290 |
[[package]]
|
|
|
|
| 4340 |
|
| 4341 |
[[package]]
|
| 4342 |
name = "pyasn1"
|
| 4343 |
+
version = "0.6.3"
|
| 4344 |
source = { registry = "https://pypi.org/simple" }
|
| 4345 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" }
|
| 4346 |
wheels = [
|
| 4347 |
+
{ url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" },
|
| 4348 |
]
|
| 4349 |
|
| 4350 |
[[package]]
|
|
|
|
| 4510 |
|
| 4511 |
[[package]]
|
| 4512 |
name = "pygments"
|
| 4513 |
+
version = "2.20.0"
|
| 4514 |
source = { registry = "https://pypi.org/simple" }
|
| 4515 |
+
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
| 4516 |
wheels = [
|
| 4517 |
+
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
| 4518 |
]
|
| 4519 |
|
| 4520 |
[[package]]
|
| 4521 |
name = "pyjwt"
|
| 4522 |
+
version = "2.12.0"
|
| 4523 |
source = { registry = "https://pypi.org/simple" }
|
| 4524 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a8/10/e8192be5f38f3e8e7e046716de4cae33d56fd5ae08927a823bb916be36c1/pyjwt-2.12.0.tar.gz", hash = "sha256:2f62390b667cd8257de560b850bb5a883102a388829274147f1d724453f8fb02", size = 102511, upload-time = "2026-03-12T17:15:30.831Z" }
|
| 4525 |
wheels = [
|
| 4526 |
+
{ url = "https://files.pythonhosted.org/packages/15/70/70f895f404d363d291dcf62c12c85fdd47619ad9674ac0f53364d035925a/pyjwt-2.12.0-py3-none-any.whl", hash = "sha256:9bb459d1bdd0387967d287f5656bf7ec2b9a26645d1961628cda1764e087fd6e", size = 29700, upload-time = "2026-03-12T17:15:29.257Z" },
|
| 4527 |
]
|
| 4528 |
|
| 4529 |
[package.optional-dependencies]
|
|
|
|
| 4625 |
|
| 4626 |
[[package]]
|
| 4627 |
name = "pytest"
|
| 4628 |
+
version = "9.0.3"
|
| 4629 |
source = { registry = "https://pypi.org/simple" }
|
| 4630 |
dependencies = [
|
| 4631 |
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
|
|
| 4634 |
{ name = "pluggy" },
|
| 4635 |
{ name = "pygments" },
|
| 4636 |
]
|
| 4637 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
|
| 4638 |
wheels = [
|
| 4639 |
+
{ url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
|
| 4640 |
]
|
| 4641 |
|
| 4642 |
[[package]]
|
|
|
|
| 4830 |
|
| 4831 |
[[package]]
|
| 4832 |
name = "requests"
|
| 4833 |
+
version = "2.33.0"
|
| 4834 |
source = { registry = "https://pypi.org/simple" }
|
| 4835 |
dependencies = [
|
| 4836 |
{ name = "certifi" },
|
|
|
|
| 4838 |
{ name = "idna" },
|
| 4839 |
{ name = "urllib3" },
|
| 4840 |
]
|
| 4841 |
+
sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" }
|
| 4842 |
wheels = [
|
| 4843 |
+
{ url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" },
|
| 4844 |
]
|
| 4845 |
|
| 4846 |
[[package]]
|
|
|
|
| 5021 |
{ url = "https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl", hash = "sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173", size = 1064234, upload-time = "2026-01-25T22:38:15.216Z" },
|
| 5022 |
]
|
| 5023 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5024 |
[[package]]
|
| 5025 |
name = "shellingham"
|
| 5026 |
version = "1.5.4"
|
|
|
|
| 5167 |
|
| 5168 |
[[package]]
|
| 5169 |
name = "starlette"
|
| 5170 |
+
version = "1.0.1"
|
| 5171 |
source = { registry = "https://pypi.org/simple" }
|
| 5172 |
dependencies = [
|
| 5173 |
{ name = "anyio" },
|
| 5174 |
{ name = "typing-extensions" },
|
| 5175 |
]
|
| 5176 |
+
sdist = { url = "https://files.pythonhosted.org/packages/08/a3/84e821cc54b4ab50ae6dbc6ac3800a651b65ec35f045cc73785380654057/starlette-1.0.1.tar.gz", hash = "sha256:512399c5f1de7fac99c88572212ded9ddeddef2fb32afa82d724000e88b38f4f", size = 2659596, upload-time = "2026-05-21T21:58:58.433Z" }
|
| 5177 |
wheels = [
|
| 5178 |
+
{ url = "https://files.pythonhosted.org/packages/ec/e1/b2df4bc09a1e51ff664c1e17018a4274b42e5e9352e4a478ea540512dc88/starlette-1.0.1-py3-none-any.whl", hash = "sha256:7c0e69b2ee1c848bd54669d908500117a3ee13de603a21427e5c6fc1adf98dcd", size = 72802, upload-time = "2026-05-21T21:58:56.551Z" },
|
| 5179 |
]
|
| 5180 |
|
| 5181 |
[[package]]
|
| 5182 |
name = "streamlit"
|
| 5183 |
+
version = "1.54.0"
|
| 5184 |
source = { registry = "https://pypi.org/simple" }
|
| 5185 |
dependencies = [
|
| 5186 |
{ name = "altair" },
|
|
|
|
| 5202 |
{ name = "typing-extensions" },
|
| 5203 |
{ name = "watchdog", marker = "sys_platform != 'darwin'" },
|
| 5204 |
]
|
| 5205 |
+
sdist = { url = "https://files.pythonhosted.org/packages/be/66/d887ee80ea85f035baee607c60af024994e17ae9b921277fca9675e76ecf/streamlit-1.54.0.tar.gz", hash = "sha256:09965e6ae7eb0357091725de1ce2a3f7e4be155c2464c505c40a3da77ab69dd8", size = 8662292, upload-time = "2026-02-04T16:37:54.734Z" }
|
| 5206 |
wheels = [
|
| 5207 |
+
{ url = "https://files.pythonhosted.org/packages/48/1d/40de1819374b4f0507411a60f4d2de0d620a9b10c817de5925799132b6c9/streamlit-1.54.0-py3-none-any.whl", hash = "sha256:a7b67d6293a9f5f6b4d4c7acdbc4980d7d9f049e78e404125022ecb1712f79fc", size = 9119730, upload-time = "2026-02-04T16:37:52.199Z" },
|
| 5208 |
]
|
| 5209 |
|
| 5210 |
[[package]]
|
|
|
|
| 5380 |
|
| 5381 |
[[package]]
|
| 5382 |
name = "tornado"
|
| 5383 |
+
version = "6.5.5"
|
| 5384 |
source = { registry = "https://pypi.org/simple" }
|
| 5385 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" }
|
| 5386 |
wheels = [
|
| 5387 |
+
{ url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" },
|
| 5388 |
+
{ url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" },
|
| 5389 |
+
{ url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" },
|
| 5390 |
+
{ url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" },
|
| 5391 |
+
{ url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" },
|
| 5392 |
+
{ url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" },
|
| 5393 |
+
{ url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" },
|
| 5394 |
+
{ url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" },
|
| 5395 |
+
{ url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" },
|
|
|
|
|
|
|
| 5396 |
]
|
| 5397 |
|
| 5398 |
[[package]]
|
|
|
|
| 5477 |
|
| 5478 |
[[package]]
|
| 5479 |
name = "transformers"
|
| 5480 |
+
version = "5.0.0rc3"
|
| 5481 |
source = { registry = "https://pypi.org/simple" }
|
| 5482 |
dependencies = [
|
| 5483 |
{ name = "filelock" },
|
|
|
|
| 5490 |
{ name = "safetensors" },
|
| 5491 |
{ name = "tokenizers" },
|
| 5492 |
{ name = "tqdm" },
|
| 5493 |
+
{ name = "typer-slim" },
|
| 5494 |
]
|
| 5495 |
+
sdist = { url = "https://files.pythonhosted.org/packages/3f/a3/7c116a8d85f69ea7749cf4c2df79e64c35d028e5fc7ea0168f299d03b8c7/transformers-5.0.0rc3.tar.gz", hash = "sha256:a0315b92b7e087617ade42ec9e6e92ee7620541cc5d6a3331886c52cbe306f5c", size = 8388520, upload-time = "2026-01-14T16:49:02.952Z" }
|
| 5496 |
wheels = [
|
| 5497 |
+
{ url = "https://files.pythonhosted.org/packages/1e/f2/ae2b8968764253bdf38a48dee3c299b8d0bedf7c8ffbe3449fca9bd95338/transformers-5.0.0rc3-py3-none-any.whl", hash = "sha256:383fad27f4f73092d330e45fae384681e5c8521e1dc1cf6cb1a297780e68bf2d", size = 10107087, upload-time = "2026-01-14T16:48:59.393Z" },
|
| 5498 |
]
|
| 5499 |
|
| 5500 |
[[package]]
|
|
|
|
| 5507 |
|
| 5508 |
[[package]]
|
| 5509 |
name = "typer"
|
| 5510 |
+
version = "0.25.1"
|
| 5511 |
source = { registry = "https://pypi.org/simple" }
|
| 5512 |
dependencies = [
|
| 5513 |
+
{ name = "annotated-doc" },
|
| 5514 |
{ name = "click" },
|
| 5515 |
{ name = "rich" },
|
| 5516 |
{ name = "shellingham" },
|
|
|
|
| 5517 |
]
|
| 5518 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e4/51/9aed62104cea109b820bbd6c14245af756112017d309da813ef107d42e7e/typer-0.25.1.tar.gz", hash = "sha256:9616eb8853a09ffeabab1698952f33c6f29ffdbceb4eaeecf571880e8d7664cc", size = 122276, upload-time = "2026-04-30T19:32:16.964Z" }
|
| 5519 |
wheels = [
|
| 5520 |
+
{ url = "https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl", hash = "sha256:75caa44ed46a03fb2dab8808753ffacdbfea88495e74c85a28c5eefcf5f39c89", size = 58409, upload-time = "2026-04-30T19:32:18.271Z" },
|
| 5521 |
+
]
|
| 5522 |
+
|
| 5523 |
+
[[package]]
|
| 5524 |
+
name = "typer-slim"
|
| 5525 |
+
version = "0.24.0"
|
| 5526 |
+
source = { registry = "https://pypi.org/simple" }
|
| 5527 |
+
dependencies = [
|
| 5528 |
+
{ name = "typer" },
|
| 5529 |
+
]
|
| 5530 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a7/a7/e6aecc4b4eb59598829a3b5076a93aff291b4fdaa2ded25efc4e1f4d219c/typer_slim-0.24.0.tar.gz", hash = "sha256:f0ed36127183f52ae6ced2ecb2521789995992c521a46083bfcdbb652d22ad34", size = 4776, upload-time = "2026-02-16T22:08:51.2Z" }
|
| 5531 |
+
wheels = [
|
| 5532 |
+
{ url = "https://files.pythonhosted.org/packages/a7/24/5480c20380dfd18cf33d14784096dca45a24eae6102e91d49a718d3b6855/typer_slim-0.24.0-py3-none-any.whl", hash = "sha256:d5d7ee1ee2834d5020c7c616ed5e0d0f29b9a4b1dd283bdebae198ec09778d0e", size = 3394, upload-time = "2026-02-16T22:08:49.92Z" },
|
| 5533 |
]
|
| 5534 |
|
| 5535 |
[[package]]
|
|
|
|
| 5756 |
|
| 5757 |
[[package]]
|
| 5758 |
name = "werkzeug"
|
| 5759 |
+
version = "3.1.6"
|
| 5760 |
source = { registry = "https://pypi.org/simple" }
|
| 5761 |
dependencies = [
|
| 5762 |
{ name = "markupsafe" },
|
| 5763 |
]
|
| 5764 |
+
sdist = { url = "https://files.pythonhosted.org/packages/61/f1/ee81806690a87dab5f5653c1f146c92bc066d7f4cebc603ef88eb9e13957/werkzeug-3.1.6.tar.gz", hash = "sha256:210c6bede5a420a913956b4791a7f4d6843a43b6fcee4dfa08a65e93007d0d25", size = 864736, upload-time = "2026-02-19T15:17:18.884Z" }
|
| 5765 |
wheels = [
|
| 5766 |
+
{ url = "https://files.pythonhosted.org/packages/4d/ec/d58832f89ede95652fd01f4f24236af7d32b70cab2196dfcc2d2fd13c5c2/werkzeug-3.1.6-py3-none-any.whl", hash = "sha256:7ddf3357bb9564e407607f988f683d72038551200c704012bb9a4c523d42f131", size = 225166, upload-time = "2026-02-19T15:17:17.475Z" },
|
| 5767 |
]
|
| 5768 |
|
| 5769 |
[[package]]
|
|
|
|
| 5873 |
|
| 5874 |
[[package]]
|
| 5875 |
name = "yt-dlp"
|
| 5876 |
+
version = "2026.2.21"
|
| 5877 |
source = { registry = "https://pypi.org/simple" }
|
| 5878 |
+
sdist = { url = "https://files.pythonhosted.org/packages/58/d9/55ffff25204733e94a507552ad984d5a8a8e4f9d1f0d91763e6b1a41c79b/yt_dlp-2026.2.21.tar.gz", hash = "sha256:4407dfc1a71fec0dee5ef916a8d4b66057812939b509ae45451fa8fb4376b539", size = 3116630, upload-time = "2026-02-21T20:40:53.522Z" }
|
| 5879 |
wheels = [
|
| 5880 |
+
{ url = "https://files.pythonhosted.org/packages/5a/40/664c99ee36d80d84ce7a96cd98aebcb3d16c19e6c3ad3461d2cf5424040e/yt_dlp-2026.2.21-py3-none-any.whl", hash = "sha256:0d8408f5b6d20487f5caeb946dfd04f9bcd2f1a3a125b744a0a982b590e449f7", size = 3313392, upload-time = "2026-02-21T20:40:51.514Z" },
|
| 5881 |
]
|
| 5882 |
|
| 5883 |
[[package]]
|