Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 1 | // 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 Lei | fd46adf | 2024-06-14 06:06:40 | [diff] [blame] | 5 | #include "content/browser/ai/echo_ai_manager_impl.h" |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 6 | |
Mingyu Lei | 682f658 | 2024-06-14 04:26:59 | [diff] [blame] | 7 | #include "base/no_destructor.h" |
Mingyu Lei | f6f9bc1c | 2024-08-15 05:23:21 | [diff] [blame] | 8 | #include "base/supports_user_data.h" |
Mingyu Lei | 7bc64b4 | 2024-10-25 05:31:00 | [diff] [blame] | 9 | #include "base/time/time.h" |
Daseul Lee | 1b3f19a | 2025-02-05 16:30:00 | [diff] [blame] | 10 | #include "components/language/core/common/locale_util.h" |
Mingyu Lei | 7cafeab | 2024-07-31 17:24:32 | [diff] [blame] | 11 | #include "components/optimization_guide/core/optimization_guide_features.h" |
Mingyu Lei | 5299ac1 | 2024-11-13 02:06:15 | [diff] [blame] | 12 | #include "content/browser/ai/echo_ai_language_model.h" |
Queenie Zhang | f78ea0f | 2025-06-17 18:03:50 | [diff] [blame] | 13 | #include "content/browser/ai/echo_ai_proofreader.h" |
Tsuyoshi Horo | 2e2bb01 | 2024-08-15 07:57:29 | [diff] [blame] | 14 | #include "content/browser/ai/echo_ai_rewriter.h" |
Jiacheng Guo | 370bade4 | 2024-08-24 04:32:03 | [diff] [blame] | 15 | #include "content/browser/ai/echo_ai_summarizer.h" |
Tsuyoshi Horo | 0a2451b | 2024-08-15 02:25:51 | [diff] [blame] | 16 | #include "content/browser/ai/echo_ai_writer.h" |
Mingyu Lei | f6f9bc1c | 2024-08-15 05:23:21 | [diff] [blame] | 17 | #include "content/public/browser/browser_context.h" |
Mingyu Lei | 4c04e11 | 2024-10-25 04:36:44 | [diff] [blame] | 18 | #include "content/public/browser/browser_thread.h" |
Tsuyoshi Horo | 0a2451b | 2024-08-15 02:25:51 | [diff] [blame] | 19 | #include "mojo/public/cpp/bindings/remote.h" |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 20 | #include "mojo/public/cpp/bindings/self_owned_receiver.h" |
Mike Wasserman | 16b5ba7 | 2025-03-24 21:17:09 | [diff] [blame] | 21 | #include "third_party/blink/public/common/features_generated.h" |
Daseul Lee | 34f55f94 | 2025-02-06 19:49:21 | [diff] [blame] | 22 | #include "third_party/blink/public/mojom/ai/ai_common.mojom.h" |
Mingyu Lei | fa31134 | 2025-01-22 04:46:14 | [diff] [blame] | 23 | #include "third_party/blink/public/mojom/ai/ai_language_model.mojom-forward.h" |
Brad Triebwasser | e163bfa | 2025-04-18 02:22:09 | [diff] [blame] | 24 | #include "third_party/blink/public/mojom/ai/ai_language_model.mojom-shared.h" |
Mingyu Lei | 5299ac1 | 2024-11-13 02:06:15 | [diff] [blame] | 25 | #include "third_party/blink/public/mojom/ai/ai_language_model.mojom.h" |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 26 | |
| 27 | namespace content { |
| 28 | |
Mingyu Lei | 7bc64b4 | 2024-10-25 05:31:00 | [diff] [blame] | 29 | namespace { |
| 30 | |
Mingyu Lei | e08bb9c | 2024-11-25 08:40:40 | [diff] [blame] | 31 | const int kMockDownloadPreparationTimeMillisecond = 300; |
Nathan Memmott | e957ae4d | 2025-03-13 20:06:15 | [diff] [blame] | 32 | const int kMockModelSizeBytes = 0x10000; |
Mingyu Lei | 7bc64b4 | 2024-10-25 05:31:00 | [diff] [blame] | 33 | |
Daseul Lee | 34f55f94 | 2025-02-06 19:49:21 | [diff] [blame] | 34 | using blink::mojom::AILanguageCodePtr; |
| 35 | |
Daseul Lee | 1b3f19a | 2025-02-05 16:30:00 | [diff] [blame] | 36 | // TODO(crbug.com/394109104): This is duplicated from chrome AIManager in order |
| 37 | // to keep the consistent wpt results run from CQ, which currently only supports |
| 38 | // running wpt_internal/ tests on content_shell, using content EchoAIManager. |
| 39 | // If there is enough divergence in two AI Managers' code, it should be |
| 40 | // refactored to share the common code or use subclasses. |
Mingyu Lei | fc5585f | 2025-02-13 01:33:00 | [diff] [blame] | 41 | auto is_language_supported = [](const AILanguageCodePtr& language) { |
| 42 | return language->code.empty() || |
| 43 | language::ExtractBaseLanguage(language->code) == "en"; |
| 44 | }; |
| 45 | |
| 46 | bool IsLanguagesSupported(const std::vector<AILanguageCodePtr>& languages) { |
| 47 | return std::ranges::all_of(languages, is_language_supported); |
| 48 | } |
| 49 | |
Daseul Lee | 34f55f94 | 2025-02-06 19:49:21 | [diff] [blame] | 50 | bool SupportedLanguages(const std::vector<AILanguageCodePtr>& input, |
| 51 | const std::vector<AILanguageCodePtr>& context, |
| 52 | const AILanguageCodePtr& output) { |
Mingyu Lei | fc5585f | 2025-02-13 01:33:00 | [diff] [blame] | 53 | return IsLanguagesSupported(input) && IsLanguagesSupported(context) && |
| 54 | is_language_supported(output); |
Daseul Lee | 1b3f19a | 2025-02-05 16:30:00 | [diff] [blame] | 55 | } |
| 56 | |
Mike Wasserman | 88fbc01 | 2025-05-23 22:56:09 | [diff] [blame] | 57 | // Returns whether optional LanguageModel expected_inputs or expected_outputs |
| 58 | // vectors contain only supported languages. Returns true for absent languages. |
| 59 | bool AreExpectedLanguagesSupported( |
| 60 | const std::optional<std::vector<blink::mojom::AILanguageModelExpectedPtr>>& |
| 61 | expected_vector) { |
| 62 | if (!expected_vector) { |
| 63 | return true; |
| 64 | } |
| 65 | for (const auto& expected_entry : expected_vector.value()) { |
| 66 | if (expected_entry->languages.has_value() && |
| 67 | !IsLanguagesSupported(expected_entry->languages.value())) { |
| 68 | return false; |
| 69 | } |
| 70 | } |
| 71 | return true; |
| 72 | } |
| 73 | |
| 74 | // Returns whether `options` contains any unsupported AILanguageModelPromptType. |
| 75 | bool HasUnsupportedType( |
| 76 | const blink::mojom::AILanguageModelCreateOptionsPtr& options) { |
| 77 | bool has_unsupported_type = false; |
| 78 | if (options) { |
| 79 | if (options->expected_inputs.has_value()) { |
| 80 | for (const auto& expected_input : options->expected_inputs.value()) { |
| 81 | has_unsupported_type |= |
| 82 | expected_input->type != |
| 83 | blink::mojom::AILanguageModelPromptType::kText && |
| 84 | !base::FeatureList::IsEnabled( |
| 85 | blink::features::kAIPromptAPIMultimodalInput); |
| 86 | } |
| 87 | } |
| 88 | if (options->expected_outputs.has_value()) { |
| 89 | for (const auto& expected_output : options->expected_outputs.value()) { |
| 90 | has_unsupported_type |= expected_output->type != |
| 91 | blink::mojom::AILanguageModelPromptType::kText; |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | return has_unsupported_type; |
| 96 | } |
| 97 | |
Mingyu Lei | 7bc64b4 | 2024-10-25 05:31:00 | [diff] [blame] | 98 | } // namespace |
| 99 | |
Fergal Daly | e835ff2 | 2024-10-11 20:07:13 | [diff] [blame] | 100 | EchoAIManagerImpl::EchoAIManagerImpl() = default; |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 101 | |
Mingyu Lei | fd46adf | 2024-06-14 06:06:40 | [diff] [blame] | 102 | EchoAIManagerImpl::~EchoAIManagerImpl() = default; |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 103 | |
| 104 | // static |
Mingyu Lei | fd46adf | 2024-06-14 06:06:40 | [diff] [blame] | 105 | void EchoAIManagerImpl::Create( |
Mingyu Lei | 9de94c6 | 2024-05-29 07:14:42 | [diff] [blame] | 106 | mojo::PendingReceiver<blink::mojom::AIManager> receiver) { |
Fergal Daly | e835ff2 | 2024-10-11 20:07:13 | [diff] [blame] | 107 | static base::NoDestructor<EchoAIManagerImpl> ai; |
Mingyu Lei | 46478fe | 2024-11-01 08:09:27 | [diff] [blame] | 108 | ai->receivers_.Add(ai.get(), std::move(receiver)); |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 109 | } |
| 110 | |
Mingyu Lei | 5299ac1 | 2024-11-13 02:06:15 | [diff] [blame] | 111 | void EchoAIManagerImpl::CanCreateLanguageModel( |
Mike Wasserman | 16b5ba7 | 2025-03-24 21:17:09 | [diff] [blame] | 112 | blink::mojom::AILanguageModelCreateOptionsPtr options, |
Mingyu Lei | 5299ac1 | 2024-11-13 02:06:15 | [diff] [blame] | 113 | CanCreateLanguageModelCallback callback) { |
Mike Wasserman | 88fbc01 | 2025-05-23 22:56:09 | [diff] [blame] | 114 | if (HasUnsupportedType(options)) { |
| 115 | std::move(callback).Run(blink::mojom::ModelAvailabilityCheckResult:: |
| 116 | kUnavailableModelAdaptationNotAvailable); |
| 117 | return; |
| 118 | } |
| 119 | if (options && (!AreExpectedLanguagesSupported(options->expected_inputs) || |
| 120 | !AreExpectedLanguagesSupported(options->expected_outputs))) { |
| 121 | std::move(callback).Run(blink::mojom::ModelAvailabilityCheckResult:: |
| 122 | kUnavailableUnsupportedLanguage); |
| 123 | return; |
Mingyu Lei | fc5585f | 2025-02-13 01:33:00 | [diff] [blame] | 124 | } |
| 125 | |
Mingyu Lei | 4ec236f | 2024-06-13 05:58:27 | [diff] [blame] | 126 | std::move(callback).Run( |
Mike Wasserman | 311bf8c | 2025-07-10 18:13:37 | [diff] [blame] | 127 | IsModelDownloadedForCurrentReciever() |
Daseul Lee | 18e6e22 | 2025-06-09 19:09:57 | [diff] [blame] | 128 | ? blink::mojom::ModelAvailabilityCheckResult::kAvailable |
| 129 | : blink::mojom::ModelAvailabilityCheckResult::kDownloadable); |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 130 | } |
| 131 | |
Mingyu Lei | 5299ac1 | 2024-11-13 02:06:15 | [diff] [blame] | 132 | void EchoAIManagerImpl::CreateLanguageModel( |
| 133 | mojo::PendingRemote<blink::mojom::AIManagerCreateLanguageModelClient> |
| 134 | client, |
| 135 | blink::mojom::AILanguageModelCreateOptionsPtr options) { |
| 136 | mojo::Remote<blink::mojom::AIManagerCreateLanguageModelClient> client_remote( |
Mingyu Lei | 633aa24 | 2024-10-04 17:10:12 | [diff] [blame] | 137 | std::move(client)); |
Mingyu Lei | 4c04e11 | 2024-10-25 04:36:44 | [diff] [blame] | 138 | |
Mike Wasserman | e1e76c8 | 2025-05-05 18:30:39 | [diff] [blame] | 139 | size_t initial_size = 0; |
| 140 | for (const auto& initial_prompt : options->initial_prompts) { |
Brad Triebwasser | 2b833ce | 2025-05-23 05:40:07 | [diff] [blame] | 141 | for (const auto& content : initial_prompt->content) { |
| 142 | if (content->is_text()) { |
| 143 | initial_size += content->get_text().size(); |
| 144 | } else { |
| 145 | initial_size += 100; // TODO(crbug.com/415304330): Improve estimate. |
| 146 | } |
| 147 | if (initial_size > kMaxContextSizeInTokens) { |
| 148 | client_remote->OnError( |
Daseul Lee | 644db35 | 2025-05-27 19:33:32 | [diff] [blame] | 149 | blink::mojom::AIManagerCreateClientError::kInitialInputTooLarge, |
| 150 | blink::mojom::QuotaErrorInfo::New(initial_size, |
| 151 | kMaxContextSizeInTokens)); |
Brad Triebwasser | 2b833ce | 2025-05-23 05:40:07 | [diff] [blame] | 152 | return; |
| 153 | } |
Mike Wasserman | e1e76c8 | 2025-05-05 18:30:39 | [diff] [blame] | 154 | } |
Mingyu Lei | e08bb9c | 2024-11-25 08:40:40 | [diff] [blame] | 155 | } |
| 156 | |
Mike Wasserman | 88fbc01 | 2025-05-23 22:56:09 | [diff] [blame] | 157 | if (HasUnsupportedType(options)) { |
| 158 | client_remote->OnError( |
Daseul Lee | 644db35 | 2025-05-27 19:33:32 | [diff] [blame] | 159 | blink::mojom::AIManagerCreateClientError::kUnableToCreateSession, |
| 160 | /*quota_error_info=*/nullptr); |
Mike Wasserman | 88fbc01 | 2025-05-23 22:56:09 | [diff] [blame] | 161 | return; |
| 162 | } |
| 163 | if (options && (!AreExpectedLanguagesSupported(options->expected_inputs) || |
| 164 | !AreExpectedLanguagesSupported(options->expected_outputs))) { |
| 165 | client_remote->OnError( |
Daseul Lee | 644db35 | 2025-05-27 19:33:32 | [diff] [blame] | 166 | blink::mojom::AIManagerCreateClientError::kUnsupportedLanguage, |
| 167 | /*quota_error_info=*/nullptr); |
Mike Wasserman | 88fbc01 | 2025-05-23 22:56:09 | [diff] [blame] | 168 | return; |
| 169 | } |
Brad Triebwasser | e163bfa | 2025-04-18 02:22:09 | [diff] [blame] | 170 | base::flat_set<blink::mojom::AILanguageModelPromptType> enabled_input_types; |
| 171 | if (options->expected_inputs.has_value()) { |
| 172 | for (const auto& expected_input : options->expected_inputs.value()) { |
| 173 | enabled_input_types.insert(expected_input->type); |
| 174 | } |
| 175 | } |
| 176 | |
Brad Triebwasser | 666c7c8 | 2025-06-09 22:25:25 | [diff] [blame] | 177 | auto return_language_model_callback = base::BindOnce( |
| 178 | &EchoAIManagerImpl::ReturnAILanguageModelCreationResult, |
| 179 | weak_ptr_factory_.GetWeakPtr(), std::move(client_remote), |
| 180 | std::move(options->sampling_params), enabled_input_types, initial_size); |
Jiacheng Guo | 50379cb | 2024-12-09 06:10:43 | [diff] [blame] | 181 | |
Mike Wasserman | 311bf8c | 2025-07-10 18:13:37 | [diff] [blame] | 182 | if (!IsModelDownloadedForCurrentReciever()) { |
| 183 | // Simulate downloading the model; cache state for the current receiver. |
| 184 | model_downloaded_receivers_.insert(receivers_.current_receiver()); |
Daseul Lee | 18e6e22 | 2025-06-09 19:09:57 | [diff] [blame] | 185 | content::GetUIThreadTaskRunner()->PostDelayedTask( |
| 186 | FROM_HERE, |
| 187 | base::BindOnce(&EchoAIManagerImpl::DoMockDownloadingAndReturn, |
| 188 | weak_ptr_factory_.GetWeakPtr(), |
| 189 | std::move(return_language_model_callback)), |
| 190 | base::Milliseconds(kMockDownloadPreparationTimeMillisecond)); |
| 191 | } else { |
| 192 | std::move(return_language_model_callback).Run(); |
| 193 | } |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 194 | } |
| 195 | |
Jiacheng Guo | 370bade4 | 2024-08-24 04:32:03 | [diff] [blame] | 196 | void EchoAIManagerImpl::CanCreateSummarizer( |
Daseul Lee | 1b3f19a | 2025-02-05 16:30:00 | [diff] [blame] | 197 | blink::mojom::AISummarizerCreateOptionsPtr options, |
Jiacheng Guo | 370bade4 | 2024-08-24 04:32:03 | [diff] [blame] | 198 | CanCreateSummarizerCallback callback) { |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 199 | CanCreateWritingAssistanceClient<blink::mojom::AISummarizerCreateOptionsPtr, |
| 200 | CanCreateSummarizerCallback>( |
| 201 | std::move(options), std::move(callback)); |
Jiacheng Guo | 370bade4 | 2024-08-24 04:32:03 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | void EchoAIManagerImpl::CreateSummarizer( |
Jiacheng Guo | 49e046a7 | 2024-08-29 06:46:15 | [diff] [blame] | 205 | mojo::PendingRemote<blink::mojom::AIManagerCreateSummarizerClient> client, |
Tsuyoshi Horo | de5d5f8a | 2024-09-03 07:31:13 | [diff] [blame] | 206 | blink::mojom::AISummarizerCreateOptionsPtr options) { |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 207 | CreateWritingAssistanceClient<blink::mojom::AISummarizerCreateOptionsPtr, |
| 208 | blink::mojom::AIManagerCreateSummarizerClient, |
| 209 | blink::mojom::AISummarizer, EchoAISummarizer>( |
| 210 | std::move(client), std::move(options)); |
Jiacheng Guo | 370bade4 | 2024-08-24 04:32:03 | [diff] [blame] | 211 | } |
| 212 | |
Mingyu Lei | e778743 | 2025-01-28 09:23:17 | [diff] [blame] | 213 | void EchoAIManagerImpl::GetLanguageModelParams( |
| 214 | GetLanguageModelParamsCallback callback) { |
| 215 | std::move(callback).Run(blink::mojom::AILanguageModelParams::New( |
Mingyu Lei | fa31134 | 2025-01-22 04:46:14 | [diff] [blame] | 216 | blink::mojom::AILanguageModelSamplingParams::New( |
| 217 | optimization_guide::features::GetOnDeviceModelDefaultTopK(), |
| 218 | optimization_guide::features::GetOnDeviceModelDefaultTemperature()), |
| 219 | blink::mojom::AILanguageModelSamplingParams::New( |
| 220 | optimization_guide::features::GetOnDeviceModelMaxTopK(), |
| 221 | /*temperature=*/2.0f))); |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 222 | } |
| 223 | |
Mike Wasserman | d5077dff | 2024-12-13 18:10:11 | [diff] [blame] | 224 | void EchoAIManagerImpl::CanCreateWriter( |
| 225 | blink::mojom::AIWriterCreateOptionsPtr options, |
| 226 | CanCreateWriterCallback callback) { |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 227 | CanCreateWritingAssistanceClient<blink::mojom::AIWriterCreateOptionsPtr, |
| 228 | CanCreateWriterCallback>( |
| 229 | std::move(options), std::move(callback)); |
Mike Wasserman | d5077dff | 2024-12-13 18:10:11 | [diff] [blame] | 230 | } |
| 231 | |
Tsuyoshi Horo | 0a2451b | 2024-08-15 02:25:51 | [diff] [blame] | 232 | void EchoAIManagerImpl::CreateWriter( |
Tsuyoshi Horo | de5d5f8a | 2024-09-03 07:31:13 | [diff] [blame] | 233 | mojo::PendingRemote<blink::mojom::AIManagerCreateWriterClient> client, |
| 234 | blink::mojom::AIWriterCreateOptionsPtr options) { |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 235 | CreateWritingAssistanceClient<blink::mojom::AIWriterCreateOptionsPtr, |
| 236 | blink::mojom::AIManagerCreateWriterClient, |
| 237 | blink::mojom::AIWriter, EchoAIWriter>( |
| 238 | std::move(client), std::move(options)); |
Tsuyoshi Horo | 0a2451b | 2024-08-15 02:25:51 | [diff] [blame] | 239 | } |
| 240 | |
Mike Wasserman | d5077dff | 2024-12-13 18:10:11 | [diff] [blame] | 241 | void EchoAIManagerImpl::CanCreateRewriter( |
| 242 | blink::mojom::AIRewriterCreateOptionsPtr options, |
| 243 | CanCreateRewriterCallback callback) { |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 244 | CanCreateWritingAssistanceClient<blink::mojom::AIRewriterCreateOptionsPtr, |
| 245 | CanCreateRewriterCallback>( |
| 246 | std::move(options), std::move(callback)); |
Mike Wasserman | d5077dff | 2024-12-13 18:10:11 | [diff] [blame] | 247 | } |
| 248 | |
Tsuyoshi Horo | 2e2bb01 | 2024-08-15 07:57:29 | [diff] [blame] | 249 | void EchoAIManagerImpl::CreateRewriter( |
Tsuyoshi Horo | de5d5f8a | 2024-09-03 07:31:13 | [diff] [blame] | 250 | mojo::PendingRemote<blink::mojom::AIManagerCreateRewriterClient> client, |
| 251 | blink::mojom::AIRewriterCreateOptionsPtr options) { |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 252 | CreateWritingAssistanceClient<blink::mojom::AIRewriterCreateOptionsPtr, |
| 253 | blink::mojom::AIManagerCreateRewriterClient, |
| 254 | blink::mojom::AIRewriter, EchoAIRewriter>( |
| 255 | std::move(client), std::move(options)); |
| 256 | } |
| 257 | |
Queenie Zhang | f78ea0f | 2025-06-17 18:03:50 | [diff] [blame] | 258 | void EchoAIManagerImpl::CanCreateProofreader( |
| 259 | blink::mojom::AIProofreaderCreateOptionsPtr options, |
| 260 | CanCreateProofreaderCallback callback) { |
| 261 | if (options && |
| 262 | !SupportedLanguages(options->expected_input_languages, {}, |
| 263 | options->correction_explanation_language)) { |
| 264 | std::move(callback).Run(blink::mojom::ModelAvailabilityCheckResult:: |
| 265 | kUnavailableUnsupportedLanguage); |
| 266 | return; |
| 267 | } |
| 268 | CanCreateClient<CanCreateProofreaderCallback>(std::move(callback)); |
| 269 | } |
| 270 | |
| 271 | void EchoAIManagerImpl::CreateProofreader( |
| 272 | mojo::PendingRemote<blink::mojom::AIManagerCreateProofreaderClient> client, |
| 273 | blink::mojom::AIProofreaderCreateOptionsPtr options) { |
| 274 | mojo::Remote<blink::mojom::AIManagerCreateProofreaderClient> client_remote( |
| 275 | std::move(client)); |
| 276 | if (options && |
| 277 | !SupportedLanguages(options->expected_input_languages, {}, |
| 278 | options->correction_explanation_language)) { |
| 279 | client_remote->OnError( |
| 280 | blink::mojom::AIManagerCreateClientError::kUnsupportedLanguage, |
| 281 | /*quota_error_info=*/nullptr); |
| 282 | return; |
| 283 | } |
| 284 | |
| 285 | CreateClient<blink::mojom::AIManagerCreateProofreaderClient, |
| 286 | blink::mojom::AIProofreader, EchoAIProofreader>( |
| 287 | std::move(client_remote)); |
| 288 | } |
| 289 | |
Mike Wasserman | 311bf8c | 2025-07-10 18:13:37 | [diff] [blame] | 290 | void EchoAIManagerImpl::AddModelDownloadProgressObserver( |
| 291 | mojo::PendingRemote<blink::mojom::ModelDownloadProgressObserver> |
| 292 | observer_remote) { |
| 293 | download_progress_observers_.Add(std::move(observer_remote)); |
| 294 | } |
| 295 | |
Queenie Zhang | f78ea0f | 2025-06-17 18:03:50 | [diff] [blame] | 296 | template <typename CanCreateCallback> |
| 297 | void EchoAIManagerImpl::CanCreateClient(CanCreateCallback callback) { |
| 298 | std::move(callback).Run( |
Mike Wasserman | 311bf8c | 2025-07-10 18:13:37 | [diff] [blame] | 299 | IsModelDownloadedForCurrentReciever() |
Queenie Zhang | f78ea0f | 2025-06-17 18:03:50 | [diff] [blame] | 300 | ? blink::mojom::ModelAvailabilityCheckResult::kAvailable |
| 301 | : blink::mojom::ModelAvailabilityCheckResult::kDownloadable); |
| 302 | } |
| 303 | |
| 304 | template <typename AIClientRemote, |
| 305 | typename AIPendingRemote, |
| 306 | typename EchoAIClient> |
| 307 | void EchoAIManagerImpl::CreateClient( |
| 308 | mojo::Remote<AIClientRemote> client_remote) { |
| 309 | auto return_task = |
| 310 | base::BindOnce(&EchoAIManagerImpl::ReturnAIClientCreationResult< |
| 311 | AIClientRemote, AIPendingRemote, EchoAIClient>, |
| 312 | weak_ptr_factory_.GetWeakPtr(), std::move(client_remote)); |
Mike Wasserman | 311bf8c | 2025-07-10 18:13:37 | [diff] [blame] | 313 | if (!IsModelDownloadedForCurrentReciever()) { |
| 314 | // Simulate downloading the model; cache state for the current receiver. |
| 315 | model_downloaded_receivers_.insert(receivers_.current_receiver()); |
Queenie Zhang | f78ea0f | 2025-06-17 18:03:50 | [diff] [blame] | 316 | content::GetUIThreadTaskRunner()->PostDelayedTask( |
| 317 | FROM_HERE, |
| 318 | base::BindOnce(&EchoAIManagerImpl::DoMockDownloadingAndReturn, |
| 319 | weak_ptr_factory_.GetWeakPtr(), std::move(return_task)), |
| 320 | base::Milliseconds(kMockDownloadPreparationTimeMillisecond)); |
| 321 | } else { |
| 322 | std::move(return_task).Run(); |
| 323 | } |
| 324 | } |
| 325 | |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 326 | template <typename AICreateOptions, typename CanCreateCallback> |
| 327 | void EchoAIManagerImpl::CanCreateWritingAssistanceClient( |
| 328 | AICreateOptions options, |
| 329 | CanCreateCallback callback) { |
| 330 | if (options && !SupportedLanguages(options->expected_input_languages, |
| 331 | options->expected_context_languages, |
| 332 | options->output_language)) { |
| 333 | std::move(callback).Run(blink::mojom::ModelAvailabilityCheckResult:: |
| 334 | kUnavailableUnsupportedLanguage); |
| 335 | return; |
| 336 | } |
Queenie Zhang | f78ea0f | 2025-06-17 18:03:50 | [diff] [blame] | 337 | CanCreateClient<CanCreateCallback>(std::move(callback)); |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 338 | } |
| 339 | |
| 340 | template <typename AICreateOptions, |
| 341 | typename AIClientRemote, |
| 342 | typename AIPendingRemote, |
| 343 | typename EchoAIClient> |
| 344 | void EchoAIManagerImpl::CreateWritingAssistanceClient( |
| 345 | mojo::PendingRemote<AIClientRemote> client, |
| 346 | AICreateOptions options) { |
| 347 | mojo::Remote<AIClientRemote> client_remote(std::move(client)); |
| 348 | if (options && !SupportedLanguages(options->expected_input_languages, |
| 349 | options->expected_context_languages, |
| 350 | options->output_language)) { |
| 351 | client_remote->OnError( |
Daseul Lee | 644db35 | 2025-05-27 19:33:32 | [diff] [blame] | 352 | blink::mojom::AIManagerCreateClientError::kUnsupportedLanguage, |
| 353 | /*quota_error_info=*/nullptr); |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 354 | return; |
| 355 | } |
Queenie Zhang | f78ea0f | 2025-06-17 18:03:50 | [diff] [blame] | 356 | |
| 357 | CreateClient<AIClientRemote, AIPendingRemote, EchoAIClient>( |
| 358 | std::move(client_remote)); |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 359 | } |
| 360 | |
| 361 | template <typename AIClientRemote, |
| 362 | typename AIPendingRemote, |
| 363 | typename EchoAIClient> |
| 364 | void EchoAIManagerImpl::ReturnAIClientCreationResult( |
| 365 | mojo::Remote<AIClientRemote> client_remote) { |
Daseul Lee | afef8e82 | 2025-05-15 21:52:24 | [diff] [blame] | 366 | mojo::PendingRemote<AIPendingRemote> pending_remote; |
| 367 | mojo::MakeSelfOwnedReceiver(std::make_unique<EchoAIClient>(), |
| 368 | pending_remote.InitWithNewPipeAndPassReceiver()); |
| 369 | client_remote->OnResult(std::move(pending_remote)); |
Tsuyoshi Horo | 2e2bb01 | 2024-08-15 07:57:29 | [diff] [blame] | 370 | } |
| 371 | |
Mingyu Lei | 5299ac1 | 2024-11-13 02:06:15 | [diff] [blame] | 372 | void EchoAIManagerImpl::ReturnAILanguageModelCreationResult( |
| 373 | mojo::Remote<blink::mojom::AIManagerCreateLanguageModelClient> |
Mingyu Lei | 82e0225 | 2025-02-25 16:23:27 | [diff] [blame] | 374 | client_remote, |
Brad Triebwasser | e163bfa | 2025-04-18 02:22:09 | [diff] [blame] | 375 | blink::mojom::AILanguageModelSamplingParamsPtr sampling_params, |
Brad Triebwasser | 666c7c8 | 2025-06-09 22:25:25 | [diff] [blame] | 376 | base::flat_set<blink::mojom::AILanguageModelPromptType> enabled_input_types, |
| 377 | uint32_t initial_input_usage) { |
Mingyu Lei | 5299ac1 | 2024-11-13 02:06:15 | [diff] [blame] | 378 | mojo::PendingRemote<blink::mojom::AILanguageModel> language_model; |
Mingyu Lei | 82e0225 | 2025-02-25 16:23:27 | [diff] [blame] | 379 | auto model_sampling_params = |
| 380 | sampling_params |
| 381 | ? std::move(sampling_params) |
| 382 | : blink::mojom::AILanguageModelSamplingParams::New( |
| 383 | optimization_guide::features::GetOnDeviceModelDefaultTopK(), |
| 384 | optimization_guide::features:: |
| 385 | GetOnDeviceModelDefaultTemperature()); |
| 386 | |
Brad Triebwasser | 666c7c8 | 2025-06-09 22:25:25 | [diff] [blame] | 387 | mojo::MakeSelfOwnedReceiver(std::make_unique<EchoAILanguageModel>( |
| 388 | model_sampling_params->Clone(), |
| 389 | enabled_input_types, initial_input_usage), |
| 390 | language_model.InitWithNewPipeAndPassReceiver()); |
Mike Wasserman | 16b5ba7 | 2025-03-24 21:17:09 | [diff] [blame] | 391 | client_remote->OnResult( |
| 392 | std::move(language_model), |
| 393 | blink::mojom::AILanguageModelInstanceInfo::New( |
Brad Triebwasser | 666c7c8 | 2025-06-09 22:25:25 | [diff] [blame] | 394 | kMaxContextSizeInTokens, initial_input_usage, |
| 395 | std::move(model_sampling_params), |
Brad Triebwasser | e163bfa | 2025-04-18 02:22:09 | [diff] [blame] | 396 | std::vector<blink::mojom::AILanguageModelPromptType>( |
| 397 | enabled_input_types.begin(), enabled_input_types.end()))); |
Mingyu Lei | 4c04e11 | 2024-10-25 04:36:44 | [diff] [blame] | 398 | } |
| 399 | |
Jiacheng Guo | 50379cb | 2024-12-09 06:10:43 | [diff] [blame] | 400 | void EchoAIManagerImpl::DoMockDownloadingAndReturn(base::OnceClosure callback) { |
Mingyu Lei | 4c04e11 | 2024-10-25 04:36:44 | [diff] [blame] | 401 | // Mock the downloading process update for testing. |
Mingyu Lei | 7bc64b4 | 2024-10-25 05:31:00 | [diff] [blame] | 402 | for (auto& observer : download_progress_observers_) { |
Mike Wasserman | 4f650837 | 2025-04-01 18:34:35 | [diff] [blame] | 403 | observer->OnDownloadProgressUpdate(0, kMockModelSizeBytes); |
Mingyu Lei | 7bc64b4 | 2024-10-25 05:31:00 | [diff] [blame] | 404 | observer->OnDownloadProgressUpdate(kMockModelSizeBytes / 3, |
| 405 | kMockModelSizeBytes); |
| 406 | observer->OnDownloadProgressUpdate(kMockModelSizeBytes / 3 * 2, |
| 407 | kMockModelSizeBytes); |
| 408 | observer->OnDownloadProgressUpdate(kMockModelSizeBytes, |
| 409 | kMockModelSizeBytes); |
Mingyu Lei | 4c04e11 | 2024-10-25 04:36:44 | [diff] [blame] | 410 | } |
| 411 | |
Jiacheng Guo | 50379cb | 2024-12-09 06:10:43 | [diff] [blame] | 412 | std::move(callback).Run(); |
Mingyu Lei | 4c04e11 | 2024-10-25 04:36:44 | [diff] [blame] | 413 | } |
| 414 | |
Mike Wasserman | 311bf8c | 2025-07-10 18:13:37 | [diff] [blame] | 415 | bool EchoAIManagerImpl::IsModelDownloadedForCurrentReciever() const { |
| 416 | return model_downloaded_receivers_.contains(receivers_.current_receiver()); |
Mingyu Lei | 4c04e11 | 2024-10-25 04:36:44 | [diff] [blame] | 417 | } |
| 418 | |
Mingyu Lei | 65f1a30b | 2024-05-29 06:21:47 | [diff] [blame] | 419 | } // namespace content |