pbigen 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 (34) hide show
  1. pbigen-0.1.0/.gitignore +26 -0
  2. pbigen-0.1.0/AUTHORS.md +7 -0
  3. pbigen-0.1.0/CHANGELOG.md +24 -0
  4. pbigen-0.1.0/LICENSE +21 -0
  5. pbigen-0.1.0/PKG-INFO +543 -0
  6. pbigen-0.1.0/README.md +469 -0
  7. pbigen-0.1.0/examples/README.md +15 -0
  8. pbigen-0.1.0/pyproject.toml +82 -0
  9. pbigen-0.1.0/src/pbigen/__init__.py +39 -0
  10. pbigen-0.1.0/src/pbigen/cli.py +114 -0
  11. pbigen-0.1.0/src/pbigen/core/__init__.py +18 -0
  12. pbigen-0.1.0/src/pbigen/core/design.py +184 -0
  13. pbigen-0.1.0/src/pbigen/core/generator.py +69 -0
  14. pbigen-0.1.0/src/pbigen/core/layout.py +88 -0
  15. pbigen-0.1.0/src/pbigen/core/schema.py +64 -0
  16. pbigen-0.1.0/src/pbigen/emit/__init__.py +12 -0
  17. pbigen-0.1.0/src/pbigen/emit/model.py +101 -0
  18. pbigen-0.1.0/src/pbigen/emit/pbir.py +187 -0
  19. pbigen-0.1.0/src/pbigen/emit/visuals.py +179 -0
  20. pbigen-0.1.0/src/pbigen/models/__init__.py +28 -0
  21. pbigen-0.1.0/src/pbigen/models/base.py +30 -0
  22. pbigen-0.1.0/src/pbigen/models/litellm_model.py +186 -0
  23. pbigen-0.1.0/src/pbigen/models/null_model.py +21 -0
  24. pbigen-0.1.0/src/pbigen/sources/__init__.py +55 -0
  25. pbigen-0.1.0/src/pbigen/sources/base.py +64 -0
  26. pbigen-0.1.0/src/pbigen/sources/bigquery.py +81 -0
  27. pbigen-0.1.0/src/pbigen/sources/cube.py +93 -0
  28. pbigen-0.1.0/src/pbigen/sources/lakehouse.py +145 -0
  29. pbigen-0.1.0/src/pbigen/sources/sql_base.py +116 -0
  30. pbigen-0.1.0/src/pbigen/sources/warehouses.py +190 -0
  31. pbigen-0.1.0/src/pbigen/themes/__init__.py +54 -0
  32. pbigen-0.1.0/src/pbigen/themes/aurora.json +25 -0
  33. pbigen-0.1.0/src/pbigen/themes/midnight.json +31 -0
  34. pbigen-0.1.0/src/pbigen/themes/slate.json +25 -0
