fiftyone-generate-data-lens-connector
Generate a Data Lens connector from an external database schema. Use when users want to connect an external data source (PostgreSQL, BigQuery, Databricks, MySQL, etc.) to FiftyOne Data Lens, or when they have a database schema and want to browse/import that data through the FiftyOne App.
What this skill does
# Generate Data Lens Connector
Generate a fully functional `DataLensOperator` plugin from a user-provided
database
schema. The generated connector lets users browse, preview, and import samples
from
their external data source directly through the FiftyOne App's Data Lens panel.
## Enterprise Notice
Data Lens is a **FiftyOne Enterprise** feature. Before proceeding, inform
the user:
> **Note:** Data Lens is an enterprise-only feature available in
> [FiftyOne Enterprise](https://docs.voxel51.com/enterprise/index.html). The
> connector generated by this skill requires a FiftyOne Enterprise deployment
> to run. If you're using the open-source version of FiftyOne, this connector
> will not work in your environment.
>
> Would you like to proceed?
Wait for the user to confirm before continuing. If they ask about alternatives
for OSS, suggest they look into custom operators for similar data-import
workflows, or the standard
[dataset import](https://docs.voxel51.com/user_guide/dataset_creation/index.html)
utilities.
## Key Directives
**ALWAYS follow these rules:**
### 1. Schema first, code second
Never generate connector code until you fully understand the source schema. Ask
clarifying questions about anything ambiguous — column semantics, coordinate
systems,
filepath conventions, image dimensions.
### 2. Propose the field mapping before generating
Present a clear table mapping source columns to FiftyOne field types. Get user
approval before writing any code. This is the most important step — a connector
that maps fields wrong is worse than no connector.
### 3. Use parameterized queries
Never interpolate user input directly into SQL strings. Use the database
driver's
parameterized query mechanism (e.g., `%s` for psycopg, `@param` for BigQuery,
`:param` for Databricks).
### 4. Respect the batching contract
Always yield `DataLensSearchResponse` objects in batches of
`request.batch_size`.
Buffer results and yield when the buffer is full, plus a final yield for
remaining
samples.
### 5. Keep it minimal
Generate only what's needed. Don't add vector search, text search, or advanced
features unless the user's schema and requirements call for them. A simple
metadata
filter connector is the right default.
## Workflow
### Phase 1: Understand the Schema
Gather the information needed to generate the connector:
1. **Get the schema.** Accept any of these formats:
- DDL (`CREATE TABLE` statements)
- Column list with types (JSON, markdown table, plain text)
- A request to introspect a live database (guide the user to export the
schema)
2. **Identify key columns.** Ask about any that aren't obvious:
- **Filepath column** — which column contains the media path? Is it
absolute,
relative (needs a prefix), or a cloud URI?
- **Label columns** — which columns contain annotations? What format?
(JSON blobs, foreign key joins, flat columns)
- **Metadata columns** — which columns should become filterable properties?
- **Coordinate system** — if bounding boxes exist: pixel-absolute or
normalized?
What are the image dimensions (fixed or per-sample)?
3. **Identify the database type.** This determines:
- Which Python driver to use
- Query syntax (parameterization style, JSON functions, etc.)
- Connection string format and required secrets
4. **Get sample data** (if available). Even 2-3 example rows dramatically
improve
the quality of the field mapping. Ask for them.
### Phase 2: Propose Field Mapping
Present a mapping table for user approval:
```
| Source Column | FiftyOne Field | Type | Notes |
|-------------------|-----------------------|---------------------|--------------------------------|
| filepath | filepath | str | Prefix: gs://bucket/path/ |
| weather | weather | Classification | Filterable enum |
| bbox_x1/y1/x2/y2 | detections | Detections | Pixel coords, normalize by WxH |
| category | detections[].label | str | Detection label |
| ... | ... | ... | ... |
```
Include:
- **Filepath construction** — how the full path is built from the column value
- **Coordinate normalization** — formula if bounding boxes are in pixel
coordinates
- **Label hierarchy** — how nested/joined label data maps to FiftyOne label
types
- **Filters** — which columns become `resolve_input` enum/text fields, with
known values if available
**Wait for user approval before proceeding.**
### Phase 3: Generate Connector
Generate a complete plugin directory with these files:
| File | Purpose |
|--------------------|---------------------------------------------------|
| `__init__.py` | Operator class + handler class + sample transform |
| `fiftyone.yml` | Plugin manifest with operator name and secrets |
| `requirements.txt` | Python driver dependency |
Use the patterns from [CONNECTOR-TEMPLATE.md](CONNECTOR-TEMPLATE.md) as your
structural guide. The generated code should follow these architectural layers:
**Layer 1 — Operator class** (`DataLensOperator` subclass):
- `config` property with `execute_as_generator=True`, `unlisted=True`
- `resolve_input()` defining the UI filter form
- `handle_lens_search_request()` delegating to the handler
**Layer 2 — Handler class** (connection + query logic):
- Context manager for connection lifecycle
- `iter_batches()` implementing the batching loop
- `_generate_query()` building parameterized SQL from `search_params`
- `_transform_sample()` mapping raw rows to `fo.Sample(...).to_dict()`
**Layer 3 — Data models** (optional, for complex schemas):
- `@dataclass` for query parameters (validated from `search_params`)
- `@dataclass` for query result rows (typed column access)
See [FIELD-MAPPING-GUIDE.md](FIELD-MAPPING-GUIDE.md) for the rules on mapping
database types to FiftyOne field types, especially for spatial data (bounding
boxes,
keypoints, segmentation masks).
### Phase 4: Validate
After generating the connector:
1. **Syntax check** — the generated code must parse without errors:
```bash
python -c "import ast; ast.parse(open('__init__.py').read()); print('OK')"
```
2. **Sample construction check** — if sample data was provided, construct
`fo.Sample` objects from it and verify they serialize correctly:
```python
import fiftyone as fo
sample = fo.Sample(
filepath="...",
# ... mapped fields
)
sample.to_dict() # Must not raise
```
3. **Walk through the generated code** with the user:
- Confirm the query logic matches their schema
- Confirm the transform logic produces correct FiftyOne samples
- Confirm the `resolve_input` filters are right
4. **Installation guidance:**
```bash
# Copy plugin to FiftyOne plugins directory
PLUGINS_DIR=$(python -c "import fiftyone as fo; print(fo.config.plugins_dir)")
cp -r ./my-connector "$PLUGINS_DIR/"
# Set required secrets
export MY_SECRET_KEY="..."
# Register in Data Lens UI: Data sources > Add > plugin-name/operator_name
```
### Phase 5: Iterate
The first generation likely needs refinement. Common adjustments:
- Adding/removing filter fields
- Fixing coordinate normalization
- Adjusting the filepath prefix
- Handling NULL/missing values in optional columns
- Adding conditional WHERE clauses for "all" filter values
## Database-Specific Patterns
### PostgreSQL
```python
# Driver: psycopg[binary]
# Parameterization: %s positional
# Connection: ctx.secret("POSTGRES_CONNECTION_STRING")
# JSON: JSON_AGG, JSON_BUILD_OBJECT
# Streaming: cursor.stream(query, params, size=batch_size)
import psycopg
from psycopg.rows import dict_row
```
### BigQuery
```python
# Driver: goRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.