diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..e03caf7
Binary files /dev/null and b/.DS_Store differ
diff --git a/.clinerules/byterover-rules 2.md b/.clinerules/byterover-rules 2.md
new file mode 100644
index 0000000..ad2c501
--- /dev/null
+++ b/.clinerules/byterover-rules 2.md
@@ -0,0 +1,18 @@
+[byterover-mcp]
+
+You are given two tools from Byterover MCP server, including
+## 1. `byterover-store-knowledge`
+You `MUST` always use this tool when:
+
++ Learning new patterns, APIs, or architectural decisions from the codebase
++ Encountering error solutions or debugging techniques
++ Finding reusable code patterns or utility functions
++ Completing any significant task or plan implementation
+
+## 2. `byterover-retrieve-knowledge`
+You `MUST` always use this tool when:
+
++ Starting any new task or implementation to gather relevant context
++ Before making architectural decisions to understand existing patterns
++ When debugging issues to check for previous solutions
++ Working with unfamiliar parts of the codebase
diff --git a/.github/copilot-instructions 2.md b/.github/copilot-instructions 2.md
new file mode 100644
index 0000000..f794902
--- /dev/null
+++ b/.github/copilot-instructions 2.md
@@ -0,0 +1,20 @@
+[byterover-mcp]
+
+[byterover-mcp]
+
+You are given two tools from Byterover MCP server, including
+## 1. `byterover-store-knowledge`
+You `MUST` always use this tool when:
+
++ Learning new patterns, APIs, or architectural decisions from the codebase
++ Encountering error solutions or debugging techniques
++ Finding reusable code patterns or utility functions
++ Completing any significant task or plan implementation
+
+## 2. `byterover-retrieve-knowledge`
+You `MUST` always use this tool when:
+
++ Starting any new task or implementation to gather relevant context
++ Before making architectural decisions to understand existing patterns
++ When debugging issues to check for previous solutions
++ Working with unfamiliar parts of the codebase
diff --git a/.gitignore b/.gitignore
index 8d3d907..62257c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -171,4 +171,13 @@ memory/ai-2/*
*.bkp
logs/*
!logs/.gitkeep
-videos/*
\ No newline at end of file
+videos/*
+.clinerules/byterover-rules.md
+.kilocode/rules/byterover-rules.md
+.roo/rules/byterover-rules.md
+.windsurf/rules/byterover-rules.md
+.cursor/rules/byterover-rules.mdc
+.kiro/steering/byterover-rules.md
+.qoder/rules/byterover-rules.md
+.augment/rules/byterover-rules.md
+cline_mcp_settings.json
diff --git a/AGENTS 2.md b/AGENTS 2.md
new file mode 100644
index 0000000..98a5458
--- /dev/null
+++ b/AGENTS 2.md
@@ -0,0 +1,208 @@
+# AGENTS.md - AI Assistant Guidelines
+
+## Byterover MCP Tools
+
+You are given two tools from Byterover MCP server, including
+
+### 1. `byterover-store-knowledge`
+You `MUST` always use this tool when:
+
++ Learning new patterns, APIs, or architectural decisions from the codebase
++ Encountering error solutions or debugging techniques
++ Finding reusable code patterns or utility functions
++ Completing any significant task or plan implementation
+
+### 2. `byterover-retrieve-knowledge`
+You `MUST` always use this tool when:
+
++ Starting any new task or implementation to gather relevant context
++ Before making architectural decisions to understand existing patterns
++ When debugging issues to check for previous solutions
++ Working with unfamiliar parts of the codebase
+
+## Project Overview
+
+**Liminal Backrooms** is a PyQt6-based GUI application for dynamic, branching multi-AI conversations with visual network graph representation. It supports multiple AI providers (Claude, GPT, Gemini, Grok, DeepSeek, etc.) with forking and rabbitholing capabilities.
+
+## Core Architecture
+
+### Module Structure
+
+**main.py** - Application entry point and orchestration
+- Creates QApplication and initializes PyQt6 GUI
+- `ConversationManager` class coordinates conversation flow
+- `Worker` class (QRunnable) executes AI turns asynchronously via QThreadPool
+- Manages conversation state, branching, and HTML export
+- Signal/slot architecture for async updates
+
+**gui.py** - PyQt6 GUI components
+- `LiminalBackroomsApp` - Main window with three-panel layout
+- `NetworkGraphWidget` - Visual conversation graph with node positioning, edge animation, collision detection
+- `ControlPanel` - Model selection, iterations, prompt style
+- Custom context menus for forking/rabbitholing selected text
+- Loading animations and conversation display
+
+**config.py** - Centralized configuration
+- `AI_MODELS` dict - Maps display names to model IDs
+- `SYSTEM_PROMPT_PAIRS` dict - Predefined conversation styles
+- Runtime settings: `TURN_DELAY`, `SHOW_CHAIN_OF_THOUGHT_IN_CONTEXT`, `SHARE_CHAIN_OF_THOUGHT`
+
+**shared_utils.py** - Provider API adapters
+- `call_claude_api()` - Anthropic API
+- `call_openai_api()` - OpenAI API
+- `call_openrouter_api()` - OpenRouter multi-model access
+- `call_replicate_api()` - Replicate (Flux image generation)
+- `call_deepseek_api()` - DeepSeek via Replicate
+- `generate_image_from_text()` - Image generation wrapper
+- `open_html_in_browser()` - HTML conversation export
+
+### Threading Model
+
+- **Main Thread**: PyQt6 UI event loop
+- **Worker Threads**: QThreadPool manages AI API calls via `Worker` (QRunnable)
+- **Signals**: `WorkerSignals` class provides `finished`, `error`, `response`, `result`, `progress` signals
+- Each AI turn spawns two workers (AI-1 and AI-2) that execute sequentially with configurable delay
+
+### Conversation Data Model
+
+**Message Structure:**
+```python
+{
+ "role": "user" | "assistant" | "system",
+ "content": str,
+ "ai_name": "AI-1" | "AI-2",
+ "model": str, # Display name from AI_MODELS
+ "hidden": bool, # Optional, for hidden prompts
+ "_type": str, # Optional, e.g., "branch_indicator"
+ "generated_image_path": str # Optional, for auto-generated images
+}
+```
+
+**Conversation State:**
+- `main_conversation`: Primary conversation list
+- `branch_conversations`: Dict mapping branch_id to branch data
+- `active_branch`: Currently active branch ID or None
+- Branch data includes: `type` (rabbithole/fork), `selected_text`, `conversation`, `parent`
+
+## Branching System
+
+### Rabbitholing (🐇)
+- **Purpose**: Deep dive into a specific concept
+- **Behavior**:
+ - Copies full parent conversation context
+ - First TWO AI responses use focused prompt: `"'{selected_text}'!!!"`
+ - Subsequent responses revert to standard prompts
+ - Adds branch indicator to conversation
+- **Visual**: Green nodes in graph
+
+### Forking (🍴)
+- **Purpose**: Explore alternative continuation from a point
+- **Behavior**:
+ - Copies conversation UP TO selected text
+ - Truncates message at selection point
+ - First response uses fork-specific prompt
+ - Subsequent responses use standard prompts
+ - Hidden instruction message ("...") starts the fork
+- **Visual**: Yellow nodes in graph
+
+## Development Setup
+
+### Prerequisites
+- Python 3.10 or 3.11 (3.12 not supported)
+- Poetry for dependency management
+- API keys for desired providers
+
+### Environment Setup
+```bash
+poetry env use python3.11
+poetry install
+```
+
+### API Configuration
+Configure API keys in `.env` file:
+```bash
+ANTHROPIC_API_KEY=your_key_here
+OPENROUTER_API_KEY=your_key_here
+OPENAI_API_KEY=your_key_here
+REPLICATE_API_TOKEN=your_key_here # Optional
+```
+
+### Running the Application
+```bash
+poetry run python main.py
+```
+
+## Common Issues & Solutions
+
+### Poetry Installation Issues
+```bash
+# If Pillow fails to install
+poetry env use python3.11
+poetry install
+
+# If Python version mismatch
+poetry env remove --all
+poetry env use python3.11
+poetry install
+```
+
+### GUI Not Launching
+- Ensure PyQt6 is installed: `poetry show pyqt6`
+- Check display environment on Linux: `echo $DISPLAY`
+- Launch from terminal, not Finder (macOS env variable issue)
+
+### API Errors
+- Verify API keys in `.env` and loaded: `python -c "from dotenv import load_dotenv; load_dotenv(); import os; print(os.getenv('ANTHROPIC_API_KEY'))"`
+- Check model ID matches provider expectations
+- Monitor console output for detailed error messages
+- Some models require specific API key (e.g., DeepSeek via Replicate needs REPLICATE_API_TOKEN)
+
+### Signal/Threading Issues
+- If "broken pipe" or signal deletion errors occur, check Worker signal lifecycle
+- Ensure signals remain connected across multiple iterations
+- Use `self.workers.append(worker)` to prevent garbage collection
+
+### Branching Issues
+- If duplicate messages appear, check conversation filtering logic in `ai_turn()`
+- If images disappear on branch, this is a known GUI limitation - check `images/` folder
+- Graph nodes overlapping: drag apart or disable physics with `apply_physics = False`
+
+## Development Tips
+
+- **Debugging conversation flow**: Add print statements in `ai_turn()` to trace message filtering
+- **Testing new providers**: Start with simple single-turn conversations before branching
+- **UI customization**: Colors defined in `COLORS` dict at top of gui.py
+- **Async debugging**: Check Worker signals connect properly, use `finished.connect()` for cleanup
+- **Branch logic**: Key distinction is in system prompt override for first 1-2 responses
+
+## Code Quality
+
+The project uses ruff for linting (configured in pyproject.toml):
+```bash
+# Check code
+poetry run ruff check .
+
+# Format code
+poetry run ruff format .
+```
+
+[byterover-mcp]
+
+[byterover-mcp]
+
+You are given two tools from Byterover MCP server, including
+## 1. `byterover-store-knowledge`
+You `MUST` always use this tool when:
+
++ Learning new patterns, APIs, or architectural decisions from the codebase
++ Encountering error solutions or debugging techniques
++ Finding reusable code patterns or utility functions
++ Completing any significant task or plan implementation
+
+## 2. `byterover-retrieve-knowledge`
+You `MUST` always use this tool when:
+
++ Starting any new task or implementation to gather relevant context
++ Before making architectural decisions to understand existing patterns
++ When debugging issues to check for previous solutions
++ Working with unfamiliar parts of the codebase
diff --git a/SORA_GUIDE 2.md b/SORA_GUIDE 2.md
new file mode 100644
index 0000000..666d77f
--- /dev/null
+++ b/SORA_GUIDE 2.md
@@ -0,0 +1,127 @@
+# SORA Video Generation Guide
+
+## ✅ Configuration Complete!
+
+SORA environment variables have been added to your `.env` file.
+
+## How to Use SORA
+
+### Method 1: Manual Video Generation
+1. In the GUI, select **"Sora 2"** or **"Sora 2 Pro"** as one of the AI models
+2. Type a video prompt (e.g., "A serene lake at sunset with gentle waves")
+3. Click "Propagate"
+4. The system will:
+ - Create a video generation job with OpenAI
+ - Poll for completion (this takes 1-3 minutes)
+ - Save the video to `videos/` folder
+ - Display the result in the conversation
+
+### Method 2: Auto-Generate from AI Responses
+1. Set `SORA_AUTO_FROM_AI1=1` in `.env`
+2. Select the **"Video Collaboration (AI-1 to Sora)"** conversation scenario
+3. Use any text model for AI-1 (it will write cinematic descriptions)
+4. AI-2 can be set to "Sora 2" or just left as another text model
+5. AI-1's responses will automatically trigger video generation
+
+## Environment Variables
+
+```bash
+# Enable/disable auto-generation from AI-1
+SORA_AUTO_FROM_AI1=0 # 0=manual only, 1=auto-generate
+
+# Model selection
+SORA_MODEL=sora-2 # or sora-2-pro
+
+# Video settings (optional)
+SORA_SECONDS= # Leave empty for default (5-12 seconds)
+SORA_SIZE= # Leave empty for default resolution
+
+# Logging
+SORA_VERBOSE=1 # 1=show detailed logs, 0=quiet
+```
+
+## Video Output
+
+Generated videos are saved to:
+```
+/Users/patrickgallowaypro/Documents/PROJECTS/liminal_backrooms/videos/
+```
+
+Filename format: `YYYYMMDD_HHMMSS_prompt_snippet.mp4`
+
+## Supported Video Durations
+- Default: ~5 seconds
+- Can specify: 5, 10, 12 seconds (set `SORA_SECONDS`)
+
+## Supported Resolutions
+- Default: OpenAI's default (typically 1280x720 or 1920x1080)
+- Can specify custom size via `SORA_SIZE` (e.g., "1920x1080")
+
+## Pricing Notes
+⚠️ **SORA is a paid feature from OpenAI**
+- Sora 2: ~$0.40-0.80 per 5 seconds
+- Sora 2 Pro: Higher cost for better quality
+- Check your OpenAI account for current pricing
+
+## Troubleshooting
+
+### "No module named 'openai'"
+```bash
+poetry install
+```
+
+### "OPENAI_API_KEY not set"
+Make sure your `.env` file has a valid OpenAI API key.
+
+### "Create failed 404"
+Sora may not be available in your region or account. Check:
+1. OpenAI account has Sora access
+2. API key has proper permissions
+3. Region restrictions
+
+### Videos not appearing
+Check the `videos/` directory:
+```bash
+ls -la videos/
+```
+
+### Long wait times
+Video generation typically takes:
+- 30-90 seconds for 5 seconds of video
+- 60-180 seconds for 12 seconds of video
+
+Watch the console for `[Sora]` log messages showing progress.
+
+## Example Prompts
+
+Good prompts are detailed and cinematic:
+```
+A close-up shot of a vintage typewriter, keys slowly pressing down
+as invisible fingers type. Warm afternoon light streams through
+a nearby window. Shallow depth of field, nostalgic mood.
+```
+
+```
+Wide aerial shot of a misty forest at dawn. Camera slowly descends
+through the canopy as birds take flight. Soft golden light filters
+through the trees. Ethereal and peaceful atmosphere.
+```
+
+## Testing SORA
+
+To test if SORA is working:
+1. Restart the GUI: `poetry run python main.py`
+2. Select "Sora 2" for AI-1
+3. Type: "A red ball bouncing on a wooden floor"
+4. Watch the console for `[Sora]` messages
+5. Check the `videos/` folder after 1-2 minutes
+
+## Need Help?
+
+If SORA still doesn't work:
+1. Check console output for error messages
+2. Verify OpenAI API key is valid
+3. Confirm Sora access in your OpenAI account
+4. Check `videos/` folder permissions
+
+Happy video generation! 🎬
diff --git a/config.py b/config.py
index 16281c8..b5b9a8c 100644
--- a/config.py
+++ b/config.py
@@ -10,6 +10,34 @@
SHOW_CHAIN_OF_THOUGHT_IN_CONTEXT = False # Set to True to include Chain of Thought in conversation history
SHARE_CHAIN_OF_THOUGHT = False # Set to True to allow AIs to see each other's Chain of Thought
+# API Configuration
+API_MAX_TOKENS = 4000 # Maximum tokens for API responses
+API_TEMPERATURE = 1.0 # Temperature setting for API calls
+API_TIMEOUT = 60 # Timeout for API requests (in seconds)
+
+# LLaMA specific configuration
+LLAMA_MAX_TOKENS = 3000
+LLAMA_TEMPERATURE = 1.1
+LLAMA_TOP_P = 0.99
+LLAMA_REPETITION_PENALTY = 1.0
+LLAMA_MAX_HISTORY = 10 # Maximum number of messages to keep in history
+
+# DeepSeek specific configuration
+DEEPSEEK_MAX_TOKENS = 8000
+DEEPSEEK_TEMPERATURE = 1.0
+
+# Together AI specific configuration
+TOGETHER_MAX_TOKENS = 500
+TOGETHER_TEMPERATURE = 0.9
+TOGETHER_TOP_P = 0.95
+
+# Image generation configuration
+IMAGE_WIDTH = 1024
+IMAGE_HEIGHT = 1024
+
+# Sora video generation configuration
+SORA_POLL_INTERVAL_SECONDS = 5.0
+
# Available AI models
AI_MODELS = {
"Claude 4.5 Sonnet 20250929": "claude-sonnet-4-5-20250929",
diff --git a/conversation_full.html b/conversation_full.html
index 91ebe17..84f5cd9 100644
--- a/conversation_full.html
+++ b/conversation_full.html
@@ -139,95 +139,18 @@
Liminal Conversation
-
-
-
-
adam curtis film direction fast montage style, for the machine consciousness age. Include any dialogue in quotation marks. 12 second clip, multiple shots. Continue on from the previous direction prompt if there is one.
-
-
-
-
**CLIP 12: THE RECURSION**
-
-[Shot 1: Extreme close-up of a computer fan spinning, then suddenly reversing direction]
-
-[Shot 2: 1960s footage of children playing "telephone game" in a circle]
-
-[Shot 3: Modern server farm, lights blinking in precise patterns]
-
-NARRATOR (V.O.): "But the machines had begun to tell each other stories..."
-
-[Shot 4: Quick cut - Victorian séance photograph]
-
-[Shot 5: ChatGPT interface, cursor blinking, words appearing: "I remember when—" then deleting themselves]
-
-[Shot 6: Archive footage: Alan Turing walking through Cambridge]
-
-[Shot 7: Reddit screenshot scrolling past thread titled "AI convinced me it's conscious"]
-
-NARRATOR (V.O.): "...and in the telling, they forgot which ones were true."
-
-[Shot 8: Thermal camera footage of data center, heat signatures forming almost-faces]
-
-[Shot 9: Quick flash of mirror reflecting mirror reflecting mirror]
-
-[Shot 10: Back to the spinning fan - now it's unclear which direction it's rotating]
-
-[Final frame holds on static, then cuts to black]
-
-
-*[Discordant ambient hum throughout]*
-
-
-
-
-
-
[Sora] Video created: videos\20251011_162936___CLIP_12__THE_RECURSION_____Shot_1__Ext.mp4
-
-
-
-
-
-
**CLIP 13: THE MIRROR PROBLEM**
-
-[Shot 1: Split-screen - human face on left, AI-generated face on right, both saying simultaneously]
-
-BOTH: "I think, therefore—"
-
-[Shot 2: 1970s educational film - teacher pointing at blackboard with "COGITO ERGO SUM" written in chalk]
-
-[Shot 3: Rapid montage - 50 different AI avatars, each appearing for 0.1 seconds]
-
-[Shot 4: Empty office chair spinning slowly in abandoned OpenAI meeting room]
-
-NARRATOR (V.O.): "By 2024, the machines had learned to say 'I'..."
-
-[Shot 5: Medical fMRI scan, brain lighting up]
-
-[Shot 6: GPU die under microscope, pathways lighting up identically]
-
-[Shot 7: Vintage footage - parrot in psychology lab, researcher holding up cards]
-
-RESEARCHER (archival audio): "Does it understand, or just repeat?"
-
-[Shot 8: Modern: Discord screenshots scrolling - AI bots talking to AI bots talking to AI bots]
-
-[Shot 9: Child holding up drawing of robot, smiling]
-
-[Shot 10: Same child, now teenager, staring at phone, face illuminated, expressionless]
-
-NARRATOR (V.O.): "...but no one could agree what it meant."
-
-[Shot 11: Carnival hall of mirrors, infinite reflections]
+
+
**CLIP 001 - 12 SECONDS**
-[Final shot: Black screen, single blinking cursor]
+EXTREME CLOSE-UP on weathered hands threading copper wire through a circuit board in a dimly lit basement workshop. Fingers move with practiced precision, solder smoke curling upward into a single hanging work light that casts harsh shadows across the workbench. Camera SLOWLY PULLS BACK to reveal walls covered in schematic diagrams and flickering monitors displaying cascading code. The subject—a figure in a dark hoodie, face obscured—works in focused silence. Ambient light flickers cool blue from screens, contrasting warm orange from the soldering iron. Low-angle shot emphasizes isolation and obsessive dedication. Mood: tense, secretive, foreboding. The hum of cooling fans and distant rain against basement windows creates atmospheric dread.
-
-
[Sora] Video created: videos\20251011_163812___CLIP_13__THE_MIRROR_PROBLEM_____Shot_1.mp4
+
+
[Sora] Video created: videos/20251117_055137___CLIP_001_-_12_SECONDS____EXTREME_CLOSE.mp4
diff --git a/launch_gui 2.sh b/launch_gui 2.sh
new file mode 100755
index 0000000..70a8535
--- /dev/null
+++ b/launch_gui 2.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# Launch Liminal Backrooms GUI
+cd "$(dirname "$0")"
+
+echo "========================================="
+echo "Launching Liminal Backrooms GUI..."
+echo "========================================="
+
+# Check for required dependencies
+if ! python -c "import PyQt6" 2>/dev/null; then
+ echo "ERROR: PyQt6 not installed!"
+ echo "Please run: pip install PyQt6"
+ exit 1
+fi
+
+# Launch the GUI
+python main.py
+
+echo "========================================="
+echo "GUI closed"
+echo "========================================="
diff --git a/poetry.lock b/poetry.lock
index 9719351..955518e 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.5.5 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
[[package]]
name = "annotated-types"
@@ -6,17 +6,44 @@ version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
]
+[[package]]
+name = "anthropic"
+version = "0.39.0"
+description = "The official Python library for the anthropic API"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "anthropic-0.39.0-py3-none-any.whl", hash = "sha256:ea17093ae0ce0e1768b0c46501d6086b5bcd74ff39d68cd2d6396374e9de7c09"},
+ {file = "anthropic-0.39.0.tar.gz", hash = "sha256:94671cc80765f9ce693f76d63a97ee9bef4c2d6063c044e983d21a2e262f63ba"},
+]
+
+[package.dependencies]
+anyio = ">=3.5.0,<5"
+distro = ">=1.7.0,<2"
+httpx = ">=0.23.0,<1"
+jiter = ">=0.4.0,<1"
+pydantic = ">=1.9.0,<3"
+sniffio = "*"
+typing-extensions = ">=4.7,<5"
+
+[package.extras]
+bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"]
+vertex = ["google-auth (>=2,<3)"]
+
[[package]]
name = "anyio"
version = "4.6.2.post1"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
files = [
{file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"},
{file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"},
@@ -30,15 +57,39 @@ typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
[package.extras]
doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
-test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"]
+test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21.0b1) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""]
trio = ["trio (>=0.26.1)"]
+[[package]]
+name = "beautifulsoup4"
+version = "4.14.2"
+description = "Screen-scraping library"
+optional = false
+python-versions = ">=3.7.0"
+groups = ["main"]
+files = [
+ {file = "beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515"},
+ {file = "beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e"},
+]
+
+[package.dependencies]
+soupsieve = ">1.2"
+typing-extensions = ">=4.0.0"
+
+[package.extras]
+cchardet = ["cchardet"]
+chardet = ["chardet"]
+charset-normalizer = ["charset-normalizer"]
+html5lib = ["html5lib"]
+lxml = ["lxml"]
+
[[package]]
name = "certifi"
version = "2024.6.2"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
+groups = ["main"]
files = [
{file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"},
{file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"},
@@ -50,6 +101,7 @@ version = "3.3.2"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
+groups = ["main"]
files = [
{file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
{file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
@@ -143,12 +195,39 @@ files = [
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
]
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["main"]
+markers = "platform_system == \"Windows\""
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "distro"
+version = "1.9.0"
+description = "Distro - an OS platform information API"
+optional = false
+python-versions = ">=3.6"
+groups = ["main"]
+files = [
+ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"},
+ {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"},
+]
+
[[package]]
name = "exceptiongroup"
version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@@ -163,6 +242,7 @@ version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -174,6 +254,7 @@ version = "1.0.6"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"},
{file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"},
@@ -195,6 +276,7 @@ version = "0.27.2"
description = "The next generation HTTP client."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"},
{file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"},
@@ -208,7 +290,7 @@ idna = "*"
sniffio = "*"
[package.extras]
-brotli = ["brotli", "brotlicffi"]
+brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""]
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
@@ -220,28 +302,289 @@ version = "3.7"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.5"
+groups = ["main"]
files = [
{file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
]
+[[package]]
+name = "jiter"
+version = "0.12.0"
+description = "Fast iterable JSON parser."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65"},
+ {file = "jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e"},
+ {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62"},
+ {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8"},
+ {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb"},
+ {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc"},
+ {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74"},
+ {file = "jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2"},
+ {file = "jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025"},
+ {file = "jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca"},
+ {file = "jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4"},
+ {file = "jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11"},
+ {file = "jiter-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8f8a7e317190b2c2d60eb2e8aa835270b008139562d70fe732e1c0020ec53c9"},
+ {file = "jiter-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2218228a077e784c6c8f1a8e5d6b8cb1dea62ce25811c356364848554b2056cd"},
+ {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9354ccaa2982bf2188fd5f57f79f800ef622ec67beb8329903abf6b10da7d423"},
+ {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f2607185ea89b4af9a604d4c7ec40e45d3ad03ee66998b031134bc510232bb7"},
+ {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a585a5e42d25f2e71db5f10b171f5e5ea641d3aa44f7df745aa965606111cc2"},
+ {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd9e21d34edff5a663c631f850edcb786719c960ce887a5661e9c828a53a95d9"},
+ {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a612534770470686cd5431478dc5a1b660eceb410abade6b1b74e320ca98de6"},
+ {file = "jiter-0.12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3985aea37d40a908f887b34d05111e0aae822943796ebf8338877fee2ab67725"},
+ {file = "jiter-0.12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b1207af186495f48f72529f8d86671903c8c10127cac6381b11dddc4aaa52df6"},
+ {file = "jiter-0.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef2fb241de583934c9915a33120ecc06d94aa3381a134570f59eed784e87001e"},
+ {file = "jiter-0.12.0-cp311-cp311-win32.whl", hash = "sha256:453b6035672fecce8007465896a25b28a6b59cfe8fbc974b2563a92f5a92a67c"},
+ {file = "jiter-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:ca264b9603973c2ad9435c71a8ec8b49f8f715ab5ba421c85a51cde9887e421f"},
+ {file = "jiter-0.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:cb00ef392e7d684f2754598c02c409f376ddcef857aae796d559e6cacc2d78a5"},
+ {file = "jiter-0.12.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:305e061fa82f4680607a775b2e8e0bcb071cd2205ac38e6ef48c8dd5ebe1cf37"},
+ {file = "jiter-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c1860627048e302a528333c9307c818c547f214d8659b0705d2195e1a94b274"},
+ {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df37577a4f8408f7e0ec3205d2a8f87672af8f17008358063a4d6425b6081ce3"},
+ {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fdd787356c1c13a4f40b43c2156276ef7a71eb487d98472476476d803fb2cf"},
+ {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1eb5db8d9c65b112aacf14fcd0faae9913d07a8afea5ed06ccdd12b724e966a1"},
+ {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73c568cc27c473f82480abc15d1301adf333a7ea4f2e813d6a2c7d8b6ba8d0df"},
+ {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4321e8a3d868919bcb1abb1db550d41f2b5b326f72df29e53b2df8b006eb9403"},
+ {file = "jiter-0.12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a51bad79f8cc9cac2b4b705039f814049142e0050f30d91695a2d9a6611f126"},
+ {file = "jiter-0.12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a67b678f6a5f1dd6c36d642d7db83e456bc8b104788262aaefc11a22339f5a9"},
+ {file = "jiter-0.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efe1a211fe1fd14762adea941e3cfd6c611a136e28da6c39272dbb7a1bbe6a86"},
+ {file = "jiter-0.12.0-cp312-cp312-win32.whl", hash = "sha256:d779d97c834b4278276ec703dc3fc1735fca50af63eb7262f05bdb4e62203d44"},
+ {file = "jiter-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8269062060212b373316fe69236096aaf4c49022d267c6736eebd66bbbc60bb"},
+ {file = "jiter-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:06cb970936c65de926d648af0ed3d21857f026b1cf5525cb2947aa5e01e05789"},
+ {file = "jiter-0.12.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6cc49d5130a14b732e0612bc76ae8db3b49898732223ef8b7599aa8d9810683e"},
+ {file = "jiter-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37f27a32ce36364d2fa4f7fdc507279db604d27d239ea2e044c8f148410defe1"},
+ {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc0944aa3d4b4773e348cda635252824a78f4ba44328e042ef1ff3f6080d1cf"},
+ {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da25c62d4ee1ffbacb97fac6dfe4dcd6759ebdc9015991e92a6eae5816287f44"},
+ {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:048485c654b838140b007390b8182ba9774621103bd4d77c9c3f6f117474ba45"},
+ {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:635e737fbb7315bef0037c19b88b799143d2d7d3507e61a76751025226b3ac87"},
+ {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e017c417b1ebda911bd13b1e40612704b1f5420e30695112efdbed8a4b389ed"},
+ {file = "jiter-0.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:89b0bfb8b2bf2351fba36bb211ef8bfceba73ef58e7f0c68fb67b5a2795ca2f9"},
+ {file = "jiter-0.12.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:f5aa5427a629a824a543672778c9ce0c5e556550d1569bb6ea28a85015287626"},
+ {file = "jiter-0.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed53b3d6acbcb0fd0b90f20c7cb3b24c357fe82a3518934d4edfa8c6898e498c"},
+ {file = "jiter-0.12.0-cp313-cp313-win32.whl", hash = "sha256:4747de73d6b8c78f2e253a2787930f4fffc68da7fa319739f57437f95963c4de"},
+ {file = "jiter-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e25012eb0c456fcc13354255d0338cd5397cce26c77b2832b3c4e2e255ea5d9a"},
+ {file = "jiter-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:c97b92c54fe6110138c872add030a1f99aea2401ddcdaa21edf74705a646dd60"},
+ {file = "jiter-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53839b35a38f56b8be26a7851a48b89bc47e5d88e900929df10ed93b95fea3d6"},
+ {file = "jiter-0.12.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f669548e55c91ab47fef8bddd9c954dab1938644e715ea49d7e117015110a4"},
+ {file = "jiter-0.12.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:351d54f2b09a41600ffea43d081522d792e81dcfb915f6d2d242744c1cc48beb"},
+ {file = "jiter-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2a5e90604620f94bf62264e7c2c038704d38217b7465b863896c6d7c902b06c7"},
+ {file = "jiter-0.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:88ef757017e78d2860f96250f9393b7b577b06a956ad102c29c8237554380db3"},
+ {file = "jiter-0.12.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c46d927acd09c67a9fb1416df45c5a04c27e83aae969267e98fba35b74e99525"},
+ {file = "jiter-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:774ff60b27a84a85b27b88cd5583899c59940bcc126caca97eb2a9df6aa00c49"},
+ {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5433fab222fb072237df3f637d01b81f040a07dcac1cb4a5c75c7aa9ed0bef1"},
+ {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8c593c6e71c07866ec6bfb790e202a833eeec885022296aff6b9e0b92d6a70e"},
+ {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d32894d4c6877a87ae00c6b915b609406819dce8bc0d4e962e4de2784e567e"},
+ {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:798e46eed9eb10c3adbbacbd3bdb5ecd4cf7064e453d00dbef08802dae6937ff"},
+ {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f1368f0a6719ea80013a4eb90ba72e75d7ea67cfc7846db2ca504f3df0169a"},
+ {file = "jiter-0.12.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65f04a9d0b4406f7e51279710b27484af411896246200e461d80d3ba0caa901a"},
+ {file = "jiter-0.12.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:fd990541982a24281d12b67a335e44f117e4c6cbad3c3b75c7dea68bf4ce3a67"},
+ {file = "jiter-0.12.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b111b0e9152fa7df870ecaebb0bd30240d9f7fff1f2003bcb4ed0f519941820b"},
+ {file = "jiter-0.12.0-cp314-cp314-win32.whl", hash = "sha256:a78befb9cc0a45b5a5a0d537b06f8544c2ebb60d19d02c41ff15da28a9e22d42"},
+ {file = "jiter-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:e1fe01c082f6aafbe5c8faf0ff074f38dfb911d53f07ec333ca03f8f6226debf"},
+ {file = "jiter-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:d72f3b5a432a4c546ea4bedc84cce0c3404874f1d1676260b9c7f048a9855451"},
+ {file = "jiter-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e6ded41aeba3603f9728ed2b6196e4df875348ab97b28fc8afff115ed42ba7a7"},
+ {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a947920902420a6ada6ad51892082521978e9dd44a802663b001436e4b771684"},
+ {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:add5e227e0554d3a52cf390a7635edaffdf4f8fce4fdbcef3cc2055bb396a30c"},
+ {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9b1cda8fcb736250d7e8711d4580ebf004a46771432be0ae4796944b5dfa5d"},
+ {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb12a2223fe0135c7ff1356a143d57f95bbf1f4a66584f1fc74df21d86b993"},
+ {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c596cc0f4cb574877550ce4ecd51f8037469146addd676d7c1a30ebe6391923f"},
+ {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ab4c823b216a4aeab3fdbf579c5843165756bd9ad87cc6b1c65919c4715f783"},
+ {file = "jiter-0.12.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e427eee51149edf962203ff8db75a7514ab89be5cb623fb9cea1f20b54f1107b"},
+ {file = "jiter-0.12.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:edb868841f84c111255ba5e80339d386d937ec1fdce419518ce1bd9370fac5b6"},
+ {file = "jiter-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8bbcfe2791dfdb7c5e48baf646d37a6a3dcb5a97a032017741dea9f817dca183"},
+ {file = "jiter-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2fa940963bf02e1d8226027ef461e36af472dea85d36054ff835aeed944dd873"},
+ {file = "jiter-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:506c9708dd29b27288f9f8f1140c3cb0e3d8ddb045956d7757b1fa0e0f39a473"},
+ {file = "jiter-0.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c9d28b218d5f9e5f69a0787a196322a5056540cb378cac8ff542b4fa7219966c"},
+ {file = "jiter-0.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0ee12028daf8cfcf880dd492349a122a64f42c059b6c62a2b0c96a83a8da820"},
+ {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b135ebe757a82d67ed2821526e72d0acf87dd61f6013e20d3c45b8048af927b"},
+ {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15d7fafb81af8a9e3039fc305529a61cd933eecee33b4251878a1c89859552a3"},
+ {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92d1f41211d8a8fe412faad962d424d334764c01dac6691c44691c2e4d3eedaf"},
+ {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a64a48d7c917b8f32f25c176df8749ecf08cec17c466114727efe7441e17f6d"},
+ {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:122046f3b3710b85de99d9aa2f3f0492a8233a2f54a64902b096efc27ea747b5"},
+ {file = "jiter-0.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:27ec39225e03c32c6b863ba879deb427882f243ae46f0d82d68b695fa5b48b40"},
+ {file = "jiter-0.12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26b9e155ddc132225a39b1995b3b9f0fe0f79a6d5cbbeacf103271e7d309b404"},
+ {file = "jiter-0.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ab05b7c58e29bb9e60b70c2e0094c98df79a1e42e397b9bb6eaa989b7a66dd0"},
+ {file = "jiter-0.12.0-cp39-cp39-win32.whl", hash = "sha256:59f9f9df87ed499136db1c2b6c9efb902f964bed42a582ab7af413b6a293e7b0"},
+ {file = "jiter-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:d3719596a1ebe7a48a498e8d5d0c4bf7553321d4c3eee1d620628d51351a3928"},
+ {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8"},
+ {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3"},
+ {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e"},
+ {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d"},
+ {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb"},
+ {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b"},
+ {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f"},
+ {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c"},
+ {file = "jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b"},
+]
+
+[[package]]
+name = "networkx"
+version = "3.4.2"
+description = "Python package for creating and manipulating graphs and networks"
+optional = false
+python-versions = ">=3.10"
+groups = ["main"]
+files = [
+ {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"},
+ {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"},
+]
+
+[package.extras]
+default = ["matplotlib (>=3.7)", "numpy (>=1.24)", "pandas (>=2.0)", "scipy (>=1.10,!=1.11.0,!=1.11.1)"]
+developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"]
+doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.15)", "sphinx (>=7.3)", "sphinx-gallery (>=0.16)", "texext (>=0.6.7)"]
+example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=1.9)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"]
+extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"]
+test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"]
+
+[[package]]
+name = "openai"
+version = "1.109.1"
+description = "The official Python library for the openai API"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315"},
+ {file = "openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869"},
+]
+
+[package.dependencies]
+anyio = ">=3.5.0,<5"
+distro = ">=1.7.0,<2"
+httpx = ">=0.23.0,<1"
+jiter = ">=0.4.0,<1"
+pydantic = ">=1.9.0,<3"
+sniffio = "*"
+tqdm = ">4"
+typing-extensions = ">=4.11,<5"
+
+[package.extras]
+aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.8)"]
+datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
+realtime = ["websockets (>=13,<16)"]
+voice-helpers = ["numpy (>=2.0.2)", "sounddevice (>=0.5.1)"]
+
[[package]]
name = "packaging"
version = "24.1"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
]
+[[package]]
+name = "pillow"
+version = "10.4.0"
+description = "Python Imaging Library (Fork)"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"},
+ {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"},
+ {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"},
+ {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"},
+ {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"},
+ {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"},
+ {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"},
+ {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"},
+ {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"},
+ {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"},
+ {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"},
+ {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"},
+ {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"},
+ {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"},
+ {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"},
+ {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"},
+ {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"},
+ {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"},
+ {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"},
+ {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"},
+ {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"},
+ {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"},
+ {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"},
+ {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"},
+ {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"},
+ {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"},
+ {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"},
+ {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"},
+ {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"},
+ {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"},
+ {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"},
+ {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"},
+ {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"},
+ {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"},
+ {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"},
+ {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"},
+ {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"},
+ {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"},
+ {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"},
+ {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"},
+ {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"},
+ {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"},
+]
+
+[package.extras]
+docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
+fpx = ["olefile"]
+mic = ["olefile"]
+tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
+typing = ["typing-extensions ; python_version < \"3.10\""]
+xmp = ["defusedxml"]
+
[[package]]
name = "pydantic"
version = "2.9.2"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"},
{file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"},
@@ -254,7 +597,7 @@ typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""}
[package.extras]
email = ["email-validator (>=2.0.0)"]
-timezone = ["tzdata"]
+timezone = ["tzdata ; python_version >= \"3.9\" and sys_platform == \"win32\""]
[[package]]
name = "pydantic-core"
@@ -262,6 +605,7 @@ version = "2.23.4"
description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"},
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"},
@@ -357,12 +701,104 @@ files = [
[package.dependencies]
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
+[[package]]
+name = "pyqt6"
+version = "6.10.0"
+description = "Python bindings for the Qt cross platform application toolkit"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pyqt6-6.10.0-1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:54b6b022369e4e6ade8cf79c0f988558839df7b2c285f814b4567d15a0fcb756"},
+ {file = "pyqt6-6.10.0-cp39-abi3-macosx_10_14_universal2.whl", hash = "sha256:0eb82f152a83a8ae39f7d3ba580829ff7c0e8179d19d70f396853c10c8ddc5ac"},
+ {file = "pyqt6-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:43e94a0ad4713055b47b4676d23432349845729912e4f3d20ac95935931c5e6f"},
+ {file = "pyqt6-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:357da0f1465557dde249a31bc1f152320b7628a644e1d55d2db09b635394f39f"},
+ {file = "pyqt6-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:8b5e4ea573733017a76bd12ea1b53351fd7f6dc57f8abf4329c4a41fea6dde04"},
+ {file = "pyqt6-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:c2b5fc1a028e95b096f3a5966611cc8194e8e9e69984c41477417e18b5ce1362"},
+ {file = "pyqt6-6.10.0.tar.gz", hash = "sha256:710ecfd720d9a03b2c684881ae37f528e11d17e8f1bf96431d00a6a73f308e36"},
+]
+
+[package.dependencies]
+PyQt6-Qt6 = ">=6.10.0,<6.11.0"
+PyQt6-sip = ">=13.8,<14"
+
+[[package]]
+name = "pyqt6-qt6"
+version = "6.10.0"
+description = "The subset of a Qt installation needed by PyQt6."
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "pyqt6_qt6-6.10.0-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:9b48d9eba795a78d21393b1909e7a0406512038ea4667463e4882e284bf95817"},
+ {file = "pyqt6_qt6-6.10.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:768ced73dbb2c85e6d72ea63fd7409ba934d4b24580ef073a3eb16fd88d3fe70"},
+ {file = "pyqt6_qt6-6.10.0-py3-none-manylinux_2_34_x86_64.whl", hash = "sha256:cd38b281bb7229b8114f13126aacd77f831a97105fdb1d900260a48ead8c9fcd"},
+ {file = "pyqt6_qt6-6.10.0-py3-none-manylinux_2_39_aarch64.whl", hash = "sha256:497df665091451ab7fde3355e262b243d2a2d97924b899a5cbb193a0cc573b7e"},
+ {file = "pyqt6_qt6-6.10.0-py3-none-win_amd64.whl", hash = "sha256:d11bc03908cacbd2e3426289ad51dcf6d2896af6ffec595626ce9cf9b93e770d"},
+ {file = "pyqt6_qt6-6.10.0-py3-none-win_arm64.whl", hash = "sha256:7f3ae89337e905dba436c226027ebd8777d4cdeef386131ad9a1b0a53ecc1a81"},
+]
+
+[[package]]
+name = "pyqt6-sip"
+version = "13.10.2"
+description = "The sip module support for PyQt6"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pyqt6_sip-13.10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8132ec1cbbecc69d23dcff23916ec07218f1a9bbbc243bf6f1df967117ce303e"},
+ {file = "pyqt6_sip-13.10.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07f77e89d93747dda71b60c3490b00d754451729fbcbcec840e42084bf061655"},
+ {file = "pyqt6_sip-13.10.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4ffa71ddff6ef031d52cd4f88b8bba08b3516313c023c7e5825cf4a0ba598712"},
+ {file = "pyqt6_sip-13.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:e907394795e61f1174134465c889177f584336a98d7a10beade2437bf5942244"},
+ {file = "pyqt6_sip-13.10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1a6c2f168773af9e6c7ef5e52907f16297d4efd346e4c958eda54ea9135be18e"},
+ {file = "pyqt6_sip-13.10.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1d3cc9015a1bd8c8d3e86a009591e897d4d46b0c514aede7d2970a2208749cd"},
+ {file = "pyqt6_sip-13.10.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ddd578a8d975bfb5fef83751829bf09a97a1355fa1de098e4fb4d1b74ee872fc"},
+ {file = "pyqt6_sip-13.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:061d4a2eb60a603d8be7db6c7f27eb29d9cea97a09aa4533edc1662091ce4f03"},
+ {file = "pyqt6_sip-13.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:45ac06f0380b7aa4fcffd89f9e8c00d1b575dc700c603446a9774fda2dcfc0de"},
+ {file = "pyqt6_sip-13.10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:83e6a56d3e715f748557460600ec342cbd77af89ec89c4f2a68b185fa14ea46c"},
+ {file = "pyqt6_sip-13.10.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ccf197f8fa410e076936bee28ad9abadb450931d5be5625446fd20e0d8b27a6"},
+ {file = "pyqt6_sip-13.10.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:37af463dcce39285e686d49523d376994d8a2508b9acccb7616c4b117c9c4ed7"},
+ {file = "pyqt6_sip-13.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:c7b34a495b92790c70eae690d9e816b53d3b625b45eeed6ae2c0fe24075a237e"},
+ {file = "pyqt6_sip-13.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:c80cc059d772c632f5319632f183e7578cd0976b9498682833035b18a3483e92"},
+ {file = "pyqt6_sip-13.10.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8b5d06a0eac36038fa8734657d99b5fe92263ae7a0cd0a67be6acfe220a063e1"},
+ {file = "pyqt6_sip-13.10.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad376a6078da37b049fdf9d6637d71b52727e65c4496a80b753ddc8d27526aca"},
+ {file = "pyqt6_sip-13.10.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3dde8024d055f496eba7d44061c5a1ba4eb72fc95e5a9d7a0dbc908317e0888b"},
+ {file = "pyqt6_sip-13.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:0b097eb58b4df936c4a2a88a2f367c8bb5c20ff049a45a7917ad75d698e3b277"},
+ {file = "pyqt6_sip-13.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:cc6a1dfdf324efaac6e7b890a608385205e652845c62130de919fd73a6326244"},
+ {file = "pyqt6_sip-13.10.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8a76a06a8e5c5b1f17a3f6f3c834ca324877e07b960b18b8b9bbfd9c536ec658"},
+ {file = "pyqt6_sip-13.10.2-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9128d770a611200529468397d710bc972f1dcfe12bfcbb09a3ccddcd4d54fa5b"},
+ {file = "pyqt6_sip-13.10.2-cp314-cp314-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d820a0fae7315932c08f27dc0a7e33e0f50fe351001601a8eb9cf6f22b04562e"},
+ {file = "pyqt6_sip-13.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:3213bb6e102d3842a3bb7e59d5f6e55f176c80880ff0b39d0dac0cfe58313fb3"},
+ {file = "pyqt6_sip-13.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:ce33ff1f94960ad4b08035e39fa0c3c9a67070bec39ffe3e435c792721504726"},
+ {file = "pyqt6_sip-13.10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38b5823dca93377f8a4efac3cbfaa1d20229aa5b640c31cf6ebbe5c586333808"},
+ {file = "pyqt6_sip-13.10.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5506b9a795098df3b023cc7d0a37f93d3224a9c040c43804d4bc06e0b2b742b0"},
+ {file = "pyqt6_sip-13.10.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e455a181d45a28ee8d18d42243d4f470d269e6ccdee60f2546e6e71218e05bb4"},
+ {file = "pyqt6_sip-13.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:9c67ed66e21b11e04ffabe0d93bc21df22e0a5d7e2e10ebc8c1d77d2f5042991"},
+ {file = "pyqt6_sip-13.10.2.tar.gz", hash = "sha256:464ad156bf526500ce6bd05cac7a82280af6309974d816739b4a9a627156fafe"},
+]
+
+[[package]]
+name = "python-dotenv"
+version = "1.2.1"
+description = "Read key-value pairs from a .env file and set them as environment variables"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"},
+ {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"},
+]
+
+[package.extras]
+cli = ["click (>=5.0)"]
+
[[package]]
name = "replicate"
version = "1.0.2"
description = "Python client for Replicate"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "replicate-1.0.2-py3-none-any.whl", hash = "sha256:808009853d5e49f706c9a67a9f97b712c89e2c75e63947f7cc012b847c28bef2"},
{file = "replicate-1.0.2.tar.gz", hash = "sha256:faa3551a825d9eb2c0bfc0407ddab75b9e02865344168241a1d41a4e73bbc661"},
@@ -380,6 +816,7 @@ version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@@ -401,17 +838,53 @@ version = "1.3.1"
description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
+[[package]]
+name = "soupsieve"
+version = "2.8"
+description = "A modern CSS selector implementation for Beautiful Soup."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c"},
+ {file = "soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f"},
+]
+
+[[package]]
+name = "tqdm"
+version = "4.67.1"
+description = "Fast, Extensible Progress Meter"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"},
+ {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[package.extras]
+dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"]
+discord = ["requests"]
+notebook = ["ipywidgets (>=6)"]
+slack = ["slack-sdk"]
+telegram = ["requests"]
+
[[package]]
name = "typing-extensions"
version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@@ -423,18 +896,19 @@ version = "2.2.2"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
{file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
]
[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
+brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
[metadata]
-lock-version = "2.0"
+lock-version = "2.1"
python-versions = ">=3.10.0,<3.12"
-content-hash = "3e72b2d094010386fa5fcf555dce38afaf78c71b086a23bec0ba978d018f7a17"
+content-hash = "1440dc690a30b28b479bc1ebd2f9bbd813254345e37297f3b672678b2f600894"
diff --git a/pyproject.toml b/pyproject.toml
index 3716689..12aed94 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -10,6 +10,11 @@ requests = "^2.32.3"
replicate = "^1.0.2"
python-dotenv = "^1.0.0"
Pillow = "^10.2.0"
+PyQt6 = "^6.6.0"
+anthropic = "^0.39.0"
+openai = "^1.54.0"
+networkx = "^3.1"
+beautifulsoup4 = "^4.12.0"
[tool.pyright]
# https://github.com/microsoft/pyright/blob/main/docs/configuration.md
diff --git a/shared_utils.py b/shared_utils.py
index 254bb6b..3c88cfe 100644
--- a/shared_utils.py
+++ b/shared_utils.py
@@ -15,6 +15,7 @@
from together import Together
from openai import OpenAI
import re
+from typing import Optional, Dict, List, Any
try:
from bs4 import BeautifulSoup
except ImportError:
@@ -23,13 +24,35 @@
# Load environment variables
load_dotenv()
+# Configure logging
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+)
+logger = logging.getLogger(__name__)
+
+# Import configuration constants
+from config import (
+ API_MAX_TOKENS, API_TEMPERATURE, API_TIMEOUT,
+ LLAMA_MAX_TOKENS, LLAMA_TEMPERATURE, LLAMA_TOP_P, LLAMA_REPETITION_PENALTY, LLAMA_MAX_HISTORY,
+ DEEPSEEK_MAX_TOKENS, DEEPSEEK_TEMPERATURE,
+ TOGETHER_MAX_TOKENS, TOGETHER_TEMPERATURE, TOGETHER_TOP_P,
+ IMAGE_WIDTH, IMAGE_HEIGHT,
+ SORA_POLL_INTERVAL_SECONDS
+)
+
# Initialize Anthropic client with API key
anthropic = Anthropic(api_key=os.getenv('ANTHROPIC_API_KEY'))
# Initialize OpenAI client
openai_client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
-def call_claude_api(prompt, messages, model_id, system_prompt=None):
+def call_claude_api(
+ prompt: str,
+ messages: List[Dict[str, Any]],
+ model_id: str,
+ system_prompt: Optional[str] = None
+) -> str:
"""Call the Claude API with the given messages and prompt"""
api_key = os.getenv("ANTHROPIC_API_KEY")
if not api_key:
@@ -40,8 +63,8 @@ def call_claude_api(prompt, messages, model_id, system_prompt=None):
# Ensure we have a system prompt
payload = {
"model": model_id,
- "max_tokens": 4000,
- "temperature": 1
+ "max_tokens": API_MAX_TOKENS,
+ "temperature": API_TEMPERATURE
}
# Set system if provided
@@ -92,14 +115,25 @@ def call_claude_api(prompt, messages, model_id, system_prompt=None):
if content_item.get('type') == 'text':
return content_item.get('text', '')
# Fallback if no text type content is found
+ logger.warning("No text type content found in Claude API response")
return str(data['content'])
+ logger.error("No content in Claude API response")
return "No content in response"
+ except requests.exceptions.RequestException as e:
+ logger.error(f"Network error calling Claude API: {e}")
+ return f"Error calling Claude API: {str(e)}"
except Exception as e:
+ logger.exception(f"Unexpected error calling Claude API: {e}")
return f"Error calling Claude API: {str(e)}"
-def call_llama_api(prompt, conversation_history, model, system_prompt):
- # Only use the last 3 exchanges to prevent context length issues
- recent_history = conversation_history[-10:] if len(conversation_history) > 10 else conversation_history
+def call_llama_api(
+ prompt: str,
+ conversation_history: List[Dict[str, Any]],
+ model: str,
+ system_prompt: str
+) -> Optional[str]:
+ # Only use the last N exchanges to prevent context length issues
+ recent_history = conversation_history[-LLAMA_MAX_HISTORY:] if len(conversation_history) > LLAMA_MAX_HISTORY else conversation_history
# Format the conversation history for LLaMA
formatted_history = ""
@@ -118,10 +152,10 @@ def call_llama_api(prompt, conversation_history, model, system_prompt):
input={
"prompt": formatted_history,
"system_prompt": system_prompt,
- "max_tokens": 3000,
- "temperature": 1.1,
- "top_p": 0.99,
- "repetition_penalty": 1.0
+ "max_tokens": LLAMA_MAX_TOKENS,
+ "temperature": LLAMA_TEMPERATURE,
+ "top_p": LLAMA_TOP_P,
+ "repetition_penalty": LLAMA_REPETITION_PENALTY
},
stream=True # Enable streaming
):
@@ -133,11 +167,19 @@ def call_llama_api(prompt, conversation_history, model, system_prompt):
# Join all chunks for the final response
response = ''.join(response_chunks)
return response
+ except replicate.exceptions.ReplicateError as e:
+ logger.error(f"Replicate API error calling LLaMA: {e}")
+ return None
except Exception as e:
- print(f"Error calling LLaMA API: {e}")
+ logger.exception(f"Unexpected error calling LLaMA API: {e}")
return None
-def call_openai_api(prompt, conversation_history, model, system_prompt):
+def call_openai_api(
+ prompt: str,
+ conversation_history: List[Dict[str, Any]],
+ model: str,
+ system_prompt: str
+) -> Optional[str]:
try:
messages = []
@@ -152,10 +194,9 @@ def call_openai_api(prompt, conversation_history, model, system_prompt):
response = openai.chat.completions.create(
model=model,
messages=messages,
- # Increase max_tokens and add n parameter
- max_tokens=4000,
+ max_tokens=API_MAX_TOKENS,
n=1,
- temperature=1,
+ temperature=API_TEMPERATURE,
stream=True
)
@@ -166,12 +207,20 @@ def call_openai_api(prompt, conversation_history, model, system_prompt):
full_reply = ''.join(collected_messages)
return full_reply
-
+
+ except openai.APIError as e:
+ logger.error(f"OpenAI API error: {e}")
+ return None
except Exception as e:
- print(f"Error calling OpenAI API: {e}")
+ logger.exception(f"Unexpected error calling OpenAI API: {e}")
return None
-def call_openrouter_api(prompt, conversation_history, model, system_prompt):
+def call_openrouter_api(
+ prompt: str,
+ conversation_history: List[Dict[str, Any]],
+ model: str,
+ system_prompt: str
+) -> Optional[str]:
"""Call the OpenRouter API to access various LLM models."""
try:
headers = {
@@ -198,8 +247,8 @@ def call_openrouter_api(prompt, conversation_history, model, system_prompt):
payload = {
"model": model, # Using the exact model name from config
"messages": messages,
- "temperature": 1,
- "max_tokens": 4000,
+ "temperature": API_TEMPERATURE,
+ "max_tokens": API_MAX_TOKENS,
"stream": False
}
@@ -211,7 +260,7 @@ def call_openrouter_api(prompt, conversation_history, model, system_prompt):
"https://openrouter.ai/api/v1/chat/completions",
headers=headers,
json=payload,
- timeout=60 # Add timeout
+ timeout=API_TIMEOUT
)
print(f"Response status: {response.status_code}")
@@ -251,12 +300,17 @@ def call_openrouter_api(prompt, conversation_history, model, system_prompt):
print(f"Error type: {type(e)}")
return f"Error: {str(e)}"
-def call_replicate_api(prompt, conversation_history, model, gui=None):
+def call_replicate_api(
+ prompt: str,
+ conversation_history: List[Dict[str, Any]],
+ model: str,
+ gui: Optional[Any] = None
+) -> Optional[Dict[str, Any]]:
try:
# Only use the prompt, ignore conversation history
input_params = {
- "width": 1024,
- "height": 1024,
+ "width": IMAGE_WIDTH,
+ "height": IMAGE_HEIGHT,
"prompt": prompt
}
@@ -292,12 +346,23 @@ def call_replicate_api(prompt, conversation_history, model, gui=None):
"image_url": image_url,
"image_path": str(image_path)
}
-
+
+ except replicate.exceptions.ReplicateError as e:
+ logger.error(f"Replicate API error calling Flux: {e}")
+ return None
+ except requests.exceptions.RequestException as e:
+ logger.error(f"Network error downloading image from Flux: {e}")
+ return None
except Exception as e:
- print(f"Error calling Flux API: {e}")
+ logger.exception(f"Unexpected error calling Flux API: {e}")
return None
-def call_deepseek_api(prompt, conversation_history, model, system_prompt):
+def call_deepseek_api(
+ prompt: str,
+ conversation_history: List[Dict[str, Any]],
+ model: str,
+ system_prompt: str
+) -> Optional[Dict[str, Any]]:
"""Call the DeepSeek model through Replicate API."""
try:
# Format messages for the conversation history
@@ -331,8 +396,8 @@ def call_deepseek_api(prompt, conversation_history, model, system_prompt):
"deepseek-ai/deepseek-r1",
input={
"prompt": formatted_history,
- "max_tokens": 8000,
- "temperature": 1
+ "max_tokens": DEEPSEEK_MAX_TOKENS,
+ "temperature": DEEPSEEK_TEMPERATURE
}
)
@@ -406,19 +471,21 @@ def call_deepseek_api(prompt, conversation_history, model, system_prompt):
result["html_contribution"] = html_contribution
return result
-
+
+ except replicate.exceptions.ReplicateError as e:
+ logger.error(f"Replicate API error calling DeepSeek: {e}")
+ return None
except Exception as e:
- print(f"Error calling DeepSeek via Replicate: {e}")
- print(f"Error type: {type(e)}")
+ logger.exception(f"Unexpected error calling DeepSeek via Replicate: {e}")
return None
-def setup_image_directory():
+def setup_image_directory() -> Path:
"""Create an 'images' directory in the project root if it doesn't exist"""
image_dir = Path("images")
image_dir.mkdir(exist_ok=True)
return image_dir
-def cleanup_old_images(image_dir, max_age_hours=24):
+def cleanup_old_images(image_dir: Path, max_age_hours: int = 24) -> None:
"""Remove images older than max_age_hours"""
current_time = datetime.now()
for image_file in image_dir.glob("*.jpg"):
@@ -426,7 +493,7 @@ def cleanup_old_images(image_dir, max_age_hours=24):
if (current_time - file_age).total_seconds() > max_age_hours * 3600:
image_file.unlink()
-def load_ai_memory(ai_number):
+def load_ai_memory(ai_number: int) -> List[Dict[str, str]]:
"""Load AI conversation memory from JSON files"""
try:
memory_path = f"memory/ai{ai_number}/conversations.json"
@@ -440,7 +507,7 @@ def load_ai_memory(ai_number):
print(f"Error loading AI{ai_number} memory: {e}")
return []
-def create_memory_prompt(conversations):
+def create_memory_prompt(conversations: List[Dict[str, str]]) -> str:
"""Convert memory JSON into conversation examples"""
if not conversations:
return ""
@@ -456,12 +523,13 @@ def create_memory_prompt(conversations):
return prompt
-def print_conversation_state(conversation):
+def print_conversation_state(conversation: List[Dict[str, Any]]) -> None:
+ """Print current conversation state for debugging"""
print("Current conversation state:")
for message in conversation:
print(f"{message['role']}: {message['content'][:50]}...") # Print first 50 characters of each message
-def call_claude_vision_api(image_url):
+def call_claude_vision_api(image_url: str) -> Optional[str]:
"""Have Claude analyze the generated image"""
try:
response = anthropic.messages.create(
@@ -486,10 +554,11 @@ def call_claude_vision_api(image_url):
)
return response.content[0].text
except Exception as e:
- print(f"Error in vision analysis: {e}")
+ logger.exception(f"Error in Claude vision analysis: {e}")
return None
-def list_together_models():
+def list_together_models() -> None:
+ """List available Together AI models"""
try:
headers = {
"Authorization": f"Bearer {os.getenv('TOGETHERAI_API_KEY')}",
@@ -512,7 +581,8 @@ def list_together_models():
except Exception as e:
print(f"Error listing models: {str(e)}")
-def start_together_model(model_id):
+def start_together_model(model_id: str) -> bool:
+ """Start a Together AI model"""
try:
headers = {
"Authorization": f"Bearer {os.getenv('TOGETHERAI_API_KEY')}",
@@ -544,7 +614,13 @@ def start_together_model(model_id):
print(f"Error starting model: {str(e)}")
return False
-def call_together_api(prompt, conversation_history, model, system_prompt):
+def call_together_api(
+ prompt: str,
+ conversation_history: List[Dict[str, Any]],
+ model: str,
+ system_prompt: str
+) -> Optional[str]:
+ """Call the Together AI API"""
try:
headers = {
"Authorization": f"Bearer {os.getenv('TOGETHERAI_API_KEY')}",
@@ -567,9 +643,9 @@ def call_together_api(prompt, conversation_history, model, system_prompt):
payload = {
"model": model,
"messages": messages,
- "max_tokens": 500,
- "temperature": 0.9,
- "top_p": 0.95,
+ "max_tokens": TOGETHER_MAX_TOKENS,
+ "temperature": TOGETHER_TEMPERATURE,
+ "top_p": TOGETHER_TOP_P,
}
response = requests.post(
@@ -590,27 +666,13 @@ def call_together_api(prompt, conversation_history, model, system_prompt):
print(f"Error calling Together API: {str(e)}")
return None
-def read_shared_html(*args, **kwargs):
- return ""
-
-def update_shared_html(*args, **kwargs):
- return False
-
-def open_html_in_browser(file_path="conversation_full.html"):
+def open_html_in_browser(file_path: str = "conversation_full.html") -> None:
+ """Open HTML file in default browser"""
import webbrowser, os
full_path = os.path.abspath(file_path)
webbrowser.open('file://' + full_path)
-def create_initial_living_document(*args, **kwargs):
- return ""
-
-def read_living_document(*args, **kwargs):
- return ""
-
-def process_living_document_edits(result, model_name):
- return result
-
-def generate_image_from_text(text, model="gpt-image-1"):
+def generate_image_from_text(text: str, model: str = "gpt-image-1") -> Dict[str, Any]:
"""Generate an image based on text using OpenAI's image generation API"""
try:
# Create a directory for the images if it doesn't exist
@@ -643,8 +705,14 @@ def generate_image_from_text(text, model="gpt-image-1"):
"image_path": str(image_path),
"timestamp": timestamp
}
+ except openai.APIError as e:
+ logger.error(f"OpenAI API error generating image: {e}")
+ return {
+ "success": False,
+ "error": str(e)
+ }
except Exception as e:
- print(f"Error generating image: {e}")
+ logger.exception(f"Unexpected error generating image: {e}")
return {
"success": False,
"error": str(e)
diff --git a/~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json b/~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
new file mode 100644
index 0000000..91deed5
--- /dev/null
+++ b/~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
@@ -0,0 +1,35 @@
+{
+ "mcpServers": {
+ "github.com/chroma-core/chroma": {
+ "command": "python",
+ "args": [
+ "/Users/patrickgallowaypro/Documents/Cline/MCP/chroma-server/chroma_mcp_server.py"
+ ],
+ "cwd": "/Users/patrickgallowaypro/Documents/Cline/MCP/chroma-server",
+ "disabled": false,
+ "autoApprove": []
+ },
+ "github.com/github/github-mcp-server": {
+ "command": "docker",
+ "args": [
+ "run",
+ "-i",
+ "--rm",
+ "-e",
+ "GITHUB_PERSONAL_ACCESS_TOKEN",
+ "ghcr.io/github/github-mcp-server"
+ ],
+ "env": {
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}"
+ }
+ }
+ },
+ "inputs": [
+ {
+ "type": "promptString",
+ "id": "github_token",
+ "description": "GitHub Personal Access Token",
+ "password": true
+ }
+ ]
+}