From 02a09d53dde8aab57d7d7387832ac1d5d3189ea0 Mon Sep 17 00:00:00 2001 From: "Marcelo G. Almiron" Date: Thu, 1 May 2025 18:29:22 +0200 Subject: [PATCH] feat(ai): Add support for AI features jira: GDAI-214 risk: low --- gooddata-sdk/gooddata_sdk/__init__.py | 4 + .../organization/entity_model/llm_endpoint.py | 157 ++ .../catalog/organization/service.py | 164 +- gooddata-sdk/gooddata_sdk/compute/service.py | 110 +- .../organization/create_llm_endpoint.yaml | 311 +++ .../organization/delete_llm_endpoint.yaml | 286 +++ .../organization/get_llm_endpoint.yaml | 228 ++ .../organization/list_llm_endpoints.yaml | 466 ++++ .../organization/update_llm_endpoint.yaml | 419 ++++ .../catalog/test_catalog_organization.py | 229 ++ .../tests/compute/fixtures/ai_search.yaml | 2114 +++++++++++++++++ .../fixtures/ai_search_full_params.yaml | 2103 ++++++++++++++++ .../b2f2d436-9831-4fe0-81df-8c59fd33242b.yaml | 194 ++ .../4717b786-2c2e-4596-adb5-4f8b0ab0e19a.yaml | 22 + .../9f2b1f37-befa-450e-a6cc-dc576845c412.yaml | 12 + .../metrics/amount_of_active_customers.yaml | 7 + .../metrics/amount_of_orders.yaml | 7 + .../metrics/amount_of_top_customers.yaml | 8 + .../metrics/amount_of_valid_orders.yaml | 8 + .../metrics/campaign_spend.yaml | 7 + .../analytics_model/metrics/order_amount.yaml | 7 + .../metrics/percent_revenue.yaml | 7 + ...percent_revenue_from_top_10_customers.yaml | 8 + ...revenue_from_top_10_percent_customers.yaml | 8 + ..._revenue_from_top_10_percent_products.yaml | 8 + .../percent_revenue_from_top_10_products.yaml | 8 + .../metrics/percent_revenue_in_category.yaml | 8 + .../metrics/percent_revenue_per_product.yaml | 7 + .../metrics/revenue-clothing.yaml | 7 + .../metrics/revenue-electronic.yaml | 7 + .../analytics_model/metrics/revenue-home.yaml | 7 + .../metrics/revenue-outdoor.yaml | 7 + .../analytics_model/metrics/revenue.yaml | 8 + .../metrics/revenue_per_customer.yaml | 7 + .../metrics/revenue_per_dollar_spent.yaml | 7 + .../metrics/revenue_top_10.yaml | 7 + .../metrics/revenue_top_10_percent.yaml | 7 + .../metrics/total_revenue-no_filters.yaml | 7 + .../metrics/total_revenue.yaml | 7 + .../visualization_objects/campaign_spend.yaml | 62 + .../customers_trend.yaml | 74 + ..._per_product_by_customer_and_category.yaml | 77 + .../percentage_of_customers_by_region.yaml | 57 + .../product_breakdown.yaml | 55 + .../product_categories_pie_chart.yaml | 50 + ...venue_comparison-over_previous_period.yaml | 73 + .../product_saleability.yaml | 55 + ..._and_quantity_by_product_and_category.yaml | 97 + .../revenue_by_category_trend.yaml | 54 + .../revenue_by_product.yaml | 37 + .../revenue_per_usd_vs_spend_by_campaign.yaml | 54 + .../visualization_objects/revenue_trend.yaml | 66 + .../top_10_customers.yaml | 55 + .../top_10_products.yaml | 55 + .../ldm/datasets/campaign_channels.yaml | 67 + .../ai_search/ldm/datasets/campaigns.yaml | 35 + .../ai_search/ldm/datasets/customers.yaml | 58 + .../ai_search/ldm/datasets/order_lines.yaml | 108 + .../load/ai_search/ldm/datasets/products.yaml | 43 + .../ai_search/ldm/date_instances/date.yaml | 15 + .../tests/compute/test_compute_service.py | 81 + 61 files changed, 8317 insertions(+), 6 deletions(-) create mode 100644 gooddata-sdk/gooddata_sdk/catalog/organization/entity_model/llm_endpoint.py create mode 100644 gooddata-sdk/tests/catalog/fixtures/organization/create_llm_endpoint.yaml create mode 100644 gooddata-sdk/tests/catalog/fixtures/organization/delete_llm_endpoint.yaml create mode 100644 gooddata-sdk/tests/catalog/fixtures/organization/get_llm_endpoint.yaml create mode 100644 gooddata-sdk/tests/catalog/fixtures/organization/list_llm_endpoints.yaml create mode 100644 gooddata-sdk/tests/catalog/fixtures/organization/update_llm_endpoint.yaml create mode 100644 gooddata-sdk/tests/compute/fixtures/ai_search.yaml create mode 100644 gooddata-sdk/tests/compute/fixtures/ai_search_full_params.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/analytical_dashboards/b2f2d436-9831-4fe0-81df-8c59fd33242b.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/4717b786-2c2e-4596-adb5-4f8b0ab0e19a.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/9f2b1f37-befa-450e-a6cc-dc576845c412.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_active_customers.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_orders.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_top_customers.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_valid_orders.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/campaign_spend.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/order_amount.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_customers.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_customers.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_products.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_products.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_in_category.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_per_product.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-clothing.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-electronic.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-home.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-outdoor.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_customer.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_dollar_spent.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10_percent.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue-no_filters.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/campaign_spend.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/customers_trend.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percent_revenue_per_product_by_customer_and_category.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percentage_of_customers_by_region.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_breakdown.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_categories_pie_chart.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_revenue_comparison-over_previous_period.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_saleability.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_and_quantity_by_product_and_category.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_category_trend.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_product.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_per_usd_vs_spend_by_campaign.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_trend.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_customers.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_products.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaign_channels.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaigns.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/customers.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/order_lines.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/products.yaml create mode 100644 gooddata-sdk/tests/compute/load/ai_search/ldm/date_instances/date.yaml create mode 100644 gooddata-sdk/tests/compute/test_compute_service.py diff --git a/gooddata-sdk/gooddata_sdk/__init__.py b/gooddata-sdk/gooddata_sdk/__init__.py index 3b2a04785..266c60e65 100644 --- a/gooddata-sdk/gooddata_sdk/__init__.py +++ b/gooddata-sdk/gooddata_sdk/__init__.py @@ -99,6 +99,10 @@ CatalogJwkDocument, CatalogRsaSpecification, ) +from gooddata_sdk.catalog.organization.entity_model.llm_endpoint import ( + CatalogLlmEndpoint, + CatalogLlmEndpointDocument, +) from gooddata_sdk.catalog.organization.entity_model.organization import CatalogOrganization from gooddata_sdk.catalog.organization.entity_model.setting import CatalogOrganizationSetting from gooddata_sdk.catalog.organization.layout.export_template import ( diff --git a/gooddata-sdk/gooddata_sdk/catalog/organization/entity_model/llm_endpoint.py b/gooddata-sdk/gooddata_sdk/catalog/organization/entity_model/llm_endpoint.py new file mode 100644 index 000000000..37831b537 --- /dev/null +++ b/gooddata-sdk/gooddata_sdk/catalog/organization/entity_model/llm_endpoint.py @@ -0,0 +1,157 @@ +# (C) 2024 GoodData Corporation +from __future__ import annotations + +from typing import Any, Optional + +from attr import define +from gooddata_api_client.model.json_api_llm_endpoint_in import JsonApiLlmEndpointIn +from gooddata_api_client.model.json_api_llm_endpoint_in_attributes import JsonApiLlmEndpointInAttributes +from gooddata_api_client.model.json_api_llm_endpoint_in_document import JsonApiLlmEndpointInDocument +from gooddata_api_client.model.json_api_llm_endpoint_patch import JsonApiLlmEndpointPatch +from gooddata_api_client.model.json_api_llm_endpoint_patch_attributes import JsonApiLlmEndpointPatchAttributes +from gooddata_api_client.model.json_api_llm_endpoint_patch_document import JsonApiLlmEndpointPatchDocument + +from gooddata_sdk.catalog.base import Base +from gooddata_sdk.utils import safeget + + +@define(kw_only=True) +class CatalogLlmEndpointDocument(Base): + data: CatalogLlmEndpoint + + @staticmethod + def client_class() -> type[JsonApiLlmEndpointInDocument]: + return JsonApiLlmEndpointInDocument + + +@define(kw_only=True) +class CatalogLlmEndpointPatchDocument(Base): + data: CatalogLlmEndpointPatch + + @staticmethod + def client_class() -> type[JsonApiLlmEndpointPatchDocument]: + return JsonApiLlmEndpointPatchDocument + + +@define(kw_only=True) +class CatalogLlmEndpoint(Base): + id: str + attributes: Optional[CatalogLlmEndpointAttributes] = None + + @staticmethod + def client_class() -> type[JsonApiLlmEndpointIn]: + return JsonApiLlmEndpointIn + + @classmethod + def init( + cls, + id: str, + title: str, + token: str, + description: Optional[str] = None, + provider: Optional[str] = None, + base_url: Optional[str] = None, + llm_organization: Optional[str] = None, + llm_model: Optional[str] = None, + workspace_ids: Optional[list[str]] = None, + ) -> CatalogLlmEndpoint: + return cls( + id=id, + attributes=CatalogLlmEndpointAttributes( + title=title, + token=token, + description=description, + provider=provider, + base_url=base_url, + llm_organization=llm_organization, + llm_model=llm_model, + workspace_ids=workspace_ids, + ), + ) + + @classmethod + def from_api(cls, entity: dict[str, Any]) -> CatalogLlmEndpoint: + ea = entity["attributes"] + attr = CatalogLlmEndpointAttributes( + title=safeget(ea, ["title"]), + token="", # Token is not returned for security reasons + description=safeget(ea, ["description"]), + provider=safeget(ea, ["provider"]), + base_url=safeget(ea, ["baseUrl"]), + llm_organization=safeget(ea, ["llmOrganization"]), + llm_model=safeget(ea, ["llmModel"]), + workspace_ids=safeget(ea, ["workspaceIds"]), + ) + return cls( + id=entity["id"], + attributes=attr, + ) + + +@define(kw_only=True) +class CatalogLlmEndpointPatch(Base): + id: str + attributes: Optional[CatalogLlmEndpointPatchAttributes] = None + + @staticmethod + def client_class() -> type[JsonApiLlmEndpointPatch]: + return JsonApiLlmEndpointPatch + + @classmethod + def init( + cls, + id: str, + title: Optional[str] = None, + token: Optional[str] = None, + description: Optional[str] = None, + provider: Optional[str] = None, + base_url: Optional[str] = None, + llm_organization: Optional[str] = None, + llm_model: Optional[str] = None, + workspace_ids: Optional[list[str]] = None, + ) -> CatalogLlmEndpointPatch: + return cls( + id=id, + attributes=CatalogLlmEndpointPatchAttributes( + title=title, + token=token, + description=description, + provider=provider, + base_url=base_url, + llm_organization=llm_organization, + llm_model=llm_model, + workspace_ids=workspace_ids, + ), + ) + + +@define(kw_only=True) +class CatalogLlmEndpointAttributes(Base): + title: str + token: str + description: Optional[str] = None + provider: Optional[str] = None + base_url: Optional[str] = None + llm_organization: Optional[str] = None + llm_model: Optional[str] = None + workspace_ids: Optional[list[str]] = None + + @staticmethod + def client_class() -> type[JsonApiLlmEndpointInAttributes]: + return JsonApiLlmEndpointInAttributes + + +@define(kw_only=True) +class CatalogLlmEndpointPatchAttributes(Base): + title: Optional[str] = None + token: Optional[str] = None + description: Optional[str] = None + provider: Optional[str] = None + base_url: Optional[str] = None + llm_organization: Optional[str] = None + llm_model: Optional[str] = None + workspace_ids: Optional[list[str]] = None + + @staticmethod + def client_class() -> type[JsonApiLlmEndpointPatchAttributes]: + return JsonApiLlmEndpointPatchAttributes diff --git a/gooddata-sdk/gooddata_sdk/catalog/organization/service.py b/gooddata-sdk/gooddata_sdk/catalog/organization/service.py index 4806ba296..7b337d6f4 100644 --- a/gooddata-sdk/gooddata_sdk/catalog/organization/service.py +++ b/gooddata-sdk/gooddata_sdk/catalog/organization/service.py @@ -2,7 +2,7 @@ from __future__ import annotations import functools -from typing import Optional +from typing import Any, Optional from gooddata_api_client.exceptions import NotFoundException from gooddata_api_client.model.declarative_export_templates import DeclarativeExportTemplates @@ -20,6 +20,12 @@ from gooddata_sdk.catalog.organization.entity_model.directive import CatalogCspDirective from gooddata_sdk.catalog.organization.entity_model.identity_provider import CatalogIdentityProvider from gooddata_sdk.catalog.organization.entity_model.jwk import CatalogJwk, CatalogJwkDocument +from gooddata_sdk.catalog.organization.entity_model.llm_endpoint import ( + CatalogLlmEndpoint, + CatalogLlmEndpointDocument, + CatalogLlmEndpointPatch, + CatalogLlmEndpointPatchDocument, +) from gooddata_sdk.catalog.organization.entity_model.organization import CatalogOrganizationDocument from gooddata_sdk.catalog.organization.entity_model.setting import CatalogOrganizationSetting from gooddata_sdk.catalog.organization.layout.identity_provider import CatalogDeclarativeIdentityProvider @@ -510,6 +516,162 @@ def list_export_templates(self) -> list[CatalogExportTemplate]: for export_template in export_templates["data"] ] + def get_llm_endpoint(self, id: str) -> CatalogLlmEndpoint: + """ + Get LLM endpoint by ID. + + Args: + id: LLM endpoint identifier + + Returns: + CatalogLlmEndpoint: Retrieved LLM endpoint + """ + response = self._entities_api.get_entity_llm_endpoints(id, _check_return_type=False) + return CatalogLlmEndpoint.from_api(response.data) + + def list_llm_endpoints( + self, + filter: Optional[str] = None, + page: Optional[int] = None, + size: Optional[int] = None, + sort: Optional[list[str]] = None, + meta_include: Optional[list[str]] = None, + ) -> list[CatalogLlmEndpoint]: + """ + List all LLM endpoints. + + Args: + filter: Optional filter string + page: Zero-based page index (0..N) + size: The size of the page to be returned + sort: Sorting criteria in the format: property,(asc|desc). Multiple sort criteria are supported. + meta_include: Include Meta objects + + Returns: + list[CatalogLlmEndpoint]: List of LLM endpoints + + Note: + Default values for optional parameters are documented in the LLM endpoints of the GoodData API. + """ + kwargs: dict[str, Any] = {} + if filter is not None: + kwargs["filter"] = filter + if page is not None: + kwargs["page"] = page + if size is not None: + kwargs["size"] = size + if sort is not None: + kwargs["sort"] = sort + if meta_include is not None: + kwargs["meta_include"] = meta_include + kwargs["_check_return_type"] = False + + response = self._entities_api.get_all_entities_llm_endpoints(**kwargs) + return [CatalogLlmEndpoint.from_api(endpoint) for endpoint in response.data] + + def create_llm_endpoint( + self, + id: str, + title: str, + token: str, + description: Optional[str] = None, + provider: Optional[str] = None, + base_url: Optional[str] = None, + llm_organization: Optional[str] = None, + llm_model: Optional[str] = None, + workspace_ids: Optional[list[str]] = None, + ) -> CatalogLlmEndpoint: + """ + Create a new LLM endpoint. + + Args: + id: Identifier of the LLM endpoint + title: User-facing title of the LLM Provider + token: The token to use to connect to the LLM provider + description: Optional user-facing description of the LLM endpoint + provider: Optional LLM provider name (e.g., "openai") + base_url: Optional base URL for custom LLM endpoint + llm_organization: Optional LLM organization identifier + llm_model: Optional LLM default model override + workspace_ids: Optional list of workspace IDs for which LLM endpoint is valid. + If empty, it is valid for all workspaces. + + Returns: + CatalogLlmEndpoint: Created LLM endpoint + """ + llm_endpoint = CatalogLlmEndpoint.init( + id=id, + title=title, + token=token, + description=description, + provider=provider, + base_url=base_url, + llm_organization=llm_organization, + llm_model=llm_model, + workspace_ids=workspace_ids, + ) + llm_endpoint_document = CatalogLlmEndpointDocument(data=llm_endpoint) + response = self._entities_api.create_entity_llm_endpoints( + json_api_llm_endpoint_in_document=llm_endpoint_document.to_api(), _check_return_type=False + ) + return CatalogLlmEndpoint.from_api(response.data) + + def update_llm_endpoint( + self, + id: str, + title: Optional[str] = None, + token: Optional[str] = None, + description: Optional[str] = None, + provider: Optional[str] = None, + base_url: Optional[str] = None, + llm_organization: Optional[str] = None, + llm_model: Optional[str] = None, + workspace_ids: Optional[list[str]] = None, + ) -> CatalogLlmEndpoint: + """ + Update an existing LLM endpoint. + + Args: + id: Identifier of the LLM endpoint + title: User-facing title of the LLM Provider + token: The token to use to connect to the LLM provider. If not provided, the existing token will be preserved. + description: User-facing description of the LLM endpoint + provider: LLM provider name (e.g., "openai") + base_url: Base URL for custom LLM endpoint + llm_organization: LLM organization identifier + llm_model: LLM default model override + workspace_ids: List of workspace IDs for which LLM endpoint is valid. + If empty, it is valid for all workspaces. + + Returns: + CatalogLlmEndpoint: Updated LLM endpoint + """ + llm_endpoint_patch = CatalogLlmEndpointPatch.init( + id=id, + title=title, + token=token, + description=description, + provider=provider, + base_url=base_url, + llm_organization=llm_organization, + llm_model=llm_model, + workspace_ids=workspace_ids, + ) + llm_endpoint_patch_document = CatalogLlmEndpointPatchDocument(data=llm_endpoint_patch) + response = self._entities_api.patch_entity_llm_endpoints( + id, llm_endpoint_patch_document.to_api(), _check_return_type=False + ) + return CatalogLlmEndpoint.from_api(response.data) + + def delete_llm_endpoint(self, id: str) -> None: + """ + Delete an LLM endpoint. + + Args: + id: LLM endpoint identifier + """ + self._entities_api.delete_entity_llm_endpoints(id, _check_return_type=False) + # Layout APIs def get_declarative_notification_channels(self) -> list[CatalogDeclarativeNotificationChannel]: diff --git a/gooddata-sdk/gooddata_sdk/compute/service.py b/gooddata-sdk/gooddata_sdk/compute/service.py index 74c4de735..d03b75cd7 100644 --- a/gooddata-sdk/gooddata_sdk/compute/service.py +++ b/gooddata-sdk/gooddata_sdk/compute/service.py @@ -2,6 +2,7 @@ from __future__ import annotations import logging +from typing import Any, Optional from gooddata_api_client import ApiException from gooddata_api_client.model.afm_cancel_tokens import AfmCancelTokens @@ -9,6 +10,8 @@ from gooddata_api_client.model.chat_history_result import ChatHistoryResult from gooddata_api_client.model.chat_request import ChatRequest from gooddata_api_client.model.chat_result import ChatResult +from gooddata_api_client.model.search_request import SearchRequest +from gooddata_api_client.model.search_result import SearchResult from gooddata_sdk.client import GoodDataApiClient from gooddata_sdk.compute.model.execution import Execution, ExecutionDefinition, ResultCacheMetadata @@ -26,6 +29,7 @@ class ComputeService: def __init__(self, api_client: GoodDataApiClient): self._api_client = api_client self._actions_api = self._api_client.actions_api + self._entities_api = self._api_client.entities_api def for_exec_def(self, workspace_id: str, exec_def: ExecutionDefinition) -> Execution: """ @@ -91,21 +95,29 @@ def ai_chat(self, workspace_id: str, question: str) -> ChatResult: response = self._actions_api.ai_chat(workspace_id, chat_request, _check_return_type=False) return response - def ai_chat_history(self, workspace_id: str, chat_history_interaction_id: int = 0) -> ChatHistoryResult: + def get_ai_chat_history( + self, + workspace_id: str, + chat_history_interaction_id: str = "", + thread_id_suffix: str = "", + ) -> ChatHistoryResult: """ Get chat history with AI in GoodData workspace. Args: workspace_id: workspace identifier - chat_history_interaction_id: collect history starting from this interaction id + chat_history_interaction_id: collect history starting from this interaction id. If None, complete chat history is returned. + thread_id_suffix: suffix to identify a specific chat thread. If provided, chat_history_interaction_id is ignored. Returns: - str: Chat history response + ChatHistoryResult: Chat history response containing interactions and other metadata """ - chat_history_request = ChatHistoryRequest(chat_history_interaction_id=chat_history_interaction_id) + chat_history_request = ChatHistoryRequest( + chat_history_interaction_id=chat_history_interaction_id, reset=False, thread_id_suffix=thread_id_suffix + ) response = self._actions_api.ai_chat_history(workspace_id, chat_history_request, _check_return_type=False) return response - def ai_chat_history_reset(self, workspace_id: str) -> None: + def reset_ai_chat_history(self, workspace_id: str) -> None: """ Reset chat history with AI in GoodData workspace. @@ -115,6 +127,74 @@ def ai_chat_history_reset(self, workspace_id: str) -> None: chat_history_request = ChatHistoryRequest(reset=True) self._actions_api.ai_chat_history(workspace_id, chat_history_request, _check_return_type=False) + def set_ai_chat_history_feedback( + self, + workspace_id: str, + user_feedback: str, + chat_history_interaction_id: str, + thread_id_suffix: str = "", + ) -> None: + """ + Provide feedback for a specific chat history interaction. + + Args: + workspace_id: workspace identifier + user_feedback: feedback to provide ("POSITIVE", "NEGATIVE" or "NONE") + chat_history_interaction_id: interaction id to provide feedback for + thread_id_suffix: suffix to identify a specific chat thread + """ + chat_history_request = ChatHistoryRequest( + user_feedback=user_feedback, + chat_history_interaction_id=chat_history_interaction_id, + thread_id_suffix=thread_id_suffix, + reset=False, + ) + self._actions_api.ai_chat_history(workspace_id, chat_history_request, _check_return_type=False) + + def search_ai( + self, + workspace_id: str, + question: str, + deep_search: Optional[bool] = None, + limit: Optional[int] = None, + object_types: Optional[list[str]] = None, + relevant_score_threshold: Optional[float] = None, + title_to_descriptor_ratio: Optional[float] = None, + ) -> SearchResult: + """ + Search for metadata objects using similarity search. + + Args: + workspace_id: workspace identifier + question: keyword/sentence input for search + deep_search: turn on deep search - if true, content of complex objects will be searched as well + limit: maximum number of results to return + object_types: list of object types to search for. Enum items: "attribute", "metric", "fact", + "label", "date", "dataset", "visualization" and "dashboard" + relevant_score_threshold: minimum relevance score threshold for results + title_to_descriptor_ratio: ratio of title score to descriptor score + + Returns: + SearchResult: Search results + + Note: + Default values for optional parameters are documented in the AI Search endpoint of the GoodData API. + """ + search_params: dict[str, Any] = {} + if deep_search is not None: + search_params["deep_search"] = deep_search + if limit is not None: + search_params["limit"] = limit + if object_types is not None: + search_params["object_types"] = object_types + if relevant_score_threshold is not None: + search_params["relevant_score_threshold"] = relevant_score_threshold + if title_to_descriptor_ratio is not None: + search_params["title_to_descriptor_ratio"] = title_to_descriptor_ratio + search_request = SearchRequest(question=question, **search_params) + response = self._actions_api.ai_search(workspace_id, search_request, _check_return_type=False) + return response + def cancel_executions(self, executions: dict[str, dict[str, str]]) -> None: """ Try to cancel given executions using the cancel api endpoint. @@ -132,3 +212,23 @@ def cancel_executions(self, executions: dict[str, dict[str, str]]) -> None: ) except ApiException as e: print("Exception when calling ActionsApi->cancel_executions: %s\n", e) + + def sync_metadata(self, workspace_id: str, async_req: bool = False) -> None: + """ + Synchronize metadata for a workspace to update embeddings used by AI features. + + This method triggers a metadata synchronization process that updates the embeddings + used by AI features like search and chat. The embeddings are created from the + workspace's metadata model and are essential for accurate AI functionality. + + Note: This is a temporary solution and will be removed in a future release when + metadata synchronization becomes automatic. + + Args: + workspace_id: Workspace identifier + async_req: If True, execute request asynchronously. Default is False. + + Returns: + None + """ + self._actions_api.metadata_sync(workspace_id, async_req=async_req, _check_return_type=False) diff --git a/gooddata-sdk/tests/catalog/fixtures/organization/create_llm_endpoint.yaml b/gooddata-sdk/tests/catalog/fixtures/organization/create_llm_endpoint.yaml new file mode 100644 index 000000000..9b57ea79d --- /dev/null +++ b/gooddata-sdk/tests/catalog/fixtures/organization/create_llm_endpoint.yaml @@ -0,0 +1,311 @@ +# (C) 2025 GoodData Corporation +version: 1 +interactions: + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: + data: + attributes: + title: Test Endpoint + token: secret-token + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '207' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: + data: + attributes: + title: Test Endpoint 2 + token: secret-token-2 + description: Test Description + provider: OPENAI + baseUrl: https://api.example.com + llmOrganization: org1 + llmModel: gpt-4 + workspaceIds: + - workspace1 + - workspace2 + id: endpoint2 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '312' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint2 + type: llmEndpoint + attributes: + provider: OPENAI + baseUrl: https://api.example.com + llmOrganization: org1 + llmModel: gpt-4 + workspaceIds: + - workspace1 + - workspace2 + title: Test Endpoint 2 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint2 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint2 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' diff --git a/gooddata-sdk/tests/catalog/fixtures/organization/delete_llm_endpoint.yaml b/gooddata-sdk/tests/catalog/fixtures/organization/delete_llm_endpoint.yaml new file mode 100644 index 000000000..d905858b6 --- /dev/null +++ b/gooddata-sdk/tests/catalog/fixtures/organization/delete_llm_endpoint.yaml @@ -0,0 +1,286 @@ +# (C) 2025 GoodData Corporation +version: 1 +interactions: + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: + data: + attributes: + title: Test Endpoint + token: secret-token + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '207' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 404 + message: Not Found + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '172' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/problem+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + detail: The requested endpoint does not exist or you do not have permission + to access it. + status: 404 + title: Not Found + traceId: 681a119f51cc193fd4c5888855cceec4 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' diff --git a/gooddata-sdk/tests/catalog/fixtures/organization/get_llm_endpoint.yaml b/gooddata-sdk/tests/catalog/fixtures/organization/get_llm_endpoint.yaml new file mode 100644 index 000000000..a728f5ae5 --- /dev/null +++ b/gooddata-sdk/tests/catalog/fixtures/organization/get_llm_endpoint.yaml @@ -0,0 +1,228 @@ +# (C) 2025 GoodData Corporation +version: 1 +interactions: + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: + data: + attributes: + title: Test Endpoint + token: secret-token + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '207' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '207' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' diff --git a/gooddata-sdk/tests/catalog/fixtures/organization/list_llm_endpoints.yaml b/gooddata-sdk/tests/catalog/fixtures/organization/list_llm_endpoints.yaml new file mode 100644 index 000000000..54ae37c6a --- /dev/null +++ b/gooddata-sdk/tests/catalog/fixtures/organization/list_llm_endpoints.yaml @@ -0,0 +1,466 @@ +# (C) 2025 GoodData Corporation +version: 1 +interactions: + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: + data: + attributes: + title: Test Endpoint 1 + token: secret-token-1 + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '209' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint 1 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: + data: + attributes: + title: Test Endpoint 2 + token: secret-token-2 + id: endpoint2 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '209' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint2 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint 2 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint2 + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '572' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + - id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint 1 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - id: endpoint2 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint 2 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint2 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints?page=0&size=20 + next: http://localhost:3000/api/v1/entities/llmEndpoints?page=1&size=20 + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/llmEndpoints?filter=title%3D%3D%27Test+Endpoint+1%27&size=1 + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '449' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + - id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Test Endpoint 1 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints?filter=title%3D%3D%27Test+Endpoint+1%27&page=0&size=1 + next: http://localhost:3000/api/v1/entities/llmEndpoints?filter=title%3D%3D%27Test+Endpoint+1%27&page=1&size=1 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint2 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' diff --git a/gooddata-sdk/tests/catalog/fixtures/organization/update_llm_endpoint.yaml b/gooddata-sdk/tests/catalog/fixtures/organization/update_llm_endpoint.yaml new file mode 100644 index 000000000..951e28ab6 --- /dev/null +++ b/gooddata-sdk/tests/catalog/fixtures/organization/update_llm_endpoint.yaml @@ -0,0 +1,419 @@ +# (C) 2025 GoodData Corporation +version: 1 +interactions: + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/llmEndpoints + body: + data: + attributes: + title: Initial Title + token: initial-token + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '207' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: &id001 + - PLACEHOLDER + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Initial Title + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: PATCH + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: + data: + attributes: + title: Updated Title + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '207' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + llmModel: gpt-4o + title: Updated Title + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: PATCH + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: + data: + attributes: + title: Updated Title 2 + token: new-token + description: Updated Description + provider: OPENAI + baseUrl: https://api.updated.com + llmOrganization: org2 + llmModel: gpt-3.5 + workspaceIds: + - workspace3 + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '301' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + baseUrl: https://api.updated.com + llmOrganization: org2 + llmModel: gpt-3.5 + workspaceIds: + - workspace3 + title: Updated Title 2 + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: PATCH + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: + data: + attributes: + title: New Title + id: endpoint1 + type: llmEndpoint + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Length: + - '295' + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: + data: + id: endpoint1 + type: llmEndpoint + attributes: + provider: OPENAI + baseUrl: https://api.updated.com + llmOrganization: org2 + llmModel: gpt-3.5 + workspaceIds: + - workspace3 + title: New Title + links: + self: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/llmEndpoints/endpoint1 + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Content-Disposition, Content-Length, Content-Range, Set-Cookie + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - keep-alive + Content-Security-Policy: + - 'default-src ''self'' *.wistia.com *.wistia.net; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' *.wistia.com *.wistia.net *.hsforms.net *.hsforms.com + src.litix.io matomo.anywhere.gooddata.com *.jquery.com unpkg.com cdnjs.cloudflare.com; + img-src * data: blob:; style-src ''self'' ''unsafe-inline'' fonts.googleapis.com + cdn.jsdelivr.net fast.fonts.net; font-src ''self'' data: fonts.gstatic.com + *.alicdn.com *.wistia.com cdn.jsdelivr.net info.gooddata.com; frame-src + ''self'' *.hsforms.net *.hsforms.com; object-src ''none''; worker-src + ''self'' blob:; child-src blob:; connect-src ''self'' *.tiles.mapbox.com + *.mapbox.com *.litix.io *.wistia.com *.hsforms.net *.hsforms.com embedwistia-a.akamaihd.net + matomo.anywhere.gooddata.com; media-src ''self'' blob: data: *.wistia.com + *.wistia.net embedwistia-a.akamaihd.net' + DATE: *id001 + Expires: + - '0' + GoodData-Deployment: + - aio + Permission-Policy: + - geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera + 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'none'; payment + 'none'; + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - nginx + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-GDC-TRACE-ID: *id001 + X-XSS-Protection: + - '0' + body: + string: '' diff --git a/gooddata-sdk/tests/catalog/test_catalog_organization.py b/gooddata-sdk/tests/catalog/test_catalog_organization.py index e142c4c4e..b69d18ed5 100644 --- a/gooddata-sdk/tests/catalog/test_catalog_organization.py +++ b/gooddata-sdk/tests/catalog/test_catalog_organization.py @@ -8,6 +8,7 @@ CatalogCspDirective, CatalogDeclarativeNotificationChannel, CatalogJwk, + CatalogLlmEndpoint, CatalogOrganization, CatalogOrganizationSetting, CatalogRsaSpecification, @@ -376,6 +377,234 @@ def test_layout_notification_channels(test_config): assert len(ncs) == 0 +@gd_vcr.use_cassette(str(_fixtures_dir / "get_llm_endpoint.yaml")) +def test_get_llm_endpoint(test_config): + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + + try: + # Create test endpoint first + test_id = "endpoint1" + test_title = "Test Endpoint" + test_token = "secret-token" + + sdk.catalog_organization.create_llm_endpoint(id=test_id, title=test_title, token=test_token) + + # Get and verify the endpoint + retrieved_endpoint = sdk.catalog_organization.get_llm_endpoint(test_id) + assert isinstance(retrieved_endpoint, CatalogLlmEndpoint) + assert retrieved_endpoint.id == test_id + assert retrieved_endpoint.attributes.title == test_title + assert not retrieved_endpoint.attributes.token # Token not returned for security + + finally: + # Clean up + sdk.catalog_organization.delete_llm_endpoint(test_id) + + +@gd_vcr.use_cassette(str(_fixtures_dir / "list_llm_endpoints.yaml")) +def test_list_llm_endpoints(test_config): + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + + try: + # Create test endpoints first + test_id1 = "endpoint1" + test_title1 = "Test Endpoint 1" + test_token1 = "secret-token-1" + + test_id2 = "endpoint2" + test_title2 = "Test Endpoint 2" + test_token2 = "secret-token-2" + + sdk.catalog_organization.create_llm_endpoint(id=test_id1, title=test_title1, token=test_token1) + + sdk.catalog_organization.create_llm_endpoint(id=test_id2, title=test_title2, token=test_token2) + + # Get and verify the endpoints list + endpoints = sdk.catalog_organization.list_llm_endpoints() + assert isinstance(endpoints, list) + assert len(endpoints) == 2 + assert all(isinstance(endpoint, CatalogLlmEndpoint) for endpoint in endpoints) + assert {endpoint.id for endpoint in endpoints} == {test_id1, test_id2} + assert {endpoint.attributes.title for endpoint in endpoints} == {test_title1, test_title2} + + # Test with optional parameters + filtered_endpoints = sdk.catalog_organization.list_llm_endpoints(filter="title=='Test Endpoint 1'", size=1) + assert isinstance(filtered_endpoints, list) + assert len(filtered_endpoints) == 1 + assert filtered_endpoints[0].id == test_id1 + assert filtered_endpoints[0].attributes.title == test_title1 + + finally: + # Clean up + sdk.catalog_organization.delete_llm_endpoint(test_id1) + sdk.catalog_organization.delete_llm_endpoint(test_id2) + + +@gd_vcr.use_cassette(str(_fixtures_dir / "create_llm_endpoint.yaml")) +def test_create_llm_endpoint(test_config): + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + + try: + # Test minimal required parameters + minimal_id = "endpoint1" + minimal_title = "Test Endpoint" + minimal_token = "secret-token" + + llm_endpoint_1 = sdk.catalog_organization.create_llm_endpoint( + id=minimal_id, title=minimal_title, token=minimal_token + ) + + assert isinstance(llm_endpoint_1, CatalogLlmEndpoint) + assert llm_endpoint_1.id == minimal_id + assert llm_endpoint_1.attributes.title == minimal_title + # Token is not returned in the API response for security reasons + assert not llm_endpoint_1.attributes.token + + # Test with all optional parameters + full_id = "endpoint2" + full_title = "Test Endpoint 2" + full_token = "secret-token-2" + full_description = "Test Description" + full_provider = "OPENAI" + full_base_url = "https://api.example.com" + full_llm_org = "org1" + full_llm_model = "gpt-4" + full_workspace_ids = ["workspace1", "workspace2"] + + llm_endpoint_2 = sdk.catalog_organization.create_llm_endpoint( + id=full_id, + title=full_title, + token=full_token, + description=full_description, + provider=full_provider, + base_url=full_base_url, + llm_organization=full_llm_org, + llm_model=full_llm_model, + workspace_ids=full_workspace_ids, + ) + assert isinstance(llm_endpoint_2, CatalogLlmEndpoint) + assert llm_endpoint_2.id == full_id + assert llm_endpoint_2.attributes.title == full_title + # Token is not returned in the API response for security reasons + assert not llm_endpoint_2.attributes.token + # Description is not returned in the API response. TODO: Check if this is correct. + # assert llm_endpoint_2.attributes.description == full_description + assert llm_endpoint_2.attributes.provider == full_provider + assert llm_endpoint_2.attributes.base_url == full_base_url + assert llm_endpoint_2.attributes.llm_organization == full_llm_org + assert llm_endpoint_2.attributes.llm_model == full_llm_model + assert llm_endpoint_2.attributes.workspace_ids == full_workspace_ids + finally: + # Cleanup + sdk.catalog_organization.delete_llm_endpoint(minimal_id) + sdk.catalog_organization.delete_llm_endpoint(full_id) + + +@gd_vcr.use_cassette(str(_fixtures_dir / "update_llm_endpoint.yaml")) +def test_update_llm_endpoint(test_config): + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + + initial_id = "endpoint1" + initial_title = "Initial Title" + initial_token = "initial-token" + + try: + # Create initial endpoint + sdk.catalog_organization.create_llm_endpoint(id=initial_id, title=initial_title, token=initial_token) + + # Test with minimal update + minimal_title = "Updated Title" + + llm_endpoint_1 = sdk.catalog_organization.update_llm_endpoint(id=initial_id, title=minimal_title) + + assert isinstance(llm_endpoint_1, CatalogLlmEndpoint) + assert llm_endpoint_1.id == initial_id + assert llm_endpoint_1.attributes.title == minimal_title + # Token is not returned in the API response for security reasons + assert not llm_endpoint_1.attributes.token + + # Test with all optional parameters + full_title = "Updated Title 2" + full_token = "new-token" + full_description = "Updated Description" + full_provider = "OPENAI" + full_base_url = "https://api.updated.com" + full_llm_org = "org2" + full_llm_model = "gpt-3.5" + full_workspace_ids = ["workspace3"] + + llm_endpoint_2 = sdk.catalog_organization.update_llm_endpoint( + id=initial_id, + title=full_title, + token=full_token, + description=full_description, + provider=full_provider, + base_url=full_base_url, + llm_organization=full_llm_org, + llm_model=full_llm_model, + workspace_ids=full_workspace_ids, + ) + + assert isinstance(llm_endpoint_2, CatalogLlmEndpoint) + assert llm_endpoint_2.id == initial_id + assert llm_endpoint_2.attributes.title == full_title + # Token is not returned in the API response for security reasons + assert not llm_endpoint_2.attributes.token + # Description is not returned in the API response. TODO: Check if this is correct. + # assert llm_endpoint_2.attributes.description == full_description + assert llm_endpoint_2.attributes.provider == full_provider + assert llm_endpoint_2.attributes.base_url == full_base_url + assert llm_endpoint_2.attributes.llm_organization == full_llm_org + assert llm_endpoint_2.attributes.llm_model == full_llm_model + assert llm_endpoint_2.attributes.workspace_ids == full_workspace_ids + + # Test that attributes are preserved when not provided + new_title = "New Title" + llm_endpoint_3 = sdk.catalog_organization.update_llm_endpoint(id=initial_id, title=new_title) + + assert isinstance(llm_endpoint_3, CatalogLlmEndpoint) + assert llm_endpoint_3.id == initial_id + assert llm_endpoint_3.attributes.title == new_title + # Token is not returned in the API response for security reasons + assert not llm_endpoint_3.attributes.token + # Verify other fields are preserved + # Description is not returned in the API response. TODO: Check if this is correct. + # assert llm_endpoint_3.attributes.description == full_description + assert llm_endpoint_3.attributes.provider == full_provider + assert llm_endpoint_3.attributes.base_url == full_base_url + assert llm_endpoint_3.attributes.llm_organization == full_llm_org + assert llm_endpoint_3.attributes.llm_model == full_llm_model + assert llm_endpoint_3.attributes.workspace_ids == full_workspace_ids + finally: + # Cleanup + sdk.catalog_organization.delete_llm_endpoint(initial_id) + + +@gd_vcr.use_cassette(str(_fixtures_dir / "delete_llm_endpoint.yaml")) +def test_delete_llm_endpoint(test_config): + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + + try: + # Create endpoint to delete + sdk.catalog_organization.create_llm_endpoint(id="endpoint1", title="Test Endpoint", token="secret-token") + + # Delete endpoint + sdk.catalog_organization.delete_llm_endpoint("endpoint1") + + # Verify deletion + try: + sdk.catalog_organization.get_llm_endpoint("endpoint1") + assert False, "Endpoint should not exist" + except NotFoundException: + pass + finally: + # Ensure cleanup + try: + sdk.catalog_organization.delete_llm_endpoint("endpoint1") + except NotFoundException: + pass + + # # The following tests are commented out as they require the organization to have the FEDERATED_IDENTITY_MANAGEMENT # entitlement enabled which cannot be done via SDK and must be done by GoodData support. diff --git a/gooddata-sdk/tests/compute/fixtures/ai_search.yaml b/gooddata-sdk/tests/compute/fixtures/ai_search.yaml new file mode 100644 index 000000000..3a10b60f7 --- /dev/null +++ b/gooddata-sdk/tests/compute/fixtures/ai_search.yaml @@ -0,0 +1,2114 @@ +# (C) 2025 GoodData Corporation +version: 1 +interactions: + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/workspaces/demo_testing?include=workspaces + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - max-age=5, private + Content-Length: + - '172' + Content-Type: + - application/problem+json + DATE: &id001 + - PLACEHOLDER + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + detail: The requested endpoint does not exist or you do not have permission + to access it. + status: 404 + title: Not Found + traceId: b15e1fd1ba18bb9d20fdc2567f8ac192 + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/workspaces/demo_testing?include=workspaces + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - max-age=5, private + Content-Length: + - '172' + Content-Type: + - application/problem+json + DATE: *id001 + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + detail: The requested endpoint does not exist or you do not have permission + to access it. + status: 404 + title: Not Found + traceId: 5dd5e19f7e2edb03505f7f0eb731516f + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/workspaces + body: + data: + id: demo_testing + type: workspace + attributes: + name: demo_testing + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Length: + - '167' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + data: + id: demo_testing + type: workspace + attributes: + name: demo_testing + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_testing + - request: + method: PUT + uri: http://localhost:3000/api/v1/layout/workspaces/demo_testing/logicalModel + body: + ldm: + datasets: + - grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + target: + id: campaign_id + type: attribute + dataType: INT + title: Campaign channels + description: Campaign channels + attributes: + - id: campaign_channel_id + labels: [] + sourceColumn: campaign_channel_id + title: Campaign channel id + sourceColumnDataType: STRING + description: Campaign channel id + tags: + - Campaign channels + - id: campaign_channels.category + labels: [] + sourceColumn: category + title: Category + sourceColumnDataType: STRING + description: Category + tags: + - Campaign channels + - id: type + labels: [] + sourceColumn: type + title: Type + sourceColumnDataType: STRING + description: Type + tags: + - Campaign channels + facts: + - id: budget + sourceColumn: budget + title: Budget + sourceColumnDataType: NUMERIC + description: Budget + tags: + - Campaign channels + - id: spend + sourceColumn: spend + title: Spend + sourceColumnDataType: NUMERIC + description: Spend + tags: + - Campaign channels + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: campaign_channels + type: dataSource + path: + - demo_6d9051d9069a8468 + - campaign_channels + tags: + - Campaign channels + - grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + title: Campaigns + description: Campaigns + attributes: + - id: campaign_id + labels: [] + sourceColumn: campaign_id + title: Campaign id + sourceColumnDataType: INT + description: Campaign id + tags: + - Campaigns + - id: campaign_name + labels: [] + sourceColumn: campaign_name + title: Campaign name + sourceColumnDataType: STRING + description: Campaign name + tags: + - Campaigns + facts: [] + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: campaigns + type: dataSource + path: + - demo_6d9051d9069a8468 + - campaigns + tags: + - Campaigns + - grain: + - id: customer_id + type: attribute + id: customers + references: [] + title: Customers + description: Customers + attributes: + - id: customer_id + labels: [] + sourceColumn: customer_id + title: Customer id + sourceColumnDataType: INT + description: Customer id + tags: + - Customers + - id: customer_name + labels: [] + sourceColumn: customer_name + title: Customer name + sourceColumnDataType: STRING + description: Customer name + tags: + - Customers + - id: region + labels: [] + sourceColumn: region + title: Region + sourceColumnDataType: STRING + description: Region + tags: + - Customers + - id: state + labels: + - id: geo__state__location + sourceColumn: geo__state__location + title: Location + sourceColumnDataType: STRING + description: Location + tags: + - Customers + sourceColumn: state + title: State + sourceColumnDataType: STRING + description: State + tags: + - Customers + facts: [] + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: customers + type: dataSource + path: + - demo_6d9051d9069a8468 + - customers + tags: + - Customers + - grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + target: + id: campaign_id + type: attribute + dataType: INT + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + target: + id: customer_id + type: attribute + dataType: INT + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + target: + id: date + type: date + dataType: DATE + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + target: + id: product_id + type: attribute + dataType: INT + title: Order lines + description: Order lines + attributes: + - id: order_id + labels: [] + sourceColumn: order_id + title: Order id + sourceColumnDataType: STRING + description: Order id + tags: + - Order lines + - id: order_line_id + labels: [] + sourceColumn: order_line_id + title: Order line id + sourceColumnDataType: STRING + description: Order line id + tags: + - Order lines + - id: order_status + labels: [] + sourceColumn: order_status + title: Order status + sourceColumnDataType: STRING + description: Order status + tags: + - Order lines + facts: + - id: price + sourceColumn: price + title: Price + sourceColumnDataType: NUMERIC + description: Price + tags: + - Order lines + - id: quantity + sourceColumn: quantity + title: Quantity + sourceColumnDataType: NUMERIC + description: Quantity + tags: + - Order lines + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: order_lines + type: dataSource + path: + - demo_6d9051d9069a8468 + - order_lines + tags: + - Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + - grain: + - id: product_id + type: attribute + id: products + references: [] + title: Products + description: Products + attributes: + - id: product_id + labels: [] + sourceColumn: product_id + title: Product id + sourceColumnDataType: INT + description: Product id + tags: + - Products + - id: product_name + labels: [] + sourceColumn: product_name + title: Product name + sourceColumnDataType: STRING + description: Product name + tags: + - Products + - id: products.category + labels: [] + sourceColumn: category + title: Category + sourceColumnDataType: STRING + description: Category + tags: + - Products + facts: [] + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: products + type: dataSource + path: + - demo_6d9051d9069a8468 + - products + tags: + - Products + dateInstances: + - granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + title: Date + description: '' + tags: + - Date + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: '' + - request: + method: PUT + uri: http://localhost:3000/api/v1/layout/workspaces/demo_testing/analyticsModel + body: + analytics: + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: 4717b786-2c2e-4596-adb5-4f8b0ab0e19a + type: filterContext + layout: + sections: + - header: + description: All in one description + title: All in one title + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_customers + type: visualizationObject + localIdentifier: 2c7400ac-5f63-46f8-aa12-a2debe13fd14 + properties: {} + title: Top 10 Customers + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_by_product + type: visualizationObject + localIdentifier: a50daab7-fb78-45eb-a2b4-d5cc8cbd89e9 + properties: {} + title: Revenue by Product + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_by_category_trend + type: visualizationObject + localIdentifier: efccc783-5896-4eb6-890f-2e51ece3f159 + properties: {} + title: Revenue by Category Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + localIdentifier: d738d85f-e935-4e2c-b8b4-a8b456f55079 + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + localIdentifier: 8c194c85-bad6-42da-b4e3-08d270278316 + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percentage_of_customers_by_region + type: visualizationObject + localIdentifier: 2c3307b2-581f-4bab-9252-6b5279565b24 + properties: {} + title: Percentage of Customers by Region + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + localIdentifier: 87505bb0-d954-4add-811d-f4e75e431660 + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + localIdentifier: 0cb01f6a-6ea6-4c22-bb12-ded00a9eac66 + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + localIdentifier: 2213d6e4-6df7-458e-806d-f02bae5ce66a + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + id: b2f2d436-9831-4fe0-81df-8c59fd33242b + title: All visualizations 1 with custom filter + description: '' + analyticalDashboardExtensions: [] + attributeHierarchies: [] + dashboardPlugins: [] + filterContexts: + - content: + filters: + - attributeFilter: + attributeElements: + uris: + - Biolid + - ChalkTalk + - Compglass + - Elentrix + displayForm: + identifier: + id: product_name + type: label + filterElementsBy: [] + localIdentifier: 6b94bbb585d44c79967867719e524fae + negativeSelection: false + selectionMode: multi + version: '2' + id: 4717b786-2c2e-4596-adb5-4f8b0ab0e19a + title: filterContext + description: '' + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.year + to: '0' + type: relative + version: '2' + id: 9f2b1f37-befa-450e-a6cc-dc576845c412 + title: filterContext + description: '' + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + id: amount_of_active_customers + title: '# of Active Customers' + description: '' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + id: amount_of_orders + title: '# of Orders' + description: '' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT {metric/revenue} + BY {attribute/customer_id}) > 10000 ' + id: amount_of_top_customers + title: '# of Top Customers' + description: '' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("null", "Returned", "Canceled")) + id: amount_of_valid_orders + title: '# of Valid Orders' + description: '' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + id: campaign_spend + title: Campaign Spend + description: '' + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + id: order_amount + title: Order Amount + description: '' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + id: percent_revenue + title: '% Revenue' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + description: '' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY {attribute/products.category}, + ALL OTHER) + id: percent_revenue_in_category + title: '% Revenue in Category' + description: '' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY ALL {attribute/product_id}) + id: percent_revenue_per_product + title: '% Revenue per Product' + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("null", "Returned", "Canceled")) + id: revenue + title: Revenue + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Clothing") + id: revenue-clothing + title: Revenue (Clothing) + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ( + "Electronics") + id: revenue-electronic + title: Revenue (Electronic) + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Home") + id: revenue-home + title: Revenue (Home) + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Outdoor") + id: revenue-outdoor + title: Revenue (Outdoor) + description: '' + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + id: revenue_per_customer + title: Revenue per Customer + description: '' + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + id: revenue_top_10 + title: Revenue / Top 10 + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + id: revenue_top_10_percent + title: Revenue / Top 10% + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + id: total_revenue + title: Total Revenue + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + id: total_revenue-no_filters + title: Total Revenue (No Filters) + description: '' + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + id: campaign_spend + title: Campaign Spend + description: '' + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + id: customers_trend + title: Customers Trend + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + sortItems: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + id: product_breakdown + title: Product Breakdown + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + id: product_categories_pie_chart + title: Product Categories Pie Chart + description: '' + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: label + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + description: '' + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + id: product_saleability + title: Product Saleability + description: '' + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + sortItems: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + id: revenue_by_category_trend + title: Revenue by Category Trend + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + id: revenue_by_product + title: Revenue by Product + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + id: revenue_trend + title: Revenue Trend + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + id: top_10_customers + title: Top 10 Customers + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + id: top_10_products + title: Top 10 Products + description: '' + exportDefinitions: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: '' + - request: + method: POST + uri: http://localhost:3000/api/v1/actions/workspaces/demo_testing/ai/search + body: + question: What is the total revenue? + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Length: + - '1408' + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + results: + - id: budget + type: fact + workspaceId: demo_testing + title: Budget + description: Budget + tags: + - Campaign channels + score: 0.5680269 + scoreTitle: 0.0 + scoreDescriptor: 0.0 + scoreExactMatch: 1 + - id: quantity + type: fact + workspaceId: demo_testing + title: Quantity + description: Quantity + tags: + - Order lines + score: 0.62020504 + scoreTitle: 0.0 + scoreDescriptor: 0.0 + scoreExactMatch: 1 + - id: price + type: fact + workspaceId: demo_testing + title: Price + description: Price + tags: + - Order lines + score: 0.6080591 + scoreTitle: 0.0 + scoreDescriptor: 0.0 + scoreExactMatch: 1 + relationships: + - sourceWorkspaceId: demo_testing + sourceObjectId: order_lines + sourceObjectType: dataset + sourceObjectTitle: Order lines + targetWorkspaceId: demo_testing + targetObjectId: quantity + targetObjectType: fact + targetObjectTitle: Quantity + - sourceWorkspaceId: demo_testing + sourceObjectId: order_lines + sourceObjectType: dataset + sourceObjectTitle: Order lines + targetWorkspaceId: demo_testing + targetObjectId: price + targetObjectType: fact + targetObjectTitle: Price + - sourceWorkspaceId: demo_testing + sourceObjectId: campaign_channels + sourceObjectType: dataset + sourceObjectTitle: Campaign channels + targetWorkspaceId: demo_testing + targetObjectId: budget + targetObjectType: fact + targetObjectTitle: Budget + reasoning: '' + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/workspaces?include=workspaces&page=0&size=500 + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Length: + - '1274' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + data: + - id: demo + type: workspace + attributes: + name: Demo + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo + - id: demo_testing + type: workspace + attributes: + name: demo_testing + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_testing + - id: demo_west + type: workspace + attributes: + name: Demo West + relationships: + parent: + data: + id: demo + type: workspace + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_west + - id: demo_west_california + type: workspace + attributes: + name: Demo West California + relationships: + parent: + data: + id: demo_west + type: workspace + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_west_california + included: + - id: demo + type: workspace + attributes: + name: Demo + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo + - id: demo_west + type: workspace + attributes: + name: Demo West + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_west + links: + self: http://localhost:3000/api/v1/entities/workspaces?include=workspaces&page=0&size=500 + next: http://localhost:3000/api/v1/entities/workspaces?include=workspaces&page=1&size=500 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/workspaces/demo_testing + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: '' diff --git a/gooddata-sdk/tests/compute/fixtures/ai_search_full_params.yaml b/gooddata-sdk/tests/compute/fixtures/ai_search_full_params.yaml new file mode 100644 index 000000000..f31ee87ba --- /dev/null +++ b/gooddata-sdk/tests/compute/fixtures/ai_search_full_params.yaml @@ -0,0 +1,2103 @@ +# (C) 2025 GoodData Corporation +version: 1 +interactions: + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/workspaces/demo_testing?include=workspaces + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - max-age=5, private + Content-Length: + - '172' + Content-Type: + - application/problem+json + DATE: &id001 + - PLACEHOLDER + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + detail: The requested endpoint does not exist or you do not have permission + to access it. + status: 404 + title: Not Found + traceId: d1aef9a66bbe03411419522809defe24 + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/workspaces/demo_testing?include=workspaces + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - max-age=5, private + Content-Length: + - '172' + Content-Type: + - application/problem+json + DATE: *id001 + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + detail: The requested endpoint does not exist or you do not have permission + to access it. + status: 404 + title: Not Found + traceId: 6133ef2c558b5caa3aa33ef2f40cc75f + - request: + method: POST + uri: http://localhost:3000/api/v1/entities/workspaces + body: + data: + id: demo_testing + type: workspace + attributes: + name: demo_testing + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/vnd.gooddata.api+json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 201 + message: Created + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Length: + - '167' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + data: + id: demo_testing + type: workspace + attributes: + name: demo_testing + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_testing + - request: + method: PUT + uri: http://localhost:3000/api/v1/layout/workspaces/demo_testing/logicalModel + body: + ldm: + datasets: + - grain: + - id: campaign_channel_id + type: attribute + id: campaign_channels + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + target: + id: campaign_id + type: attribute + dataType: INT + title: Campaign channels + description: Campaign channels + attributes: + - id: campaign_channel_id + labels: [] + sourceColumn: campaign_channel_id + title: Campaign channel id + sourceColumnDataType: STRING + description: Campaign channel id + tags: + - Campaign channels + - id: campaign_channels.category + labels: [] + sourceColumn: category + title: Category + sourceColumnDataType: STRING + description: Category + tags: + - Campaign channels + - id: type + labels: [] + sourceColumn: type + title: Type + sourceColumnDataType: STRING + description: Type + tags: + - Campaign channels + facts: + - id: budget + sourceColumn: budget + title: Budget + sourceColumnDataType: NUMERIC + description: Budget + tags: + - Campaign channels + - id: spend + sourceColumn: spend + title: Spend + sourceColumnDataType: NUMERIC + description: Spend + tags: + - Campaign channels + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: campaign_channels + type: dataSource + path: + - demo_6d9051d9069a8468 + - campaign_channels + tags: + - Campaign channels + - grain: + - id: campaign_id + type: attribute + id: campaigns + references: [] + title: Campaigns + description: Campaigns + attributes: + - id: campaign_id + labels: [] + sourceColumn: campaign_id + title: Campaign id + sourceColumnDataType: INT + description: Campaign id + tags: + - Campaigns + - id: campaign_name + labels: [] + sourceColumn: campaign_name + title: Campaign name + sourceColumnDataType: STRING + description: Campaign name + tags: + - Campaigns + facts: [] + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: campaigns + type: dataSource + path: + - demo_6d9051d9069a8468 + - campaigns + tags: + - Campaigns + - grain: + - id: customer_id + type: attribute + id: customers + references: [] + title: Customers + description: Customers + attributes: + - id: customer_id + labels: [] + sourceColumn: customer_id + title: Customer id + sourceColumnDataType: INT + description: Customer id + tags: + - Customers + - id: customer_name + labels: [] + sourceColumn: customer_name + title: Customer name + sourceColumnDataType: STRING + description: Customer name + tags: + - Customers + - id: region + labels: [] + sourceColumn: region + title: Region + sourceColumnDataType: STRING + description: Region + tags: + - Customers + - id: state + labels: + - id: geo__state__location + sourceColumn: geo__state__location + title: Location + sourceColumnDataType: STRING + description: Location + tags: + - Customers + sourceColumn: state + title: State + sourceColumnDataType: STRING + description: State + tags: + - Customers + facts: [] + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: customers + type: dataSource + path: + - demo_6d9051d9069a8468 + - customers + tags: + - Customers + - grain: + - id: order_line_id + type: attribute + id: order_lines + references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + target: + id: campaign_id + type: attribute + dataType: INT + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + target: + id: customer_id + type: attribute + dataType: INT + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + target: + id: date + type: date + dataType: DATE + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + target: + id: product_id + type: attribute + dataType: INT + title: Order lines + description: Order lines + attributes: + - id: order_id + labels: [] + sourceColumn: order_id + title: Order id + sourceColumnDataType: STRING + description: Order id + tags: + - Order lines + - id: order_line_id + labels: [] + sourceColumn: order_line_id + title: Order line id + sourceColumnDataType: STRING + description: Order line id + tags: + - Order lines + - id: order_status + labels: [] + sourceColumn: order_status + title: Order status + sourceColumnDataType: STRING + description: Order status + tags: + - Order lines + facts: + - id: price + sourceColumn: price + title: Price + sourceColumnDataType: NUMERIC + description: Price + tags: + - Order lines + - id: quantity + sourceColumn: quantity + title: Quantity + sourceColumnDataType: NUMERIC + description: Quantity + tags: + - Order lines + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: order_lines + type: dataSource + path: + - demo_6d9051d9069a8468 + - order_lines + tags: + - Order lines + workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state + - grain: + - id: product_id + type: attribute + id: products + references: [] + title: Products + description: Products + attributes: + - id: product_id + labels: [] + sourceColumn: product_id + title: Product id + sourceColumnDataType: INT + description: Product id + tags: + - Products + - id: product_name + labels: [] + sourceColumn: product_name + title: Product name + sourceColumnDataType: STRING + description: Product name + tags: + - Products + - id: products.category + labels: [] + sourceColumn: category + title: Category + sourceColumnDataType: STRING + description: Category + tags: + - Products + facts: [] + dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: products + type: dataSource + path: + - demo_6d9051d9069a8468 + - products + tags: + - Products + dateInstances: + - granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR + granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' + id: date + title: Date + description: '' + tags: + - Date + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: '' + - request: + method: PUT + uri: http://localhost:3000/api/v1/layout/workspaces/demo_testing/analyticsModel + body: + analytics: + analyticalDashboards: + - content: + filterContextRef: + identifier: + id: 4717b786-2c2e-4596-adb5-4f8b0ab0e19a + type: filterContext + layout: + sections: + - header: + description: All in one description + title: All in one title + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_customers + type: visualizationObject + localIdentifier: 2c7400ac-5f63-46f8-aa12-a2debe13fd14 + properties: {} + title: Top 10 Customers + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_by_product + type: visualizationObject + localIdentifier: a50daab7-fb78-45eb-a2b4-d5cc8cbd89e9 + properties: {} + title: Revenue by Product + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_by_category_trend + type: visualizationObject + localIdentifier: efccc783-5896-4eb6-890f-2e51ece3f159 + properties: {} + title: Revenue by Category Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + localIdentifier: d738d85f-e935-4e2c-b8b4-a8b456f55079 + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + localIdentifier: 8c194c85-bad6-42da-b4e3-08d270278316 + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percentage_of_customers_by_region + type: visualizationObject + localIdentifier: 2c3307b2-581f-4bab-9252-6b5279565b24 + properties: {} + title: Percentage of Customers by Region + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + localIdentifier: 87505bb0-d954-4add-811d-f4e75e431660 + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + localIdentifier: 0cb01f6a-6ea6-4c22-bb12-ded00a9eac66 + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + localIdentifier: 2213d6e4-6df7-458e-806d-f02bae5ce66a + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' + id: b2f2d436-9831-4fe0-81df-8c59fd33242b + title: All visualizations 1 with custom filter + description: '' + analyticalDashboardExtensions: [] + attributeHierarchies: [] + dashboardPlugins: [] + filterContexts: + - content: + filters: + - attributeFilter: + attributeElements: + uris: + - Biolid + - ChalkTalk + - Compglass + - Elentrix + displayForm: + identifier: + id: product_name + type: label + filterElementsBy: [] + localIdentifier: 6b94bbb585d44c79967867719e524fae + negativeSelection: false + selectionMode: multi + version: '2' + id: 4717b786-2c2e-4596-adb5-4f8b0ab0e19a + title: filterContext + description: '' + - content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.year + to: '0' + type: relative + version: '2' + id: 9f2b1f37-befa-450e-a6cc-dc576845c412 + title: filterContext + description: '' + metrics: + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) + id: amount_of_active_customers + title: '# of Active Customers' + description: '' + - content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) + id: amount_of_orders + title: '# of Orders' + description: '' + - content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT {metric/revenue} + BY {attribute/customer_id}) > 10000 ' + id: amount_of_top_customers + title: '# of Top Customers' + description: '' + - content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} + IN ("null", "Returned", "Canceled")) + id: amount_of_valid_orders + title: '# of Valid Orders' + description: '' + - content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) + id: campaign_spend + title: Campaign Spend + description: '' + - content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) + id: order_amount + title: Order Amount + description: '' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} + id: percent_revenue + title: '% Revenue' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_customers + title: '% Revenue from Top 10 Customers' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_percent_customers + title: '% Revenue from Top 10% Customers' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_percent_products + title: '% Revenue from Top 10% Products' + description: '' + - content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" + id: percent_revenue_from_top_10_products + title: '% Revenue from Top 10 Products' + description: '' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY {attribute/products.category}, + ALL OTHER) + id: percent_revenue_in_category + title: '% Revenue in Category' + description: '' + - content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY ALL {attribute/product_id}) + id: percent_revenue_per_product + title: '% Revenue per Product' + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} + IN ("null", "Returned", "Canceled")) + id: revenue + title: Revenue + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Clothing") + id: revenue-clothing + title: Revenue (Clothing) + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ( + "Electronics") + id: revenue-electronic + title: Revenue (Electronic) + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Home") + id: revenue-home + title: Revenue (Home) + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Outdoor") + id: revenue-outdoor + title: Revenue (Outdoor) + description: '' + - content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) + id: revenue_per_customer + title: Revenue per Customer + description: '' + - content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} + id: revenue_per_dollar_spent + title: Revenue per Dollar Spent + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) + id: revenue_top_10 + title: Revenue / Top 10 + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) + id: revenue_top_10_percent + title: Revenue / Top 10% + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER + id: total_revenue + title: Total Revenue + description: '' + - content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER + id: total_revenue-no_filters + title: Total Revenue (No Filters) + description: '' + visualizationObjects: + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + id: campaign_spend + title: Campaign Spend + description: '' + - content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + id: customers_trend + title: Customers Trend + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + sortItems: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table + id: percent_revenue_per_product_by_customer_and_category + title: '% Revenue per Product by Customer and Category' + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area + id: percentage_of_customers_by_region + title: Percentage of Customers by Region + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap + id: product_breakdown + title: Product Breakdown + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut + id: product_categories_pie_chart + title: Product Categories Pie Chart + description: '' + - content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: label + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column + id: product_revenue_comparison-over_previous_period + title: Product Revenue Comparison (over previous period) + description: '' + - content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter + id: product_saleability + title: Product Saleability + description: '' + - content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + sortItems: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table + id: revenue_and_quantity_by_product_and_category + title: Revenue and Quantity by Product and Category + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line + id: revenue_by_category_trend + title: Revenue by Category Trend + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar + id: revenue_by_product + title: Revenue by Product + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter + id: revenue_per_usd_vs_spend_by_campaign + title: Revenue per $ vs Spend by Campaign + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 + id: revenue_trend + title: Revenue Trend + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + id: top_10_customers + title: Top 10 Customers + description: '' + - content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar + id: top_10_products + title: Top 10 Products + description: '' + exportDefinitions: [] + headers: + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: '' + - request: + method: POST + uri: http://localhost:3000/api/v1/actions/workspaces/demo_testing/ai/search + body: + question: What is the total revenue? + deepSearch: true + limit: 2 + objectTypes: + - metric + - attribute + - fact + relevantScoreThreshold: 0.5 + titleToDescriptorRatio: 0.7 + headers: + Accept: + - application/json + Accept-Encoding: + - br, gzip, deflate + Content-Type: + - application/json + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Length: + - '944' + Content-Type: + - application/json + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + results: + - id: quantity + type: fact + workspaceId: demo_testing + title: Quantity + description: Quantity + tags: + - Order lines + score: 0.62020504 + scoreTitle: 0.0 + scoreDescriptor: 0.0 + scoreExactMatch: 1 + - id: price + type: fact + workspaceId: demo_testing + title: Price + description: Price + tags: + - Order lines + score: 0.6080591 + scoreTitle: 0.0 + scoreDescriptor: 0.0 + scoreExactMatch: 1 + relationships: + - sourceWorkspaceId: demo_testing + sourceObjectId: order_lines + sourceObjectType: dataset + sourceObjectTitle: Order lines + targetWorkspaceId: demo_testing + targetObjectId: quantity + targetObjectType: fact + targetObjectTitle: Quantity + - sourceWorkspaceId: demo_testing + sourceObjectId: order_lines + sourceObjectType: dataset + sourceObjectTitle: Order lines + targetWorkspaceId: demo_testing + targetObjectId: price + targetObjectType: fact + targetObjectTitle: Price + reasoning: '' + - request: + method: GET + uri: http://localhost:3000/api/v1/entities/workspaces?include=workspaces&page=0&size=500 + body: null + headers: + Accept: + - application/vnd.gooddata.api+json + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Length: + - '1274' + Content-Type: + - application/vnd.gooddata.api+json + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: + data: + - id: demo + type: workspace + attributes: + name: Demo + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo + - id: demo_testing + type: workspace + attributes: + name: demo_testing + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_testing + - id: demo_west + type: workspace + attributes: + name: Demo West + relationships: + parent: + data: + id: demo + type: workspace + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_west + - id: demo_west_california + type: workspace + attributes: + name: Demo West California + relationships: + parent: + data: + id: demo_west + type: workspace + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_west_california + included: + - id: demo + type: workspace + attributes: + name: Demo + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo + - id: demo_west + type: workspace + attributes: + name: Demo West + links: + self: http://localhost:3000/api/v1/entities/workspaces/demo_west + links: + self: http://localhost:3000/api/v1/entities/workspaces?include=workspaces&page=0&size=500 + next: http://localhost:3000/api/v1/entities/workspaces?include=workspaces&page=1&size=500 + - request: + method: DELETE + uri: http://localhost:3000/api/v1/entities/workspaces/demo_testing + body: null + headers: + Accept-Encoding: + - br, gzip, deflate + X-GDC-VALIDATE-RELATIONS: + - 'true' + X-Requested-With: + - XMLHttpRequest + response: + status: + code: 204 + message: No Content + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + DATE: *id001 + Expires: + - '0' + Featurepolicy: + - geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr + 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope + 'none'; speaker 'none'; vibrate 'none'; fullscreen 'none'; payment 'none'; + Pragma: + - no-cache + Referrer-Policy: + - same-origin + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-GDC-TRACE-ID: *id001 + X-Xss-Protection: + - 1; mode=block + body: + string: '' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/analytical_dashboards/b2f2d436-9831-4fe0-81df-8c59fd33242b.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/analytical_dashboards/b2f2d436-9831-4fe0-81df-8c59fd33242b.yaml new file mode 100644 index 000000000..ef4dfab69 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/analytical_dashboards/b2f2d436-9831-4fe0-81df-8c59fd33242b.yaml @@ -0,0 +1,194 @@ +# (C) 2025 GoodData Corporation +content: + filterContextRef: + identifier: + id: 4717b786-2c2e-4596-adb5-4f8b0ab0e19a + type: filterContext + layout: + sections: + - header: + description: All in one description + title: All in one title + items: + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: top_10_customers + type: visualizationObject + localIdentifier: 2c7400ac-5f63-46f8-aa12-a2debe13fd14 + properties: {} + title: Top 10 Customers + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_by_product + type: visualizationObject + localIdentifier: a50daab7-fb78-45eb-a2b4-d5cc8cbd89e9 + properties: {} + title: Revenue by Product + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: revenue_by_category_trend + type: visualizationObject + localIdentifier: efccc783-5896-4eb6-890f-2e51ece3f159 + properties: {} + title: Revenue by Category Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_saleability + type: visualizationObject + localIdentifier: d738d85f-e935-4e2c-b8b4-a8b456f55079 + properties: {} + title: Product Saleability + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: product_categories_pie_chart + type: visualizationObject + localIdentifier: 8c194c85-bad6-42da-b4e3-08d270278316 + properties: {} + title: Product Categories Pie Chart + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percentage_of_customers_by_region + type: visualizationObject + localIdentifier: 2c3307b2-581f-4bab-9252-6b5279565b24 + properties: {} + title: Percentage of Customers by Region + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: customers_trend + type: visualizationObject + localIdentifier: 87505bb0-d954-4add-811d-f4e75e431660 + properties: {} + title: Customers Trend + type: insight + - size: + xl: + gridWidth: 6 + type: IDashboardLayoutItem + widget: + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: campaign_spend + type: visualizationObject + localIdentifier: 0cb01f6a-6ea6-4c22-bb12-ded00a9eac66 + properties: {} + title: Campaign Spend + type: insight + - size: + xl: + gridWidth: 12 + type: IDashboardLayoutItem + widget: + dateDataSet: + identifier: + id: date + type: dataset + description: '' + drills: [] + ignoreDashboardFilters: [] + insight: + identifier: + id: percent_revenue_per_product_by_customer_and_category + type: visualizationObject + localIdentifier: 2213d6e4-6df7-458e-806d-f02bae5ce66a + properties: {} + title: '% Revenue per Product by Customer and Category' + type: insight + type: IDashboardLayoutSection + type: IDashboardLayout + version: '2' +description: '' +id: b2f2d436-9831-4fe0-81df-8c59fd33242b +title: All visualizations 1 with custom filter diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/4717b786-2c2e-4596-adb5-4f8b0ab0e19a.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/4717b786-2c2e-4596-adb5-4f8b0ab0e19a.yaml new file mode 100644 index 000000000..852c92031 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/4717b786-2c2e-4596-adb5-4f8b0ab0e19a.yaml @@ -0,0 +1,22 @@ +# (C) 2025 GoodData Corporation +content: + filters: + - attributeFilter: + attributeElements: + uris: + - Biolid + - ChalkTalk + - Compglass + - Elentrix + displayForm: + identifier: + id: product_name + type: label + filterElementsBy: [] + localIdentifier: 6b94bbb585d44c79967867719e524fae + negativeSelection: false + selectionMode: multi + version: '2' +description: '' +id: 4717b786-2c2e-4596-adb5-4f8b0ab0e19a +title: filterContext diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/9f2b1f37-befa-450e-a6cc-dc576845c412.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/9f2b1f37-befa-450e-a6cc-dc576845c412.yaml new file mode 100644 index 000000000..8ec1d3ebb --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/filter_contexts/9f2b1f37-befa-450e-a6cc-dc576845c412.yaml @@ -0,0 +1,12 @@ +# (C) 2025 GoodData Corporation +content: + filters: + - dateFilter: + from: '0' + granularity: GDC.time.year + to: '0' + type: relative + version: '2' +description: '' +id: 9f2b1f37-befa-450e-a6cc-dc576845c412 +title: filterContext diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_active_customers.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_active_customers.yaml new file mode 100644 index 000000000..1dfb3eff8 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_active_customers.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0' + maql: SELECT COUNT({attribute/customer_id},{attribute/order_line_id}) +description: '' +id: amount_of_active_customers +title: '# of Active Customers' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_orders.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_orders.yaml new file mode 100644 index 000000000..73bc6a977 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_orders.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0' + maql: SELECT COUNT({attribute/order_id}) +description: '' +id: amount_of_orders +title: '# of Orders' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_top_customers.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_top_customers.yaml new file mode 100644 index 000000000..bc2547333 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_top_customers.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0' + maql: 'SELECT {metric/amount_of_active_customers} WHERE (SELECT {metric/revenue} + BY {attribute/customer_id}) > 10000 ' +description: '' +id: amount_of_top_customers +title: '# of Top Customers' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_valid_orders.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_valid_orders.yaml new file mode 100644 index 000000000..35a719267 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/amount_of_valid_orders.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.00' + maql: SELECT {metric/amount_of_orders} WHERE NOT ({label/order_status} IN ("null", + "Returned", "Canceled")) +description: '' +id: amount_of_valid_orders +title: '# of Valid Orders' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/campaign_spend.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/campaign_spend.yaml new file mode 100644 index 000000000..93f99d910 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/campaign_spend.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT SUM({fact/spend}) +description: '' +id: campaign_spend +title: Campaign Spend diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/order_amount.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/order_amount.yaml new file mode 100644 index 000000000..ca0efae86 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/order_amount.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT SUM({fact/price}*{fact/quantity}) +description: '' +id: order_amount +title: Order Amount diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue.yaml new file mode 100644 index 000000000..c52541fa4 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / {metric/total_revenue} +description: '' +id: percent_revenue +title: '% Revenue' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_customers.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_customers.yaml new file mode 100644 index 000000000..13ac3c103 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_customers.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10} BY\ + \ {attribute/customer_id}) > 0)\n /\n {metric/revenue}" +description: '' +id: percent_revenue_from_top_10_customers +title: '% Revenue from Top 10 Customers' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_customers.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_customers.yaml new file mode 100644 index 000000000..514f4e13e --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_customers.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/customer_id}) > 0)\n /\n {metric/revenue}" +description: '' +id: percent_revenue_from_top_10_percent_customers +title: '% Revenue from Top 10% Customers' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_products.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_products.yaml new file mode 100644 index 000000000..962393d29 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_percent_products.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10_percent}\ + \ BY {attribute/product_id}) > 0)\n /\n {metric/revenue}" +description: '' +id: percent_revenue_from_top_10_percent_products +title: '% Revenue from Top 10% Products' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_products.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_products.yaml new file mode 100644 index 000000000..4f825ef41 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_from_top_10_products.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.0%' + maql: "SELECT\n (SELECT {metric/revenue} WHERE (SELECT {metric/revenue_top_10} BY\ + \ {attribute/product_id}) > 0)\n /\n {metric/revenue}" +description: '' +id: percent_revenue_from_top_10_products +title: '% Revenue from Top 10 Products' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_in_category.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_in_category.yaml new file mode 100644 index 000000000..491f870b0 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_in_category.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY {attribute/products.category}, + ALL OTHER) +description: '' +id: percent_revenue_in_category +title: '% Revenue in Category' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_per_product.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_per_product.yaml new file mode 100644 index 000000000..1d8d1e0fc --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/percent_revenue_per_product.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: '#,##0.0%' + maql: SELECT {metric/revenue} / (SELECT {metric/revenue} BY ALL {attribute/product_id}) +description: '' +id: percent_revenue_per_product +title: '% Revenue per Product' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-clothing.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-clothing.yaml new file mode 100644 index 000000000..ee50ebe45 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-clothing.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Clothing") +description: '' +id: revenue-clothing +title: Revenue (Clothing) diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-electronic.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-electronic.yaml new file mode 100644 index 000000000..bf706b4f0 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-electronic.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ( "Electronics") +description: '' +id: revenue-electronic +title: Revenue (Electronic) diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-home.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-home.yaml new file mode 100644 index 000000000..6521c722d --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-home.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Home") +description: '' +id: revenue-home +title: Revenue (Home) diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-outdoor.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-outdoor.yaml new file mode 100644 index 000000000..92af3b14a --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue-outdoor.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE {label/products.category} IN ("Outdoor") +description: '' +id: revenue-outdoor +title: Revenue (Outdoor) diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue.yaml new file mode 100644 index 000000000..278fc315d --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue.yaml @@ -0,0 +1,8 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/order_amount} WHERE NOT ({label/order_status} IN ("null", "Returned", + "Canceled")) +description: '' +id: revenue +title: Revenue diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_customer.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_customer.yaml new file mode 100644 index 000000000..6815dc309 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_customer.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0.0 + maql: SELECT AVG(SELECT {metric/revenue} BY {attribute/customer_id}) +description: '' +id: revenue_per_customer +title: Revenue per Customer diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_dollar_spent.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_dollar_spent.yaml new file mode 100644 index 000000000..01c0ac775 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_per_dollar_spent.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0.0 + maql: SELECT {metric/revenue} / {metric/campaign_spend} +description: '' +id: revenue_per_dollar_spent +title: Revenue per Dollar Spent diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10.yaml new file mode 100644 index 000000000..fd92065fe --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10) OF ({metric/revenue}) +description: '' +id: revenue_top_10 +title: Revenue / Top 10 diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10_percent.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10_percent.yaml new file mode 100644 index 000000000..ffae3797b --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/revenue_top_10_percent.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/revenue} WHERE TOP(10%) OF ({metric/revenue}) +description: '' +id: revenue_top_10_percent +title: Revenue / Top 10% diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue-no_filters.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue-no_filters.yaml new file mode 100644 index 000000000..7b29ce6b6 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue-no_filters.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/total_revenue} WITHOUT PARENT FILTER +description: '' +id: total_revenue-no_filters +title: Total Revenue (No Filters) diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue.yaml new file mode 100644 index 000000000..30d1cebf0 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/metrics/total_revenue.yaml @@ -0,0 +1,7 @@ +# (C) 2025 GoodData Corporation +content: + format: $#,##0 + maql: SELECT {metric/revenue} BY ALL OTHER +description: '' +id: total_revenue +title: Total Revenue diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/campaign_spend.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/campaign_spend.yaml new file mode 100644 index 000000000..e4bccc985 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/campaign_spend.yaml @@ -0,0 +1,62 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: d319bcb2d8c04442a684e3b3cd063381 + title: Campaign Spend + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_channels.category + type: label + localIdentifier: 291c085e7df8420db84117ca49f59c49 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: d9dd143d647d4d148405a60ec2cf59bc + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: type + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_channels.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap +description: '' +id: campaign_spend +title: Campaign Spend diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/customers_trend.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/customers_trend.yaml new file mode 100644 index 000000000..b74740893 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/customers_trend.yaml @@ -0,0 +1,74 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + alias: Active Customers + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 2ba0b87b59ca41a4b1530e81a5c1d081 + title: '# of Active Customers' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_customer + type: metric + localIdentifier: ec0606894b9f4897b7beaf1550608928 + title: Revenue per Customer + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 0de7d7f08af7480aa636857a26be72b6 + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + colorMapping: + - color: + type: guid + value: '20' + id: 2ba0b87b59ca41a4b1530e81a5c1d081 + - color: + type: guid + value: '4' + id: ec0606894b9f4897b7beaf1550608928 + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - ec0606894b9f4897b7beaf1550608928 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 +description: '' +id: customers_trend +title: Customers Trend diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percent_revenue_per_product_by_customer_and_category.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percent_revenue_per_product_by_customer_and_category.yaml new file mode 100644 index 000000000..ad33a7fca --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percent_revenue_per_product_by_customer_and_category.yaml @@ -0,0 +1,77 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_per_product + type: metric + localIdentifier: 08d8346c1ce7438994b251991c0fbf65 + title: '% Revenue per Product' + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: b2350c06688b4da9b3833ebcce65527f + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: 7a4045fd00ac44579f52406df679435f + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 6a003ffd14994237ba64c4a02c488429 + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 75ea396d0c8b48098e31dccf8b5801d3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + sortItems: + - attributeSortItem: + attributeIdentifier: 7a4045fd00ac44579f52406df679435f + direction: asc + version: '2' + visualizationUrl: local:table +description: '' +id: percent_revenue_per_product_by_customer_and_category +title: '% Revenue per Product by Customer and Category' diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percentage_of_customers_by_region.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percentage_of_customers_by_region.yaml new file mode 100644 index 000000000..6f57db4f0 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/percentage_of_customers_by_region.yaml @@ -0,0 +1,57 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_active_customers + type: metric + localIdentifier: 1a14cdc1293c46e89a2e25d3e741d235 + title: '# of Active Customers' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: c1feca1864244ec2ace7a9b9d7fda231 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: region + type: label + localIdentifier: 530cddbd7ca04d039e73462d81ed44d5 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: region + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + properties: + controls: + legend: + position: bottom + stackMeasuresToPercent: true + version: '2' + visualizationUrl: local:area +description: '' +id: percentage_of_customers_by_region +title: Percentage of Customers by Region diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_breakdown.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_breakdown.yaml new file mode 100644 index 000000000..214952fda --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_breakdown.yaml @@ -0,0 +1,55 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 590d332ef686468b8878ae41b23341c6 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: b166c71091864312a14c7ae8ff886ffe + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: e920a50e0bbb49788df0aac53634c1cd + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:treemap +description: '' +id: product_breakdown +title: Product Breakdown diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_categories_pie_chart.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_categories_pie_chart.yaml new file mode 100644 index 000000000..247c8983b --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_categories_pie_chart.yaml @@ -0,0 +1,50 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: true + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 162b857af49d45769bc12604a5c192b9 + title: '% Revenue' + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + legend: + position: bottom + version: '2' + visualizationUrl: local:donut +description: '' +id: product_categories_pie_chart +title: Product Categories Pie Chart diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_revenue_comparison-over_previous_period.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_revenue_comparison-over_previous_period.yaml new file mode 100644 index 000000000..697db6ce5 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_revenue_comparison-over_previous_period.yaml @@ -0,0 +1,73 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + alias: Previous Period + definition: + popMeasureDefinition: + measureIdentifier: c82e025fa2db4afea9a600a424591dbe + popAttribute: + identifier: + id: date.year + type: label + localIdentifier: c82e025fa2db4afea9a600a424591dbe_pop + - measure: + alias: This Period + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: c82e025fa2db4afea9a600a424591dbe + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: c804ef5ba7944a5a9f360c86a9e95e9a + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -11 + granularity: GDC.time.month + to: 0 + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + stackMeasures: false + xaxis: + name: + visible: false + yaxis: + name: + visible: false + version: '2' + visualizationUrl: local:column +description: '' +id: product_revenue_comparison-over_previous_period +title: Product Revenue Comparison (over previous period) diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_saleability.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_saleability.yaml new file mode 100644 index 000000000..205996760 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/product_saleability.yaml @@ -0,0 +1,55 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: aeb5d51a162d4b59aba3bd6ddebcc780 + title: '# of Orders' + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 94b3edd3a73c4a48a4d13bbe9442cc98 + title: Revenue + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: d2a991bdd123448eb2be73d79f1180c4 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: + controls: + dataLabels: + visible: auto + grid: + enabled: true + version: '2' + visualizationUrl: local:scatter +description: '' +id: product_saleability +title: Product Saleability diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_and_quantity_by_product_and_category.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_and_quantity_by_product_and_category.yaml new file mode 100644 index 000000000..e63f146b6 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_and_quantity_by_product_and_category.yaml @@ -0,0 +1,97 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + alias: Items Sold + definition: + measureDefinition: + aggregation: sum + filters: [] + item: + identifier: + id: quantity + type: fact + format: '#,##0.00' + localIdentifier: 29486504dd0e4a36a18b0b2f792d3a46 + title: Sum of Quantity + - measure: + definition: + measureDefinition: + aggregation: avg + filters: [] + item: + identifier: + id: price + type: fact + format: '#,##0.00' + localIdentifier: aa6391acccf1452f8011201aef9af492 + title: Avg Price + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: percent_revenue_in_category + type: metric + localIdentifier: 2cd39539d8da46c9883e63caa3ba7cc0 + title: '% Revenue in Category' + - measure: + alias: Total Revenue + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 9a0f08331c094c7facf2a0b4f418de0a + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 06bc6b3b9949466494e4f594c11f1bff + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 192668bfb6a74e9ab7b5d1ce7cb68ea3 + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + sortItems: + - attributeSortItem: + attributeIdentifier: 06bc6b3b9949466494e4f594c11f1bff + direction: asc + version: '2' + visualizationUrl: local:table +description: '' +id: revenue_and_quantity_by_product_and_category +title: Revenue and Quantity by Product and Category diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_category_trend.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_category_trend.yaml new file mode 100644 index 000000000..5c3221033 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_category_trend.yaml @@ -0,0 +1,54 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 7df6c34387744d69b23ec92e1a5cf543 + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 4bb4fc1986c546de9ad976e6ec23fed4 + localIdentifier: trend + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: 34bddcb1cd024902a82396216b0fa9d8 + localIdentifier: segment + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + granularity: GDC.time.year + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:line +description: '' +id: revenue_by_category_trend +title: Revenue by Category Trend diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_product.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_product.yaml new file mode 100644 index 000000000..520b12972 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_by_product.yaml @@ -0,0 +1,37 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 4ae3401bdbba4938afe983df4ba04e1c + title: Revenue + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 1c8ba72dbfc84ddd913bf81dc355c427 + localIdentifier: view + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + properties: {} + version: '2' + visualizationUrl: local:bar +description: '' +id: revenue_by_product +title: Revenue by Product diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_per_usd_vs_spend_by_campaign.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_per_usd_vs_spend_by_campaign.yaml new file mode 100644 index 000000000..6d0f7cbde --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_per_usd_vs_spend_by_campaign.yaml @@ -0,0 +1,54 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: campaign_spend + type: metric + localIdentifier: 13a50d811e474ac6808d8da7f4673b35 + title: Campaign Spend + localIdentifier: measures + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_per_dollar_spent + type: metric + localIdentifier: a0f15e82e6334280a44dbedc7d086e7c + title: Revenue per Dollar Spent + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: campaign_name + type: label + localIdentifier: 1d9fa968bafb423eb29c938dfb1207ff + localIdentifier: attribute + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: campaign_name + type: label + notIn: + values: [] + properties: + controls: + xaxis: + min: '0' + yaxis: + min: '0' + version: '2' + visualizationUrl: local:scatter +description: '' +id: revenue_per_usd_vs_spend_by_campaign +title: Revenue per $ vs Spend by Campaign diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_trend.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_trend.yaml new file mode 100644 index 000000000..e0ded10f3 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/revenue_trend.yaml @@ -0,0 +1,66 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: revenue + type: metric + localIdentifier: 60c854969a9c4c278ab596d99c222e92 + title: Revenue + localIdentifier: measures + - items: + - measure: + alias: Number of Orders + definition: + measureDefinition: + computeRatio: false + filters: [] + item: + identifier: + id: amount_of_orders + type: metric + localIdentifier: c2fa7ef48cc54af99f8c280eb451e051 + title: '# of Orders' + localIdentifier: secondary_measures + - items: + - attribute: + displayForm: + identifier: + id: date.month + type: label + localIdentifier: 413ac374b65648fa96826ca01d47bdda + localIdentifier: view + filters: + - relativeDateFilter: + dataSet: + identifier: + id: date + type: dataset + from: -3 + granularity: GDC.time.quarter + to: 0 + properties: + controls: + dualAxis: true + legend: + position: bottom + primaryChartType: column + secondaryChartType: line + secondary_yaxis: + measures: + - c2fa7ef48cc54af99f8c280eb451e051 + xaxis: + name: + visible: false + rotation: auto + version: '2' + visualizationUrl: local:combo2 +description: '' +id: revenue_trend +title: Revenue Trend diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_customers.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_customers.yaml new file mode 100644 index 000000000..9a191a086 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_customers.yaml @@ -0,0 +1,55 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 3f127ccfe57a40399e23f9ae2a4ad810 + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: customer_name + type: label + localIdentifier: f4e39e24f11e4827a191c30d65c89d2c + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: state + type: label + localIdentifier: bbccd430176d428caed54c99afc9589e + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: customer_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: state + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar +description: '' +id: top_10_customers +title: Top 10 Customers diff --git a/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_products.yaml b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_products.yaml new file mode 100644 index 000000000..c5f39d2ec --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/analytics_model/visualization_objects/top_10_products.yaml @@ -0,0 +1,55 @@ +# (C) 2025 GoodData Corporation +content: + buckets: + - items: + - measure: + definition: + measureDefinition: + filters: [] + item: + identifier: + id: revenue_top_10 + type: metric + localIdentifier: 77dc71bbac92412bac5f94284a5919df + title: Revenue / Top 10 + localIdentifier: measures + - items: + - attribute: + displayForm: + identifier: + id: product_name + type: label + localIdentifier: 781952e728204dcf923142910cc22ae2 + localIdentifier: view + - items: + - attribute: + displayForm: + identifier: + id: products.category + type: label + localIdentifier: fe513cef1c6244a5ac21c5f49c56b108 + localIdentifier: stack + filters: + - negativeAttributeFilter: + displayForm: + identifier: + id: product_name + type: label + notIn: + values: [] + - negativeAttributeFilter: + displayForm: + identifier: + id: products.category + type: label + notIn: + values: [] + properties: + controls: + legend: + position: bottom + version: '2' + visualizationUrl: local:bar +description: '' +id: top_10_products +title: Top 10 Products diff --git a/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaign_channels.yaml b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaign_channels.yaml new file mode 100644 index 000000000..e97992521 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaign_channels.yaml @@ -0,0 +1,67 @@ +# (C) 2025 GoodData Corporation +attributes: + - description: Campaign channel id + id: campaign_channel_id + labels: [] + sourceColumn: campaign_channel_id + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Campaign channel id + - description: Category + id: campaign_channels.category + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Category + - description: Type + id: type + labels: [] + sourceColumn: type + sourceColumnDataType: STRING + tags: + - Campaign channels + title: Type +dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: campaign_channels + path: + - demo_6d9051d9069a8468 + - campaign_channels + type: dataSource +description: Campaign channels +facts: + - description: Budget + id: budget + sourceColumn: budget + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Budget + - description: Spend + id: spend + sourceColumn: spend + sourceColumnDataType: NUMERIC + tags: + - Campaign channels + title: Spend +grain: + - id: campaign_channel_id + type: attribute +id: campaign_channels +references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + target: + id: campaign_id + type: attribute +tags: + - Campaign channels +title: Campaign channels diff --git a/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaigns.yaml b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaigns.yaml new file mode 100644 index 000000000..9e66fc8ff --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/campaigns.yaml @@ -0,0 +1,35 @@ +# (C) 2025 GoodData Corporation +attributes: + - description: Campaign id + id: campaign_id + labels: [] + sourceColumn: campaign_id + sourceColumnDataType: INT + tags: + - Campaigns + title: Campaign id + - description: Campaign name + id: campaign_name + labels: [] + sourceColumn: campaign_name + sourceColumnDataType: STRING + tags: + - Campaigns + title: Campaign name +dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: campaigns + path: + - demo_6d9051d9069a8468 + - campaigns + type: dataSource +description: Campaigns +facts: [] +grain: + - id: campaign_id + type: attribute +id: campaigns +references: [] +tags: + - Campaigns +title: Campaigns diff --git a/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/customers.yaml b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/customers.yaml new file mode 100644 index 000000000..031777a44 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/customers.yaml @@ -0,0 +1,58 @@ +# (C) 2025 GoodData Corporation +attributes: + - description: Customer id + id: customer_id + labels: [] + sourceColumn: customer_id + sourceColumnDataType: INT + tags: + - Customers + title: Customer id + - description: Customer name + id: customer_name + labels: [] + sourceColumn: customer_name + sourceColumnDataType: STRING + tags: + - Customers + title: Customer name + - description: Region + id: region + labels: [] + sourceColumn: region + sourceColumnDataType: STRING + tags: + - Customers + title: Region + - description: State + id: state + labels: + - description: Location + id: geo__state__location + sourceColumn: geo__state__location + sourceColumnDataType: STRING + tags: + - Customers + title: Location + sourceColumn: state + sourceColumnDataType: STRING + tags: + - Customers + title: State +dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: customers + path: + - demo_6d9051d9069a8468 + - customers + type: dataSource +description: Customers +facts: [] +grain: + - id: customer_id + type: attribute +id: customers +references: [] +tags: + - Customers +title: Customers diff --git a/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/order_lines.yaml b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/order_lines.yaml new file mode 100644 index 000000000..c244ca158 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/order_lines.yaml @@ -0,0 +1,108 @@ +# (C) 2025 GoodData Corporation +attributes: + - description: Order id + id: order_id + labels: [] + sourceColumn: order_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order id + - description: Order line id + id: order_line_id + labels: [] + sourceColumn: order_line_id + sourceColumnDataType: STRING + tags: + - Order lines + title: Order line id + - description: Order status + id: order_status + labels: [] + sourceColumn: order_status + sourceColumnDataType: STRING + tags: + - Order lines + title: Order status +dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: order_lines + path: + - demo_6d9051d9069a8468 + - order_lines + type: dataSource +description: Order lines +facts: + - description: Price + id: price + sourceColumn: price + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Price + - description: Quantity + id: quantity + sourceColumn: quantity + sourceColumnDataType: NUMERIC + tags: + - Order lines + title: Quantity +grain: + - id: order_line_id + type: attribute +id: order_lines +references: + - identifier: + id: campaigns + type: dataset + multivalue: false + sources: + - column: campaign_id + dataType: INT + target: + id: campaign_id + type: attribute + - identifier: + id: customers + type: dataset + multivalue: false + sources: + - column: customer_id + dataType: INT + target: + id: customer_id + type: attribute + - identifier: + id: date + type: dataset + multivalue: false + sources: + - column: date + dataType: DATE + target: + id: date + type: date + - identifier: + id: products + type: dataset + multivalue: false + sources: + - column: product_id + dataType: INT + target: + id: product_id + type: attribute +tags: + - Order lines +title: Order lines +workspaceDataFilterColumns: + - dataType: STRING + name: wdf__region + - dataType: STRING + name: wdf__state +workspaceDataFilterReferences: + - filterColumn: wdf__region + filterColumnDataType: STRING + filterId: + id: wdf__region + type: workspaceDataFilter diff --git a/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/products.yaml b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/products.yaml new file mode 100644 index 000000000..2096de7ab --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/ldm/datasets/products.yaml @@ -0,0 +1,43 @@ +# (C) 2025 GoodData Corporation +attributes: + - description: Product id + id: product_id + labels: [] + sourceColumn: product_id + sourceColumnDataType: INT + tags: + - Products + title: Product id + - description: Product name + id: product_name + labels: [] + sourceColumn: product_name + sourceColumnDataType: STRING + tags: + - Products + title: Product name + - description: Category + id: products.category + labels: [] + sourceColumn: category + sourceColumnDataType: STRING + tags: + - Products + title: Category +dataSourceTableId: + dataSourceId: pg_local_docker-demo + id: products + path: + - demo_6d9051d9069a8468 + - products + type: dataSource +description: Products +facts: [] +grain: + - id: product_id + type: attribute +id: products +references: [] +tags: + - Products +title: Products diff --git a/gooddata-sdk/tests/compute/load/ai_search/ldm/date_instances/date.yaml b/gooddata-sdk/tests/compute/load/ai_search/ldm/date_instances/date.yaml new file mode 100644 index 000000000..5ba24d1a8 --- /dev/null +++ b/gooddata-sdk/tests/compute/load/ai_search/ldm/date_instances/date.yaml @@ -0,0 +1,15 @@ +# (C) 2025 GoodData Corporation +description: '' +granularities: + - DAY + - WEEK + - MONTH + - QUARTER + - YEAR +granularitiesFormatting: + titleBase: '' + titlePattern: '%titleBase - %granularityTitle' +id: date +tags: + - Date +title: Date diff --git a/gooddata-sdk/tests/compute/test_compute_service.py b/gooddata-sdk/tests/compute/test_compute_service.py new file mode 100644 index 000000000..5c0d85342 --- /dev/null +++ b/gooddata-sdk/tests/compute/test_compute_service.py @@ -0,0 +1,81 @@ +# (C) 2025 GoodData Corporation +from pathlib import Path + +from gooddata_sdk import CatalogWorkspace +from gooddata_sdk.sdk import GoodDataSdk +from tests_support.vcrpy_utils import get_vcr + +gd_vcr = get_vcr() + +_current_dir = Path(__file__).parent.absolute() +_fixtures_dir = _current_dir / "fixtures" + + +def _setup_test_workspace(sdk: GoodDataSdk, test_workspace_id: str, path: Path) -> None: + """Helper function to set up test workspace with required models. + + Args: + sdk: GoodData SDK instance + test_workspace_id: ID of the test workspace + path: Path to the directory containing model files + """ + # Check if workspace already exists + try: + sdk.catalog_workspace.get_workspace(test_workspace_id) + except Exception: + workspace = CatalogWorkspace(workspace_id=test_workspace_id, name=test_workspace_id) + sdk.catalog_workspace.create_or_update(workspace) + + # Load LDM from disk and put it to the workspace + ldm_from_disk = sdk.catalog_workspace_content.load_ldm_from_disk(path) + sdk.catalog_workspace_content.put_declarative_ldm(test_workspace_id, ldm_from_disk, standalone_copy=True) + + # Load Analytics Model from disk and put it to the workspace + am_from_disk = sdk.catalog_workspace_content.load_analytics_model_from_disk(path) + sdk.catalog_workspace_content.put_declarative_analytics_model(test_workspace_id, am_from_disk) + + +@gd_vcr.use_cassette(str(_fixtures_dir / "ai_search.yaml")) +def test_search_ai(test_config): + """Test AI search with minimal required parameters.""" + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + path = _current_dir / "load" / "ai_search" + test_workspace_id = test_config["workspace_test"] + + try: + _setup_test_workspace(sdk, test_workspace_id, path) + result = sdk.compute.search_ai(test_workspace_id, "What is the total revenue?") + assert len(result.results) == 3 + finally: + # Clean up workspace and all related content + sdk.catalog_workspace.delete_workspace(test_workspace_id) + + +@gd_vcr.use_cassette(str(_fixtures_dir / "ai_search_full_params.yaml")) +def test_search_ai_full_params(test_config): + """Test AI search with all available parameters.""" + sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"]) + path = _current_dir / "load" / "ai_search" + test_workspace_id = test_config["workspace_test"] + + try: + _setup_test_workspace(sdk, test_workspace_id, path) + + # Test search_ai with all parameters + result = sdk.compute.search_ai( + workspace_id=test_workspace_id, + question="What is the total revenue?", + deep_search=True, + limit=2, + object_types=["metric", "attribute", "fact"], + relevant_score_threshold=0.5, + title_to_descriptor_ratio=0.7, + ) + + # Verify the results + assert result is not None + assert hasattr(result, "results") + assert len(result.results) <= 2 + finally: + # Clean up workspace and all related content + sdk.catalog_workspace.delete_workspace(test_workspace_id)