// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.cloud.discoveryengine.v1alpha;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/discoveryengine/v1alpha/document.proto";
import "google/cloud/discoveryengine/v1alpha/user_event.proto";
import "google/protobuf/struct.proto";

option csharp_namespace = "Google.Cloud.DiscoveryEngine.V1Alpha";
option go_package = "cloud.google.com/go/discoveryengine/apiv1alpha/discoveryenginepb;discoveryenginepb";
option java_multiple_files = true;
option java_outer_classname = "RecommendationServiceProto";
option java_package = "com.google.cloud.discoveryengine.v1alpha";
option objc_class_prefix = "DISCOVERYENGINE";
option php_namespace = "Google\\Cloud\\DiscoveryEngine\\V1alpha";
option ruby_package = "Google::Cloud::DiscoveryEngine::V1alpha";

// Service for making recommendations.
service RecommendationService {
  option (google.api.default_host) = "discoveryengine.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Makes a recommendation, which requires a contextual user event.
  rpc Recommend(RecommendRequest) returns (RecommendResponse) {
    option (google.api.http) = {
      post: "/v1alpha/{serving_config=projects/*/locations/*/dataStores/*/servingConfigs/*}:recommend"
      body: "*"
      additional_bindings {
        post: "/v1alpha/{serving_config=projects/*/locations/*/collections/*/dataStores/*/servingConfigs/*}:recommend"
        body: "*"
      }
      additional_bindings {
        post: "/v1alpha/{serving_config=projects/*/locations/*/collections/*/engines/*/servingConfigs/*}:recommend"
        body: "*"
      }
    };
  }
}

