Database-BI

 view release on metacpan or  search on metacpan

lib/Database/BI/Ask.pm  view on Meta::CPAN

		}
		(my $path = $spec_key) =~ s/\Apath://;
		require Database::BI::Model::DataSource;
		my ($file, $internal) = Database::BI::Model::DataSource::split_path($path);
		return '/open?path=' . urlencode($file) . (defined $internal ? '&it=' . urlencode($internal) : '');
	}

	my $route  = $KIND_ROUTE{$kind} // $kind;
	my @params = ('l=' . urlencode($spec_key));
	for my $key (sort keys %$encode) {
		my $val = $encode->{$key};
		next unless defined $val && length $val;
		push @params, "$key=" . urlencode($val);
	}
	return "/$route?" . join('&', @params);
}

sub _build_spec {
	my ($visual, $label, $spec_key) = @_;
	return {
		name     => ($visual->{title} || "$label analysis"),
		datasets => [{ spec => $spec_key }],
		version  => 1,
		visuals  => [{
			kind    => $visual->{kind},
			title   => ($visual->{title} // ''),
			encode  => ($visual->{encode} // {}),
			options => {},
		}],
	};
}


1;

__END__

=head1 NAME

Database::BI::Ask - Natural language to analysis spec

=head1 SYNOPSIS

  use Database::BI::Ask;

  my $typed = Database::BI::Ask::infer_column_types(\@records, \@columns);

  my $result = Database::BI::Ask::ask(
      question  => 'show me sales by region as a pie chart',
      spec_key  => 'table:sales',
      label     => 'sales',
      columns   => $typed,
      ai_config => { provider => 'anthropic', api_key => $key, model => 'claude-haiku-5-5' },
  );
  # $result = { spec => {...}, url => '/pie?l=...&cat=region', valid => 1 }

=head1 DESCRIPTION

Translates a plain-English question into an analysis spec by calling
the Anthropic Messages API.  The model receives only column names and types
-- never raw row data, file paths, or credentials.

The returned spec is validated before being returned to the caller: every
column name in the C<encode> section must appear in the supplied column list,
and the C<kind> must be a supported chart type.  An invalid spec is returned
as C<{ error =E<gt> 'ask_invalid_spec:...' }> and never executed.

The feature is entirely absent (returns C<ask_unavailable>) when no
C<api_key> is supplied, keeping the app functional with no AI configured.

=head1 FUNCTIONS

=head2 ask(%args)

Returns C<{ spec, url, valid =E<gt> 1 }> on success, or C<{ error =E<gt> 'code' }>
on failure.  Error codes: C<ask_no_question>, C<ask_unavailable>,
C<ask_provider_error>, C<ask_unparseable>, C<ask_invalid_spec:col>.

=head3 API SPECIFICATION

=head4 INPUT

	{
	    question  => 'string',     # required; empty returns ask_no_question
	    spec_key  => 'string',     # l= spec the URL is built on, e.g. "table:sales"
	    label     => 'string',     # optional; dataset name shown to the model (default "dataset")
	    columns   => 'arrayref',   # [ { name, type } ... ], as infer_column_types returns
	    ai_config => 'hashref',    # { api_key, model, provider }; no api_key returns ask_unavailable
	}

A flat key/value list.  C<ask> does not croak: every failure, including no
arguments, comes back as an error code.

=head4 OUTPUT

	{ spec => 'hashref', url => 'string', valid => 1 }   # success
	{ error => 'string' }                              # one of the codes above

The model sees only the question, the label and C<columns>.  No row data,
file path or C<spec_key> is sent.

=head2 infer_column_types($records, $columns)

Infers each column's type (C<'number'>, C<'date'>, C<'string'>) from a
sample of records.  A column is C<'number'> when more than half its
non-empty values pass C<Scalar::Util::looks_like_number>.  It is C<'date'>
when more than half match C<YYYY-MM-DD> or C<M/D/YYYY>.  Otherwise C<'string'>.

=head3 API SPECIFICATION

=head4 INPUT

	$records   # arrayref of hashrefs (rows)
	$columns   # arrayref of column names to classify

=head4 OUTPUT

	[ { name => 'string', type => 'number' | 'date' | 'string' }, ... ]

One entry per name in C<$columns>, in that order.  Either argument not an
array reference returns C<[]>.  A column with no non-empty values is



( run in 0.605 second using v1.01-cache-2.11-cpan-3f962061493 )