Skip to content

Commit 987f4d4

Browse files
matthew29tangcopybara-github
authored andcommitted
feat: Add AI content detection support
PiperOrigin-RevId: 1014211788
1 parent 720b112 commit 987f4d4

6 files changed

Lines changed: 793 additions & 0 deletions

File tree

‎agentplatform/_genai/_transformers.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from typing import Any
2020

2121
from google.genai._common import get_value_by_path as getv
22+
from google.genai._transformers import t_content, t_model # noqa: F401
2223

2324
from . import _evals_constant
2425
from . import _evals_data_converters

‎agentplatform/_genai/client.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
from agentplatform._genai import (
6666
serving_profiles as serving_profiles_module,
6767
)
68+
from agentplatform._genai import (
69+
detections as detections_module,
70+
)
6871

6972

7073
_GENAI_MODULES_TELEMETRY_HEADER = "vertex-genai-modules"
@@ -117,6 +120,7 @@ def __init__(self, api_client: genai_client.BaseApiClient): # type: ignore[name
117120
self._sandboxes: Optional[ModuleType] = None
118121
self._memory_banks: Optional[ModuleType] = None
119122
self._serving_profiles: Optional[ModuleType] = None
123+
self._detections: Optional[ModuleType] = None
120124

121125
@property
122126
@_common.experimental_warning(
@@ -303,6 +307,17 @@ def serving_profiles(
303307
)
304308
return self._serving_profiles.AsyncServingProfiles(self._api_client) # type: ignore[no-any-return]
305309

310+
@property
311+
def detections(
312+
self,
313+
) -> "detections_module.AsyncDetections":
314+
if self._detections is None:
315+
self._detections = importlib.import_module(
316+
".detections",
317+
__package__,
318+
)
319+
return self._detections.AsyncDetections(self._api_client) # type: ignore[no-any-return]
320+
306321
async def aclose(self) -> None:
307322
"""Closes the async client explicitly.
308323
@@ -416,6 +431,7 @@ def __init__(
416431
self._sandboxes: Optional[ModuleType] = None
417432
self._memory_banks: Optional[ModuleType] = None
418433
self._serving_profiles: Optional[ModuleType] = None
434+
self._detections: Optional[ModuleType] = None
419435

420436
@property
421437
def evals(self) -> "evals_module.Evals":
@@ -624,3 +640,12 @@ def serving_profiles(self) -> "serving_profiles_module.ServingProfiles":
624640
__package__,
625641
)
626642
return self._serving_profiles.ServingProfiles(self._api_client) # type: ignore[no-any-return]
643+
644+
@property
645+
def detections(self) -> "detections_module.Detections":
646+
if self._detections is None:
647+
self._detections = importlib.import_module(
648+
".detections",
649+
__package__,
650+
)
651+
return self._detections.Detections(self._api_client) # type: ignore[no-any-return]

‎agentplatform/_genai/detections.py‎

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# Copyright 2025 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+
16+
# Code generated by the Google Gen AI SDK generator DO NOT EDIT.
17+
18+
import json
19+
import logging
20+
from typing import Any, Optional, Union
21+
from urllib.parse import urlencode
22+
23+
from google.genai import _api_module
24+
from google.genai import _common
25+
from google.genai import types as genai_types
26+
from google.genai._api_client import BaseApiClient
27+
from google.genai._common import get_value_by_path as getv
28+
from google.genai._common import set_value_by_path as setv
29+
30+
from . import _transformers as t
31+
from . import types
32+
33+
logger = logging.getLogger("agentplatform_genai.detections")
34+
35+
36+
def _DetectContentParameters_to_vertex(
37+
api_client: BaseApiClient,
38+
from_object: Union[dict[str, Any], object],
39+
parent_object: Optional[dict[str, Any]] = None,
40+
) -> dict[str, Any]:
41+
to_object: dict[str, Any] = {}
42+
if getv(from_object, ["model"]) is not None:
43+
setv(
44+
to_object,
45+
["_url", "model"],
46+
t.t_model(api_client, getv(from_object, ["model"])),
47+
)
48+
49+
if getv(from_object, ["content"]) is not None:
50+
setv(to_object, ["content"], t.t_content(getv(from_object, ["content"])))
51+
52+
return to_object
53+
54+
55+
class Detections(_api_module.BaseModule):
56+
"""Class for detecting AI-generated content."""
57+
58+
def detect_content(
59+
self,
60+
*,
61+
model: str,
62+
content: Union[genai_types.ContentUnion, genai_types.ContentUnionDict],
63+
config: Optional[types.DetectContentConfigOrDict] = None,
64+
) -> types.DetectContentResponse:
65+
"""
66+
Detects AI-generated content and C2PA Content Credentials in media inputs.
67+
"""
68+
69+
parameter_model = types._DetectContentParameters(
70+
model=model,
71+
content=content,
72+
config=config,
73+
)
74+
75+
request_url_dict: Optional[dict[str, str]]
76+
if not self._api_client.vertexai:
77+
raise ValueError(
78+
"This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
79+
)
80+
else:
81+
request_dict = _DetectContentParameters_to_vertex(
82+
self._api_client, parameter_model
83+
)
84+
request_url_dict = request_dict.get("_url")
85+
if request_url_dict:
86+
path = "{model}:detectContent".format_map(request_url_dict)
87+
else:
88+
path = "{model}:detectContent"
89+
90+
query_params = request_dict.get("_query")
91+
if query_params:
92+
path = f"{path}?{urlencode(query_params)}"
93+
# TODO: remove the hack that pops config.
94+
request_dict.pop("config", None)
95+
96+
http_options: Optional[types.HttpOptions] = None
97+
if (
98+
parameter_model.config is not None
99+
and parameter_model.config.http_options is not None
100+
):
101+
http_options = parameter_model.config.http_options
102+
103+
request_dict = _common.convert_to_dict(request_dict)
104+
request_dict = _common.encode_unserializable_types(request_dict)
105+
106+
response = self._api_client.request("post", path, request_dict, http_options)
107+
108+
response_dict = {} if not response.body else json.loads(response.body)
109+
110+
return_value = types.DetectContentResponse._from_response(
111+
response=response_dict,
112+
kwargs=(
113+
{
114+
"config": {
115+
"response_schema": getattr(
116+
parameter_model.config, "response_schema", None
117+
),
118+
"response_json_schema": getattr(
119+
parameter_model.config, "response_json_schema", None
120+
),
121+
"include_all_fields": getattr(
122+
parameter_model.config, "include_all_fields", None
123+
),
124+
}
125+
}
126+
if getattr(parameter_model, "config", None)
127+
else {}
128+
),
129+
)
130+
131+
self._api_client._verify_response(return_value)
132+
return return_value
133+
134+
135+
class AsyncDetections(_api_module.BaseModule):
136+
"""Class for detecting AI-generated content."""
137+
138+
async def detect_content(
139+
self,
140+
*,
141+
model: str,
142+
content: Union[genai_types.ContentUnion, genai_types.ContentUnionDict],
143+
config: Optional[types.DetectContentConfigOrDict] = None,
144+
) -> types.DetectContentResponse:
145+
"""
146+
Detects AI-generated content and C2PA Content Credentials in media inputs.
147+
"""
148+
149+
parameter_model = types._DetectContentParameters(
150+
model=model,
151+
content=content,
152+
config=config,
153+
)
154+
155+
request_url_dict: Optional[dict[str, str]]
156+
if not self._api_client.vertexai:
157+
raise ValueError(
158+
"This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
159+
)
160+
else:
161+
request_dict = _DetectContentParameters_to_vertex(
162+
self._api_client, parameter_model
163+
)
164+
request_url_dict = request_dict.get("_url")
165+
if request_url_dict:
166+
path = "{model}:detectContent".format_map(request_url_dict)
167+
else:
168+
path = "{model}:detectContent"
169+
170+
query_params = request_dict.get("_query")
171+
if query_params:
172+
path = f"{path}?{urlencode(query_params)}"
173+
# TODO: remove the hack that pops config.
174+
request_dict.pop("config", None)
175+
176+
http_options: Optional[types.HttpOptions] = None
177+
if (
178+
parameter_model.config is not None
179+
and parameter_model.config.http_options is not None
180+
):
181+
http_options = parameter_model.config.http_options
182+
183+
request_dict = _common.convert_to_dict(request_dict)
184+
request_dict = _common.encode_unserializable_types(request_dict)
185+
186+
response = await self._api_client.async_request(
187+
"post", path, request_dict, http_options
188+
)
189+
190+
response_dict = {} if not response.body else json.loads(response.body)
191+
192+
return_value = types.DetectContentResponse._from_response(
193+
response=response_dict,
194+
kwargs=(
195+
{
196+
"config": {
197+
"response_schema": getattr(
198+
parameter_model.config, "response_schema", None
199+
),
200+
"response_json_schema": getattr(
201+
parameter_model.config, "response_json_schema", None
202+
),
203+
"include_all_fields": getattr(
204+
parameter_model.config, "include_all_fields", None
205+
),
206+
}
207+
}
208+
if getattr(parameter_model, "config", None)
209+
else {}
210+
),
211+
)
212+
213+
self._api_client._verify_response(return_value)
214+
return return_value

‎agentplatform/_genai/types/__init__.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
from .common import _DeleteServingProfileRequestParameters
7474
from .common import _DeleteSkillRequestParameters
7575
from .common import _DeployRequestParameters
76+
from .common import _DetectContentParameters
7677
from .common import _EvaluateInstancesRequestParameters
7778
from .common import _ExecuteCodeRuntimeSandboxRequestParameters
7879
from .common import _ExportPublisherModelRequestParameters
@@ -212,6 +213,7 @@
212213
from .common import AggregatedMetricResult
213214
from .common import AggregatedMetricResultDict
214215
from .common import AggregatedMetricResultOrDict
216+
from .common import AiGeneratedLikelihood
215217
from .common import AnalysisConfig
216218
from .common import AnalysisConfigDict
217219
from .common import AnalysisConfigOrDict
@@ -288,6 +290,15 @@
288290
from .common import BlurBaselineConfig
289291
from .common import BlurBaselineConfigDict
290292
from .common import BlurBaselineConfigOrDict
293+
from .common import C2paResult
294+
from .common import C2paResultDict
295+
from .common import C2paResultManifest
296+
from .common import C2paResultManifestAction
297+
from .common import C2paResultManifestCreationType
298+
from .common import C2paResultManifestDict
299+
from .common import C2paResultManifestOrDict
300+
from .common import C2paResultOrDict
301+
from .common import C2paResultOutcome
291302
from .common import CancelQueryJobResult
292303
from .common import CancelQueryJobResultDict
293304
from .common import CancelQueryJobResultOrDict
@@ -592,6 +603,12 @@
592603
from .common import DeployResponse
593604
from .common import DeployResponseDict
594605
from .common import DeployResponseOrDict
606+
from .common import DetectContentConfig
607+
from .common import DetectContentConfigDict
608+
from .common import DetectContentConfigOrDict
609+
from .common import DetectContentResponse
610+
from .common import DetectContentResponseDict
611+
from .common import DetectContentResponseOrDict
595612
from .common import DirectUploadSource
596613
from .common import DirectUploadSourceDict
597614
from .common import DirectUploadSourceOrDict
@@ -4393,6 +4410,18 @@
43934410
"GetServingProfileOperationConfig",
43944411
"GetServingProfileOperationConfigDict",
43954412
"GetServingProfileOperationConfigOrDict",
4413+
"DetectContentConfig",
4414+
"DetectContentConfigDict",
4415+
"DetectContentConfigOrDict",
4416+
"C2paResultManifest",
4417+
"C2paResultManifestDict",
4418+
"C2paResultManifestOrDict",
4419+
"C2paResult",
4420+
"C2paResultDict",
4421+
"C2paResultOrDict",
4422+
"DetectContentResponse",
4423+
"DetectContentResponseDict",
4424+
"DetectContentResponseOrDict",
43964425
"PromptOptimizerConfig",
43974426
"PromptOptimizerConfigDict",
43984427
"PromptOptimizerConfigOrDict",
@@ -4558,6 +4587,10 @@
45584587
"GenerateMemoriesResponseGeneratedMemoryAction",
45594588
"RagFileState",
45604589
"SkillRevisionState",
4590+
"AiGeneratedLikelihood",
4591+
"C2paResultOutcome",
4592+
"C2paResultManifestCreationType",
4593+
"C2paResultManifestAction",
45614594
"PromptOptimizerMethod",
45624595
"OptimizationMethod",
45634596
"PromptData",
@@ -4756,6 +4789,7 @@
47564789
"_ListServingProfilesRequestParameters",
47574790
"_DeleteServingProfileRequestParameters",
47584791
"_GetServingProfileOperationParameters",
4792+
"_DetectContentParameters",
47594793
"evals",
47604794
"agent_engines",
47614795
"prompts",

0 commit comments

Comments
 (0)