@@ -0,0 +1,26 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ htmlcov/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+
18
+ # Generated output
19
+ out/
20
+ *.pbip.bak
21
+
22
+ # OS / editor
23
+ .DS_Store
24
+ .idea/
25
+ .vscode/
26
+ *.swp
@@ -0,0 +1,7 @@
1
+ # Authors
2
+
3
+ pbigen is created and maintained by:
4
+
5
+ - **Arka Gupta** — author and maintainer <arka.jojo@gmail.com>
6
+
7
+ Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Contributors will be listed here.
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/), and the project adheres to semantic versioning.
5
+
6
+ ## [0.1.0] — Unreleased
7
+
8
+ Initial release.
9
+
10
+ ### Added
11
+
12
+ - Source adapters with one read-only introspect / cardinality / connect contract:
13
+ - BigQuery, BigLake, BigQuery Omni
14
+ - Redshift, Athena, Snowflake, Synapse/Fabric, Databricks, ClickHouse, PostgreSQL
15
+ - Parquet, Apache Iceberg and Delta Lake on local disk, GCS, S3 or ADLS (DuckDB)
16
+ - Cube semantic layer
17
+ - Deterministic, cardinality-aware design engine (charts and filters chosen from data shape).
18
+ - Optional LLM design refinement through LiteLLM (bring your own hosted or local model); metadata
19
+ only, with schema-validated output and graceful fallback.
20
+ - Power BI emitter producing an openable PBIP project: PBIR report with a navigation sidebar,
21
+ KPI cards, data-appropriate visuals and usage notes, plus a TMDL semantic model wired to the
22
+ source. Output validates against Microsoft's published PBIR schemas.
23
+ - Built-in themes (midnight, slate, aurora) and bring-your-own Power BI theme JSON support.
24
+ - `pbigen` CLI (`generate`, `test`, `sources`, `themes`) and a `pbigen.generate()` Python API.
pbigen-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arka Gupta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
pbigen-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,543 @@
1
+ Metadata-Version: 2.5
2
+ Name: pbigen
3
+ Version: 0.1.0
4
+ Summary: Generate governed, version-controlled Power BI reports from any warehouse or lakehouse — from a table and a plain-language objective.
5
+ Project-URL: Homepage, https://github.com/arkajojo/pbigen
6
+ Project-URL: Repository, https://github.com/arkajojo/pbigen
7
+ Project-URL: Issues, https://github.com/arkajojo/pbigen/issues
8
+ Project-URL: Changelog, https://github.com/arkajojo/pbigen/blob/main/CHANGELOG.md
9
+ Author-email: Arka Gupta <arka.jojo@gmail.com>
10
+ Maintainer-email: Arka Gupta <arka.jojo@gmail.com>
11
+ License: MIT
12
+ License-File: AUTHORS.md
13
+ License-File: LICENSE
14
+ Keywords: analytics-engineering,bigquery,business-intelligence,dashboards-as-code,data-visualization,databricks,delta-lake,iceberg,llm,pbip,pbir,power-bi,redshift,snowflake
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Intended Audience :: Information Technology
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: Database :: Front-Ends
25
+ Classifier: Topic :: Scientific/Engineering :: Visualization
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.9
28
+ Provides-Extra: all
29
+ Requires-Dist: duckdb>=1.0; extra == 'all'
30
+ Requires-Dist: google-cloud-bigquery>=3.11; extra == 'all'
31
+ Requires-Dist: litellm>=1.40; extra == 'all'
32
+ Requires-Dist: requests>=2.28; extra == 'all'
33
+ Requires-Dist: sqlalchemy>=2.0; extra == 'all'
34
+ Provides-Extra: athena
35
+ Requires-Dist: pyathena[sqlalchemy]>=3.0; extra == 'athena'
36
+ Requires-Dist: sqlalchemy>=2.0; extra == 'athena'
37
+ Provides-Extra: bigquery
38
+ Requires-Dist: google-cloud-bigquery>=3.11; extra == 'bigquery'
39
+ Provides-Extra: clickhouse
40
+ Requires-Dist: clickhouse-sqlalchemy>=0.3; extra == 'clickhouse'
41
+ Requires-Dist: sqlalchemy>=2.0; extra == 'clickhouse'
42
+ Provides-Extra: cube
43
+ Requires-Dist: requests>=2.28; extra == 'cube'
44
+ Provides-Extra: databricks
45
+ Requires-Dist: databricks-sql-connector>=3.0; extra == 'databricks'
46
+ Requires-Dist: sqlalchemy>=2.0; extra == 'databricks'
47
+ Provides-Extra: dev
48
+ Requires-Dist: build>=1.2; extra == 'dev'
49
+ Requires-Dist: pillow>=10.0; extra == 'dev'
50
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
51
+ Requires-Dist: pytest>=7.4; extra == 'dev'
52
+ Requires-Dist: ruff>=0.5; extra == 'dev'
53
+ Requires-Dist: twine>=5.0; extra == 'dev'
54
+ Provides-Extra: lakehouse
55
+ Requires-Dist: duckdb>=1.0; extra == 'lakehouse'
56
+ Provides-Extra: llm
57
+ Requires-Dist: litellm>=1.40; extra == 'llm'
58
+ Provides-Extra: postgres
59
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
60
+ Requires-Dist: sqlalchemy>=2.0; extra == 'postgres'
61
+ Provides-Extra: redshift
62
+ Requires-Dist: redshift-connector>=2.0; extra == 'redshift'
63
+ Requires-Dist: sqlalchemy-redshift>=0.8; extra == 'redshift'
64
+ Requires-Dist: sqlalchemy>=2.0; extra == 'redshift'
65
+ Provides-Extra: snowflake
66
+ Requires-Dist: snowflake-sqlalchemy>=1.5; extra == 'snowflake'
67
+ Requires-Dist: sqlalchemy>=2.0; extra == 'snowflake'
68
+ Provides-Extra: sqlalchemy
69
+ Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
70
+ Provides-Extra: synapse
71
+ Requires-Dist: pyodbc>=5.0; extra == 'synapse'
72
+ Requires-Dist: sqlalchemy>=2.0; extra == 'synapse'
73
+ Description-Content-Type: text/markdown
74
+
75
+ <p align="center">
76
+ <img src="https://raw.githubusercontent.com/arkajojo/pbigen/main/assets/logo.svg" alt="pbigen" width="440">
77
+ </p>
78
+
79
+ <h3 align="center">Generate world-class Power BI dashboards from any data source — automatically.</h3>
80
+
81
+ <p align="center">
82
+ <a href="https://pypi.org/project/pbigen/"><img alt="PyPI" src="https://img.shields.io/pypi/v/pbigen.svg?color=4C6FFF"></a>
83
+ <a href="https://pypi.org/project/pbigen/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/pbigen.svg?color=22C1C3"></a>
84
+ <a href="https://github.com/arkajojo/pbigen/actions"><img alt="CI" src="https://github.com/arkajojo/pbigen/actions/workflows/ci.yml/badge.svg"></a>
85
+ <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-1B1F3B.svg"></a>
86
+ <img alt="Status" src="https://img.shields.io/badge/status-beta-FDBB2D.svg">
87
+ </p>
88
+
89
+ ---
90
+
91
+ Point **pbigen** at a table or view. It reads the schema, reasons about the *shape* of the data
92
+ (types and cardinality), and writes a ready-to-open Power BI project: a left navigation sidebar with
93
+ your brand and filters, KPI cards, data-appropriate charts, a detail table, and a "how to use this
94
+ report" note — laid out cleanly, every time.
95
+
96
+ No hand-built templates. No copy-pasting M queries. No guessing which chart fits which column.
97
+
98
+ ```python
99
+ import pbigen
100
+
101
+ result = pbigen.generate(
102
+ "bigquery",
103
+ source_config={"project": "my-proj", "dataset": "sales", "table": "orders"},
104
+ objective="Revenue and orders by region over time",
105
+ theme="midnight",
106
+ out_dir="out",
107
+ )
108
+ print(result.pbip_path) # open this in Power BI Desktop
109
+ ```
110
+
111
+ <br>
112
+
113
+ ## Table of contents
114
+
115
+ - [Why pbigen](#why-pbigen)
116
+ - [How pbigen compares](#how-pbigen-compares)
117
+ - [Features](#features)
118
+ - [Installation](#installation)
119
+ - [Quickstart](#quickstart)
120
+ - [Supported sources](#supported-sources)
121
+ - [Models: deterministic by default, LLM optional](#models-deterministic-by-default-llm-optional)
122
+ - [Themes: bring your own, or use a built-in](#themes-bring-your-own-or-use-a-built-in)
123
+ - [How it works](#how-it-works)
124
+ - [Anatomy of the output](#anatomy-of-the-output)
125
+ - [Opening the result in Power BI Desktop](#opening-the-result-in-power-bi-desktop)
126
+ - [The design intelligence](#the-design-intelligence)
127
+ - [Python API](#python-api)
128
+ - [Command-line interface](#command-line-interface)
129
+ - [Extending pbigen](#extending-pbigen)
130
+ - [Roadmap](#roadmap)
131
+ - [FAQ](#faq)
132
+ - [Contributing](#contributing)
133
+ - [License](#license)
134
+
135
+ <br>
136
+
137
+ ## Why pbigen
138
+
139
+ Building a good Power BI report by hand is slow and inconsistent. Someone picks the charts, wires
140
+ every field, styles every visual, writes the connection query, and repeats it for the next dataset.
141
+ The mechanical 90% eats the time that should go to the 10% that actually needs judgement.
142
+
143
+ pbigen does the mechanical 90% correctly and consistently. It is **opinionated about good
144
+ defaults** and **unopinionated about your stack**:
145
+
146
+ - **Opinionated defaults** — cardinality-aware chart selection, a date column becomes a range filter
147
+ (never a 500-row dropdown), wide breakdowns go in a matrix, KPIs lead every page, and a clean
148
+ navigation sidebar is always there.
149
+ - **Unopinionated stack** — bring your own warehouse or lakehouse, your own model (or none), and your
150
+ own theme.
151
+
152
+ The output is a standard, version-controllable **PBIP** project — not a black-box binary — so it
153
+ drops straight into source control and your existing Power BI workflow.
154
+
155
+ <br>
156
+
157
+ ## How pbigen compares
158
+
159
+ AI dashboard generation is a crowded space in 2026 — Power BI Copilot and Agent Skills, plus
160
+ agentic BI platforms like ThoughtSpot, Tableau Pulse, Sigma, Domo and Tellius. Most of them are
161
+ powerful, and most are **cloud services that build dashboards inside their own surface**. pbigen
162
+ takes a different shape: it's a small, open-source library that turns a table into **portable,
163
+ version-controlled Power BI files** on your machine — free, and offline by default.
164
+
165
+ | Capability | **pbigen** | Power BI Copilot / Agent Skills | Agentic BI platforms<br>(ThoughtSpot, Sigma, Tableau Pulse, Domo, Tellius) | Generic LLM<br>(ChatGPT / Claude) |
166
+ |---|:---:|:---:|:---:|:---:|
167
+ | Outputs **native, portable Power BI files** (PBIP you own) | ✅ | ⚠️ builds in the service | ❌ their own BI surface | ❌ snippets only |
168
+ | **Version-controlled, CI-friendly** text output (PBIR + TMDL) | ✅ | ⚠️ not the generation flow | ❌ | ❌ |
169
+ | Runs **locally / in CI**, no paid cloud capacity | ✅ | ❌ needs Fabric capacity (F2+) | ❌ SaaS subscription | ⚠️ needs API/subscription |
170
+ | Works with **no LLM / API key** (deterministic) | ✅ | ❌ | ❌ | ❌ |
171
+ | One interface across warehouses **+ lakehouse (Iceberg/Delta) + semantic layer**, multi-cloud | ✅ | ⚠️ Fabric / OneLake-centric | ⚠️ varies by vendor | ❌ |
172
+ | **Metadata-only** — no row data leaves your environment to design | ✅ | ⚠️ cloud service | ⚠️ SaaS | ❌ you paste data |
173
+ | **Open source (MIT)**, self-hostable, no lock-in | ✅ | ❌ | ❌ | ❌ |
174
+ | Cost | **Free** | Paid (Fabric capacity) | Paid (per-seat SaaS) | Usage-based |
175
+
176
+ *(⚠️ = partial or conditional; comparisons reflect each tool's common default in 2026, not every edge case. Copilot / Agent Skills and the agentic platforms are genuinely capable — pbigen is the open, local, file-first option, and pairs fine alongside them.)*
177
+
178
+ <br>
179
+
180
+ ## Features
181
+
182
+ - 🔌 **16 source kinds, one interface** — warehouses, query engines, open table formats on every
183
+ major cloud, and a semantic layer.
184
+ - 🧠 **Data-shape-aware design** — chart and filter choices follow from column types and cardinality,
185
+ not guesswork.
186
+ - 🎨 **Themes** — three polished built-ins, or drop in your corporate Power BI theme JSON.
187
+ - 🤖 **Pluggable design model** — deterministic by default (no key, no network); optionally let any
188
+ LiteLLM model (hosted or fully local) refine the design. **Only metadata is ever sent.**
189
+ - 🧱 **Standards-based output** — a PBIP project (PBIR report + TMDL semantic model) that validates
190
+ against Microsoft's published schemas and opens directly in Power BI Desktop.
191
+ - 🔒 **Read-only and safe** — sources are introspection-only; no rows are read to design the report.
192
+ - 🧩 **Clean seams** — source → design → layout → emit are independent and individually testable.
193
+ - 🖥️ **Python API and CLI** — script it or run it from the terminal.
194
+
195
+ <br>
196
+
197
+ ## Installation
198
+
199
+ ```bash
200
+ pip install pbigen
201
+ ```
202
+
203
+ The core is dependency-light. Install only the extras you need — each pulls in exactly one stack's
204
+ driver:
205
+
206
+ | Extra | Installs support for |
207
+ |-------|----------------------|
208
+ | `pbigen[bigquery]` | BigQuery, BigLake, BigQuery Omni |
209
+ | `pbigen[redshift]` | Amazon Redshift |
210
+ | `pbigen[athena]` | Amazon Athena |
211
+ | `pbigen[snowflake]` | Snowflake |
212
+ | `pbigen[synapse]` | Azure Synapse / Microsoft Fabric / SQL Server |
213
+ | `pbigen[databricks]` | Databricks SQL |
214
+ | `pbigen[clickhouse]` | ClickHouse |
215
+ | `pbigen[postgres]` | PostgreSQL |
216
+ | `pbigen[lakehouse]` | Parquet, Iceberg, Delta on local / GCS / S3 / ADLS (DuckDB) |
217
+ | `pbigen[cube]` | Cube semantic layer |
218
+ | `pbigen[llm]` | LLM-refined design via LiteLLM |
219
+ | `pbigen[all]` | Everything above |
220
+
221
+ ```bash
222
+ pip install "pbigen[bigquery]"
223
+ pip install "pbigen[lakehouse,llm]"
224
+ pip install "pbigen[all]"
225
+ ```
226
+
227
+ **Requirements:** Python 3.10+. To open the generated project you need Power BI Desktop with the
228
+ PBIR preview enabled — see [Opening the result](#opening-the-result-in-power-bi-desktop).
229
+
230
+ <br>
231
+
232
+ ## Quickstart
233
+
234
+ ### Python
235
+
236
+ ```python
237
+ import pbigen
238
+
239
+ result = pbigen.generate(
240
+ "snowflake",
241
+ source_config={
242
+ "account": "ab12345", "warehouse": "BI_WH",
243
+ "database": "ANALYTICS", "schema": "SALES", "table": "ORDERS",
244
+ },
245
+ objective="Sales performance by region and product",
246
+ theme="midnight",
247
+ out_dir="out",
248
+ name="SalesOverview",
249
+ )
250
+ print(f"{result.n_pages} pages, {result.n_columns} columns → {result.pbip_path}")
251
+ ```
252
+
253
+ ### Command line
254
+
255
+ ```bash
256
+ pbigen generate --source snowflake \
257
+ --set account=ab12345 warehouse=BI_WH database=ANALYTICS schema=SALES table=ORDERS \
258
+ --objective "Sales performance by region and product" \
259
+ --theme midnight --out out --name SalesOverview
260
+ ```
261
+
262
+ ### Try it offline in 30 seconds
263
+
264
+ No cloud account needed — generate from a local Parquet file:
265
+
266
+ ```bash
267
+ pip install "pbigen[lakehouse]" pyarrow
268
+ python examples/generate_from_parquet.py # builds a sample file and generates from it
269
+ ```
270
+
271
+ <br>
272
+
273
+ ## Supported sources
274
+
275
+ Every adapter implements the same read-only contract — **introspect** (columns + canonical types),
276
+ **approx_distinct** (cardinality, to drive design), and **power_query** (the M the report uses to
277
+ connect at refresh). Full config and credentials for each live in **[docs/sources.md](docs/sources.md)**.
278
+
279
+ | Cloud / family | Sources | Extra |
280
+ |----------------|---------|-------|
281
+ | **GCP** | BigQuery, BigLake, BigQuery Omni; Parquet / Iceberg / Delta in GCS | `bigquery`, `lakehouse` |
282
+ | **AWS** | Redshift, Athena; Parquet / Iceberg / Delta in S3 | `redshift`, `athena`, `lakehouse` |
283
+ | **Azure** | Synapse, Fabric (SQL endpoint); Parquet / Iceberg / Delta in ADLS | `synapse`, `lakehouse` |
284
+ | **Multi / other** | Snowflake, Databricks, ClickHouse, PostgreSQL | `snowflake`, `databricks`, `clickhouse`, `postgres` |
285
+ | **Semantic layer** | Cube | `cube` |
286
+
287
+ ```bash
288
+ pbigen sources # list every source kind
289
+ pbigen test --source lakehouse --set uri=./sales.parquet fmt=parquet # verify connectivity
290
+ ```
291
+
292
+ Open table formats (Parquet, Apache Iceberg, Delta Lake) are read on local disk or any of the three
293
+ clouds through a single DuckDB-powered adapter — no cluster required for introspection. For *report
294
+ refresh*, raw Parquet is reachable via Power BI's storage connectors; Iceberg/Delta are best served
295
+ through a Fabric Lakehouse or Databricks SQL endpoint (details in [docs/sources.md](docs/sources.md)).
296
+
297
+ <br>
298
+
299
+ ## Models: deterministic by default, LLM optional
300
+
301
+ Out of the box, pbigen designs dashboards with a **deterministic, no-key engine** — no network
302
+ call, no cost, fully reproducible. To let a language model refine the design, pass any
303
+ [LiteLLM](https://github.com/BerriAI/litellm) model id — hosted or a local open-source model:
304
+
305
+ ```python
306
+ pbigen.generate("bigquery", source_config={...},
307
+ model="gpt-4o-mini") # bring your own key via env
308
+
309
+ pbigen.generate("bigquery", source_config={...},
310
+ model="anthropic/claude-sonnet-4-6")
311
+
312
+ pbigen.generate("bigquery", source_config={...},
313
+ model="ollama/llama3", # fully local, open-source
314
+ model_config={"api_base": "http://localhost:11434"})
315
+ ```
316
+
317
+ > **Privacy:** only **metadata** — column names, canonical types and approximate distinct counts —
318
+ > is ever sent to a model. No row data leaves your machine. Every field the model returns is
319
+ > validated against the live schema, and if the model is unreachable or returns something unusable,
320
+ > pbigen falls back to the deterministic design so generation never hard-fails.
321
+
322
+ More in **[docs/models.md](docs/models.md)**.
323
+
324
+ <br>
325
+
326
+ ## Themes: bring your own, or use a built-in
327
+
328
+ ```python
329
+ pbigen.generate(..., theme="midnight") # built-in: midnight | slate | aurora
330
+ pbigen.generate(..., theme="./corporate.json") # your Power BI theme JSON, applied as-is
331
+ ```
332
+
333
+ | Theme | Look |
334
+ |-------|------|
335
+ | `midnight` | Deep indigo sidebar, blue/teal data colours |
336
+ | `slate` | Neutral slate, red accent |
337
+ | `aurora` | Deep green sidebar, green/blue data colours |
338
+
339
+ Your theme travels with the project as a registered custom theme. More in
340
+ **[docs/themes.md](docs/themes.md)**.
341
+
342
+ <br>
343
+
344
+ ## How it works
345
+
346
+ ```
347
+ source ──introspect──▶ canonical schema ──▶ design brain ──▶ layout ──▶ Power BI project
348
+ (+cardinality) (types, counts) (charts+filters) (sidebar) (PBIP + PBIR + TMDL)
349
+
350
+ optional LLM refine
351
+ (metadata only)
352
+ ```
353
+
354
+ 1. **Source** introspects the table (metadata only) and reports approximate cardinality.
355
+ 2. **Design brain** classifies every column (measure / date / category / geo / id), proposes
356
+ measures, and picks visuals and filters from the data shape. An LLM can refine this; the rules
357
+ always produce a complete design on their own.
358
+ 3. **Layout** packs the page — a left sidebar for brand + filters + notes, a KPI row, then charts
359
+ and tables placed by footprint.
360
+ 4. **Emitter** writes a standard PBIP project: a PBIR report and a TMDL semantic model wired to the
361
+ source via Power Query.
362
+
363
+ <br>
364
+
365
+ ## Anatomy of the output
366
+
367
+ ```
368
+ out/SalesOverview/
369
+ ├── SalesOverview.pbip # open this in Power BI Desktop
370
+ ├── SalesOverview.Report/ # the report (PBIR format)
371
+ │ ├── definition.pbir
372
+ │ └── definition/
373
+ │ ├── report.json # theme + layout settings
374
+ │ ├── version.json
375
+ │ ├── pages/
376
+ │ │ ├── pages.json # page order
377
+ │ │ └── <page>/page.json + visuals/<v>/visual.json
378
+ │ └── StaticResources/RegisteredResources/<theme>.json
379
+ └── SalesOverview.SemanticModel/ # the model (TMDL)
380
+ ├── definition.pbism
381
+ └── definition/
382
+ ├── database.tmdl
383
+ ├── model.tmdl
384
+ └── tables/<table>.tmdl # columns, DAX measures, the M connection
385
+ ```
386
+
387
+ Everything is text and version-control-friendly. The report JSON validates against Microsoft's
388
+ published PBIR JSON schemas.
389
+
390
+ <br>
391
+
392
+ ## Opening the result in Power BI Desktop
393
+
394
+ The output is a **PBIP** project. Enable the enhanced report format once:
395
+
396
+ 1. **File → Options and settings → Options → Preview features**
397
+ 2. Tick **"Store reports using enhanced metadata format (PBIR)"**
398
+ 3. Restart Power BI Desktop.
399
+
400
+ Then open the `.pbip` file and **Refresh** to load data through the generated connection. (This is a
401
+ one-time setting; PBIR is Microsoft's text-based report format that pbigen emits.)
402
+
403
+ <br>
404
+
405
+ ## The design intelligence
406
+
407
+ The deterministic engine makes these calls from the data shape, before any LLM is involved:
408
+
409
+ - **Column roles** — measures, dates, categories, geo and identifiers are detected from type and
410
+ name, so ids and codes never get charted as if they were metrics.
411
+ - **Dates are ranges, not dropdowns** — a real date/time column drives a range slider; a 500-value
412
+ dropdown never happens.
413
+ - **Donut vs. bar** — a breakdown with ≤ 8 categories becomes a donut, otherwise a bar.
414
+ - **Redundant filters dropped** — once a real date exists, derived period columns (year, month,
415
+ `year_month`) are kept out of the filter rail.
416
+ - **Wide goes wide** — matrices with a series or many measures, and wide tables, get full width;
417
+ narrow visuals pair up two-across.
418
+ - **A narrative** — pages flow Executive Summary → Trends → Segmentation → Detail, each led by KPI
419
+ cards, with a "how to use this report" note in the sidebar.
420
+
421
+ <br>
422
+
423
+ ## Python API
424
+
425
+ ```python
426
+ pbigen.generate(
427
+ source, # a source kind string, or a configured Source instance
428
+ *,
429
+ out_dir="out", # where to write the project
430
+ name=None, # project name (defaults to the table's display name)
431
+ objective="", # plain-language description of what the report should answer
432
+ model=None, # None/"deterministic" | LiteLLM model id | a Model instance
433
+ theme=None, # built-in name | path to a Power BI theme JSON
434
+ source_config=None, # dict passed to the source adapter (when source is a string)
435
+ model_config=None, # dict passed to the model (e.g. api_key, api_base, temperature)
436
+ ) -> GenerateResult
437
+ ```
438
+
439
+ ```python
440
+ @dataclass
441
+ class GenerateResult:
442
+ pbip_path: str # path to the .pbip to open
443
+ design: Design # the pages/visuals/measures that were generated
444
+ table: str
445
+ n_columns: int
446
+ n_pages: int
447
+ model_name: str # "deterministic" or e.g. "litellm:gpt-4o-mini"
448
+ ```
449
+
450
+ Helpers: `pbigen.available_kinds()`, `pbigen.available_themes()`, `pbigen.get_source(kind, **cfg)`.
451
+
452
+ <br>
453
+
454
+ ## Command-line interface
455
+
456
+ ```bash
457
+ pbigen generate --source <kind> [--set k=v ...] [--objective ...] \
458
+ [--model ...] [--theme ...] [--out DIR] [--name NAME]
459
+ pbigen test --source <kind> [--set k=v ...] # verify connectivity + introspection
460
+ pbigen sources # list available source kinds
461
+ pbigen themes # list built-in themes
462
+ pbigen --version
463
+ ```
464
+
465
+ `--set` takes `key=value` pairs forwarded to the adapter; integers and booleans are coerced.
466
+
467
+ <br>
468
+
469
+ ## Extending pbigen
470
+
471
+ **Add a source** — subclass `Source` (or `SqlSource` for a SQLAlchemy dialect), implement
472
+ `introspect`, `approx_distinct` and `power_query`, and register it:
473
+
474
+ ```python
475
+ from pbigen.sources.base import Source
476
+
477
+ class MySource(Source):
478
+ kind = "mysource"
479
+ def introspect(self): ...
480
+ def approx_distinct(self, columns): ...
481
+ def power_query(self): ...
482
+ ```
483
+
484
+ **Add a design model** — subclass `Model` and return a `Design` (start from the deterministic one):
485
+
486
+ ```python
487
+ from pbigen.models.base import Model
488
+ from pbigen.core.design import design as deterministic
489
+
490
+ class MyModel(Model):
491
+ name = "my-model"
492
+ def design(self, schema, objective):
493
+ return deterministic(schema, objective) # then refine
494
+
495
+ pbigen.generate(..., model=MyModel())
496
+ ```
497
+
498
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide.
499
+
500
+ <br>
501
+
502
+ ## Roadmap
503
+
504
+ - Live smoke-test matrix across every credentialed connector
505
+ - Refresh-friendly adapters for Iceberg/Delta via Fabric Lakehouse shortcuts
506
+ - Refactor mode: add pages / visuals to an existing report
507
+ - Additional emit targets beyond Power BI
508
+ - Relationship and multi-table (star-schema) modelling
509
+
510
+ Ideas and issues welcome — see [Contributing](#contributing).
511
+
512
+ <br>
513
+
514
+ ## FAQ
515
+
516
+ **Does it read my data?** No. Sources introspect *metadata only* to design the report. Data is
517
+ loaded by Power BI at refresh time, on your machine, through the generated connection.
518
+
519
+ **Do I need an API key or an LLM?** No. The default design engine is deterministic and offline. An
520
+ LLM is entirely optional.
521
+
522
+ **What exactly gets sent to an LLM if I enable one?** Only column names, canonical types and
523
+ approximate distinct counts — never rows.
524
+
525
+ **Can I use my company's Power BI theme?** Yes — pass the path to your theme JSON as `theme=`.
526
+
527
+ **Why PBIP/PBIR?** It's Microsoft's text-based, source-control-friendly report format, so the output
528
+ is diffable, reviewable and CI-friendly rather than an opaque binary.
529
+
530
+ <br>
531
+
532
+ ## Contributing
533
+
534
+ Contributions are very welcome. Set up a dev environment, run `ruff` and `pytest` (the suite runs
535
+ fully offline), and open a focused PR. See **[CONTRIBUTING.md](CONTRIBUTING.md)**.
536
+
537
+ <br>
538
+
539
+ ## License
540
+
541
+ MIT © [Arka Gupta](AUTHORS.md). See [LICENSE](LICENSE).
542
+
543
+ <p align="center"><sub>Built by Arka Gupta.</sub></p>