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.
Files changed (51) hide show
  1. lutflow-0.1.0/.gitignore +250 -0
  2. lutflow-0.1.0/CHANGELOG.md +139 -0
  3. lutflow-0.1.0/DEMO_SCRIPT_FINAL.py +238 -0
  4. lutflow-0.1.0/FIXES_REQUIRED.md +247 -0
  5. lutflow-0.1.0/LICENSE +107 -0
  6. lutflow-0.1.0/PKG-INFO +326 -0
  7. lutflow-0.1.0/README.md +169 -0
  8. lutflow-0.1.0/docs/DEMO_SCRIPT.md +174 -0
  9. lutflow-0.1.0/docs/PUBLISHING.md +76 -0
  10. lutflow-0.1.0/docs/SOCIAL_MEDIA_PHASE2.md +161 -0
  11. lutflow-0.1.0/docs/TINYFISH_INTEGRATION.md +103 -0
  12. lutflow-0.1.0/docs/USAGE.md +274 -0
  13. lutflow-0.1.0/docs/VIDEO_DEMO_GUIDE_FINAL.md +451 -0
  14. lutflow-0.1.0/docs/budget-strategies.mdx +115 -0
  15. lutflow-0.1.0/docs/cli.mdx +135 -0
  16. lutflow-0.1.0/docs/client.mdx +166 -0
  17. lutflow-0.1.0/docs/examples.mdx +174 -0
  18. lutflow-0.1.0/docs/quickstart.mdx +56 -0
  19. lutflow-0.1.0/docs/tinyfish.mdx +257 -0
  20. lutflow-0.1.0/docs/wrappers.mdx +195 -0
  21. lutflow-0.1.0/examples/demo_cli_commands.sh +57 -0
  22. lutflow-0.1.0/examples/tinyfish_gpu_lookup.py +93 -0
  23. lutflow-0.1.0/lutflow/__init__.py +44 -0
  24. lutflow-0.1.0/lutflow/budget.py +161 -0
  25. lutflow-0.1.0/lutflow/cli.py +699 -0
  26. lutflow-0.1.0/lutflow/client.py +472 -0
  27. lutflow-0.1.0/lutflow/executors/__init__.py +5 -0
  28. lutflow-0.1.0/lutflow/executors/self_kill.py +191 -0
  29. lutflow-0.1.0/lutflow/kafka/__init__.py +3 -0
  30. lutflow-0.1.0/lutflow/pcpo.py +597 -0
  31. lutflow-0.1.0/lutflow/pricing.py +211 -0
  32. lutflow-0.1.0/lutflow/py.typed +1 -0
  33. lutflow-0.1.0/lutflow/tinyfish.py +1318 -0
  34. lutflow-0.1.0/lutflow/wrappers/__init__.py +3 -0
  35. lutflow-0.1.0/lutflow/wrappers/anthropic.py +336 -0
  36. lutflow-0.1.0/lutflow/wrappers/gemini.py +244 -0
  37. lutflow-0.1.0/lutflow/wrappers/openai.py +276 -0
  38. lutflow-0.1.0/pyproject.toml +82 -0
  39. lutflow-0.1.0/scripts/fraud_detection_search.py +310 -0
  40. lutflow-0.1.0/scripts/stress_tests/01_basic_budget_enforcement.py +99 -0
  41. lutflow-0.1.0/scripts/stress_tests/02_pricing_accuracy.py +97 -0
  42. lutflow-0.1.0/scripts/stress_tests/03_tinyfish_cached.py +105 -0
  43. lutflow-0.1.0/scripts/stress_tests/04_pcpo_predictor.py +117 -0
  44. lutflow-0.1.0/scripts/stress_tests/05_executor_safety.py +94 -0
  45. lutflow-0.1.0/scripts/stress_tests/06_tinyfish_live_lambdalabs.py +102 -0
  46. lutflow-0.1.0/scripts/stress_tests/07_gemini_live_enforcement.py +109 -0
  47. lutflow-0.1.0/scripts/stress_tests/08_full_stack_integration.py +151 -0
  48. lutflow-0.1.0/scripts/stress_tests/09_cli_validation.py +105 -0
  49. lutflow-0.1.0/scripts/stress_tests/10_edge_cases.py +159 -0
  50. lutflow-0.1.0/tests/conftest.py +53 -0
  51. lutflow-0.1.0/tests/integration/__init__.py +1 -0
@@ -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())