// Request message for Recommend method.
message RecommendRequest {
  // Required. Full resource name of a
  // [ServingConfig][google.cloud.discoveryengine.v1alpha.ServingConfig]:
  // `projects/*/locations/global/collections/*/engines/*/servingConfigs/*`, or
  // `projects/*/locations/global/collections/*/dataStores/*/servingConfigs/*`
  //
  // One default serving config is created along with your recommendation engine
  // creation. The engine ID is used as the ID of the default serving
  // config. For example, for Engine
  // `projects/*/locations/global/collections/*/engines/my-engine`, you can use
  // `projects/*/locations/global/collections/*/engines/my-engine/servingConfigs/my-engine`
  // for your
  // [RecommendationService.Recommend][google.cloud.discoveryengine.v1alpha.RecommendationService.Recommend]
  // requests.
  string serving_config = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/ServingConfig"
    }
  ];

  // Required. Context about the user, what they are looking at and what action
  // they took to trigger the Recommend request. Note that this user event
  // detail won't be ingested to userEvent logs. Thus, a separate userEvent
  // write request is required for event logging.
  //
  // Don't set
  // [UserEvent.user_pseudo_id][google.cloud.discoveryengine.v1alpha.UserEvent.user_pseudo_id]
  // or
  // [UserEvent.user_info.user_id][google.cloud.discoveryengine.v1alpha.UserInfo.user_id]
  // to the same fixed ID for different users. If you are trying to receive
  // non-personalized recommendations (not recommended; this can negatively
  // impact model performance), instead set
  // [UserEvent.user_pseudo_id][google.cloud.discoveryengine.v1alpha.UserEvent.user_pseudo_id]
  // to a random unique ID and leave
  // [UserEvent.user_info.user_id][google.cloud.discoveryengine.v1alpha.UserInfo.user_id]
  // unset.
  UserEvent user_event = 2 [(google.api.field_behavior) = REQUIRED];

  // Maximum number of results to return. Set this property
  // to the number of recommendation results needed. If zero, the service
  // chooses a reasonable default. The maximum allowed value is 100. Values
  // above 100 are set to 100.
  int32 page_size = 3;

  // Filter for restricting recommendation results with a length limit of 5,000
  // characters. Currently, only filter expressions on the `filter_tags`
  // attribute is supported.
  //
  //
  // Examples:
  //
  //  * `(filter_tags: ANY("Red", "Blue") OR filter_tags: ANY("Hot", "Cold"))`
  //  * `(filter_tags: ANY("Red", "Blue")) AND NOT (filter_tags: ANY("Green"))`
  //
  // If `attributeFilteringSyntax` is set to true under the `params` field, then
  // attribute-based expressions are expected instead of the above described
  // tag-based syntax. Examples:
  //
  //  * (launguage: ANY("en", "es")) AND NOT (categories: ANY("Movie"))
  //  * (available: true) AND
  //    (launguage: ANY("en", "es")) OR (categories: ANY("Movie"))
  //
  // If your filter blocks all results, the API returns generic
  // (unfiltered) popular Documents. If you only want results strictly matching
  // the filters, set `strictFiltering` to `true` in
  // [RecommendRequest.params][google.cloud.discoveryengine.v1alpha.RecommendRequest.params]
  // to receive empty results instead.
  //
  // Note that the API never returns
  // [Document][google.cloud.discoveryengine.v1alpha.Document]s with
  // `storageStatus` as `EXPIRED` or `DELETED` regardless of filter choices.
  string filter = 4;

  // Use validate only mode for this recommendation query. If set to `true`, a
  // fake model is used that returns arbitrary Document IDs.
  // Note that the validate only mode should only be used for testing the API,
  // or if the model is not ready.
  bool validate_only = 5;

  // Additional domain specific parameters for the recommendations.
  //
  // Allowed values:
  //
  // * `returnDocument`: Boolean. If set to `true`, the associated Document
  //    object is returned in
  //    [RecommendResponse.RecommendationResult.document][google.cloud.discoveryengine.v1alpha.RecommendResponse.RecommendationResult.document].
  // * `returnScore`: Boolean. If set to true, the recommendation score
  //    corresponding to each returned Document is set in
  //    [RecommendResponse.RecommendationResult.metadata][google.cloud.discoveryengine.v1alpha.RecommendResponse.RecommendationResult.metadata].
  //    The given score indicates the probability of a Document conversion given
  //    the user's context and history.
  // * `strictFiltering`: Boolean. True by default. If set to `false`, the
  // service
  //    returns generic (unfiltered) popular Documents instead of empty if
  //    your filter blocks all recommendation results.
  // * `diversityLevel`: String. Default empty. If set to be non-empty, then
  //    it needs to be one of:
  //     *  `no-diversity`
  //     *  `low-diversity`
  //     *  `medium-diversity`
  //     *  `high-diversity`
  //     *  `auto-diversity`
  //    This gives request-level control and adjusts recommendation results
  //    based on Document category.
  // * `attributeFilteringSyntax`: Boolean. False by default. If set to true,
  //    the `filter` field is interpreted according to the new,
  //    attribute-based syntax.
  map<string, google.protobuf.Value> params = 6;

  // The user labels applied to a resource must meet the following requirements:
  //
  // * Each resource can have multiple labels, up to a maximum of 64.
  // * Each label must be a key-value pair.
  // * Keys have a minimum length of 1 character and a maximum length of 63
  //   characters and cannot be empty. Values can be empty and have a maximum
  //   length of 63 characters.
  // * Keys and values can contain only lowercase letters, numeric characters,
  //   underscores, and dashes. All characters must use UTF-8 encoding, and
  //   international characters are allowed.
  // * The key portion of a label must be unique. However, you can use the same
  //   key with multiple resources.
  // * Keys must start with a lowercase letter or international character.
  //
  // See [Requirements for
  // labels](https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements)
  // for more details.
  map<string, string> user_labels = 8;
}

// Response message for Recommend method.
message RecommendResponse {
  // RecommendationResult represents a generic recommendation result with
  // associated metadata.
  message RecommendationResult {
    // Resource ID of the recommended Document.
    string id = 1;

    // Set if `returnDocument` is set to true in
    // [RecommendRequest.params][google.cloud.discoveryengine.v1alpha.RecommendRequest.params].
    Document document = 2;

    // Additional Document metadata or annotations.
    //
    // Possible values:
    //
    // * `score`: Recommendation score in double value. Is set if
    //   `returnScore` is set to true in
    //   [RecommendRequest.params][google.cloud.discoveryengine.v1alpha.RecommendRequest.params].
    map<string, google.protobuf.Value> metadata = 3;
  }

  // A list of recommended Documents. The order represents the ranking (from the
  // most relevant Document to the least).
  repeated RecommendationResult results = 1;

  // A unique attribution token. This should be included in the
  // [UserEvent][google.cloud.discoveryengine.v1alpha.UserEvent] logs resulting
  // from this recommendation, which enables accurate attribution of
  // recommendation model performance.
  string attribution_token = 2;

  // IDs of documents in the request that were missing from the default Branch
  // associated with the requested ServingConfig.
  repeated string missing_ids = 3;

  // True if
  // [RecommendRequest.validate_only][google.cloud.discoveryengine.v1alpha.RecommendRequest.validate_only]
  // was set.
  bool validate_only = 4;
}
