lutflow 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lutflow-0.1.0/.gitignore +250 -0
- lutflow-0.1.0/CHANGELOG.md +139 -0
- lutflow-0.1.0/DEMO_SCRIPT_FINAL.py +238 -0
- lutflow-0.1.0/FIXES_REQUIRED.md +247 -0
- lutflow-0.1.0/LICENSE +107 -0
- lutflow-0.1.0/PKG-INFO +326 -0
- lutflow-0.1.0/README.md +169 -0
- lutflow-0.1.0/docs/DEMO_SCRIPT.md +174 -0
- lutflow-0.1.0/docs/PUBLISHING.md +76 -0
- lutflow-0.1.0/docs/SOCIAL_MEDIA_PHASE2.md +161 -0
- lutflow-0.1.0/docs/TINYFISH_INTEGRATION.md +103 -0
- lutflow-0.1.0/docs/USAGE.md +274 -0
- lutflow-0.1.0/docs/VIDEO_DEMO_GUIDE_FINAL.md +451 -0
- lutflow-0.1.0/docs/budget-strategies.mdx +115 -0
- lutflow-0.1.0/docs/cli.mdx +135 -0
- lutflow-0.1.0/docs/client.mdx +166 -0
- lutflow-0.1.0/docs/examples.mdx +174 -0
- lutflow-0.1.0/docs/quickstart.mdx +56 -0
- lutflow-0.1.0/docs/tinyfish.mdx +257 -0
- lutflow-0.1.0/docs/wrappers.mdx +195 -0
- lutflow-0.1.0/examples/demo_cli_commands.sh +57 -0
- lutflow-0.1.0/examples/tinyfish_gpu_lookup.py +93 -0
- lutflow-0.1.0/lutflow/__init__.py +44 -0
- lutflow-0.1.0/lutflow/budget.py +161 -0
- lutflow-0.1.0/lutflow/cli.py +699 -0
- lutflow-0.1.0/lutflow/client.py +472 -0
- lutflow-0.1.0/lutflow/executors/__init__.py +5 -0
- lutflow-0.1.0/lutflow/executors/self_kill.py +191 -0
- lutflow-0.1.0/lutflow/kafka/__init__.py +3 -0
- lutflow-0.1.0/lutflow/pcpo.py +597 -0
- lutflow-0.1.0/lutflow/pricing.py +211 -0
- lutflow-0.1.0/lutflow/py.typed +1 -0
- lutflow-0.1.0/lutflow/tinyfish.py +1318 -0
- lutflow-0.1.0/lutflow/wrappers/__init__.py +3 -0
- lutflow-0.1.0/lutflow/wrappers/anthropic.py +336 -0
- lutflow-0.1.0/lutflow/wrappers/gemini.py +244 -0
- lutflow-0.1.0/lutflow/wrappers/openai.py +276 -0
- lutflow-0.1.0/pyproject.toml +82 -0
- lutflow-0.1.0/scripts/fraud_detection_search.py +310 -0
- lutflow-0.1.0/scripts/stress_tests/01_basic_budget_enforcement.py +99 -0
- lutflow-0.1.0/scripts/stress_tests/02_pricing_accuracy.py +97 -0
- lutflow-0.1.0/scripts/stress_tests/03_tinyfish_cached.py +105 -0
- lutflow-0.1.0/scripts/stress_tests/04_pcpo_predictor.py +117 -0
- lutflow-0.1.0/scripts/stress_tests/05_executor_safety.py +94 -0
- lutflow-0.1.0/scripts/stress_tests/06_tinyfish_live_lambdalabs.py +102 -0
- lutflow-0.1.0/scripts/stress_tests/07_gemini_live_enforcement.py +109 -0
- lutflow-0.1.0/scripts/stress_tests/08_full_stack_integration.py +151 -0
- lutflow-0.1.0/scripts/stress_tests/09_cli_validation.py +105 -0
- lutflow-0.1.0/scripts/stress_tests/10_edge_cases.py +159 -0
- lutflow-0.1.0/tests/conftest.py +53 -0
- lutflow-0.1.0/tests/integration/__init__.py +1 -0
lutflow-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Lutflow .gitignore
|
|
2
|
+
# Enterprise MLOps Platform
|
|
3
|
+
# =========================
|
|
4
|
+
|
|
5
|
+
# ============================================
|
|
6
|
+
# OS Generated Files
|
|
7
|
+
# ============================================
|
|
8
|
+
.DS_Store
|
|
9
|
+
.DS_Store?
|
|
10
|
+
._*
|
|
11
|
+
.Spotlight-V100
|
|
12
|
+
.Trashes
|
|
13
|
+
ehthumbs.db
|
|
14
|
+
Thumbs.db
|
|
15
|
+
*.swp
|
|
16
|
+
*.swo
|
|
17
|
+
*~
|
|
18
|
+
|
|
19
|
+
# ============================================
|
|
20
|
+
# IDE / Editor
|
|
21
|
+
# ============================================
|
|
22
|
+
.idea/
|
|
23
|
+
.vscode/
|
|
24
|
+
*.sublime-workspace
|
|
25
|
+
*.sublime-project
|
|
26
|
+
.cursor/
|
|
27
|
+
.claude/
|
|
28
|
+
.cursorrules
|
|
29
|
+
|
|
30
|
+
# ============================================
|
|
31
|
+
# Environment & Secrets
|
|
32
|
+
# ============================================
|
|
33
|
+
.env
|
|
34
|
+
.env.demo
|
|
35
|
+
.env.local
|
|
36
|
+
.env.*.local
|
|
37
|
+
*.env
|
|
38
|
+
.envrc
|
|
39
|
+
.secrets
|
|
40
|
+
secrets/
|
|
41
|
+
*.pem
|
|
42
|
+
*.key
|
|
43
|
+
credentials*.json
|
|
44
|
+
|
|
45
|
+
# ============================================
|
|
46
|
+
# Go
|
|
47
|
+
# ============================================
|
|
48
|
+
*.exe
|
|
49
|
+
*.exe~
|
|
50
|
+
*.dll
|
|
51
|
+
*.so
|
|
52
|
+
*.dylib
|
|
53
|
+
bin/
|
|
54
|
+
services/*/bin/
|
|
55
|
+
services/*/tmp/
|
|
56
|
+
*.test
|
|
57
|
+
*.out
|
|
58
|
+
coverage.html
|
|
59
|
+
vendor/
|
|
60
|
+
go.work.sum
|
|
61
|
+
|
|
62
|
+
# ============================================
|
|
63
|
+
# Python
|
|
64
|
+
# ============================================
|
|
65
|
+
__pycache__/
|
|
66
|
+
*.py[cod]
|
|
67
|
+
*$py.class
|
|
68
|
+
.venv/
|
|
69
|
+
venv/
|
|
70
|
+
ENV/
|
|
71
|
+
env/
|
|
72
|
+
.python-version
|
|
73
|
+
build/
|
|
74
|
+
develop-eggs/
|
|
75
|
+
dist/
|
|
76
|
+
downloads/
|
|
77
|
+
eggs/
|
|
78
|
+
.eggs/
|
|
79
|
+
lib/
|
|
80
|
+
lib64/
|
|
81
|
+
parts/
|
|
82
|
+
sdist/
|
|
83
|
+
var/
|
|
84
|
+
wheels/
|
|
85
|
+
*.egg-info/
|
|
86
|
+
.installed.cfg
|
|
87
|
+
*.egg
|
|
88
|
+
pip-log.txt
|
|
89
|
+
pip-delete-this-directory.txt
|
|
90
|
+
htmlcov/
|
|
91
|
+
.tox/
|
|
92
|
+
.nox/
|
|
93
|
+
.coverage
|
|
94
|
+
.coverage.*
|
|
95
|
+
.cache
|
|
96
|
+
nosetests.xml
|
|
97
|
+
coverage.xml
|
|
98
|
+
*.cover
|
|
99
|
+
.hypothesis/
|
|
100
|
+
.pytest_cache/
|
|
101
|
+
.mypy_cache/
|
|
102
|
+
.dmypy.json
|
|
103
|
+
dmypy.json
|
|
104
|
+
.ruff_cache/
|
|
105
|
+
uv.lock
|
|
106
|
+
.ipynb_checkpoints
|
|
107
|
+
|
|
108
|
+
# ============================================
|
|
109
|
+
# Node.js / Next.js
|
|
110
|
+
# ============================================
|
|
111
|
+
node_modules/
|
|
112
|
+
.pnpm-store/
|
|
113
|
+
apps/web/.next/
|
|
114
|
+
apps/web/out/
|
|
115
|
+
apps/web/build/
|
|
116
|
+
.turbo/
|
|
117
|
+
.vercel/
|
|
118
|
+
|
|
119
|
+
# ============================================
|
|
120
|
+
# Docker
|
|
121
|
+
# ============================================
|
|
122
|
+
docker/data/
|
|
123
|
+
*.log
|
|
124
|
+
|
|
125
|
+
# ============================================
|
|
126
|
+
# Terraform
|
|
127
|
+
# ============================================
|
|
128
|
+
.terraform/
|
|
129
|
+
*.tfstate
|
|
130
|
+
*.tfstate.*
|
|
131
|
+
*.tfvars
|
|
132
|
+
!example.tfvars
|
|
133
|
+
.terraform.lock.hcl
|
|
134
|
+
|
|
135
|
+
# ============================================
|
|
136
|
+
# ML Artifacts (use MinIO/S3)
|
|
137
|
+
# ============================================
|
|
138
|
+
*.h5
|
|
139
|
+
*.hdf5
|
|
140
|
+
*.pkl
|
|
141
|
+
*.pickle
|
|
142
|
+
*.joblib
|
|
143
|
+
*.model
|
|
144
|
+
*.pt
|
|
145
|
+
*.pth
|
|
146
|
+
*.onnx
|
|
147
|
+
/models/ # Root-level ML models dir only — NOT services/*/models (Go packages)
|
|
148
|
+
artifacts/
|
|
149
|
+
mlruns/
|
|
150
|
+
luts/
|
|
151
|
+
|
|
152
|
+
# ============================================
|
|
153
|
+
# Logs & Debug
|
|
154
|
+
# ============================================
|
|
155
|
+
logs/
|
|
156
|
+
*.log
|
|
157
|
+
npm-debug.log*
|
|
158
|
+
yarn-debug.log*
|
|
159
|
+
yarn-error.log*
|
|
160
|
+
pnpm-debug.log*
|
|
161
|
+
|
|
162
|
+
# ============================================
|
|
163
|
+
# Testing
|
|
164
|
+
# ============================================
|
|
165
|
+
coverage/
|
|
166
|
+
.nyc_output/
|
|
167
|
+
test-results/
|
|
168
|
+
playwright-report/
|
|
169
|
+
|
|
170
|
+
# ============================================
|
|
171
|
+
# Local Development / Temporary Files
|
|
172
|
+
# ============================================
|
|
173
|
+
backup/
|
|
174
|
+
*.bak
|
|
175
|
+
*.tmp
|
|
176
|
+
*.temp
|
|
177
|
+
quick_test.py
|
|
178
|
+
demo_*.py
|
|
179
|
+
test_*.py
|
|
180
|
+
!services/**/test_*.py
|
|
181
|
+
!services/**/tests/
|
|
182
|
+
|
|
183
|
+
# ============================================
|
|
184
|
+
# Documentation (Internal Only - Root Level)
|
|
185
|
+
# Keep docs/ folder for public documentation
|
|
186
|
+
# ============================================
|
|
187
|
+
/AUDIT_*.md
|
|
188
|
+
/AUDITORIA_*.md
|
|
189
|
+
/*COMPLETE*.md
|
|
190
|
+
/*PROGRESS*.md
|
|
191
|
+
/*REPORT*.md
|
|
192
|
+
/MEGA_PROMPT_*.md
|
|
193
|
+
/PLAN_MAESTRO*.md
|
|
194
|
+
/compass_artifact*.md
|
|
195
|
+
/INFORME_*.md
|
|
196
|
+
/ESTADO_*.md
|
|
197
|
+
/EXECUTION_PLAN*.md
|
|
198
|
+
/RELEASE_*.txt
|
|
199
|
+
/SPRINT_*.md
|
|
200
|
+
/VERIFICATION_*.md
|
|
201
|
+
/VERIFICACION_*.md
|
|
202
|
+
/VERIFICADO*.md
|
|
203
|
+
/VAULT_*.md
|
|
204
|
+
/QA_*.md
|
|
205
|
+
/TESTING_GUIDE.md
|
|
206
|
+
/COMPREHENSIVE_*.md
|
|
207
|
+
/BENTOML_*.md
|
|
208
|
+
/OPERACIONALIZACION_*.md
|
|
209
|
+
/PCPO_*.md
|
|
210
|
+
/FLYWHEEL_*.md
|
|
211
|
+
/LUTFLOW_*.md
|
|
212
|
+
!/LUTFLOW_GROUP_B_TECHNICAL_REPORT.md
|
|
213
|
+
!/LUTFLOW_S0_GONOGO_REPORT.md
|
|
214
|
+
/Refactorizaci*.md
|
|
215
|
+
/FASE_*.md
|
|
216
|
+
/SISTEMA_*.md
|
|
217
|
+
/info.md
|
|
218
|
+
/test-vault.sh
|
|
219
|
+
|
|
220
|
+
# ============================================
|
|
221
|
+
# Transcriptions & Research
|
|
222
|
+
# ============================================
|
|
223
|
+
transcrip_AWS_AI/
|
|
224
|
+
|
|
225
|
+
# ============================================
|
|
226
|
+
# Images (except docs)
|
|
227
|
+
# ============================================
|
|
228
|
+
*.png
|
|
229
|
+
*.jpg
|
|
230
|
+
*.jpeg
|
|
231
|
+
*.gif
|
|
232
|
+
!docs/**/*.png
|
|
233
|
+
!docs/**/*.jpg
|
|
234
|
+
|
|
235
|
+
# ============================================
|
|
236
|
+
# Local Scripts (Windows)
|
|
237
|
+
# ============================================
|
|
238
|
+
*.bat
|
|
239
|
+
start-lutflow.ps1
|
|
240
|
+
|
|
241
|
+
# ============================================
|
|
242
|
+
# MCP Config (Local)
|
|
243
|
+
# ============================================
|
|
244
|
+
.mcp.json
|
|
245
|
+
|
|
246
|
+
# ============================================
|
|
247
|
+
# Local SDK / Tooling Downloads
|
|
248
|
+
# ============================================
|
|
249
|
+
google-cloud-sdk/
|
|
250
|
+
google-cloud-sdk-*.tar.gz
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Lutflow SDK will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-05-15
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- First stable release — exits alpha
|
|
13
|
+
- Development status updated to `5 - Production/Stable`
|
|
14
|
+
- All 3 version strings (`pyproject.toml`, `__init__.py`, CLI) bumped to `0.1.0`
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- `test_cli.py`: version assertion updated from `0.1.0a5` → `0.1.0a6` (test was hardcoded to stale version)
|
|
19
|
+
- `test_tinyfish_real.py`: mock for live API call updated to correctly simulate async submit→poll flow; spot price updated to reflect current RunPod cached rate ($0.44/hr)
|
|
20
|
+
|
|
21
|
+
## [0.1.0a6] - 2026-03-31
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Version consistency: `pyproject.toml` and `__init__.py` bumped to `0.1.0a6` after `a5` was published
|
|
26
|
+
- Minor internal cleanup for stable release preparation
|
|
27
|
+
|
|
28
|
+
## [0.1.0a5] - 2026-03-30
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **P0**: `lutflow.__version__` was stuck at `0.1.0a2` while `pyproject.toml` and CLI reported `0.1.0a4`
|
|
33
|
+
- **P0**: Anthropic dependency version mismatch — `[anthropic]` extra now requires `>=1.0.0` (was `>=0.18.0`)
|
|
34
|
+
- **P0**: CHANGELOG duplicate `0.1.0a3`/`0.1.0a4` sections collapsed
|
|
35
|
+
- **P0**: `demo-search --live` flag was dead code — `fetch_model_benchmarks_with_session` now accepts `quick` parameter
|
|
36
|
+
- **P0**: Removed unused `_endpoint()` helper in CLI
|
|
37
|
+
- **P1**: Gemini `wrap()` now passes full `Client` for unified cloud reporting (was only `BudgetGuard`)
|
|
38
|
+
- **P1**: `recommend()` source metadata reflects actual data provenance instead of API key presence
|
|
39
|
+
- **P1**: `compare_with_neo4j()` guards against missing `"name"` key in Neo4j dicts
|
|
40
|
+
- **P1**: `deploy` command now shows actual HTTP errors for 4xx/5xx instead of fake offline success
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- 24 tests for PCPO module (`CostPredictor`, `PredictiveBudgetGuard`, `PredictionResult`)
|
|
45
|
+
- 15 tests for OpenAI wrapper (token counting, chat completions, embeddings, budget enforcement)
|
|
46
|
+
- 17 tests for Anthropic wrapper (messages, streaming, model normalization)
|
|
47
|
+
- 7 tests for Client cloud reporting and version consistency
|
|
48
|
+
- 4 integration smoke test suites (73 tests total): imports, CLI, wrappers, TinyFish
|
|
49
|
+
- Test for Gemini `wrap()` passing full Client
|
|
50
|
+
- Test for `deploy` HTTP error handling
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- Total tests: 231 (up from 109)
|
|
55
|
+
- All 3 version strings (`pyproject.toml`, `__init__.py`, `cli.py`) now stay in sync with a consistency test
|
|
56
|
+
|
|
57
|
+
## [0.1.0a4] - 2026-03-29
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- **Model Intelligence**: New TinyFish integration for HuggingFace Leaderboard model benchmarks
|
|
62
|
+
- `fetch_model_benchmarks(task, max_params_b, quick)` - Fetch model benchmarks from HuggingFace
|
|
63
|
+
- `enrich_with_pricing(benchmarks, gpu_type)` - Add GPU pricing and VRAM estimates to benchmarks
|
|
64
|
+
- `recommend(task, budget_usd_per_hour, gpu_type, quick)` - Get top model recommendation within budget
|
|
65
|
+
- New dataclasses: `ModelBenchmark`, `EnrichedBenchmark`, `ModelRecommendation`
|
|
66
|
+
- `ModelIntelligenceEvent` dataclass for Kafka publishing
|
|
67
|
+
- `publish_model_intelligence_to_kafka()` function with mock support when Kafka not configured
|
|
68
|
+
- Cached benchmarks for 3 tasks: tabular-classification, text-classification, tabular-regression
|
|
69
|
+
- Task aliases: "classification" -> "text-classification", "tabular" -> "tabular-classification"
|
|
70
|
+
- CLI command: `lutflow recommend --task TEXT --budget FLOAT --gpu TEXT [--live] [--tenant TEXT]`
|
|
71
|
+
- CLI output includes "Knowledge graph updated: 1 new ModelIntelligence node → Neo4j"
|
|
72
|
+
- 24 new tests for model benchmark and Kafka functionality
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
|
|
76
|
+
- Documentation links now point to PyPI (https://pypi.org/project/lutflow/) instead of docs.lutflow.dev
|
|
77
|
+
- CLI help text updated with PyPI documentation URL
|
|
78
|
+
- Website link changed to lutflow.dev
|
|
79
|
+
|
|
80
|
+
## [0.1.0a3] - 2026-03-29
|
|
81
|
+
|
|
82
|
+
Skipped — version published incorrectly to PyPI, immediately replaced by 0.1.0a4.
|
|
83
|
+
|
|
84
|
+
## [0.1.0a2] - 2026-03-29
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- Google Gemini wrapper (gemini-2.5-flash, gemini-2.5-pro, gemini-2.0-flash, gemini-1.5-flash, gemini-1.5-pro, gemini-1.0-pro)
|
|
89
|
+
- `pip install lutflow[gemini]` for Google AI support
|
|
90
|
+
- Gemini pricing table (input/output per 1K tokens)
|
|
91
|
+
- Multi-GPU cached prices in TinyFish (L4, A100-80GB, H100-80GB, T4)
|
|
92
|
+
- GPU type aliases in TinyFish ("l4" -> "nvidia-l4", "a100" -> "nvidia-a100-80gb")
|
|
93
|
+
- `as_dict()` method on GPUPrice and GPUPricingResult for JSON serialization
|
|
94
|
+
- `is_live` property on GPUPricingResult to check if any price is live
|
|
95
|
+
- `quick=True` parameter for TinyFish to use cached prices instantly (recommended for demos)
|
|
96
|
+
- Documentation: Confluent Kafka/Flink/Tableflow architecture
|
|
97
|
+
- 13 new tests for Gemini wrapper (including gemini-2.5 normalization)
|
|
98
|
+
- 18 new tests for enhanced TinyFish integration (including quick mode)
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
|
|
102
|
+
- **BREAKING**: Default `on_budget_exceeded` strategy changed from `SELF_KILL` to `RAISE_ERROR`
|
|
103
|
+
- This is safer for new users who may not expect their process to be killed
|
|
104
|
+
- Use `on_budget_exceeded=BudgetStrategy.SELF_KILL` to restore previous behavior
|
|
105
|
+
- CLI commands now show `[OFFLINE MODE]` when Lutflow API is unreachable
|
|
106
|
+
- Previously showed misleading success messages
|
|
107
|
+
- CLI `watch` command now shows `[SIMULATED DATA]` header
|
|
108
|
+
- Clarifies that data is simulated until connected to Lutflow Cloud
|
|
109
|
+
- Removed `pydantic` from core dependencies (~30MB lighter install)
|
|
110
|
+
- README updated with Confluent AI Accelerator Cohort 3 and TinyFish Accelerator mentions
|
|
111
|
+
- TinyFish prices now sorted by spot price (cheapest first)
|
|
112
|
+
- TinyFish source field changed from "cached_fallback" to "cached" for clarity
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
|
|
116
|
+
- CLI `deploy` no longer prints fake "Kill path: ACTIVE" when API is unreachable
|
|
117
|
+
- CLI `status` no longer prints hardcoded fake data when API is unreachable
|
|
118
|
+
- CLI `kill` no longer prints fake "kubectl delete deployment executed" when API is unreachable
|
|
119
|
+
|
|
120
|
+
### Notes
|
|
121
|
+
|
|
122
|
+
- TinyFish live price fetching can take 1-3 minutes per provider due to complex JavaScript sites
|
|
123
|
+
- Use `quick=True` for instant cached prices (recommended for demos and CI/CD)
|
|
124
|
+
- Cached prices are updated weekly and are accurate for most use cases
|
|
125
|
+
|
|
126
|
+
## [0.1.0a1] - 2026-03-28
|
|
127
|
+
|
|
128
|
+
### Added
|
|
129
|
+
|
|
130
|
+
- Initial alpha release
|
|
131
|
+
- `Client` class for budget-aware LLM API usage
|
|
132
|
+
- OpenAI wrapper (`chat.completions`, `embeddings`)
|
|
133
|
+
- Anthropic wrapper (`messages`, `stream`)
|
|
134
|
+
- Four budget strategies: `RAISE_ERROR`, `WARN_ONLY`, `CALLBACK`, `SELF_KILL`
|
|
135
|
+
- Token-based pricing for 13 models (OpenAI, Anthropic, Google)
|
|
136
|
+
- GPU-time pricing for 5 GPU types
|
|
137
|
+
- TinyFish integration for real-time GPU price discovery
|
|
138
|
+
- CLI commands: `lookup`, `deploy`, `status`, `watch`, `kill`
|
|
139
|
+
- Local-only mode (no Lutflow Cloud required)
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
DEMO_SCRIPT_FINAL.py — TinyFish Accelerator x Google for Startups video demo.
|
|
4
|
+
|
|
5
|
+
This script demonstrates Lutflow's GPU Financial Firewall capabilities:
|
|
6
|
+
1. TinyFish GPU price lookup (works with cached fallback)
|
|
7
|
+
2. Budget enforcement with Google Gemini
|
|
8
|
+
3. Cost tracking across multiple API calls
|
|
9
|
+
|
|
10
|
+
REQUIREMENTS:
|
|
11
|
+
- pip install lutflow[gemini]
|
|
12
|
+
- GOOGLE_API_KEY environment variable (for Gemini API calls)
|
|
13
|
+
- TINYFISH_API_KEY environment variable (optional, for live prices)
|
|
14
|
+
|
|
15
|
+
CONTINGENCY PLAN (if something fails in live demo):
|
|
16
|
+
- If TinyFish fails: cached prices will be shown (still looks good)
|
|
17
|
+
- If Gemini fails: the budget enforcement still works with simulation
|
|
18
|
+
- If budget doesn't trigger: lower the budget_usd
|
|
19
|
+
|
|
20
|
+
Run: python DEMO_SCRIPT_FINAL.py
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
# ==============================================================================
|
|
27
|
+
# CONFIGURATION — Adjust these for the demo
|
|
28
|
+
# ==============================================================================
|
|
29
|
+
DEMO_BUDGET_USD = 0.00008 # triggers enforcement around 13-15 Gemini 2.5 Flash calls
|
|
30
|
+
DEMO_MODEL = "gemini-2.5-flash" # Latest fast model for demo
|
|
31
|
+
DEMO_MAX_CALLS = 20 # Safety limit
|
|
32
|
+
|
|
33
|
+
# ==============================================================================
|
|
34
|
+
# PART 1: TinyFish GPU Price Lookup
|
|
35
|
+
# ==============================================================================
|
|
36
|
+
def demo_tinyfish_lookup():
|
|
37
|
+
"""Demonstrate TinyFish GPU price discovery."""
|
|
38
|
+
print()
|
|
39
|
+
print("=" * 55)
|
|
40
|
+
print(" Step 1/3: GPU Price Lookup (powered by TinyFish)")
|
|
41
|
+
print("=" * 55)
|
|
42
|
+
print()
|
|
43
|
+
|
|
44
|
+
from lutflow.tinyfish import TinyFishClient
|
|
45
|
+
|
|
46
|
+
tf = TinyFishClient()
|
|
47
|
+
|
|
48
|
+
# Use quick=True for instant results (cached prices)
|
|
49
|
+
# Set quick=False and increase timeout for live prices (takes 1-3 min/provider)
|
|
50
|
+
result = tf.fetch_all_prices(gpu_type="nvidia-l4", quick=True)
|
|
51
|
+
|
|
52
|
+
mode = "LIVE" if result.is_live else "CACHED"
|
|
53
|
+
print(f" Source: {mode} prices")
|
|
54
|
+
print()
|
|
55
|
+
|
|
56
|
+
for p in result.prices:
|
|
57
|
+
marker = " <- CHEAPEST" if p == result.cheapest else ""
|
|
58
|
+
print(f" {p.provider:<12} ${p.spot_usd_per_hour:.2f}/hr{marker}")
|
|
59
|
+
|
|
60
|
+
print()
|
|
61
|
+
if result.cheapest:
|
|
62
|
+
runtime = result.budget_runtime_minutes(0.05)
|
|
63
|
+
print(f" $0.05 budget = ~{runtime:.0f} min on {result.cheapest.provider}")
|
|
64
|
+
print()
|
|
65
|
+
|
|
66
|
+
return result
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ==============================================================================
|
|
70
|
+
# PART 2: Budget Enforcement with Gemini
|
|
71
|
+
# ==============================================================================
|
|
72
|
+
def demo_budget_enforcement():
|
|
73
|
+
"""Demonstrate budget enforcement with Google Gemini."""
|
|
74
|
+
print("=" * 55)
|
|
75
|
+
print(" Step 2/3: Budget Enforcement with Google Gemini")
|
|
76
|
+
print("=" * 55)
|
|
77
|
+
print()
|
|
78
|
+
|
|
79
|
+
gemini_key = os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")
|
|
80
|
+
if not gemini_key:
|
|
81
|
+
print(" GOOGLE_API_KEY not set - running in simulation mode")
|
|
82
|
+
print()
|
|
83
|
+
return demo_budget_enforcement_simulated()
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
import google.generativeai as genai
|
|
87
|
+
except ImportError:
|
|
88
|
+
print(" google-generativeai not installed")
|
|
89
|
+
print(" Run: pip install lutflow[gemini]")
|
|
90
|
+
print()
|
|
91
|
+
return demo_budget_enforcement_simulated()
|
|
92
|
+
|
|
93
|
+
from lutflow import Client, BudgetStrategy, BudgetExceededError
|
|
94
|
+
|
|
95
|
+
genai.configure(api_key=gemini_key)
|
|
96
|
+
model = genai.GenerativeModel(DEMO_MODEL)
|
|
97
|
+
|
|
98
|
+
print(f" Budget: ${DEMO_BUDGET_USD:.2f}")
|
|
99
|
+
print(f" Model: {DEMO_MODEL}")
|
|
100
|
+
print(f" Strategy: RAISE_ERROR")
|
|
101
|
+
print()
|
|
102
|
+
|
|
103
|
+
client = Client(
|
|
104
|
+
tenant_id="tinyfish-demo",
|
|
105
|
+
budget_usd=DEMO_BUDGET_USD,
|
|
106
|
+
on_budget_exceeded=BudgetStrategy.RAISE_ERROR,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
wrapped = client.wrap(model)
|
|
110
|
+
|
|
111
|
+
print(f" {'Call':<6} {'Spent':<12} {'Remaining':<12} Response")
|
|
112
|
+
print(" " + "-" * 50)
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
for i in range(1, DEMO_MAX_CALLS + 1):
|
|
116
|
+
response = wrapped.generate_content(
|
|
117
|
+
f"In one sentence, what is the number {i}?"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
text = response.text[:40].replace("\n", " ") if response.text else ""
|
|
121
|
+
print(
|
|
122
|
+
f" {i:<6} "
|
|
123
|
+
f"${client.accumulated_cost_usd:<11.6f} "
|
|
124
|
+
f"${client.remaining_budget_usd:<11.6f} "
|
|
125
|
+
f"{text}..."
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
except BudgetExceededError as e:
|
|
129
|
+
print()
|
|
130
|
+
print(" " + "=" * 50)
|
|
131
|
+
print(" BUDGET ENFORCED")
|
|
132
|
+
print(f" Spent: ${e.spent_usd:.6f}")
|
|
133
|
+
print(f" Budget: ${e.budget_usd:.2f}")
|
|
134
|
+
print(" " + "=" * 50)
|
|
135
|
+
print()
|
|
136
|
+
return True
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
print(f"\n Error: {type(e).__name__}: {e}")
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
print("\n Budget was not exceeded within the call limit.")
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def demo_budget_enforcement_simulated():
|
|
147
|
+
"""Simulated budget enforcement without real API calls."""
|
|
148
|
+
from lutflow import Client, BudgetStrategy, BudgetExceededError
|
|
149
|
+
|
|
150
|
+
print(f" Budget: ${DEMO_BUDGET_USD:.2f}")
|
|
151
|
+
print(f" Strategy: RAISE_ERROR")
|
|
152
|
+
print()
|
|
153
|
+
|
|
154
|
+
client = Client(
|
|
155
|
+
tenant_id="tinyfish-demo",
|
|
156
|
+
budget_usd=DEMO_BUDGET_USD,
|
|
157
|
+
on_budget_exceeded=BudgetStrategy.RAISE_ERROR,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
print(" Simulating Gemini API calls...")
|
|
161
|
+
print()
|
|
162
|
+
print(f" {'Call':<6} {'Spent':<12} {'Remaining':<12} Status")
|
|
163
|
+
print(" " + "-" * 40)
|
|
164
|
+
|
|
165
|
+
# Simulate costs similar to gemini-2.0-flash
|
|
166
|
+
simulated_cost_per_call = 0.003 # ~$0.003 per call
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
for i in range(1, DEMO_MAX_CALLS + 1):
|
|
170
|
+
client.add_cost(simulated_cost_per_call)
|
|
171
|
+
|
|
172
|
+
status = "OK" if client.budget_utilization_percent < 80 else "WARNING"
|
|
173
|
+
|
|
174
|
+
print(
|
|
175
|
+
f" {i:<6} "
|
|
176
|
+
f"${client.accumulated_cost_usd:<11.6f} "
|
|
177
|
+
f"${client.remaining_budget_usd:<11.6f} "
|
|
178
|
+
f"{status}"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
except BudgetExceededError as e:
|
|
182
|
+
print()
|
|
183
|
+
print(" " + "=" * 40)
|
|
184
|
+
print(" BUDGET ENFORCED (simulated)")
|
|
185
|
+
print(f" Spent: ${e.spent_usd:.6f}")
|
|
186
|
+
print(f" Budget: ${e.budget_usd:.2f}")
|
|
187
|
+
print(" " + "=" * 40)
|
|
188
|
+
print()
|
|
189
|
+
return True
|
|
190
|
+
|
|
191
|
+
return False
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# ==============================================================================
|
|
195
|
+
# PART 3: Summary
|
|
196
|
+
# ==============================================================================
|
|
197
|
+
def demo_summary():
|
|
198
|
+
"""Print demo summary."""
|
|
199
|
+
print("=" * 55)
|
|
200
|
+
print(" Step 3/3: Summary")
|
|
201
|
+
print("=" * 55)
|
|
202
|
+
print()
|
|
203
|
+
print(" What you just saw:")
|
|
204
|
+
print(" - TinyFish found cheapest GPU provider")
|
|
205
|
+
print(" - Gemini tracked every token automatically")
|
|
206
|
+
print(" - Budget enforced before damage occurred")
|
|
207
|
+
print()
|
|
208
|
+
print(" Lookup -> Flow -> Value")
|
|
209
|
+
print()
|
|
210
|
+
print(" pip install lutflow[gemini]")
|
|
211
|
+
print(" pypi.org/project/lutflow")
|
|
212
|
+
print()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ==============================================================================
|
|
216
|
+
# MAIN
|
|
217
|
+
# ==============================================================================
|
|
218
|
+
def main():
|
|
219
|
+
print()
|
|
220
|
+
print("=" * 55)
|
|
221
|
+
print(" LUTFLOW — GPU Financial Firewall")
|
|
222
|
+
print(" TinyFish Accelerator x Google for Startups")
|
|
223
|
+
print("=" * 55)
|
|
224
|
+
|
|
225
|
+
# Part 1: TinyFish lookup
|
|
226
|
+
demo_tinyfish_lookup()
|
|
227
|
+
|
|
228
|
+
# Part 2: Budget enforcement
|
|
229
|
+
success = demo_budget_enforcement()
|
|
230
|
+
|
|
231
|
+
# Part 3: Summary
|
|
232
|
+
demo_summary()
|
|
233
|
+
|
|
234
|
+
return 0 if success else 1
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
if __name__ == "__main__":
|
|
238
|
+
sys.exit(main())
|