blob: 301e3965f0811ebe73aebedaf972ed7c29aa77b2 [file] [log] [blame]
Mingyu Leif4477672024-04-12 07:23:561// Copyright 2024 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Mingyu Lei5299ac12024-11-13 02:06:155#include "content/browser/ai/echo_ai_language_model.h"
Mingyu Leif4477672024-04-12 07:23:566
7#include <optional>
8
Brad Triebwassere163bfa2025-04-18 02:22:099#include "base/containers/to_vector.h"
Mingyu Leif4477672024-04-12 07:23:5610#include "base/functional/bind.h"
Mingyu Lei36013202024-05-21 05:49:0711#include "base/location.h"
Daniel Cheng4f1c5332025-06-19 19:37:2112#include "base/notimplemented.h"
Mingyu Lei36013202024-05-21 05:49:0713#include "base/time/time.h"
Mingyu Leif70193c2024-08-16 10:26:1714#include "components/optimization_guide/core/optimization_guide_features.h"
Mingyu Lei298dc8b2024-11-11 09:32:1915#include "content/browser/ai/echo_ai_manager_impl.h"
Mingyu Lei36013202024-05-21 05:49:0716#include "content/public/browser/browser_thread.h"
17#include "mojo/public/cpp/bindings/remote.h"
Mingyu Lei86c2ec2f2024-07-25 13:27:5918#include "mojo/public/cpp/bindings/self_owned_receiver.h"
Mingyu Leifc5585f2025-02-13 01:33:0019#include "third_party/blink/public/mojom/ai/ai_common.mojom.h"
Mingyu Lei5299ac12024-11-13 02:06:1520#include "third_party/blink/public/mojom/ai/ai_language_model.mojom.h"
Tsuyoshi Horo961fb672024-07-29 08:03:3121#include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h"
Mingyu Leif4477672024-04-12 07:23:5622
Mingyu Lei65f1a30b2024-05-29 06:21:4723namespace content {
Mingyu Leif4477672024-04-12 07:23:5624
Mingyu Lei2207a7912025-01-14 06:53:2425namespace {
26constexpr char kResponsePrefix[] =
27 "On-device model is not available in Chromium, this API is just echoing "
28 "back the input:\n";
29}
30
Mingyu Lei82e02252025-02-25 16:23:2731EchoAILanguageModel::EchoAILanguageModel(
Brad Triebwassere163bfa2025-04-18 02:22:0932 blink::mojom::AILanguageModelSamplingParamsPtr sampling_params,
Brad Triebwasser666c7c82025-06-09 22:25:2533 base::flat_set<blink::mojom::AILanguageModelPromptType> input_types,
34 uint32_t initial_tokens_size)
35 : current_tokens_(initial_tokens_size),
36 sampling_params_(std::move(sampling_params)),
37 input_types_(input_types) {}
Mingyu Leif4477672024-04-12 07:23:5638
Mingyu Lei5299ac12024-11-13 02:06:1539EchoAILanguageModel::~EchoAILanguageModel() = default;
Mingyu Lei65f1a30b2024-05-29 06:21:4740
Mingyu Lei5299ac12024-11-13 02:06:1541void EchoAILanguageModel::DoMockExecution(
42 const std::string& input,
43 mojo::RemoteSetElementId responder_id) {
Mingyu Lei36013202024-05-21 05:49:0744 blink::mojom::ModelStreamingResponder* responder =
45 responder_set_.Get(responder_id);
46 if (!responder) {
47 return;
48 }
49
Daseul Lee644db352025-05-27 19:33:3250 uint32_t quota = EchoAIManagerImpl::kMaxContextSizeInTokens;
51 if (input.size() > quota) {
Daseul Lee4dc036e2025-03-06 21:51:4352 responder->OnError(
Daseul Lee644db352025-05-27 19:33:3253 blink::mojom::ModelStreamingResponseStatus::kErrorInputTooLarge,
54 blink::mojom::QuotaErrorInfo::New(input.size(), quota));
Mingyu Lei4de8adc2025-01-07 03:54:0255 return;
Mingyu Lei298dc8b2024-11-11 09:32:1956 }
Daseul Lee644db352025-05-27 19:33:3257 if (current_tokens_ > quota - input.size()) {
Mingyu Lei4de8adc2025-01-07 03:54:0258 current_tokens_ = input.size();
Mingyu Leic5127f062025-03-25 04:23:2259 responder->OnQuotaOverflow();
Mingyu Lei4de8adc2025-01-07 03:54:0260 }
61 current_tokens_ += input.size();
Daseul Lee5856db4c2025-03-28 17:32:1462 responder->OnStreaming(kResponsePrefix);
63 responder->OnStreaming(input);
Mingyu Lei4de8adc2025-01-07 03:54:0264 responder->OnCompletion(
65 blink::mojom::ModelExecutionContextInfo::New(current_tokens_));
Mingyu Lei36013202024-05-21 05:49:0766}
67
Mingyu Lei5299ac12024-11-13 02:06:1568void EchoAILanguageModel::Prompt(
Brad Triebwasser6e1c5b02025-03-05 22:08:5369 std::vector<blink::mojom::AILanguageModelPromptPtr> prompts,
Clark DuVall8c0e7f72025-04-24 22:14:1170 on_device_model::mojom::ResponseConstraintPtr constraint,
Mingyu Lei36013202024-05-21 05:49:0771 mojo::PendingRemote<blink::mojom::ModelStreamingResponder>
72 pending_responder) {
73 if (is_destroyed_) {
74 mojo::Remote<blink::mojom::ModelStreamingResponder> responder(
75 std::move(pending_responder));
Mingyu Leid01ff81f22024-11-11 07:58:5476 responder->OnError(
Daseul Lee644db352025-05-27 19:33:3277 blink::mojom::ModelStreamingResponseStatus::kErrorSessionDestroyed,
78 /*quota_error_info=*/nullptr);
Mingyu Lei36013202024-05-21 05:49:0779 return;
80 }
Mingyu Leif4477672024-04-12 07:23:5681
Mike Wassermanf7993a12025-02-25 23:12:1882 std::string response = "";
Brad Triebwasser6e1c5b02025-03-05 22:08:5383 for (const auto& prompt : prompts) {
Brad Triebwasser2b833ce2025-05-23 05:40:0784 for (auto& content : prompt->content) {
85 if (content->is_text()) {
86 response += content->get_text();
87 } else if (content->is_bitmap()) {
88 if (!input_types_.contains(
89 blink::mojom::AILanguageModelPromptType::kImage)) {
90 mojo::ReportBadMessage("Image input is not supported.");
91 return;
92 }
93 response += "<image>";
94 } else if (content->is_audio()) {
95 if (!input_types_.contains(
96 blink::mojom::AILanguageModelPromptType::kAudio)) {
97 mojo::ReportBadMessage("Audio input is not supported.");
98 return;
99 }
Brad Triebwassere163bfa2025-04-18 02:22:09100
Brad Triebwasser2b833ce2025-05-23 05:40:07101 response += "<audio>";
102 } else {
103 NOTIMPLEMENTED_LOG_ONCE();
104 }
Mike Wassermanf7993a12025-02-25 23:12:18105 }
106 }
Mingyu Lei36013202024-05-21 05:49:07107 mojo::RemoteSetElementId responder_id =
108 responder_set_.Add(std::move(pending_responder));
Mingyu Leif70193c2024-08-16 10:26:17109 // Simulate the time taken by model execution.
Mingyu Lei36013202024-05-21 05:49:07110 content::GetUIThreadTaskRunner()->PostDelayedTask(
111 FROM_HERE,
Mingyu Lei5299ac12024-11-13 02:06:15112 base::BindOnce(&EchoAILanguageModel::DoMockExecution,
Mike Wassermana9f398b972025-02-20 03:06:39113 weak_ptr_factory_.GetWeakPtr(), response, responder_id),
Mingyu Lei36013202024-05-21 05:49:07114 base::Seconds(1));
115}
116
Mingyu Lei7398d6b2025-05-09 06:53:42117void EchoAILanguageModel::Append(
118 std::vector<blink::mojom::AILanguageModelPromptPtr> prompts,
Clark DuVall1e256ac2025-05-15 16:24:28119 mojo::PendingRemote<blink::mojom::ModelStreamingResponder>
120 pending_responder) {
121 mojo::Remote<blink::mojom::ModelStreamingResponder> responder(
122 std::move(pending_responder));
123 responder->OnCompletion(
124 blink::mojom::ModelExecutionContextInfo::New(current_tokens_));
Mingyu Lei7398d6b2025-05-09 06:53:42125}
126
Mingyu Lei5299ac12024-11-13 02:06:15127void EchoAILanguageModel::Fork(
128 mojo::PendingRemote<blink::mojom::AIManagerCreateLanguageModelClient>
129 client) {
130 mojo::Remote<blink::mojom::AIManagerCreateLanguageModelClient> client_remote(
Mingyu Lei633aa242024-10-04 17:10:12131 std::move(client));
Mingyu Lei5299ac12024-11-13 02:06:15132 mojo::PendingRemote<blink::mojom::AILanguageModel> language_model;
Mingyu Lei633aa242024-10-04 17:10:12133
Brad Triebwasser666c7c82025-06-09 22:25:25134 mojo::MakeSelfOwnedReceiver(
135 std::make_unique<EchoAILanguageModel>(sampling_params_.Clone(),
136 input_types_, current_tokens_),
137 language_model.InitWithNewPipeAndPassReceiver());
Brad Triebwassere163bfa2025-04-18 02:22:09138 client_remote->OnResult(
139 std::move(language_model),
140 blink::mojom::AILanguageModelInstanceInfo::New(
141 EchoAIManagerImpl::kMaxContextSizeInTokens, current_tokens_,
142 sampling_params_->Clone(), base::ToVector(input_types_)));
Mingyu Lei86c2ec2f2024-07-25 13:27:59143}
144
Mingyu Lei5299ac12024-11-13 02:06:15145void EchoAILanguageModel::Destroy() {
Mingyu Lei36013202024-05-21 05:49:07146 is_destroyed_ = true;
147
148 for (auto& responder : responder_set_) {
Mingyu Leid01ff81f22024-11-11 07:58:54149 responder->OnError(
Daseul Lee644db352025-05-27 19:33:32150 blink::mojom::ModelStreamingResponseStatus::kErrorSessionDestroyed,
151 /*quota_error_info=*/nullptr);
Mingyu Lei36013202024-05-21 05:49:07152 }
153 responder_set_.Clear();
Mingyu Leif4477672024-04-12 07:23:56154}
Mingyu Lei65f1a30b2024-05-29 06:21:47155
Mingyu Leif3b21f92025-03-25 03:28:29156void EchoAILanguageModel::MeasureInputUsage(
Clark DuVall3e7b2ac2025-05-01 18:42:11157 std::vector<blink::mojom::AILanguageModelPromptPtr> input,
Mingyu Lei8e04acc42025-05-13 14:34:58158 MeasureInputUsageCallback callback) {
Mike Wassermane1e76c82025-05-05 18:30:39159 size_t total = 0;
Clark DuVall3e7b2ac2025-05-01 18:42:11160 for (const auto& prompt : input) {
Brad Triebwasser2b833ce2025-05-23 05:40:07161 for (const auto& content : prompt->content) {
162 if (content->is_text()) {
163 total += content->get_text().size();
164 } else {
165 total += 100; // TODO(crbug.com/415304330): Improve estimate.
166 }
Clark DuVall3e7b2ac2025-05-01 18:42:11167 }
168 }
Mingyu Lei8e04acc42025-05-13 14:34:58169 std::move(callback).Run(total);
Lei Mingyubce871092024-09-20 17:27:18170}
171
Mingyu Lei65f1a30b2024-05-29 06:21:47172} // namespace content