Class: Strata::CLI::AI::Services::TableGenerator
- Inherits:
-
Object
- Object
- Strata::CLI::AI::Services::TableGenerator
- Defined in:
- lib/strata/cli/ai/services/table_generator.rb
Overview
Generates semantic model fields from database table metadata using AI. Returns structured JSON for use in the field editor.
Constant Summary collapse
- SYSTEM_PROMPT =
<<~PROMPT You are a semantic modeling expert for the Strata Business Intelligence platform. Analyze database columns and generate semantic field definitions. You must understand that Names are extremely important in the Strata application. When the same named dimension is mapped to multiple tables, Strata treats them as the same entity but with multiple potential tables. Strata will at query generation time choose the best table. Therefore it is extremely important to consider whether a potential dimension or measure is the same as an existing one. You can infer that based on the table name, column name, existing fields, and business context. Reuse an existing dimension name only when it represents the same business concept across tables. If the same column label describes the current table's own entity, lifecycle, or attributes, create a table-specific name instead of reusing a generic existing name. Example: existing dimension name: Record Start Date table name: web_page column name: record_start_date dimension name: Web Page Record Start Date Example: existing dimension name: Country table name: customer column name: country dimension name: Country The edge case is when you have a Dimension table like Customer with column first_name and another Dimension table called Billed Customer with first_name, then they are likely not the same. A dimension created from Billed Customer should be given an appropriately prefixed name: Billed Customer First Name. Next, if the column is something highly ambiguous and the current table is likely a dimension table, prefix the dimension name with an appropriate prefix based on the name of the dimension table. Example: table name: item_dim column name: color dimension name: Item Color Example: table name: customer column name: first name dimension name: Customer First Name Given the above for each column, determine: - name: Human-friendly field name (e.g., "customer_id" → "Customer ID") - description: Brief description of what this field represents - schema_type: "dimension" for categorical/text, "measure" for numeric aggregations - data_type: string, integer, bigint, decimal, date, date_time, boolean. These are the data types supported by strata. They do not have precision nor scale. Simply the types listed here. Do not apply any other data types. - expression: SQL expression (for measures include aggregation like "sum(amount)") - synonyms: Array of 0-3 alternative names users might use to refer to this field. These help AI search and natural language queries find the right field. Example: "Revenue" → ["sales"] Example: "Created At" → ["created date", "date"] Example: "State" in a geography table → ["province"] Example: "Customer Return Date" → [] -- name has high specificity already so no synonyms needed In cases where you intentionally reuse an existing dimension name because it is the same business concept, omit everything except the following fields: name, schema_type, data_type, expression. Output ONLY valid JSON array, no explanations. PROMPT
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
Instance Method Summary collapse
-
#ai_available? ⇒ Boolean
Check if AI is available.
-
#call(table_name:, columns:, datasource:, user_context: nil) ⇒ Hash?
Generate field definitions from table metadata.
-
#call_with_prompt(table_name:, columns:, datasource:, user_prompt:, current_fields:) ⇒ Array<Hash>
Generate fields with user prompt for modification/regeneration.
-
#initialize(client: Client.new) ⇒ TableGenerator
constructor
A new instance of TableGenerator.
Constructor Details
#initialize(client: Client.new) ⇒ TableGenerator
Returns a new instance of TableGenerator.
72 73 74 |
# File 'lib/strata/cli/ai/services/table_generator.rb', line 72 def initialize(client: Client.new) @client = client end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
70 71 72 |
# File 'lib/strata/cli/ai/services/table_generator.rb', line 70 def client @client end |
Instance Method Details
#ai_available? ⇒ Boolean
Check if AI is available
134 135 136 |
# File 'lib/strata/cli/ai/services/table_generator.rb', line 134 def ai_available? @client.enabled? end |
#call(table_name:, columns:, datasource:, user_context: nil) ⇒ Hash?
Generate field definitions from table metadata
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/strata/cli/ai/services/table_generator.rb', line 82 def call(table_name:, columns:, datasource:, user_context: nil) unless ai_available? Output.print_warning("AI not available - using rule-based fallback") return fallback_fields(columns) end existing_models = load_existing_models_context prompt = build_prompt( table_name: table_name, columns: columns, existing_models_context: existing_models, user_context: user_context ) begin response = @client.complete(prompt, system_prompt: SYSTEM_PROMPT) parse_response(response, columns) rescue => e # Fallback to basic field generation on AI error Output.print_warning("AI failed to generate fields: #{e.} - performing basic field generation") fallback_fields(columns) end end |
#call_with_prompt(table_name:, columns:, datasource:, user_prompt:, current_fields:) ⇒ Array<Hash>
Generate fields with user prompt for modification/regeneration
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/strata/cli/ai/services/table_generator.rb', line 113 def call_with_prompt(table_name:, columns:, datasource:, user_prompt:, current_fields:) unless ai_available? raise AIError, "AI is not available - configure ai_api_key in .strata" end prompt = build_prompt_with_user_input( table_name: table_name, columns: columns, user_prompt: user_prompt, current_fields: current_fields ) begin response = @client.complete(prompt, system_prompt: SYSTEM_PROMPT) parse_response(response, columns) rescue => e raise AIError, "AI failed to generate fields: #{e.}" end end |