Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- .claude/settings.local.json +47 -1
- .env.example +15 -0
- .gitattributes +2 -0
- README.md +21 -3
- auto_diffusers/__init__.py +20 -0
- auto_diffusers/__pycache__/__init__.cpython-311.pyc +0 -0
- auto_diffusers/__pycache__/__init__.cpython-312.pyc +0 -0
- auto_diffusers/core/__init__.py +14 -0
- auto_diffusers/core/__pycache__/__init__.cpython-311.pyc +0 -0
- auto_diffusers/core/__pycache__/__init__.cpython-312.pyc +0 -0
- auto_diffusers/core/__pycache__/generator.cpython-311.pyc +0 -0
- auto_diffusers/core/__pycache__/generator.cpython-312.pyc +0 -0
- auto_diffusers/core/__pycache__/knowledge_base.cpython-311.pyc +0 -0
- auto_diffusers/core/__pycache__/knowledge_base.cpython-312.pyc +0 -0
- auto_diffusers/core/generator.py +564 -0
- auto_diffusers/core/knowledge_base.py +206 -0
- auto_diffusers/hardware/__init__.py +14 -0
- auto_diffusers/hardware/__pycache__/__init__.cpython-311.pyc +0 -0
- auto_diffusers/hardware/__pycache__/__init__.cpython-312.pyc +0 -0
- auto_diffusers/hardware/__pycache__/detector.cpython-311.pyc +0 -0
- auto_diffusers/hardware/__pycache__/detector.cpython-312.pyc +0 -0
- auto_diffusers/hardware/__pycache__/memory_calculator.cpython-311.pyc +0 -0
- auto_diffusers/hardware/__pycache__/memory_calculator.cpython-312.pyc +0 -0
- auto_diffusers/hardware/detector.py +196 -0
- auto_diffusers/hardware/memory_calculator.py +276 -0
- auto_diffusers/ui/__init__.py +12 -0
- auto_diffusers/ui/__pycache__/__init__.cpython-311.pyc +0 -0
- auto_diffusers/ui/__pycache__/__init__.cpython-312.pyc +0 -0
- auto_diffusers/ui/__pycache__/gradio_interface.cpython-311.pyc +3 -0
- auto_diffusers/ui/__pycache__/gradio_interface.cpython-312.pyc +3 -0
- auto_diffusers/ui/gradio_interface.py +0 -0
- auto_diffusers/utils/__init__.py +14 -0
- auto_diffusers/utils/logging_config.py +162 -0
- main.py +10 -0
- scripts/__init__.py +3 -0
- scripts/launch.py +126 -0
- tests/__init__.py +3 -0
.claude/settings.local.json
CHANGED
@@ -79,7 +79,53 @@
|
|
79 |
"Bash(grep -n \"section-header\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)",
|
80 |
"Bash(grep -n \"memory-card\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)",
|
81 |
"Bash(grep -n -A 5 \"Configure your system hardware\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)",
|
82 |
-
"Bash(grep -n -A 5 \"Configure the AI model\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
],
|
84 |
"deny": []
|
85 |
},
|
|
|
79 |
"Bash(grep -n \"section-header\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)",
|
80 |
"Bash(grep -n \"memory-card\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)",
|
81 |
"Bash(grep -n -A 5 \"Configure your system hardware\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)",
|
82 |
+
"Bash(grep -n -A 5 \"Configure the AI model\" /Users/deep-diver/Developers/auto-diffusers/gradio_app.py)",
|
83 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/model_memory_calculator.py)",
|
84 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/flux_optimized_apple_silicon.py)",
|
85 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/generated_optimized.py)",
|
86 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/sample_optimized_apple_silicon.py)",
|
87 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/test_flux_specific.py)",
|
88 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/test_generation.py)",
|
89 |
+
"Bash(grep -n \"debug_config\\|setup_debug_logging\" /Users/deep-diver/Developers/auto-diffusers/launch_gradio.py)",
|
90 |
+
"Bash(rm -rf /Users/deep-diver/Developers/auto-diffusers/logs/*)",
|
91 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/auto_diffusers.log)",
|
92 |
+
"Bash(mkdir -p auto_diffusers/{core,hardware,ui,utils} scripts docs tests/{test_core,test_hardware,test_ui})",
|
93 |
+
"Bash(mv auto_diffusers.py auto_diffusers/core/generator.py)",
|
94 |
+
"Bash(mv optimization_knowledge.py auto_diffusers/core/knowledge_base.py)",
|
95 |
+
"Bash(mv hardware_detector.py auto_diffusers/hardware/detector.py)",
|
96 |
+
"Bash(mv simple_memory_calculator.py auto_diffusers/hardware/memory_calculator.py)",
|
97 |
+
"Bash(mv gradio_app.py auto_diffusers/ui/gradio_interface.py)",
|
98 |
+
"Bash(mv debug_config.py auto_diffusers/utils/logging_config.py)",
|
99 |
+
"Bash(mv launch_gradio.py scripts/launch.py)",
|
100 |
+
"Bash(mv *.md docs/)",
|
101 |
+
"Bash(grep -n \"gradio_app\" /Users/deep-diver/Developers/auto-diffusers/scripts/launch.py)",
|
102 |
+
"Bash(chmod +x /Users/deep-diver/Developers/auto-diffusers/main.py)",
|
103 |
+
"Bash(python -c \"from auto_diffusers import AutoDiffusersGenerator, HardwareDetector, SimpleMemoryCalculator; print('β
Core imports work!')\")",
|
104 |
+
"Bash(python -c \"from auto_diffusers.ui.gradio_interface import create_gradio_interface; print('β
UI imports work!')\")",
|
105 |
+
"Bash(ls /Users/deep-diver/Developers/auto-diffusers/docs/)",
|
106 |
+
"Bash(find /Users/deep-diver/Developers/auto-diffusers -name \"*.md\" -not -path \"*/docs/*\")",
|
107 |
+
"Bash(rm /Users/deep-diver/Developers/auto-diffusers/setup.py)",
|
108 |
+
"Bash(ls -la /Users/deep-diver/Developers/auto-diffusers/)",
|
109 |
+
"Bash(grep -n -A 10 -B 2 \"Apple Silicon.*choices\" /Users/deep-diver/Developers/auto-diffusers/auto_diffusers/ui/gradio_interface.py)",
|
110 |
+
"Bash(grep -n -A 20 \"def on_gpu_vendor_change\" /Users/deep-diver/Developers/auto-diffusers/auto_diffusers/ui/gradio_interface.py)",
|
111 |
+
"Bash(grep -n -A 35 \"def on_gpu_vendor_change\" /Users/deep-diver/Developers/auto-diffusers/auto_diffusers/ui/gradio_interface.py)",
|
112 |
+
"Bash(python -c \"from auto_diffusers.ui.gradio_interface import create_gradio_interface; print('β
Updated interface imports work!')\")",
|
113 |
+
"Bash(python -c \"from auto_diffusers.ui.gradio_interface import create_gradio_interface; print('β
Fixed interface imports work!')\")",
|
114 |
+
"Bash(python main.py --auto-hardware-detection)",
|
115 |
+
"Bash(GRADIO_SERVER_PORT=7861 python main.py --auto-hardware-detection)",
|
116 |
+
"Bash(python main.py --auto-hardware-detection --port 7861)",
|
117 |
+
"Bash(rg -n \"π§ GPU Model|gpu_model\" auto_diffusers/ui/gradio_interface.py)",
|
118 |
+
"Bash(grep -n \"π§ GPU Model\\|gpu_model\" auto_diffusers/ui/gradio_interface.py)",
|
119 |
+
"Bash(grep -n -A 10 \"def on_gpu_model_change\" auto_diffusers/ui/gradio_interface.py)",
|
120 |
+
"Bash(grep -n -A 5 \"def update_hardware_accordion\" auto_diffusers/ui/gradio_interface.py)",
|
121 |
+
"Bash(grep -n -A 5 \"def generate_with_combined_gpu_name\" auto_diffusers/ui/gradio_interface.py)",
|
122 |
+
"Bash(grep -n -A 5 \"def generate_and_store_code\" auto_diffusers/ui/gradio_interface.py)",
|
123 |
+
"Bash(grep -n -A 3 -B 3 \"gpu_series.*change\\|gpu_model.*change\" auto_diffusers/ui/gradio_interface.py)",
|
124 |
+
"Bash(grep -n -A 5 -B 5 \"inputs=\\[.*gpu_model\" auto_diffusers/ui/gradio_interface.py)",
|
125 |
+
"Bash(grep -n -A 10 \"generate_btn.click\" auto_diffusers/ui/gradio_interface.py)",
|
126 |
+
"Bash(ls -la)",
|
127 |
+
"Bash(find . -name \"hardware_detector.py\" -o -name \"auto_diffusers.py\")",
|
128 |
+
"Bash(grep -r \"Interactive Mode\" .)"
|
129 |
],
|
130 |
"deny": []
|
131 |
},
|
.env.example
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Auto Diffusers Configuration
|
2 |
+
# Copy this file to .env and fill in your values
|
3 |
+
|
4 |
+
# Google Gemini API Key (required)
|
5 |
+
GOOGLE_API_KEY=your_google_gemini_api_key_here
|
6 |
+
|
7 |
+
# Debug Configuration (optional)
|
8 |
+
DEBUG_LEVEL=INFO
|
9 |
+
LOG_TO_FILE=true
|
10 |
+
LOG_TO_CONSOLE=true
|
11 |
+
|
12 |
+
# Application Configuration (optional)
|
13 |
+
# PORT=7860
|
14 |
+
# HOST=0.0.0.0
|
15 |
+
# SHARE=true
|
.gitattributes
CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
auto_diffusers/ui/__pycache__/gradio_interface.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
37 |
+
auto_diffusers/ui/__pycache__/gradio_interface.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
@@ -37,14 +37,32 @@ export GEMINI_API_KEY="your_api_key_here"
|
|
37 |
|
38 |
### Interactive Mode
|
39 |
```bash
|
40 |
-
python
|
41 |
```
|
42 |
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
```bash
|
45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
```
|
47 |
|
|
|
48 |
### Programmatic Usage
|
49 |
```python
|
50 |
from auto_diffusers import AutoDiffusersGenerator
|
|
|
37 |
|
38 |
### Interactive Mode
|
39 |
```bash
|
40 |
+
python main.py
|
41 |
```
|
42 |
|
43 |
+
**Available Options:**
|
44 |
+
- `--auto-hardware-detection` - Enable automatic hardware detection on startup (disabled by default)
|
45 |
+
- `--no-auto-hardware-detection` - Explicitly disable automatic hardware detection
|
46 |
+
- `--port PORT` - Specify port to run the server on (default: 7860)
|
47 |
+
- `--host HOST` - Specify host to run the server on (default: 0.0.0.0)
|
48 |
+
- `--no-share` - Disable public sharing of the interface (local access only)
|
49 |
+
|
50 |
+
**Examples:**
|
51 |
```bash
|
52 |
+
# Launch with auto hardware detection enabled
|
53 |
+
python main.py --auto-hardware-detection
|
54 |
+
|
55 |
+
# Launch on a different port
|
56 |
+
python main.py --port 8080
|
57 |
+
|
58 |
+
# Launch for local access only
|
59 |
+
python main.py --no-share
|
60 |
+
|
61 |
+
# Combine options
|
62 |
+
python main.py --auto-hardware-detection --port 8080 --no-share
|
63 |
```
|
64 |
|
65 |
+
|
66 |
### Programmatic Usage
|
67 |
```python
|
68 |
from auto_diffusers import AutoDiffusersGenerator
|
auto_diffusers/__init__.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Auto Diffusers - Hardware-Optimized Code Generator
|
3 |
+
|
4 |
+
A tool for generating hardware-optimized diffusion model code using AI.
|
5 |
+
"""
|
6 |
+
|
7 |
+
__version__ = "1.0.0"
|
8 |
+
__author__ = "Auto-Diffusers Team"
|
9 |
+
__description__ = "Hardware-Optimized Diffusion Model Code Generator"
|
10 |
+
|
11 |
+
# Main exports
|
12 |
+
from .core.generator import AutoDiffusersGenerator
|
13 |
+
from .hardware.detector import HardwareDetector
|
14 |
+
from .hardware.memory_calculator import SimpleMemoryCalculator
|
15 |
+
|
16 |
+
__all__ = [
|
17 |
+
"AutoDiffusersGenerator",
|
18 |
+
"HardwareDetector",
|
19 |
+
"SimpleMemoryCalculator"
|
20 |
+
]
|
auto_diffusers/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (768 Bytes). View file
|
|
auto_diffusers/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (702 Bytes). View file
|
|
auto_diffusers/core/__init__.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Core application logic and AI integration.
|
3 |
+
|
4 |
+
This module contains the main generator class and knowledge base
|
5 |
+
for the Auto Diffusers application.
|
6 |
+
"""
|
7 |
+
|
8 |
+
from .generator import AutoDiffusersGenerator
|
9 |
+
from .knowledge_base import get_optimization_guide
|
10 |
+
|
11 |
+
__all__ = [
|
12 |
+
"AutoDiffusersGenerator",
|
13 |
+
"get_optimization_guide"
|
14 |
+
]
|
auto_diffusers/core/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (544 Bytes). View file
|
|
auto_diffusers/core/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (503 Bytes). View file
|
|
auto_diffusers/core/__pycache__/generator.cpython-311.pyc
ADDED
Binary file (32.1 kB). View file
|
|
auto_diffusers/core/__pycache__/generator.cpython-312.pyc
ADDED
Binary file (28.5 kB). View file
|
|
auto_diffusers/core/__pycache__/knowledge_base.cpython-311.pyc
ADDED
Binary file (6.41 kB). View file
|
|
auto_diffusers/core/__pycache__/knowledge_base.cpython-312.pyc
ADDED
Binary file (6.33 kB). View file
|
|
auto_diffusers/core/generator.py
ADDED
@@ -0,0 +1,564 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
import google.generativeai as genai
|
5 |
+
from ..hardware.detector import HardwareDetector
|
6 |
+
from .knowledge_base import get_optimization_guide
|
7 |
+
from typing import Dict, List
|
8 |
+
import json
|
9 |
+
|
10 |
+
# Optional imports for tool calling
|
11 |
+
try:
|
12 |
+
import requests
|
13 |
+
from urllib.parse import urljoin, urlparse
|
14 |
+
from bs4 import BeautifulSoup
|
15 |
+
TOOLS_AVAILABLE = True
|
16 |
+
except ImportError:
|
17 |
+
TOOLS_AVAILABLE = False
|
18 |
+
requests = None
|
19 |
+
urlparse = None
|
20 |
+
BeautifulSoup = None
|
21 |
+
|
22 |
+
load_dotenv()
|
23 |
+
|
24 |
+
# Configure logging
|
25 |
+
logging.basicConfig(
|
26 |
+
level=logging.DEBUG,
|
27 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
28 |
+
handlers=[
|
29 |
+
logging.FileHandler('auto_diffusers.log'),
|
30 |
+
logging.StreamHandler()
|
31 |
+
]
|
32 |
+
)
|
33 |
+
logger = logging.getLogger(__name__)
|
34 |
+
|
35 |
+
|
36 |
+
class AutoDiffusersGenerator:
|
37 |
+
def __init__(self, api_key: str):
|
38 |
+
logger.info("Initializing AutoDiffusersGenerator")
|
39 |
+
logger.debug(f"API key length: {len(api_key) if api_key else 'None'}")
|
40 |
+
|
41 |
+
try:
|
42 |
+
genai.configure(api_key=api_key)
|
43 |
+
|
44 |
+
# Define tools for Gemini to use (if available)
|
45 |
+
if TOOLS_AVAILABLE:
|
46 |
+
self.tools = self._create_tools()
|
47 |
+
# Initialize model with tools
|
48 |
+
self.model = genai.GenerativeModel(
|
49 |
+
'gemini-2.5-flash-preview-05-20',
|
50 |
+
tools=self.tools
|
51 |
+
)
|
52 |
+
logger.info("Successfully configured Gemini AI model with tools")
|
53 |
+
else:
|
54 |
+
self.tools = None
|
55 |
+
# Initialize model without tools
|
56 |
+
self.model = genai.GenerativeModel('gemini-2.5-flash-preview-05-20')
|
57 |
+
logger.warning("Tool calling dependencies not available, running without tools")
|
58 |
+
except Exception as e:
|
59 |
+
logger.error(f"Failed to configure Gemini AI: {e}")
|
60 |
+
raise
|
61 |
+
|
62 |
+
try:
|
63 |
+
self.hardware_detector = HardwareDetector()
|
64 |
+
logger.info("Hardware detector initialized successfully")
|
65 |
+
except Exception as e:
|
66 |
+
logger.error(f"Failed to initialize hardware detector: {e}")
|
67 |
+
raise
|
68 |
+
|
69 |
+
def _create_tools(self):
|
70 |
+
"""Create function tools for Gemini to use."""
|
71 |
+
logger.debug("Creating tools for Gemini")
|
72 |
+
|
73 |
+
if not TOOLS_AVAILABLE:
|
74 |
+
logger.warning("Tools dependencies not available, returning empty tools")
|
75 |
+
return []
|
76 |
+
|
77 |
+
def fetch_huggingface_docs(url: str) -> str:
|
78 |
+
"""Fetch documentation from HuggingFace URLs."""
|
79 |
+
logger.info("π TOOL CALL: fetch_huggingface_docs")
|
80 |
+
logger.info(f"π Requested URL: {url}")
|
81 |
+
|
82 |
+
try:
|
83 |
+
# Validate URL is from HuggingFace
|
84 |
+
parsed = urlparse(url)
|
85 |
+
logger.debug(f"URL validation - Domain: {parsed.netloc}, Path: {parsed.path}")
|
86 |
+
|
87 |
+
if not any(domain in parsed.netloc for domain in ['huggingface.co', 'hf.co']):
|
88 |
+
error_msg = "Error: URL must be from huggingface.co domain"
|
89 |
+
logger.warning(f"β URL validation failed: {error_msg}")
|
90 |
+
return error_msg
|
91 |
+
|
92 |
+
logger.info(f"β
URL validation passed for domain: {parsed.netloc}")
|
93 |
+
|
94 |
+
headers = {
|
95 |
+
'User-Agent': 'Auto-Diffusers-Config/1.0 (Educational Tool)'
|
96 |
+
}
|
97 |
+
|
98 |
+
logger.info(f"π Fetching content from: {url}")
|
99 |
+
response = requests.get(url, headers=headers, timeout=10)
|
100 |
+
response.raise_for_status()
|
101 |
+
logger.info(f"β
HTTP {response.status_code} - Successfully fetched {len(response.text)} characters")
|
102 |
+
|
103 |
+
# Parse HTML content
|
104 |
+
logger.info("π Parsing HTML content...")
|
105 |
+
soup = BeautifulSoup(response.text, 'html.parser')
|
106 |
+
|
107 |
+
# Extract main content (remove navigation, footers, etc.)
|
108 |
+
content = ""
|
109 |
+
element_count = 0
|
110 |
+
for element in soup.find_all(['p', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'li']):
|
111 |
+
text = element.get_text().strip()
|
112 |
+
if text:
|
113 |
+
content += text + "\\n"
|
114 |
+
element_count += 1
|
115 |
+
|
116 |
+
logger.info(f"π Extracted content from {element_count} HTML elements")
|
117 |
+
|
118 |
+
# Limit content length
|
119 |
+
original_length = len(content)
|
120 |
+
if len(content) > 5000:
|
121 |
+
content = content[:5000] + "...[truncated]"
|
122 |
+
logger.info(f"βοΈ Content truncated from {original_length} to 5000 characters")
|
123 |
+
|
124 |
+
logger.info(f"π Final processed content: {len(content)} characters")
|
125 |
+
|
126 |
+
# Log a preview of the fetched content
|
127 |
+
preview = content[:200].replace('\\n', ' ')
|
128 |
+
logger.info(f"π Content preview: {preview}...")
|
129 |
+
|
130 |
+
# Log content sections found
|
131 |
+
sections = []
|
132 |
+
for header in soup.find_all(['h1', 'h2', 'h3']):
|
133 |
+
header_text = header.get_text().strip()
|
134 |
+
if header_text:
|
135 |
+
sections.append(header_text)
|
136 |
+
|
137 |
+
if sections:
|
138 |
+
logger.info(f"π Found sections: {', '.join(sections[:5])}{'...' if len(sections) > 5 else ''}")
|
139 |
+
|
140 |
+
logger.info("β
Content extraction completed successfully")
|
141 |
+
return content
|
142 |
+
|
143 |
+
except Exception as e:
|
144 |
+
logger.error(f"β Error fetching {url}: {type(e).__name__}: {e}")
|
145 |
+
return f"Error fetching documentation: {str(e)}"
|
146 |
+
|
147 |
+
def fetch_model_info(model_id: str) -> str:
|
148 |
+
"""Fetch model information from HuggingFace API."""
|
149 |
+
logger.info("π€ TOOL CALL: fetch_model_info")
|
150 |
+
logger.info(f"π Requested model: {model_id}")
|
151 |
+
try:
|
152 |
+
# Use HuggingFace API to get model info
|
153 |
+
api_url = f"https://huggingface.co/api/models/{model_id}"
|
154 |
+
logger.info(f"π Fetching model info from: {api_url}")
|
155 |
+
headers = {
|
156 |
+
'User-Agent': 'Auto-Diffusers-Config/1.0 (Educational Tool)'
|
157 |
+
}
|
158 |
+
|
159 |
+
response = requests.get(api_url, headers=headers, timeout=10)
|
160 |
+
response.raise_for_status()
|
161 |
+
logger.info(f"β
HTTP {response.status_code} - Model API response received")
|
162 |
+
|
163 |
+
model_data = response.json()
|
164 |
+
logger.info(f"π Raw API response contains {len(model_data)} fields")
|
165 |
+
|
166 |
+
# Extract relevant information
|
167 |
+
info = {
|
168 |
+
'model_id': model_data.get('id', model_id),
|
169 |
+
'pipeline_tag': model_data.get('pipeline_tag', 'unknown'),
|
170 |
+
'tags': model_data.get('tags', []),
|
171 |
+
'library_name': model_data.get('library_name', 'unknown'),
|
172 |
+
'downloads': model_data.get('downloads', 0),
|
173 |
+
'likes': model_data.get('likes', 0)
|
174 |
+
}
|
175 |
+
|
176 |
+
logger.info(f"π Extracted model info:")
|
177 |
+
logger.info(f" - Pipeline: {info['pipeline_tag']}")
|
178 |
+
logger.info(f" - Library: {info['library_name']}")
|
179 |
+
logger.info(f" - Downloads: {info['downloads']:,}")
|
180 |
+
logger.info(f" - Likes: {info['likes']:,}")
|
181 |
+
logger.info(f" - Tags: {len(info['tags'])} tags")
|
182 |
+
|
183 |
+
result = json.dumps(info, indent=2)
|
184 |
+
logger.info(f"β
Model info formatting completed ({len(result)} characters)")
|
185 |
+
return result
|
186 |
+
|
187 |
+
except Exception as e:
|
188 |
+
logger.error(f"Error fetching model info for {model_id}: {e}")
|
189 |
+
return f"Error fetching model information: {str(e)}"
|
190 |
+
|
191 |
+
def search_optimization_guides(query: str) -> str:
|
192 |
+
"""Search for optimization guides and best practices."""
|
193 |
+
logger.info("π TOOL CALL: search_optimization_guides")
|
194 |
+
logger.info(f"π Search query: '{query}'")
|
195 |
+
try:
|
196 |
+
# Search common optimization documentation URLs
|
197 |
+
docs_urls = [
|
198 |
+
"https://huggingface.co/docs/diffusers/optimization/fp16",
|
199 |
+
"https://huggingface.co/docs/diffusers/optimization/memory",
|
200 |
+
"https://huggingface.co/docs/diffusers/optimization/torch2",
|
201 |
+
"https://huggingface.co/docs/diffusers/optimization/mps",
|
202 |
+
"https://huggingface.co/docs/diffusers/optimization/xformers"
|
203 |
+
]
|
204 |
+
|
205 |
+
logger.info(f"π Searching through {len(docs_urls)} optimization guide URLs...")
|
206 |
+
|
207 |
+
results = []
|
208 |
+
matched_urls = []
|
209 |
+
for url in docs_urls:
|
210 |
+
if any(keyword in url for keyword in query.lower().split()):
|
211 |
+
logger.info(f"β
URL matched query: {url}")
|
212 |
+
matched_urls.append(url)
|
213 |
+
content = fetch_huggingface_docs(url)
|
214 |
+
if not content.startswith("Error"):
|
215 |
+
results.append(f"From {url}:\\n{content[:1000]}...\\n")
|
216 |
+
logger.info(f"π Successfully processed content from {url}")
|
217 |
+
else:
|
218 |
+
logger.warning(f"β Failed to fetch content from {url}")
|
219 |
+
else:
|
220 |
+
logger.debug(f"βοΈ URL skipped (no match): {url}")
|
221 |
+
|
222 |
+
logger.info(f"π Search completed: {len(matched_urls)} URLs matched, {len(results)} successful fetches")
|
223 |
+
|
224 |
+
if results:
|
225 |
+
final_result = "\\n".join(results)
|
226 |
+
logger.info(f"β
Returning combined content ({len(final_result)} characters)")
|
227 |
+
return final_result
|
228 |
+
else:
|
229 |
+
logger.warning("β No specific optimization guides found for the query")
|
230 |
+
return "No specific optimization guides found for the query"
|
231 |
+
|
232 |
+
except Exception as e:
|
233 |
+
logger.error(f"Error searching optimization guides: {e}")
|
234 |
+
return f"Error searching guides: {str(e)}"
|
235 |
+
|
236 |
+
# Define tools schema for Gemini (simplified for now)
|
237 |
+
tools = [
|
238 |
+
{
|
239 |
+
"function_declarations": [
|
240 |
+
{
|
241 |
+
"name": "fetch_huggingface_docs",
|
242 |
+
"description": "Fetch current documentation from HuggingFace URLs for diffusers library, models, or optimization guides",
|
243 |
+
"parameters": {
|
244 |
+
"type": "object",
|
245 |
+
"properties": {
|
246 |
+
"url": {
|
247 |
+
"type": "string",
|
248 |
+
"description": "The HuggingFace documentation URL to fetch"
|
249 |
+
}
|
250 |
+
},
|
251 |
+
"required": ["url"]
|
252 |
+
}
|
253 |
+
},
|
254 |
+
{
|
255 |
+
"name": "fetch_model_info",
|
256 |
+
"description": "Fetch current model information and metadata from HuggingFace API",
|
257 |
+
"parameters": {
|
258 |
+
"type": "object",
|
259 |
+
"properties": {
|
260 |
+
"model_id": {
|
261 |
+
"type": "string",
|
262 |
+
"description": "The HuggingFace model ID (e.g., 'black-forest-labs/FLUX.1-schnell')"
|
263 |
+
}
|
264 |
+
},
|
265 |
+
"required": ["model_id"]
|
266 |
+
}
|
267 |
+
},
|
268 |
+
{
|
269 |
+
"name": "search_optimization_guides",
|
270 |
+
"description": "Search for optimization guides and best practices for diffusers models",
|
271 |
+
"parameters": {
|
272 |
+
"type": "object",
|
273 |
+
"properties": {
|
274 |
+
"query": {
|
275 |
+
"type": "string",
|
276 |
+
"description": "Search query for optimization topics (e.g., 'memory', 'fp16', 'torch compile')"
|
277 |
+
}
|
278 |
+
},
|
279 |
+
"required": ["query"]
|
280 |
+
}
|
281 |
+
}
|
282 |
+
]
|
283 |
+
}
|
284 |
+
]
|
285 |
+
|
286 |
+
# Store function implementations for execution
|
287 |
+
self.tool_functions = {
|
288 |
+
'fetch_huggingface_docs': fetch_huggingface_docs,
|
289 |
+
'fetch_model_info': fetch_model_info,
|
290 |
+
'search_optimization_guides': search_optimization_guides
|
291 |
+
}
|
292 |
+
|
293 |
+
logger.info(f"Created {len(tools[0]['function_declarations'])} tools for Gemini")
|
294 |
+
return tools
|
295 |
+
|
296 |
+
def generate_optimized_code(self,
|
297 |
+
model_name: str,
|
298 |
+
prompt_text: str,
|
299 |
+
image_size: tuple = (768, 1360),
|
300 |
+
num_inference_steps: int = 4,
|
301 |
+
use_manual_specs: bool = False,
|
302 |
+
manual_specs: Dict = None,
|
303 |
+
memory_analysis: Dict = None) -> str:
|
304 |
+
"""Generate optimized diffusers code based on hardware specs and memory analysis."""
|
305 |
+
|
306 |
+
logger.info(f"Starting code generation for model: {model_name}")
|
307 |
+
logger.debug(f"Parameters: prompt='{prompt_text[:50]}...', size={image_size}, steps={num_inference_steps}")
|
308 |
+
logger.debug(f"Manual specs: {use_manual_specs}, Memory analysis provided: {memory_analysis is not None}")
|
309 |
+
|
310 |
+
# Get hardware specifications
|
311 |
+
if use_manual_specs and manual_specs:
|
312 |
+
logger.info("Using manual hardware specifications")
|
313 |
+
hardware_specs = manual_specs
|
314 |
+
logger.debug(f"Manual specs: {hardware_specs}")
|
315 |
+
|
316 |
+
# Determine optimization profile based on manual specs
|
317 |
+
if hardware_specs.get('gpu_info') and hardware_specs['gpu_info']:
|
318 |
+
vram_gb = hardware_specs['gpu_info'][0]['memory_mb'] / 1024
|
319 |
+
logger.debug(f"GPU detected with {vram_gb:.1f} GB VRAM")
|
320 |
+
|
321 |
+
if vram_gb >= 16:
|
322 |
+
optimization_profile = 'performance'
|
323 |
+
elif vram_gb >= 8:
|
324 |
+
optimization_profile = 'balanced'
|
325 |
+
else:
|
326 |
+
optimization_profile = 'memory_efficient'
|
327 |
+
else:
|
328 |
+
optimization_profile = 'cpu_only'
|
329 |
+
logger.info("No GPU detected, using CPU-only profile")
|
330 |
+
|
331 |
+
logger.info(f"Selected optimization profile: {optimization_profile}")
|
332 |
+
else:
|
333 |
+
logger.info("Using automatic hardware detection")
|
334 |
+
hardware_specs = self.hardware_detector.specs
|
335 |
+
optimization_profile = self.hardware_detector.get_optimization_profile()
|
336 |
+
logger.debug(f"Detected specs: {hardware_specs}")
|
337 |
+
logger.info(f"Auto-detected optimization profile: {optimization_profile}")
|
338 |
+
|
339 |
+
# Create the prompt for Gemini API
|
340 |
+
logger.debug("Creating generation prompt for Gemini API")
|
341 |
+
system_prompt = self._create_generation_prompt(
|
342 |
+
model_name, prompt_text, image_size, num_inference_steps,
|
343 |
+
hardware_specs, optimization_profile, memory_analysis
|
344 |
+
)
|
345 |
+
logger.debug(f"Prompt length: {len(system_prompt)} characters")
|
346 |
+
|
347 |
+
# Log the actual prompt being sent to Gemini API
|
348 |
+
logger.info("=" * 80)
|
349 |
+
logger.info("PROMPT SENT TO GEMINI API:")
|
350 |
+
logger.info("=" * 80)
|
351 |
+
logger.info(system_prompt)
|
352 |
+
logger.info("=" * 80)
|
353 |
+
|
354 |
+
try:
|
355 |
+
logger.info("Sending request to Gemini API")
|
356 |
+
response = self.model.generate_content(system_prompt)
|
357 |
+
|
358 |
+
# Handle tool calling if present and tools are available
|
359 |
+
if self.tools and response.candidates[0].content.parts:
|
360 |
+
for part in response.candidates[0].content.parts:
|
361 |
+
if hasattr(part, 'function_call') and part.function_call:
|
362 |
+
function_name = part.function_call.name
|
363 |
+
function_args = dict(part.function_call.args)
|
364 |
+
|
365 |
+
logger.info("π οΈ " + "=" * 60)
|
366 |
+
logger.info(f"π οΈ GEMINI REQUESTED TOOL CALL: {function_name}")
|
367 |
+
logger.info("π οΈ " + "=" * 60)
|
368 |
+
logger.info(f"π Tool arguments: {function_args}")
|
369 |
+
|
370 |
+
if function_name in self.tool_functions:
|
371 |
+
logger.info(f"β
Tool function found, executing...")
|
372 |
+
tool_result = self.tool_functions[function_name](**function_args)
|
373 |
+
logger.info("π οΈ " + "=" * 60)
|
374 |
+
logger.info(f"π οΈ TOOL EXECUTION COMPLETED: {function_name}")
|
375 |
+
logger.info("π οΈ " + "=" * 60)
|
376 |
+
logger.info(f"π Tool result length: {len(str(tool_result))} characters")
|
377 |
+
|
378 |
+
# Log a preview of the tool result
|
379 |
+
preview = str(tool_result)[:300].replace('\\n', ' ')
|
380 |
+
logger.info(f"π Tool result preview: {preview}...")
|
381 |
+
logger.info("π οΈ " + "=" * 60)
|
382 |
+
|
383 |
+
# Create a follow-up conversation with the tool result
|
384 |
+
follow_up_prompt = f"""
|
385 |
+
{system_prompt}
|
386 |
+
|
387 |
+
ADDITIONAL CONTEXT FROM TOOLS:
|
388 |
+
Tool: {function_name}
|
389 |
+
Result: {tool_result}
|
390 |
+
|
391 |
+
Please use this current information to generate the most up-to-date and optimized code.
|
392 |
+
"""
|
393 |
+
|
394 |
+
# Log the follow-up prompt
|
395 |
+
logger.info("=" * 80)
|
396 |
+
logger.info("FOLLOW-UP PROMPT SENT TO GEMINI API (WITH TOOL RESULTS):")
|
397 |
+
logger.info("=" * 80)
|
398 |
+
logger.info(follow_up_prompt)
|
399 |
+
logger.info("=" * 80)
|
400 |
+
# Generate final response with tool context
|
401 |
+
logger.info("Generating final response with tool context")
|
402 |
+
final_response = self.model.generate_content(follow_up_prompt)
|
403 |
+
logger.info("Successfully received final response from Gemini API")
|
404 |
+
logger.debug(f"Final response length: {len(final_response.text)} characters")
|
405 |
+
return final_response.text
|
406 |
+
|
407 |
+
# No tool calling, return direct response
|
408 |
+
logger.info("Successfully received response from Gemini API (no tools used)")
|
409 |
+
logger.debug(f"Response length: {len(response.text)} characters")
|
410 |
+
return response.text
|
411 |
+
|
412 |
+
except Exception as e:
|
413 |
+
logger.error(f"Error generating code: {str(e)}")
|
414 |
+
return f"Error generating code: {str(e)}"
|
415 |
+
|
416 |
+
def _create_generation_prompt(self,
|
417 |
+
model_name: str,
|
418 |
+
prompt_text: str,
|
419 |
+
image_size: tuple,
|
420 |
+
num_inference_steps: int,
|
421 |
+
hardware_specs: Dict,
|
422 |
+
optimization_profile: str,
|
423 |
+
memory_analysis: Dict = None) -> str:
|
424 |
+
"""Create the prompt for Gemini API to generate optimized code."""
|
425 |
+
|
426 |
+
base_prompt = f"""
|
427 |
+
You are an expert in optimizing diffusers library code for different hardware configurations.
|
428 |
+
|
429 |
+
NOTE: This system includes curated optimization knowledge from HuggingFace documentation.
|
430 |
+
|
431 |
+
TASK: Generate optimized Python code for running a diffusion model with the following specifications:
|
432 |
+
- Model: {model_name}
|
433 |
+
- Prompt: "{prompt_text}"
|
434 |
+
- Image size: {image_size[0]}x{image_size[1]}
|
435 |
+
- Inference steps: {num_inference_steps}
|
436 |
+
|
437 |
+
HARDWARE SPECIFICATIONS:
|
438 |
+
- Platform: {hardware_specs['platform']} ({hardware_specs['architecture']})
|
439 |
+
- CPU Cores: {hardware_specs['cpu_count']}
|
440 |
+
- CUDA Available: {hardware_specs['cuda_available']}
|
441 |
+
- MPS Available: {hardware_specs['mps_available']}
|
442 |
+
- Optimization Profile: {optimization_profile}
|
443 |
+
"""
|
444 |
+
|
445 |
+
if hardware_specs.get('gpu_info'):
|
446 |
+
base_prompt += f"- GPU: {hardware_specs['gpu_info'][0]['name']} ({hardware_specs['gpu_info'][0]['memory_mb']/1024:.1f} GB VRAM)\n"
|
447 |
+
|
448 |
+
# Add user dtype preference if specified
|
449 |
+
if hardware_specs.get('user_dtype'):
|
450 |
+
base_prompt += f"- User specified dtype: {hardware_specs['user_dtype']}\n"
|
451 |
+
|
452 |
+
# Add memory analysis information
|
453 |
+
if memory_analysis:
|
454 |
+
memory_info = memory_analysis.get('memory_info', {})
|
455 |
+
recommendations = memory_analysis.get('recommendations', {})
|
456 |
+
|
457 |
+
base_prompt += f"\nMEMORY ANALYSIS:\n"
|
458 |
+
if memory_info.get('estimated_inference_memory_fp16_gb'):
|
459 |
+
base_prompt += f"- Model Memory Requirements: {memory_info['estimated_inference_memory_fp16_gb']} GB (FP16 inference)\n"
|
460 |
+
if memory_info.get('memory_fp16_gb'):
|
461 |
+
base_prompt += f"- Model Weights Size: {memory_info['memory_fp16_gb']} GB (FP16)\n"
|
462 |
+
if recommendations.get('recommendations'):
|
463 |
+
base_prompt += f"- Memory Recommendation: {', '.join(recommendations['recommendations'])}\n"
|
464 |
+
if recommendations.get('recommended_precision'):
|
465 |
+
base_prompt += f"- Recommended Precision: {recommendations['recommended_precision']}\n"
|
466 |
+
if recommendations.get('cpu_offload'):
|
467 |
+
base_prompt += f"- CPU Offloading Required: {recommendations['cpu_offload']}\n"
|
468 |
+
if recommendations.get('attention_slicing'):
|
469 |
+
base_prompt += f"- Attention Slicing Recommended: {recommendations['attention_slicing']}\n"
|
470 |
+
if recommendations.get('vae_slicing'):
|
471 |
+
base_prompt += f"- VAE Slicing Recommended: {recommendations['vae_slicing']}\n"
|
472 |
+
|
473 |
+
base_prompt += f"""
|
474 |
+
OPTIMIZATION KNOWLEDGE BASE:
|
475 |
+
{get_optimization_guide()}
|
476 |
+
|
477 |
+
IMPORTANT: For FLUX.1-schnell models, do NOT include guidance_scale parameter as it's not needed.
|
478 |
+
|
479 |
+
Using the OPTIMIZATION KNOWLEDGE BASE above, generate Python code that:
|
480 |
+
|
481 |
+
1. **Selects the best optimization techniques** for the specific hardware profile
|
482 |
+
2. **Applies appropriate memory optimizations** based on available VRAM
|
483 |
+
3. **Uses optimal data types** for the target hardware:
|
484 |
+
- User specified dtype (if provided): Use exactly as specified
|
485 |
+
- Apple Silicon (MPS): prefer torch.bfloat16
|
486 |
+
- NVIDIA GPUs: prefer torch.float16 or torch.bfloat16
|
487 |
+
- CPU only: use torch.float32
|
488 |
+
4. **Implements hardware-specific optimizations** (CUDA, MPS, CPU)
|
489 |
+
5. **Follows model-specific guidelines** (e.g., FLUX guidance_scale handling)
|
490 |
+
|
491 |
+
IMPORTANT GUIDELINES:
|
492 |
+
- Reference the OPTIMIZATION KNOWLEDGE BASE to select appropriate techniques
|
493 |
+
- Include all necessary imports
|
494 |
+
- Add brief comments explaining optimization choices
|
495 |
+
- Generate compact, production-ready code
|
496 |
+
- Inline values where possible for concise code
|
497 |
+
- Generate ONLY the Python code, no explanations before or after the code block
|
498 |
+
"""
|
499 |
+
|
500 |
+
return base_prompt
|
501 |
+
|
502 |
+
def run_interactive_mode(self):
|
503 |
+
"""Run the generator in interactive mode."""
|
504 |
+
print("=== Auto-Diffusers Code Generator ===")
|
505 |
+
print("This tool generates optimized diffusers code based on your hardware.\n")
|
506 |
+
|
507 |
+
# Check hardware
|
508 |
+
print("=== Hardware Detection ===")
|
509 |
+
self.hardware_detector.print_specs()
|
510 |
+
|
511 |
+
use_manual = input("\nUse manual hardware input? (y/n): ").lower() == 'y'
|
512 |
+
|
513 |
+
# Get user inputs
|
514 |
+
print("\n=== Model Configuration ===")
|
515 |
+
model_name = input("Model name (default: black-forest-labs/FLUX.1-schnell): ").strip()
|
516 |
+
if not model_name:
|
517 |
+
model_name = "black-forest-labs/FLUX.1-schnell"
|
518 |
+
|
519 |
+
prompt_text = input("Prompt text (default: A cat holding a sign that says hello world): ").strip()
|
520 |
+
if not prompt_text:
|
521 |
+
prompt_text = "A cat holding a sign that says hello world"
|
522 |
+
|
523 |
+
try:
|
524 |
+
width = int(input("Image width (default: 1360): ") or "1360")
|
525 |
+
height = int(input("Image height (default: 768): ") or "768")
|
526 |
+
steps = int(input("Inference steps (default: 4): ") or "4")
|
527 |
+
except ValueError:
|
528 |
+
width, height, steps = 1360, 768, 4
|
529 |
+
|
530 |
+
print("\n=== Generating Optimized Code ===")
|
531 |
+
|
532 |
+
# Generate code
|
533 |
+
optimized_code = self.generate_optimized_code(
|
534 |
+
model_name=model_name,
|
535 |
+
prompt_text=prompt_text,
|
536 |
+
image_size=(height, width),
|
537 |
+
num_inference_steps=steps,
|
538 |
+
use_manual_specs=use_manual
|
539 |
+
)
|
540 |
+
|
541 |
+
print("\n" + "="*60)
|
542 |
+
print("OPTIMIZED DIFFUSERS CODE:")
|
543 |
+
print("="*60)
|
544 |
+
print(optimized_code)
|
545 |
+
print("="*60)
|
546 |
+
|
547 |
+
|
548 |
+
def main():
|
549 |
+
# Get API key from .env file
|
550 |
+
api_key = os.getenv('GOOGLE_API_KEY')
|
551 |
+
if not api_key:
|
552 |
+
api_key = os.getenv('GEMINI_API_KEY') # fallback
|
553 |
+
if not api_key:
|
554 |
+
api_key = input("Enter your Gemini API key: ").strip()
|
555 |
+
if not api_key:
|
556 |
+
print("API key is required!")
|
557 |
+
return
|
558 |
+
|
559 |
+
generator = AutoDiffusersGenerator(api_key)
|
560 |
+
generator.run_interactive_mode()
|
561 |
+
|
562 |
+
|
563 |
+
if __name__ == "__main__":
|
564 |
+
main()
|
auto_diffusers/core/knowledge_base.py
ADDED
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Curated HuggingFace Diffusers optimization knowledge base
|
3 |
+
Manually extracted and organized for reliable prompt injection
|
4 |
+
"""
|
5 |
+
|
6 |
+
OPTIMIZATION_GUIDE = """
|
7 |
+
# DIFFUSERS OPTIMIZATION TECHNIQUES
|
8 |
+
|
9 |
+
## Memory Optimization Techniques
|
10 |
+
|
11 |
+
### 1. Model CPU Offloading
|
12 |
+
Use `enable_model_cpu_offload()` to move models between GPU and CPU automatically:
|
13 |
+
```python
|
14 |
+
pipe.enable_model_cpu_offload()
|
15 |
+
```
|
16 |
+
- Saves significant VRAM by keeping only active models on GPU
|
17 |
+
- Automatic management, no manual intervention needed
|
18 |
+
- Compatible with all pipelines
|
19 |
+
|
20 |
+
### 2. Sequential CPU Offloading
|
21 |
+
Use `enable_sequential_cpu_offload()` for more aggressive memory saving:
|
22 |
+
```python
|
23 |
+
pipe.enable_sequential_cpu_offload()
|
24 |
+
```
|
25 |
+
- More memory efficient than model offloading
|
26 |
+
- Moves models to CPU after each forward pass
|
27 |
+
- Best for very limited VRAM scenarios
|
28 |
+
|
29 |
+
### 3. Attention Slicing
|
30 |
+
Use `enable_attention_slicing()` to reduce memory during attention computation:
|
31 |
+
```python
|
32 |
+
pipe.enable_attention_slicing()
|
33 |
+
# or specify slice size
|
34 |
+
pipe.enable_attention_slicing("max") # maximum slicing
|
35 |
+
pipe.enable_attention_slicing(1) # slice_size = 1
|
36 |
+
```
|
37 |
+
- Trades compute time for memory
|
38 |
+
- Most effective for high-resolution images
|
39 |
+
- Can be combined with other techniques
|
40 |
+
|
41 |
+
### 4. VAE Slicing
|
42 |
+
Use `enable_vae_slicing()` for large batch processing:
|
43 |
+
```python
|
44 |
+
pipe.enable_vae_slicing()
|
45 |
+
```
|
46 |
+
- Decodes images one at a time instead of all at once
|
47 |
+
- Essential for batch sizes > 4
|
48 |
+
- Minimal performance impact on single images
|
49 |
+
|
50 |
+
### 5. VAE Tiling
|
51 |
+
Use `enable_vae_tiling()` for high-resolution image generation:
|
52 |
+
```python
|
53 |
+
pipe.enable_vae_tiling()
|
54 |
+
```
|
55 |
+
- Enables 4K+ image generation on 8GB VRAM
|
56 |
+
- Splits images into overlapping tiles
|
57 |
+
- Automatically disabled for 512x512 or smaller images
|
58 |
+
|
59 |
+
### 6. Memory Efficient Attention (xFormers)
|
60 |
+
Use `enable_xformers_memory_efficient_attention()` if xFormers is installed:
|
61 |
+
```python
|
62 |
+
pipe.enable_xformers_memory_efficient_attention()
|
63 |
+
```
|
64 |
+
- Significantly reduces memory usage and improves speed
|
65 |
+
- Requires xformers library installation
|
66 |
+
- Compatible with most models
|
67 |
+
|
68 |
+
## Performance Optimization Techniques
|
69 |
+
|
70 |
+
### 1. Half Precision (FP16/BF16)
|
71 |
+
Use lower precision for better memory and speed:
|
72 |
+
```python
|
73 |
+
# FP16 (widely supported)
|
74 |
+
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
|
75 |
+
|
76 |
+
# BF16 (better numerical stability, newer hardware)
|
77 |
+
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.bfloat16)
|
78 |
+
```
|
79 |
+
- FP16: Halves memory usage, widely supported
|
80 |
+
- BF16: Better numerical stability, requires newer GPUs
|
81 |
+
- Essential for most optimization scenarios
|
82 |
+
|
83 |
+
### 2. Torch Compile (PyTorch 2.0+)
|
84 |
+
Use `torch.compile()` for significant speed improvements:
|
85 |
+
```python
|
86 |
+
pipe.unet = torch.compile(pipe.unet, mode="reduce-overhead", fullgraph=True)
|
87 |
+
# For some models, compile VAE too:
|
88 |
+
pipe.vae.decode = torch.compile(pipe.vae.decode, mode="reduce-overhead", fullgraph=True)
|
89 |
+
```
|
90 |
+
- 5-50% speed improvement
|
91 |
+
- Requires PyTorch 2.0+
|
92 |
+
- First run is slower due to compilation
|
93 |
+
|
94 |
+
### 3. Fast Schedulers
|
95 |
+
Use faster schedulers for fewer steps:
|
96 |
+
```python
|
97 |
+
from diffusers import LMSDiscreteScheduler, UniPCMultistepScheduler
|
98 |
+
|
99 |
+
# LMS Scheduler (good quality, fast)
|
100 |
+
pipe.scheduler = LMSDiscreteScheduler.from_config(pipe.scheduler.config)
|
101 |
+
|
102 |
+
# UniPC Scheduler (fastest)
|
103 |
+
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
|
104 |
+
```
|
105 |
+
|
106 |
+
## Hardware-Specific Optimizations
|
107 |
+
|
108 |
+
### NVIDIA GPU Optimizations
|
109 |
+
```python
|
110 |
+
# Enable Tensor Cores
|
111 |
+
torch.backends.cudnn.benchmark = True
|
112 |
+
|
113 |
+
# Optimal data type for NVIDIA
|
114 |
+
torch_dtype = torch.float16 # or torch.bfloat16 for RTX 30/40 series
|
115 |
+
```
|
116 |
+
|
117 |
+
### Apple Silicon (MPS) Optimizations
|
118 |
+
```python
|
119 |
+
# Use MPS device
|
120 |
+
device = "mps" if torch.backends.mps.is_available() else "cpu"
|
121 |
+
pipe = pipe.to(device)
|
122 |
+
|
123 |
+
# Recommended dtype for Apple Silicon
|
124 |
+
torch_dtype = torch.bfloat16 # Better than float16 on Apple Silicon
|
125 |
+
|
126 |
+
# Attention slicing often helps on MPS
|
127 |
+
pipe.enable_attention_slicing()
|
128 |
+
```
|
129 |
+
|
130 |
+
### CPU Optimizations
|
131 |
+
```python
|
132 |
+
# Use float32 for CPU
|
133 |
+
torch_dtype = torch.float32
|
134 |
+
|
135 |
+
# Enable optimized attention
|
136 |
+
pipe.enable_attention_slicing()
|
137 |
+
```
|
138 |
+
|
139 |
+
## Model-Specific Guidelines
|
140 |
+
|
141 |
+
### FLUX Models
|
142 |
+
- Do NOT use guidance_scale parameter (not needed for FLUX)
|
143 |
+
- Use 4-8 inference steps maximum
|
144 |
+
- BF16 dtype recommended
|
145 |
+
- Enable attention slicing for memory optimization
|
146 |
+
|
147 |
+
### Stable Diffusion XL
|
148 |
+
- Enable attention slicing for high resolutions
|
149 |
+
- Use refiner model sparingly to save memory
|
150 |
+
- Consider VAE tiling for >1024px images
|
151 |
+
|
152 |
+
### Stable Diffusion 1.5/2.1
|
153 |
+
- Very memory efficient base models
|
154 |
+
- Can often run without optimizations on 8GB+ VRAM
|
155 |
+
- Enable VAE slicing for batch processing
|
156 |
+
|
157 |
+
## Memory Usage Estimation
|
158 |
+
- FLUX.1: ~24GB for full precision, ~12GB for FP16
|
159 |
+
- SDXL: ~7GB for FP16, ~14GB for FP32
|
160 |
+
- SD 1.5: ~2GB for FP16, ~4GB for FP32
|
161 |
+
|
162 |
+
## Optimization Combinations by VRAM
|
163 |
+
|
164 |
+
### 24GB+ VRAM (High-end)
|
165 |
+
```python
|
166 |
+
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.bfloat16)
|
167 |
+
pipe = pipe.to("cuda")
|
168 |
+
pipe.unet = torch.compile(pipe.unet, mode="reduce-overhead", fullgraph=True)
|
169 |
+
```
|
170 |
+
|
171 |
+
### 12-24GB VRAM (Mid-range)
|
172 |
+
```python
|
173 |
+
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
|
174 |
+
pipe = pipe.to("cuda")
|
175 |
+
pipe.enable_model_cpu_offload()
|
176 |
+
pipe.enable_xformers_memory_efficient_attention()
|
177 |
+
```
|
178 |
+
|
179 |
+
### 8-12GB VRAM (Entry-level)
|
180 |
+
```python
|
181 |
+
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
|
182 |
+
pipe.enable_sequential_cpu_offload()
|
183 |
+
pipe.enable_attention_slicing()
|
184 |
+
pipe.enable_vae_slicing()
|
185 |
+
pipe.enable_xformers_memory_efficient_attention()
|
186 |
+
```
|
187 |
+
|
188 |
+
### <8GB VRAM (Low-end)
|
189 |
+
```python
|
190 |
+
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
|
191 |
+
pipe.enable_sequential_cpu_offload()
|
192 |
+
pipe.enable_attention_slicing("max")
|
193 |
+
pipe.enable_vae_slicing()
|
194 |
+
pipe.enable_vae_tiling()
|
195 |
+
```
|
196 |
+
"""
|
197 |
+
|
198 |
+
|
199 |
+
def get_optimization_guide():
|
200 |
+
"""Return the curated optimization guide."""
|
201 |
+
return OPTIMIZATION_GUIDE
|
202 |
+
|
203 |
+
|
204 |
+
if __name__ == "__main__":
|
205 |
+
print("Optimization guide loaded successfully!")
|
206 |
+
print(f"Guide length: {len(OPTIMIZATION_GUIDE)} characters")
|
auto_diffusers/hardware/__init__.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Hardware detection and analysis components.
|
3 |
+
|
4 |
+
This module provides hardware detection capabilities and memory
|
5 |
+
requirement analysis for diffusion models.
|
6 |
+
"""
|
7 |
+
|
8 |
+
from .detector import HardwareDetector
|
9 |
+
from .memory_calculator import SimpleMemoryCalculator
|
10 |
+
|
11 |
+
__all__ = [
|
12 |
+
"HardwareDetector",
|
13 |
+
"SimpleMemoryCalculator"
|
14 |
+
]
|
auto_diffusers/hardware/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (551 Bytes). View file
|
|
auto_diffusers/hardware/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (510 Bytes). View file
|
|
auto_diffusers/hardware/__pycache__/detector.cpython-311.pyc
ADDED
Binary file (12.8 kB). View file
|
|
auto_diffusers/hardware/__pycache__/detector.cpython-312.pyc
ADDED
Binary file (11.3 kB). View file
|
|
auto_diffusers/hardware/__pycache__/memory_calculator.cpython-311.pyc
ADDED
Binary file (12.8 kB). View file
|
|
auto_diffusers/hardware/__pycache__/memory_calculator.cpython-312.pyc
ADDED
Binary file (11.6 kB). View file
|
|
auto_diffusers/hardware/detector.py
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import platform
|
2 |
+
import subprocess
|
3 |
+
import os
|
4 |
+
import logging
|
5 |
+
from typing import Dict, Optional
|
6 |
+
|
7 |
+
# Configure logging
|
8 |
+
logger = logging.getLogger(__name__)
|
9 |
+
|
10 |
+
|
11 |
+
class HardwareDetector:
|
12 |
+
def __init__(self):
|
13 |
+
logger.info("Initializing HardwareDetector")
|
14 |
+
try:
|
15 |
+
self.specs = self._detect_system_specs()
|
16 |
+
logger.info("Hardware detection completed successfully")
|
17 |
+
logger.debug(f"Detected specs: {self.specs}")
|
18 |
+
except Exception as e:
|
19 |
+
logger.error(f"Failed to detect hardware specs: {e}")
|
20 |
+
raise
|
21 |
+
|
22 |
+
def _detect_system_specs(self) -> Dict:
|
23 |
+
"""Detect system hardware specifications automatically."""
|
24 |
+
logger.debug("Starting system hardware detection")
|
25 |
+
|
26 |
+
platform_info = platform.system()
|
27 |
+
architecture = platform.machine()
|
28 |
+
cpu_count = os.cpu_count()
|
29 |
+
python_version = platform.python_version()
|
30 |
+
|
31 |
+
logger.debug(f"Platform: {platform_info}, Architecture: {architecture}")
|
32 |
+
logger.debug(f"CPU cores: {cpu_count}, Python: {python_version}")
|
33 |
+
|
34 |
+
gpu_info = self._detect_gpu()
|
35 |
+
|
36 |
+
specs = {
|
37 |
+
'platform': platform_info,
|
38 |
+
'architecture': architecture,
|
39 |
+
'cpu_count': cpu_count,
|
40 |
+
'python_version': python_version,
|
41 |
+
'gpu_info': gpu_info,
|
42 |
+
'cuda_available': False,
|
43 |
+
'mps_available': False
|
44 |
+
}
|
45 |
+
|
46 |
+
# Check for PyTorch and device availability
|
47 |
+
logger.debug("Checking PyTorch availability")
|
48 |
+
try:
|
49 |
+
import torch
|
50 |
+
torch_version = torch.__version__
|
51 |
+
cuda_available = torch.cuda.is_available()
|
52 |
+
mps_available = torch.backends.mps.is_available()
|
53 |
+
|
54 |
+
logger.info(f"PyTorch {torch_version} detected")
|
55 |
+
logger.debug(f"CUDA available: {cuda_available}, MPS available: {mps_available}")
|
56 |
+
|
57 |
+
specs['torch_version'] = torch_version
|
58 |
+
specs['cuda_available'] = cuda_available
|
59 |
+
specs['mps_available'] = mps_available
|
60 |
+
|
61 |
+
if cuda_available:
|
62 |
+
device_count = torch.cuda.device_count()
|
63 |
+
device_name = torch.cuda.get_device_name(0)
|
64 |
+
device_memory = torch.cuda.get_device_properties(0).total_memory // (1024**3)
|
65 |
+
|
66 |
+
logger.info(f"CUDA devices: {device_count}, Primary: {device_name} ({device_memory}GB)")
|
67 |
+
|
68 |
+
specs['cuda_device_count'] = device_count
|
69 |
+
specs['cuda_device_name'] = device_name
|
70 |
+
specs['cuda_memory'] = device_memory
|
71 |
+
|
72 |
+
except ImportError as e:
|
73 |
+
logger.warning(f"PyTorch not installed: {e}")
|
74 |
+
specs['torch_version'] = 'Not installed'
|
75 |
+
|
76 |
+
return specs
|
77 |
+
|
78 |
+
def _detect_gpu(self) -> Optional[Dict]:
|
79 |
+
"""Attempt to detect GPU information using nvidia-smi."""
|
80 |
+
logger.debug("Attempting GPU detection via nvidia-smi")
|
81 |
+
try:
|
82 |
+
result = subprocess.run([
|
83 |
+
'nvidia-smi',
|
84 |
+
'--query-gpu=name,memory.total',
|
85 |
+
'--format=csv,noheader,nounits'
|
86 |
+
], capture_output=True, text=True, check=True)
|
87 |
+
|
88 |
+
logger.debug(f"nvidia-smi output: {result.stdout}")
|
89 |
+
|
90 |
+
lines = result.stdout.strip().split('\n')
|
91 |
+
gpus = []
|
92 |
+
logger.debug(f"Found {len(lines)} GPU entries")
|
93 |
+
for line in lines:
|
94 |
+
if line.strip():
|
95 |
+
try:
|
96 |
+
name, memory = line.split(', ')
|
97 |
+
gpu_entry = {'name': name.strip(), 'memory_mb': int(memory)}
|
98 |
+
gpus.append(gpu_entry)
|
99 |
+
logger.debug(f"Parsed GPU: {gpu_entry}")
|
100 |
+
except ValueError as e:
|
101 |
+
logger.warning(f"Failed to parse GPU line '{line}': {e}")
|
102 |
+
|
103 |
+
logger.info(f"Successfully detected {len(gpus)} GPUs")
|
104 |
+
return gpus
|
105 |
+
|
106 |
+
except subprocess.CalledProcessError as e:
|
107 |
+
logger.warning(f"nvidia-smi command failed: {e}")
|
108 |
+
return None
|
109 |
+
except FileNotFoundError:
|
110 |
+
logger.debug("nvidia-smi not found, no NVIDIA GPU detected")
|
111 |
+
return None
|
112 |
+
except Exception as e:
|
113 |
+
logger.error(f"Unexpected error during GPU detection: {e}")
|
114 |
+
return None
|
115 |
+
|
116 |
+
def get_manual_input(self) -> Dict:
|
117 |
+
"""Get hardware specifications via manual user input."""
|
118 |
+
logger.info("Starting manual hardware input")
|
119 |
+
print("Enter your hardware specifications manually:")
|
120 |
+
|
121 |
+
gpu_name = input("GPU Name (e.g., RTX 4090, A100, leave empty if none): ").strip()
|
122 |
+
logger.debug(f"User input GPU name: '{gpu_name}'")
|
123 |
+
|
124 |
+
if gpu_name:
|
125 |
+
try:
|
126 |
+
vram_gb = int(input("VRAM in GB (e.g., 24): "))
|
127 |
+
gpu_info = [{'name': gpu_name, 'memory_mb': vram_gb * 1024}]
|
128 |
+
logger.info(f"Manual GPU configured: {gpu_name} with {vram_gb}GB VRAM")
|
129 |
+
except ValueError as e:
|
130 |
+
logger.warning(f"Invalid VRAM input: {e}")
|
131 |
+
gpu_info = None
|
132 |
+
else:
|
133 |
+
gpu_info = None
|
134 |
+
logger.info("No GPU specified in manual input")
|
135 |
+
|
136 |
+
try:
|
137 |
+
ram_gb = int(input("System RAM in GB (e.g., 32): "))
|
138 |
+
logger.debug(f"User input RAM: {ram_gb}GB")
|
139 |
+
except ValueError as e:
|
140 |
+
logger.warning(f"Invalid RAM input: {e}, using default 16GB")
|
141 |
+
ram_gb = 16 # Default
|
142 |
+
|
143 |
+
specs = self.specs.copy()
|
144 |
+
specs['gpu_info'] = gpu_info
|
145 |
+
specs['ram_gb'] = ram_gb
|
146 |
+
specs['manual_input'] = True
|
147 |
+
|
148 |
+
logger.info(f"Manual hardware specs configured: {specs}")
|
149 |
+
return specs
|
150 |
+
|
151 |
+
def get_optimization_profile(self) -> str:
|
152 |
+
"""Determine the best optimization profile based on hardware."""
|
153 |
+
logger.debug("Determining optimization profile")
|
154 |
+
|
155 |
+
if self.specs['cuda_available']:
|
156 |
+
cuda_memory = self.specs.get('cuda_memory', 0)
|
157 |
+
logger.debug(f"CUDA available with {cuda_memory}GB memory")
|
158 |
+
|
159 |
+
if cuda_memory >= 20:
|
160 |
+
profile = 'high_end_gpu'
|
161 |
+
elif cuda_memory >= 8:
|
162 |
+
profile = 'mid_range_gpu'
|
163 |
+
else:
|
164 |
+
profile = 'low_vram_gpu'
|
165 |
+
|
166 |
+
elif self.specs['mps_available']:
|
167 |
+
logger.debug("MPS available, using Apple Silicon profile")
|
168 |
+
profile = 'apple_silicon'
|
169 |
+
else:
|
170 |
+
logger.debug("No GPU acceleration available, using CPU-only profile")
|
171 |
+
profile = 'cpu_only'
|
172 |
+
|
173 |
+
logger.info(f"Selected optimization profile: {profile}")
|
174 |
+
return profile
|
175 |
+
|
176 |
+
def print_specs(self):
|
177 |
+
"""Print detected hardware specifications."""
|
178 |
+
logger.info("Printing hardware specifications")
|
179 |
+
|
180 |
+
print(f"Platform: {self.specs['platform']} ({self.specs['architecture']})")
|
181 |
+
print(f"CPU Cores: {self.specs['cpu_count']}")
|
182 |
+
print(f"Python: {self.specs['python_version']}")
|
183 |
+
print(f"PyTorch: {self.specs.get('torch_version', 'Not detected')}")
|
184 |
+
print(f"CUDA Available: {self.specs['cuda_available']}")
|
185 |
+
print(f"MPS Available: {self.specs['mps_available']}")
|
186 |
+
|
187 |
+
logger.debug("Hardware specs display completed")
|
188 |
+
|
189 |
+
if self.specs['gpu_info']:
|
190 |
+
print("GPU Information:")
|
191 |
+
for i, gpu in enumerate(self.specs['gpu_info']):
|
192 |
+
vram_gb = gpu['memory_mb'] / 1024
|
193 |
+
print(f" GPU {i}: {gpu['name']} ({vram_gb:.1f} GB VRAM)")
|
194 |
+
else:
|
195 |
+
print("No GPU detected")
|
196 |
+
|
auto_diffusers/hardware/memory_calculator.py
ADDED
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from huggingface_hub import HfApi, hf_hub_download
|
2 |
+
from typing import Dict, Optional
|
3 |
+
import json
|
4 |
+
import os
|
5 |
+
import logging
|
6 |
+
|
7 |
+
# Configure logging
|
8 |
+
logger = logging.getLogger(__name__)
|
9 |
+
|
10 |
+
|
11 |
+
class SimpleMemoryCalculator:
|
12 |
+
def __init__(self):
|
13 |
+
logger.info("Initializing SimpleMemoryCalculator")
|
14 |
+
try:
|
15 |
+
self.hf_api = HfApi()
|
16 |
+
logger.debug("HuggingFace API initialized")
|
17 |
+
except Exception as e:
|
18 |
+
logger.error(f"Failed to initialize HuggingFace API: {e}")
|
19 |
+
raise
|
20 |
+
|
21 |
+
self.cache = {}
|
22 |
+
|
23 |
+
# Known model memory requirements (in GB for FP16)
|
24 |
+
self.known_models = {
|
25 |
+
"black-forest-labs/FLUX.1-schnell": {
|
26 |
+
"params_billions": 12.0,
|
27 |
+
"fp16_gb": 24.0,
|
28 |
+
"inference_fp16_gb": 36.0
|
29 |
+
},
|
30 |
+
"black-forest-labs/FLUX.1-dev": {
|
31 |
+
"params_billions": 12.0,
|
32 |
+
"fp16_gb": 24.0,
|
33 |
+
"inference_fp16_gb": 36.0
|
34 |
+
},
|
35 |
+
"stabilityai/stable-diffusion-xl-base-1.0": {
|
36 |
+
"params_billions": 3.5,
|
37 |
+
"fp16_gb": 7.0,
|
38 |
+
"inference_fp16_gb": 12.0
|
39 |
+
},
|
40 |
+
"runwayml/stable-diffusion-v1-5": {
|
41 |
+
"params_billions": 0.86,
|
42 |
+
"fp16_gb": 1.7,
|
43 |
+
"inference_fp16_gb": 4.0
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
logger.debug(f"Known models in database: {len(self.known_models)}")
|
48 |
+
|
49 |
+
def get_model_memory_requirements(self, model_id: str) -> Dict:
|
50 |
+
"""
|
51 |
+
Get memory requirements for a model, using known values or estimating from file sizes.
|
52 |
+
"""
|
53 |
+
logger.info(f"Getting memory requirements for model: {model_id}")
|
54 |
+
|
55 |
+
if model_id in self.cache:
|
56 |
+
logger.debug(f"Using cached memory data for {model_id}")
|
57 |
+
return self.cache[model_id]
|
58 |
+
|
59 |
+
# Check if we have known values
|
60 |
+
if model_id in self.known_models:
|
61 |
+
logger.info(f"Using known memory data for {model_id}")
|
62 |
+
known = self.known_models[model_id]
|
63 |
+
logger.debug(f"Known data: {known}")
|
64 |
+
|
65 |
+
result = {
|
66 |
+
'model_id': model_id,
|
67 |
+
'total_params': int(known['params_billions'] * 1e9),
|
68 |
+
'total_params_billions': known['params_billions'],
|
69 |
+
'memory_fp32_gb': known['fp16_gb'] * 2,
|
70 |
+
'memory_fp16_gb': known['fp16_gb'],
|
71 |
+
'memory_bf16_gb': known['fp16_gb'],
|
72 |
+
'memory_int8_gb': known['fp16_gb'] / 2,
|
73 |
+
'estimated_inference_memory_fp16_gb': known['inference_fp16_gb'],
|
74 |
+
'estimated_inference_memory_bf16_gb': known['inference_fp16_gb'],
|
75 |
+
'source': 'known_values'
|
76 |
+
}
|
77 |
+
self.cache[model_id] = result
|
78 |
+
return result
|
79 |
+
|
80 |
+
# Try to estimate from HuggingFace API
|
81 |
+
try:
|
82 |
+
return self._estimate_from_api(model_id)
|
83 |
+
except Exception as e:
|
84 |
+
# Fallback to generic estimation
|
85 |
+
return self._generic_estimation(model_id, str(e))
|
86 |
+
|
87 |
+
def _estimate_from_api(self, model_id: str) -> Dict:
|
88 |
+
"""Estimate memory from HuggingFace model info."""
|
89 |
+
try:
|
90 |
+
print(f"Fetching model info for: {model_id}")
|
91 |
+
model_info = self.hf_api.model_info(model_id)
|
92 |
+
print(f"Successfully fetched model info for: {model_id}")
|
93 |
+
|
94 |
+
# Get file sizes from model repo
|
95 |
+
total_size_bytes = 0
|
96 |
+
safetensor_files = []
|
97 |
+
files_without_size = 0
|
98 |
+
|
99 |
+
for sibling in model_info.siblings:
|
100 |
+
if sibling.rfilename.endswith('.safetensors'):
|
101 |
+
file_size_bytes = sibling.size
|
102 |
+
if file_size_bytes is None or file_size_bytes == 0:
|
103 |
+
files_without_size += 1
|
104 |
+
print(f"Warning: No size info for {sibling.rfilename}")
|
105 |
+
# Try to estimate based on typical safetensor file sizes
|
106 |
+
if 'unet' in sibling.rfilename.lower():
|
107 |
+
file_size_bytes = 3_400_000_000 # ~3.4GB typical for UNet
|
108 |
+
elif 'text_encoder' in sibling.rfilename.lower():
|
109 |
+
file_size_bytes = 500_000_000 # ~500MB typical for text encoder
|
110 |
+
elif 'vae' in sibling.rfilename.lower():
|
111 |
+
file_size_bytes = 160_000_000 # ~160MB typical for VAE
|
112 |
+
else:
|
113 |
+
file_size_bytes = 500_000_000 # Default fallback
|
114 |
+
print(f" β Using estimated size: {file_size_bytes / (1024**3):.2f} GB")
|
115 |
+
else:
|
116 |
+
print(f"File {sibling.rfilename}: {file_size_bytes / (1024**3):.2f} GB")
|
117 |
+
|
118 |
+
size_mb = file_size_bytes / (1024 * 1024)
|
119 |
+
safetensor_files.append({
|
120 |
+
'filename': sibling.rfilename,
|
121 |
+
'size_mb': size_mb,
|
122 |
+
'estimated': file_size_bytes != sibling.size
|
123 |
+
})
|
124 |
+
total_size_bytes += file_size_bytes
|
125 |
+
|
126 |
+
print(f"Found {len(safetensor_files)} safetensor files, total size: {total_size_bytes / (1024**3):.2f} GB")
|
127 |
+
if files_without_size > 0:
|
128 |
+
print(f"Warning: {files_without_size} files had no size info, used estimates")
|
129 |
+
|
130 |
+
# Estimate parameters from file size (assuming FP16)
|
131 |
+
total_size_gb = total_size_bytes / (1024**3)
|
132 |
+
estimated_params = int((total_size_bytes / 2)) # 2 bytes per param for FP16
|
133 |
+
estimated_params_billions = estimated_params / 1e9
|
134 |
+
|
135 |
+
# Estimate inference memory (model + activations)
|
136 |
+
inference_multiplier = 1.5 # Conservative estimate
|
137 |
+
estimated_inference_memory = total_size_gb * inference_multiplier
|
138 |
+
|
139 |
+
result = {
|
140 |
+
'model_id': model_id,
|
141 |
+
'total_params': estimated_params,
|
142 |
+
'total_params_billions': estimated_params_billions,
|
143 |
+
'memory_fp32_gb': total_size_gb * 2,
|
144 |
+
'memory_fp16_gb': total_size_gb,
|
145 |
+
'memory_bf16_gb': total_size_gb,
|
146 |
+
'memory_int8_gb': total_size_gb / 2,
|
147 |
+
'estimated_inference_memory_fp16_gb': estimated_inference_memory,
|
148 |
+
'estimated_inference_memory_bf16_gb': estimated_inference_memory,
|
149 |
+
'safetensors_files': safetensor_files,
|
150 |
+
'files_without_size': files_without_size,
|
151 |
+
'source': 'api_estimation'
|
152 |
+
}
|
153 |
+
|
154 |
+
self.cache[model_id] = result
|
155 |
+
logger.info(f"Successfully estimated memory for {model_id} via API")
|
156 |
+
logger.debug(f"API estimation result: {result}")
|
157 |
+
return result
|
158 |
+
|
159 |
+
except Exception as api_error:
|
160 |
+
logger.error(f"API Error for model {model_id}: {type(api_error).__name__}: {str(api_error)}")
|
161 |
+
# Re-raise with more context
|
162 |
+
raise Exception(f"HuggingFace API Error: {type(api_error).__name__}: {str(api_error)}")
|
163 |
+
|
164 |
+
def _generic_estimation(self, model_id: str, error_msg: str) -> Dict:
|
165 |
+
"""Generic fallback estimation."""
|
166 |
+
logger.warning(f"Using generic estimation for {model_id} due to: {error_msg}")
|
167 |
+
|
168 |
+
# Default to medium-sized model estimates
|
169 |
+
default_params_billions = 3.0
|
170 |
+
default_fp16_gb = 6.0
|
171 |
+
|
172 |
+
logger.debug(f"Generic estimation parameters: {default_params_billions}B params, {default_fp16_gb}GB FP16")
|
173 |
+
|
174 |
+
result = {
|
175 |
+
'model_id': model_id,
|
176 |
+
'total_params': int(default_params_billions * 1e9),
|
177 |
+
'total_params_billions': default_params_billions,
|
178 |
+
'memory_fp32_gb': default_fp16_gb * 2,
|
179 |
+
'memory_fp16_gb': default_fp16_gb,
|
180 |
+
'memory_bf16_gb': default_fp16_gb,
|
181 |
+
'memory_int8_gb': default_fp16_gb / 2,
|
182 |
+
'estimated_inference_memory_fp16_gb': default_fp16_gb * 1.5,
|
183 |
+
'estimated_inference_memory_bf16_gb': default_fp16_gb * 1.5,
|
184 |
+
'source': 'generic_fallback',
|
185 |
+
'error': error_msg
|
186 |
+
}
|
187 |
+
|
188 |
+
logger.info(f"Generic estimation completed for {model_id}")
|
189 |
+
return result
|
190 |
+
|
191 |
+
def get_memory_recommendation(self, model_id: str, available_vram_gb: float) -> Dict:
|
192 |
+
"""Get memory recommendations based on available VRAM."""
|
193 |
+
logger.info(f"Generating memory recommendations for {model_id} with {available_vram_gb}GB VRAM")
|
194 |
+
|
195 |
+
memory_info = self.get_model_memory_requirements(model_id)
|
196 |
+
|
197 |
+
recommendations = {
|
198 |
+
'model_id': model_id,
|
199 |
+
'available_vram_gb': available_vram_gb,
|
200 |
+
'model_memory_fp16_gb': memory_info['memory_fp16_gb'],
|
201 |
+
'estimated_inference_memory_fp16_gb': memory_info['estimated_inference_memory_fp16_gb'],
|
202 |
+
'recommendations': []
|
203 |
+
}
|
204 |
+
|
205 |
+
inference_memory_fp16 = memory_info['estimated_inference_memory_fp16_gb']
|
206 |
+
model_memory_fp16 = memory_info['memory_fp16_gb']
|
207 |
+
|
208 |
+
logger.debug(f"Model memory: {model_memory_fp16}GB, Inference memory: {inference_memory_fp16}GB")
|
209 |
+
|
210 |
+
# Determine recommendations
|
211 |
+
if available_vram_gb >= inference_memory_fp16:
|
212 |
+
recommendations['recommendations'].append("β
Full model can fit in VRAM")
|
213 |
+
recommendations['recommended_precision'] = 'float16'
|
214 |
+
recommendations['cpu_offload'] = False
|
215 |
+
recommendations['attention_slicing'] = False
|
216 |
+
|
217 |
+
elif available_vram_gb >= model_memory_fp16:
|
218 |
+
recommendations['recommendations'].append("β οΈ Model weights fit, enable memory optimizations")
|
219 |
+
recommendations['recommended_precision'] = 'float16'
|
220 |
+
recommendations['cpu_offload'] = False
|
221 |
+
recommendations['attention_slicing'] = True
|
222 |
+
recommendations['vae_slicing'] = True
|
223 |
+
|
224 |
+
elif available_vram_gb >= model_memory_fp16 * 0.7:
|
225 |
+
recommendations['recommendations'].append("π Use CPU offloading for some components")
|
226 |
+
recommendations['recommended_precision'] = 'float16'
|
227 |
+
recommendations['cpu_offload'] = True
|
228 |
+
recommendations['attention_slicing'] = True
|
229 |
+
recommendations['vae_slicing'] = True
|
230 |
+
|
231 |
+
else:
|
232 |
+
recommendations['recommendations'].append("π Requires sequential CPU offloading")
|
233 |
+
recommendations['recommended_precision'] = 'float16'
|
234 |
+
recommendations['sequential_offload'] = True
|
235 |
+
recommendations['attention_slicing'] = True
|
236 |
+
recommendations['vae_slicing'] = True
|
237 |
+
|
238 |
+
return recommendations
|
239 |
+
|
240 |
+
def format_memory_info(self, model_id: str) -> str:
|
241 |
+
"""Format memory information for display."""
|
242 |
+
info = self.get_model_memory_requirements(model_id)
|
243 |
+
|
244 |
+
source_text = {
|
245 |
+
'known_values': 'π Known model specifications',
|
246 |
+
'api_estimation': 'π Estimated from model files',
|
247 |
+
'generic_fallback': 'β οΈ Generic estimation (API error)'
|
248 |
+
}.get(info.get('source', 'unknown'), 'β Unknown source')
|
249 |
+
|
250 |
+
# Add warning if file sizes were estimated
|
251 |
+
if info.get('files_without_size', 0) > 0:
|
252 |
+
source_text += f" (β οΈ {info['files_without_size']} files used size estimates)"
|
253 |
+
|
254 |
+
output = f"""
|
255 |
+
π€ **Memory Analysis for {model_id}**
|
256 |
+
|
257 |
+
{source_text}
|
258 |
+
|
259 |
+
π’ **Parameters**: {info['total_params_billions']:.1f}B parameters
|
260 |
+
|
261 |
+
πΎ **Model Memory Requirements**:
|
262 |
+
β’ FP32: {info['memory_fp32_gb']:.1f} GB
|
263 |
+
β’ FP16/BF16: {info['memory_fp16_gb']:.1f} GB
|
264 |
+
β’ INT8: {info['memory_int8_gb']:.1f} GB
|
265 |
+
|
266 |
+
π **Estimated Inference Memory**:
|
267 |
+
β’ FP16: {info['estimated_inference_memory_fp16_gb']:.1f} GB
|
268 |
+
β’ BF16: {info['estimated_inference_memory_bf16_gb']:.1f} GB
|
269 |
+
"""
|
270 |
+
|
271 |
+
if 'error' in info:
|
272 |
+
output += f"\nβ οΈ **Note**: {info['error']}"
|
273 |
+
|
274 |
+
return output.strip()
|
275 |
+
|
276 |
+
|
auto_diffusers/ui/__init__.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
User interface components.
|
3 |
+
|
4 |
+
This module contains the web interface and UI components
|
5 |
+
for the Auto Diffusers application.
|
6 |
+
"""
|
7 |
+
|
8 |
+
from .gradio_interface import create_gradio_interface
|
9 |
+
|
10 |
+
__all__ = [
|
11 |
+
"create_gradio_interface"
|
12 |
+
]
|
auto_diffusers/ui/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (439 Bytes). View file
|
|
auto_diffusers/ui/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (413 Bytes). View file
|
|
auto_diffusers/ui/__pycache__/gradio_interface.cpython-311.pyc
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:817b8406277df29c7ea8920085efcaca842422c6228346dbcacd5ce39853bf4e
|
3 |
+
size 106270
|
auto_diffusers/ui/__pycache__/gradio_interface.cpython-312.pyc
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:bb50d6060e996af9fc7a103042a23da0a351042bf02882f8d3dd3eae4dd37a67
|
3 |
+
size 100434
|
auto_diffusers/ui/gradio_interface.py
ADDED
The diff for this file is too large to render.
See raw diff
|
|
auto_diffusers/utils/__init__.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Utilities and configuration.
|
3 |
+
|
4 |
+
This module contains shared utilities, configuration management,
|
5 |
+
and logging setup for the Auto Diffusers application.
|
6 |
+
"""
|
7 |
+
|
8 |
+
from .logging_config import setup_debug_logging, log_system_info, log_session_end
|
9 |
+
|
10 |
+
__all__ = [
|
11 |
+
"setup_debug_logging",
|
12 |
+
"log_system_info",
|
13 |
+
"log_session_end"
|
14 |
+
]
|
auto_diffusers/utils/logging_config.py
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Debug configuration for Auto Diffusers Config
|
3 |
+
Provides centralized logging setup for the entire application
|
4 |
+
"""
|
5 |
+
|
6 |
+
import logging
|
7 |
+
import os
|
8 |
+
from datetime import datetime
|
9 |
+
|
10 |
+
def setup_debug_logging(log_level='DEBUG', log_to_file=True, log_to_console=True):
|
11 |
+
"""
|
12 |
+
Set up comprehensive debug logging for the entire application
|
13 |
+
|
14 |
+
Args:
|
15 |
+
log_level (str): Logging level ('DEBUG', 'INFO', 'WARNING', 'ERROR')
|
16 |
+
log_to_file (bool): Whether to log to files
|
17 |
+
log_to_console (bool): Whether to log to console
|
18 |
+
"""
|
19 |
+
|
20 |
+
# Create logs directory if it doesn't exist
|
21 |
+
if log_to_file:
|
22 |
+
os.makedirs('logs', exist_ok=True)
|
23 |
+
|
24 |
+
# Clear any existing handlers
|
25 |
+
root_logger = logging.getLogger()
|
26 |
+
root_logger.handlers.clear()
|
27 |
+
|
28 |
+
# Set root logging level
|
29 |
+
numeric_level = getattr(logging, log_level.upper(), logging.DEBUG)
|
30 |
+
root_logger.setLevel(numeric_level)
|
31 |
+
|
32 |
+
# Create formatter
|
33 |
+
formatter = logging.Formatter(
|
34 |
+
'%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s',
|
35 |
+
datefmt='%Y-%m-%d %H:%M:%S'
|
36 |
+
)
|
37 |
+
|
38 |
+
handlers = []
|
39 |
+
|
40 |
+
# Console handler
|
41 |
+
if log_to_console:
|
42 |
+
console_handler = logging.StreamHandler()
|
43 |
+
console_handler.setLevel(numeric_level)
|
44 |
+
console_handler.setFormatter(formatter)
|
45 |
+
handlers.append(console_handler)
|
46 |
+
|
47 |
+
# File handlers
|
48 |
+
if log_to_file:
|
49 |
+
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
50 |
+
|
51 |
+
# Main application log
|
52 |
+
main_log_file = f'logs/auto_diffusers_{timestamp}.log'
|
53 |
+
file_handler = logging.FileHandler(main_log_file)
|
54 |
+
file_handler.setLevel(numeric_level)
|
55 |
+
file_handler.setFormatter(formatter)
|
56 |
+
handlers.append(file_handler)
|
57 |
+
|
58 |
+
# Error-only log
|
59 |
+
error_log_file = f'logs/errors_{timestamp}.log'
|
60 |
+
error_handler = logging.FileHandler(error_log_file)
|
61 |
+
error_handler.setLevel(logging.ERROR)
|
62 |
+
error_handler.setFormatter(formatter)
|
63 |
+
handlers.append(error_handler)
|
64 |
+
|
65 |
+
# Add all handlers to root logger
|
66 |
+
for handler in handlers:
|
67 |
+
root_logger.addHandler(handler)
|
68 |
+
|
69 |
+
# Set up specific logger configurations
|
70 |
+
configure_component_loggers(numeric_level)
|
71 |
+
|
72 |
+
logging.info("=" * 80)
|
73 |
+
logging.info("AUTO DIFFUSERS CONFIG - DEBUG SESSION STARTED")
|
74 |
+
logging.info("=" * 80)
|
75 |
+
logging.info(f"Log level: {log_level}")
|
76 |
+
logging.info(f"Logging to console: {log_to_console}")
|
77 |
+
logging.info(f"Logging to file: {log_to_file}")
|
78 |
+
if log_to_file:
|
79 |
+
logging.info(f"Main log file: {main_log_file}")
|
80 |
+
logging.info(f"Error log file: {error_log_file}")
|
81 |
+
logging.info("=" * 80)
|
82 |
+
|
83 |
+
|
84 |
+
def configure_component_loggers(level):
|
85 |
+
"""Configure logging for individual components"""
|
86 |
+
|
87 |
+
# Main application components
|
88 |
+
components = [
|
89 |
+
'auto_diffusers',
|
90 |
+
'hardware_detector',
|
91 |
+
'simple_memory_calculator',
|
92 |
+
'gradio_app',
|
93 |
+
'__main__'
|
94 |
+
]
|
95 |
+
|
96 |
+
for component in components:
|
97 |
+
logger = logging.getLogger(component)
|
98 |
+
logger.setLevel(level)
|
99 |
+
# Don't propagate to avoid duplicate messages
|
100 |
+
logger.propagate = True
|
101 |
+
|
102 |
+
# Third-party library logging (reduce verbosity)
|
103 |
+
third_party_loggers = {
|
104 |
+
'urllib3': logging.WARNING,
|
105 |
+
'requests': logging.WARNING,
|
106 |
+
'httpx': logging.WARNING,
|
107 |
+
'gradio': logging.INFO,
|
108 |
+
'google': logging.INFO,
|
109 |
+
'huggingface_hub': logging.INFO
|
110 |
+
}
|
111 |
+
|
112 |
+
for lib_name, lib_level in third_party_loggers.items():
|
113 |
+
lib_logger = logging.getLogger(lib_name)
|
114 |
+
lib_logger.setLevel(lib_level)
|
115 |
+
|
116 |
+
|
117 |
+
def log_system_info():
|
118 |
+
"""Log comprehensive system information at startup"""
|
119 |
+
import platform
|
120 |
+
import sys
|
121 |
+
import os
|
122 |
+
|
123 |
+
logger = logging.getLogger(__name__)
|
124 |
+
|
125 |
+
logger.info("SYSTEM INFORMATION:")
|
126 |
+
logger.info(f" Platform: {platform.system()} {platform.release()}")
|
127 |
+
logger.info(f" Architecture: {platform.machine()}")
|
128 |
+
logger.info(f" Python: {sys.version}")
|
129 |
+
logger.info(f" Working directory: {os.getcwd()}")
|
130 |
+
logger.info(f" Process ID: {os.getpid()}")
|
131 |
+
|
132 |
+
# Environment variables (non-sensitive)
|
133 |
+
env_vars = ['GOOGLE_API_KEY', 'CUDA_VISIBLE_DEVICES', 'PYTORCH_CUDA_ALLOC_CONF']
|
134 |
+
logger.info("ENVIRONMENT VARIABLES:")
|
135 |
+
for var in env_vars:
|
136 |
+
value = os.getenv(var, 'Not set')
|
137 |
+
if var == 'GOOGLE_API_KEY' and value != 'Not set':
|
138 |
+
value = f"Set (length: {len(value)})"
|
139 |
+
logger.info(f" {var}: {value}")
|
140 |
+
|
141 |
+
|
142 |
+
def log_session_end():
|
143 |
+
"""Log session end information"""
|
144 |
+
logger = logging.getLogger(__name__)
|
145 |
+
logger.info("=" * 80)
|
146 |
+
logger.info("AUTO DIFFUSERS CONFIG - DEBUG SESSION ENDED")
|
147 |
+
logger.info("=" * 80)
|
148 |
+
|
149 |
+
|
150 |
+
if __name__ == "__main__":
|
151 |
+
# Example usage
|
152 |
+
setup_debug_logging(log_level='DEBUG')
|
153 |
+
log_system_info()
|
154 |
+
|
155 |
+
# Test logging from different components
|
156 |
+
logger = logging.getLogger(__name__)
|
157 |
+
logger.debug("This is a debug message")
|
158 |
+
logger.info("This is an info message")
|
159 |
+
logger.warning("This is a warning message")
|
160 |
+
logger.error("This is an error message")
|
161 |
+
|
162 |
+
log_session_end()
|
main.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
Main entry point for the Auto Diffusers application.
|
4 |
+
Simple launcher that starts the Gradio web interface.
|
5 |
+
"""
|
6 |
+
|
7 |
+
from auto_diffusers.ui.gradio_interface import main
|
8 |
+
|
9 |
+
if __name__ == "__main__":
|
10 |
+
main()
|
scripts/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Entry point scripts for the Auto Diffusers application.
|
3 |
+
"""
|
scripts/launch.py
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
Simple launcher script for the Gradio app with better error handling and debug logging.
|
4 |
+
"""
|
5 |
+
|
6 |
+
import os
|
7 |
+
import sys
|
8 |
+
from dotenv import load_dotenv
|
9 |
+
|
10 |
+
# Load environment variables
|
11 |
+
load_dotenv()
|
12 |
+
|
13 |
+
# Import and setup debug configuration
|
14 |
+
try:
|
15 |
+
from auto_diffusers.utils.logging_config import setup_debug_logging, log_system_info, log_session_end
|
16 |
+
import logging
|
17 |
+
|
18 |
+
# Setup debug logging (can be controlled via environment variable)
|
19 |
+
debug_level = os.getenv('DEBUG_LEVEL', 'INFO')
|
20 |
+
log_to_file = os.getenv('LOG_TO_FILE', 'true').lower() == 'true'
|
21 |
+
log_to_console = os.getenv('LOG_TO_CONSOLE', 'true').lower() == 'true'
|
22 |
+
|
23 |
+
setup_debug_logging(log_level=debug_level, log_to_file=log_to_file, log_to_console=log_to_console)
|
24 |
+
logger = logging.getLogger(__name__)
|
25 |
+
|
26 |
+
except ImportError:
|
27 |
+
# Fallback if logging_config is not available
|
28 |
+
import logging
|
29 |
+
logging.basicConfig(level=logging.INFO)
|
30 |
+
logger = logging.getLogger(__name__)
|
31 |
+
|
32 |
+
def check_requirements():
|
33 |
+
"""Check if all required packages are installed."""
|
34 |
+
logger.info("Checking package requirements...")
|
35 |
+
|
36 |
+
required_packages = [
|
37 |
+
'gradio', 'google.generativeai', 'torch', 'psutil'
|
38 |
+
]
|
39 |
+
|
40 |
+
missing = []
|
41 |
+
for package in required_packages:
|
42 |
+
try:
|
43 |
+
__import__(package.replace('-', '_'))
|
44 |
+
logger.debug(f"β Package {package} found")
|
45 |
+
except ImportError:
|
46 |
+
missing.append(package)
|
47 |
+
logger.warning(f"β Package {package} missing")
|
48 |
+
|
49 |
+
if missing:
|
50 |
+
logger.error(f"Missing packages: {', '.join(missing)}")
|
51 |
+
print(f"Missing packages: {', '.join(missing)}")
|
52 |
+
print("Please run: pip install -r requirements.txt")
|
53 |
+
return False
|
54 |
+
|
55 |
+
logger.info("All required packages are available")
|
56 |
+
return True
|
57 |
+
|
58 |
+
def check_api_key():
|
59 |
+
"""Check if API key is configured."""
|
60 |
+
logger.info("Checking API key configuration...")
|
61 |
+
|
62 |
+
api_key = os.getenv('GOOGLE_API_KEY')
|
63 |
+
if not api_key:
|
64 |
+
logger.error("GOOGLE_API_KEY not found in environment variables")
|
65 |
+
print("ERROR: GOOGLE_API_KEY not found in .env file")
|
66 |
+
print("Please add your Gemini API key to the .env file:")
|
67 |
+
print("GOOGLE_API_KEY=your_api_key_here")
|
68 |
+
return False
|
69 |
+
|
70 |
+
logger.info(f"API key found (length: {len(api_key)})")
|
71 |
+
return True
|
72 |
+
|
73 |
+
def main():
|
74 |
+
logger.info("Starting Auto Diffusers Config application")
|
75 |
+
print("π Starting Auto Diffusers Config Gradio App...")
|
76 |
+
|
77 |
+
# Log system information
|
78 |
+
try:
|
79 |
+
log_system_info()
|
80 |
+
except:
|
81 |
+
logger.warning("Could not log system info")
|
82 |
+
|
83 |
+
# Check requirements
|
84 |
+
if not check_requirements():
|
85 |
+
logger.error("Requirements check failed, exiting")
|
86 |
+
sys.exit(1)
|
87 |
+
|
88 |
+
if not check_api_key():
|
89 |
+
logger.error("API key check failed, exiting")
|
90 |
+
sys.exit(1)
|
91 |
+
|
92 |
+
try:
|
93 |
+
logger.info("Importing Gradio interface module")
|
94 |
+
from auto_diffusers.ui.gradio_interface import create_gradio_interface
|
95 |
+
|
96 |
+
logger.info("All requirements satisfied, launching interface")
|
97 |
+
print("β
All requirements satisfied")
|
98 |
+
print("π Launching Gradio interface...")
|
99 |
+
|
100 |
+
interface = create_gradio_interface()
|
101 |
+
logger.info("Gradio interface created successfully")
|
102 |
+
|
103 |
+
logger.info("Starting Gradio server on 0.0.0.0:7860")
|
104 |
+
interface.launch(
|
105 |
+
server_name="0.0.0.0",
|
106 |
+
server_port=7860,
|
107 |
+
share=True,
|
108 |
+
show_error=True,
|
109 |
+
inbrowser=True
|
110 |
+
)
|
111 |
+
|
112 |
+
except ImportError as e:
|
113 |
+
logger.error(f"Import error: {e}")
|
114 |
+
print(f"Import error: {e}")
|
115 |
+
print("Make sure all dependencies are installed: pip install -r requirements.txt")
|
116 |
+
except Exception as e:
|
117 |
+
logger.error(f"Error launching app: {e}", exc_info=True)
|
118 |
+
print(f"Error launching app: {e}")
|
119 |
+
finally:
|
120 |
+
try:
|
121 |
+
log_session_end()
|
122 |
+
except:
|
123 |
+
logger.warning("Could not log session end")
|
124 |
+
|
125 |
+
if __name__ == "__main__":
|
126 |
+
main()
|
tests/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Test suite for the Auto Diffusers application.
|
3 |
+
"""
|