feat: add `bigframes.bigquery.ai.generate_embedding` (#2343) · google/bigframes@e91536c · GitHub
Skip to content

Commit e91536c

Browse files
google-labs-jules[bot]tswastsycai
authored
feat: add bigframes.bigquery.ai.generate_embedding (#2343)
Implement AI.GENERATE_EMBEDDING function in bigframes.bigquery.ai. --- *PR created automatically by Jules for task [11924477578091076513](https://jules.google.com/task/11924477578091076513) started by @tswast* --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Tim Sweña <swast@google.com> Co-authored-by: Shenyang Cai <sycai@users.noreply.github.com>
1 parent 4b0f13b commit e91536c

5 files changed

Lines changed: 305 additions & 33 deletions

File tree

bigframes/bigquery/_operations/ai.py

Lines changed: 109 additions & 1 deletion

bigframes/bigquery/ai.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
generate,
2323
generate_bool,
2424
generate_double,
25+
generate_embedding,
2526
generate_int,
2627
if_,
2728
score,
@@ -33,6 +34,7 @@
3334
"generate",
3435
"generate_bool",
3536
"generate_double",
37+
"generate_embedding",
3638
"generate_int",
3739
"if_",
3840
"score",

bigframes/core/sql/literals.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import annotations
16+
17+
import collections.abc
18+
import json
19+
from typing import Any, List, Mapping, Union
20+
21+
import bigframes.core.sql
22+
23+
STRUCT_VALUES = Union[
24+
str, int, float, bool, Mapping[str, str], List[str], Mapping[str, Any]
25+
]
26+
STRUCT_TYPE = Mapping[str, STRUCT_VALUES]
27+
28+
29+
def struct_literal(struct_options: STRUCT_TYPE) -> str:
30+
rendered_options = []
31+
for option_name, option_value in struct_options.items():
32+
if option_name == "model_params":
33+
json_str = json.dumps(option_value)
34+
# Escape single quotes for SQL string literal
35+
sql_json_str = json_str.replace("'", "''")
36+
rendered_val = f"JSON'{sql_json_str}'"
37+
elif isinstance(option_value, collections.abc.Mapping):
38+
struct_body = ", ".join(
39+
[
40+
f"{bigframes.core.sql.simple_literal(v)} AS {k}"
41+
for k, v in option_value.items()
42+
]
43+
)
44+
rendered_val = f"STRUCT({struct_body})"
45+
elif isinstance(option_value, list):
46+
rendered_val = (
47+
"["
48+
+ ", ".join(
49+
[bigframes.core.sql.simple_literal(v) for v in option_value]
50+
)
51+
+ "]"
52+
)
53+
elif isinstance(option_value, bool):
54+
rendered_val = str(option_value).lower()
55+
else:
56+
rendered_val = bigframes.core.sql.simple_literal(option_value)
57+
rendered_options.append(f"{rendered_val} AS {option_name}")
58+
return f"STRUCT({', '.join(rendered_options)})"

bigframes/core/sql/ml.py

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@
1414

1515
from __future__ import annotations
1616

17-
import collections.abc
18-
import json
1917
from typing import Any, Dict, List, Mapping, Optional, Union
2018

2119
import bigframes.core.compile.googlesql as googlesql
2220
import bigframes.core.sql
21+
import bigframes.core.sql.literals
2322

2423

2524
def create_model_ddl(
@@ -109,36 +108,7 @@ def _build_struct_sql(
109108
) -> str:
110109
if not struct_options:
111110
return ""
112-
113-
rendered_options = []
114-
for option_name, option_value in struct_options.items():
115-
if option_name == "model_params":
116-
json_str = json.dumps(option_value)
117-
# Escape single quotes for SQL string literal
118-
sql_json_str = json_str.replace("'", "''")
119-
rendered_val = f"JSON'{sql_json_str}'"
120-
elif isinstance(option_value, collections.abc.Mapping):
121-
struct_body = ", ".join(
122-
[
123-
f"{bigframes.core.sql.simple_literal(v)} AS {k}"
124-
for k, v in option_value.items()
125-
]
126-
)
127-
rendered_val = f"STRUCT({struct_body})"
128-
elif isinstance(option_value, list):
129-
rendered_val = (
130-
"["
131-
+ ", ".join(
132-
[bigframes.core.sql.simple_literal(v) for v in option_value]
133-
)
134-
+ "]"
135-
)
136-
elif isinstance(option_value, bool):
137-
rendered_val = str(option_value).lower()
138-
else:
139-
rendered_val = bigframes.core.sql.simple_literal(option_value)
140-
rendered_options.append(f"{rendered_val} AS {option_name}")
141-
return f", STRUCT({', '.join(rendered_options)})"
111+
return f", {bigframes.core.sql.literals.struct_literal(struct_options)}"
142112

143113

144114
def evaluate(

tests/unit/bigquery/test_ai.py

Lines changed: 134 additions & 0 deletions

0 commit comments

Comments
 (0)