Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions runtime/server/generate_metrics_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ func (s *Server) GenerateMetricsViewFile(ctx context.Context, req *runtimev1.Gen
if req.Connector == "" {
req.Connector = inst.ResolveOLAPConnector()
}
isDefaultConnector := req.Connector == inst.ResolveOLAPConnector()

// Connect to connector and check it's an OLAP db
olap, release, err := s.runtime.OLAP(ctx, req.InstanceId, req.Connector)
Expand All @@ -141,7 +140,7 @@ func (s *Server) GenerateMetricsViewFile(ctx context.Context, req *runtimev1.Gen
if req.UseAi {
// Generate
start := time.Now()
res, err := s.generateMetricsViewYAMLWithAI(ctx, req.InstanceId, olap.Dialect().String(), req.Connector, tbl, isDefaultConnector, modelFound, req.Prompt)
res, err := s.generateMetricsViewYAMLWithAI(ctx, req.InstanceId, olap.Dialect().String(), req.Connector, tbl, modelFound, req.Prompt)
if err != nil {
s.logger.Warn("failed to generate metrics view YAML using AI", zap.Error(err), observability.ZapCtx(ctx))
} else {
Expand Down Expand Up @@ -169,7 +168,7 @@ func (s *Server) GenerateMetricsViewFile(ctx context.Context, req *runtimev1.Gen

// If we didn't manage to generate the YAML using AI, we fall back to the simple generator
if data == "" {
data, err = generateMetricsViewYAMLSimple(req.Connector, tbl, isDefaultConnector, modelFound)
data, err = generateMetricsViewYAMLSimple(req.Connector, tbl, modelFound)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -198,7 +197,7 @@ type generateMetricsViewYAMLWithres struct {

// generateMetricsViewYAMLWithAI attempts to generate a metrics view YAML definition from a table schema using AI.
// It validates that the result is a valid metrics view. Due to the unpredictable nature of AI (and chance of downtime), this function may error non-deterministically.
func (s *Server) generateMetricsViewYAMLWithAI(ctx context.Context, instanceID, dialect, connector string, tbl *drivers.OlapTable, isDefaultConnector, isModel bool, prompt string) (*generateMetricsViewYAMLWithres, error) {
func (s *Server) generateMetricsViewYAMLWithAI(ctx context.Context, instanceID, dialect, connector string, tbl *drivers.OlapTable, isModel bool, prompt string) (*generateMetricsViewYAMLWithres, error) {
// Build messages
systemPrompt := metricsViewYAMLSystemPrompt()
userPrompt := metricsViewYAMLUserPrompt(dialect, tbl.Name, tbl.Schema, prompt)
Expand Down Expand Up @@ -279,12 +278,10 @@ func (s *Server) generateMetricsViewYAMLWithAI(ctx context.Context, instanceID,
// Apply the default format preset to measures (the AI doesn't set the format preset).
measure.FormatPreset = "humanize"
}
doc.Connector = connector
if isModel {
doc.Model = tbl.Name
} else {
if !isDefaultConnector {
doc.Connector = connector
}
doc.Model = tbl.Name // Note: We also reference externally managed tables with `model:`. This is supported in the metrics view YAML.
if tbl.Database != "" && !tbl.IsDefaultDatabase {
doc.Database = tbl.Database
Expand Down Expand Up @@ -420,7 +417,7 @@ Give me up to 10 suggested metrics using the %q SQL dialect based on the table n
}

// generateMetricsViewYAMLSimple generates a simple metrics view YAML definition from a table schema.
func generateMetricsViewYAMLSimple(connector string, tbl *drivers.OlapTable, isDefaultConnector, isModel bool) (string, error) {
func generateMetricsViewYAMLSimple(connector string, tbl *drivers.OlapTable, isModel bool) (string, error) {
doc := &metricsViewYAML{
Version: 1,
Type: "metrics_view",
Expand All @@ -430,12 +427,10 @@ func generateMetricsViewYAMLSimple(connector string, tbl *drivers.OlapTable, isD
Measures: generateMetricsViewYAMLSimpleMeasures(tbl),
}

doc.Connector = connector
if isModel {
doc.Model = tbl.Name
} else {
if !isDefaultConnector {
doc.Connector = connector
}
if tbl.Database != "" && !tbl.IsDefaultDatabase {
doc.Database = tbl.Database
}
Expand Down
7 changes: 4 additions & 3 deletions runtime/server/generate_metrics_view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ driver: duckdb
name: "model passed in request",
model: "ad_bids",
contains: []string{
"connector: duckdb",
"model: ad_bids",
"measures:",
"format_preset: humanize",
Expand All @@ -64,17 +65,17 @@ driver: duckdb
{
name: "model passed in request that matches a table",
model: "foo",
contains: []string{"model: foo"},
contains: []string{"connector: duckdb", "model: foo"},
},
{
name: "table passed in request that matches a model",
table: "ad_bids",
contains: []string{"model: ad_bids"},
contains: []string{"connector: duckdb", "model: ad_bids"},
},
{
name: "table passed in request that does not match a model",
table: "foo",
contains: []string{"model: foo"},
contains: []string{"connector: duckdb", "model: foo"},
},
{
name: "table in non-default connector passed in request",
Expand Down
20 changes: 20 additions & 0 deletions web-local/tests/explores/explores.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,33 @@ test.describe("explores", () => {
// Temporary timeout while the issue is looked into
await page.waitForTimeout(1000);
await assertAdBidsDashboard(page);

// Verify generated metrics view YAML contains connector
await gotoNavEntry(page, "/metrics/AdBids_metrics.yaml");
await page.getByRole("button", { name: "switch to code editor" }).click();
const metricsCodeEditor = page
.getByLabel("codemirror editor")
.getByRole("textbox");
await expect(metricsCodeEditor).toContainText("connector: duckdb");
});

test("Autogenerate explore from model", async ({ page }) => {
await createAdBidsModel(page);
await createExploreFromModel(page, true);
await assertAdBidsDashboard(page);

// Verify generated metrics view YAML contains connector
await gotoNavEntry(page, AD_BIDS_METRICS_PATH);
await page.getByRole("button", { name: "switch to code editor" }).click();
const metricsCodeEditor = page
.getByLabel("codemirror editor")
.getByRole("textbox");
await expect(metricsCodeEditor).toContainText("connector: duckdb");

// Navigate back to the explore dashboard
await gotoNavEntry(page, AD_BIDS_EXPLORE_PATH);
await clickPreviewButton(page);

// click on publisher=Facebook leaderboard value
await page.getByRole("row", { name: "Facebook 19.3k" }).click();
await wrapRetryAssertion(() =>
Expand Down
Loading