diff --git a/packages/firebase_vertexai/all_lint_rules.yaml b/packages/firebase_vertexai/all_lint_rules.yaml new file mode 100644 index 000000000000..dc4ec3a951c3 --- /dev/null +++ b/packages/firebase_vertexai/all_lint_rules.yaml @@ -0,0 +1,183 @@ +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# in the LICENSE file. + +linter: + rules: + - always_declare_return_types + - always_put_control_body_on_new_line + - always_put_required_named_parameters_first + - always_require_non_null_named_parameters + - always_specify_types + - always_use_package_imports + - annotate_overrides + - avoid_annotating_with_dynamic + - avoid_bool_literals_in_conditional_expressions + - avoid_catches_without_on_clauses + - avoid_catching_errors + - avoid_classes_with_only_static_members + - avoid_double_and_int_checks + - avoid_empty_else + - avoid_equals_and_hash_code_on_mutable_classes + - avoid_escaping_inner_quotes + - avoid_field_initializers_in_const_classes + - avoid_function_literals_in_foreach_calls + - avoid_implementing_value_types + - avoid_init_to_null + - avoid_js_rounded_ints + - avoid_null_checks_in_equality_operators + - avoid_positional_boolean_parameters + - avoid_print + - avoid_private_typedef_functions + - avoid_redundant_argument_values + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + - avoid_returning_null + - avoid_returning_null_for_future + - avoid_returning_null_for_void + - avoid_returning_this + - avoid_setters_without_getters + - avoid_shadowing_type_parameters + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_type_to_string + - avoid_types_as_parameter_names + - avoid_types_on_closure_parameters + - avoid_unnecessary_containers + - avoid_unused_constructor_parameters + - avoid_void_async + - avoid_web_libraries_in_flutter + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + - cascade_invocations + - cast_nullable_to_non_nullable + - close_sinks + - comment_references + - constant_identifier_names + - control_flow_in_finally + - curly_braces_in_flow_control_structures + - diagnostic_describe_all_properties + - directives_ordering + - do_not_use_environment + - empty_catches + - empty_constructor_bodies + - empty_statements + - exhaustive_cases + - file_names + - flutter_style_todos + - hash_and_equals + - implementation_imports + - invariant_booleans + - iterable_contains_unrelated_type + - join_return_with_assignment + - leading_newlines_in_multiline_strings + - library_names + - library_prefixes + - lines_longer_than_80_chars + - list_remove_unrelated_type + - literal_only_boolean_expressions + - missing_whitespace_between_adjacent_strings + - no_adjacent_strings_in_list + - no_default_cases + - no_duplicate_case_values + - no_logic_in_create_state + - no_runtimeType_toString + - non_constant_identifier_names + - null_check_on_nullable_type_parameter + - null_closures + - omit_local_variable_types + - one_member_abstracts + - only_throw_errors + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + - parameter_assignments + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + - prefer_asserts_with_message + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + - prefer_constructors_over_static_methods + - prefer_contains + - prefer_double_quotes + - prefer_equal_for_default_values + - prefer_expression_function_bodies + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + - prefer_for_elements_to_map_fromIterable + - prefer_foreach + - prefer_function_declarations_over_variables + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + - prefer_int_literals + - prefer_interpolation_to_compose_strings + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + - prefer_mixin + - prefer_null_aware_operators + - prefer_relative_imports + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + - provide_deprecation_message + - public_member_api_docs + - recursive_getters + - sized_box_for_whitespace + - slash_for_doc_comments + - sort_child_properties_last + - sort_constructors_first + - sort_pub_dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + - tighten_type_of_initializing_formals + - type_annotate_public_apis + - type_init_formals + - unawaited_futures + - unnecessary_await_in_return + - unnecessary_brace_in_string_interps + - unnecessary_const + - unnecessary_final + - unnecessary_getters_setters + - unnecessary_lambdas + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_checks + - unnecessary_null_in_if_null_operators + - unnecessary_nullable_for_final_variable_declarations + - unnecessary_overrides + - unnecessary_parenthesis + - unnecessary_raw_strings + - unnecessary_statements + - unnecessary_string_escapes + - unnecessary_string_interpolations + - unnecessary_this + - unrelated_type_equality_checks + - unsafe_html + - use_full_hex_values_for_flutter_colors + - use_function_type_syntax_for_parameters + - use_is_even_rather_than_modulo + - use_key_in_widget_constructors + - use_late_for_private_fields_and_variables + - use_raw_strings + - use_rethrow_when_possible + - use_setters_to_change_properties + - use_string_buffers + - use_to_and_as_if_applicable + - valid_regexps + - void_checks diff --git a/packages/firebase_vertexai/analysis_options.yaml b/packages/firebase_vertexai/analysis_options.yaml new file mode 100644 index 000000000000..f41d32929033 --- /dev/null +++ b/packages/firebase_vertexai/analysis_options.yaml @@ -0,0 +1,88 @@ +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# in the LICENSE file. + +include: all_lint_rules.yaml +analyzer: + # TODO(rrousselGit): disable implicit-cast/implicit-dynamic + errors: + # Otherwise cause the import of all_lint_rules to warn because of some rules conflicts. + # We explicitly enabled even conflicting rules and are fixing the conflict + # in this file + included_file_warning: ignore + +linter: + rules: + ## Disabled rules because the repository doesn't respect them (yet) + + always_put_control_body_on_new_line: false + comment_references: false + prefer_constructors_over_static_methods: false + prefer_final_fields: false + prefer_final_locals: false + omit_local_variable_types: false + avoid_equals_and_hash_code_on_mutable_classes: false + + ############# + + # Personal preference. I don't find it more readable + cascade_invocations: false + + # Conflicts with `prefer_single_quotes` + # Single quotes are easier to type and don't compromise on readability. + prefer_double_quotes: false + + # Conflicts with `omit_local_variable_types` and other rules. + # As per Dart guidelines, we want to avoid unnecessary types to make the code + # more readable. + # See https://dart.dev/guides/language/effective-dart/design#avoid-type-annotating-initialized-local-variables + always_specify_types: false + + # Incompatible with `prefer_final_locals` + # Having immutable local variables makes larger functions more predictible + # so we will use `prefer_final_locals` instead. + unnecessary_final: false + + # Not quite suitable for Flutter, which may have a `build` method with a single + # return, but that return is still complex enough that a "body" is worth it. + prefer_expression_function_bodies: false + + # Conflicts with the convention used by flutter, which puts `Key key` + # and `@required Widget child` last. + always_put_required_named_parameters_first: false + + # This project doesn't use Flutter-style todos + flutter_style_todos: false + + # There are situations where we voluntarily want to catch everything, + # especially as a library. + avoid_catches_without_on_clauses: false + + # Boring as it sometimes force a line of 81 characters to be split in two. + # As long as we try to respect that 80 characters limit, going slightly + # above is fine. + lines_longer_than_80_chars: false + + # Conflicts with disabling `implicit-dynamic` + avoid_annotating_with_dynamic: false + + # conflicts with `prefer_relative_imports` + always_use_package_imports: false + + # Disabled for now until we have NNBD as it otherwise conflicts with `missing_return` + no_default_cases: false + + # False positive, null checks don't need a message + prefer_asserts_with_message: false + + # Cumbersome with `context.select` + avoid_types_on_closure_parameters: false + + # Too many false positive (builders) + diagnostic_describe_all_properties: false + + # false positives (setter-like functions) + avoid_positional_boolean_parameters: false + + # Does not apply to providers + prefer_const_constructors_in_immutables: false diff --git a/packages/firebase_vertexai/firebase_vertexai/.gitignore b/packages/firebase_vertexai/firebase_vertexai/.gitignore new file mode 100644 index 000000000000..ac5aa9893e48 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/.gitignore @@ -0,0 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ diff --git a/packages/firebase_vertexai/firebase_vertexai/.metadata b/packages/firebase_vertexai/firebase_vertexai/.metadata new file mode 100644 index 000000000000..f1665318eeba --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "b7e7d46a046ba8a22897a514bf2311a0f81ab198" + channel: "beta" + +project_type: package diff --git a/packages/firebase_vertexai/firebase_vertexai/CHANGELOG.md b/packages/firebase_vertexai/firebase_vertexai/CHANGELOG.md new file mode 100644 index 000000000000..08758edac505 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +- Initial public preview release. diff --git a/packages/firebase_vertexai/firebase_vertexai/LICENSE b/packages/firebase_vertexai/firebase_vertexai/LICENSE new file mode 100644 index 000000000000..e58143fccfb6 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 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. diff --git a/packages/firebase_vertexai/firebase_vertexai/README.md b/packages/firebase_vertexai/firebase_vertexai/README.md new file mode 100644 index 000000000000..ac6d9b84e48f --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/README.md @@ -0,0 +1,24 @@ +# Vertex AI for Firebase Flutter +[![pub package](https://img.shields.io/pub/v/firebase_vertexai.svg)](https://pub.dev/packages/firebase_vertexai) + +A Flutter plugin to use the [Vertex AI](https://firebase.google.com/docs/vertex-ai/). + +To learn more about Vertex AI, please visit the [website](https://cloud.google.com/vertex-ai) + +## Getting Started + +To get started with Vertex AI for Firebase Flutter, please [see the documentation](https://firebase.google.com/docs/vertex-ai/get-started?platform=flutter). + +## Usage + +To start use this plugin, please visit the [Text only prompt documentation](https://firebase.google.com/docs/vertex-ai/text-gen-from-text?platform=flutter) + +## Issues and feedback + +Please file FlutterFire specific issues, bugs, or feature requests in our [issue tracker](https://github.com/firebase/flutterfire/issues/new). + +Plugin issues that are not specific to FlutterFire can be filed in the [Flutter issue tracker](https://github.com/flutter/flutter/issues/new). + +To contribute a change to this plugin, +please review our [contribution guide](https://github.com/firebase/flutterfire/blob/master/CONTRIBUTING.md) +and open a [pull request](https://github.com/firebase/flutterfire/pulls). diff --git a/packages/firebase_vertexai/firebase_vertexai/example/.gitignore b/packages/firebase_vertexai/firebase_vertexai/example/.gitignore new file mode 100644 index 000000000000..db070ebdbf4f --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/.gitignore @@ -0,0 +1,48 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +#firebase +firebase_options.dart +google-services.json +GoogleService-Info.plist diff --git a/packages/firebase_vertexai/firebase_vertexai/example/.metadata b/packages/firebase_vertexai/firebase_vertexai/example/.metadata new file mode 100644 index 000000000000..6995524c80e1 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "b7e7d46a046ba8a22897a514bf2311a0f81ab198" + channel: "beta" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + base_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + - platform: android + create_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + base_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + - platform: ios + create_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + base_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + - platform: linux + create_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + base_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + - platform: macos + create_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + base_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + - platform: web + create_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + base_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + - platform: windows + create_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + base_revision: b7e7d46a046ba8a22897a514bf2311a0f81ab198 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/firebase_vertexai/firebase_vertexai/example/README.md b/packages/firebase_vertexai/firebase_vertexai/example/README.md new file mode 100644 index 000000000000..5cc7a3f01c7b --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/README.md @@ -0,0 +1,16 @@ +# firebase_vertexai_example + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/firebase_vertexai/firebase_vertexai/example/analysis_options.yaml b/packages/firebase_vertexai/firebase_vertexai/example/analysis_options.yaml new file mode 100644 index 000000000000..b6cd704fb940 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/analysis_options.yaml @@ -0,0 +1,10 @@ +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# in the LICENSE file. + +include: ../../../../analysis_options.yaml +linter: + rules: + avoid_print: false + depend_on_referenced_packages: false + library_private_types_in_public_api: false diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/.gitignore b/packages/firebase_vertexai/firebase_vertexai/example/android/.gitignore new file mode 100644 index 000000000000..6f568019d3c6 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/build.gradle b/packages/firebase_vertexai/firebase_vertexai/example/android/app/build.gradle new file mode 100644 index 000000000000..ca2ef836736c --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/build.gradle @@ -0,0 +1,58 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +// START: FlutterFire Configuration +apply plugin: 'com.google.gms.google-services' +// END: FlutterFire Configuration +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + namespace "com.example.example" + + compileSdk 33 + + defaultConfig { + applicationId "com.example.example" + minSdk 21 + targetSdk 33 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/debug/AndroidManifest.xml b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000000..399f6981d5d3 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/AndroidManifest.xml b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000000..aff7dec7b850 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 000000000000..70f8f08f2479 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000000..f74085f3f6a2 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/drawable/launch_background.xml b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000000..304732f88420 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000000..db77bb4b7b09 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000000..17987b79bb8a Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000000..09d4391482be Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000000..d5f1c8d34e7a Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000000..4d6372eebdb2 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/values-night/styles.xml b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000000..06952be745f9 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/values/styles.xml b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000000..cb1ef88056ed --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/profile/AndroidManifest.xml b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000000..399f6981d5d3 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/build.gradle b/packages/firebase_vertexai/firebase_vertexai/example/android/build.gradle new file mode 100644 index 000000000000..97c6de922a3d --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/build.gradle @@ -0,0 +1,32 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.1.2' + // START: FlutterFire Configuration + classpath 'com.google.gms:google-services:4.4.0' + // END: FlutterFire Configuration + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/gradle.properties b/packages/firebase_vertexai/firebase_vertexai/example/android/gradle.properties new file mode 100644 index 000000000000..598d13fee446 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/firebase_vertexai/firebase_vertexai/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000000..e1ca574ef017 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip diff --git a/packages/firebase_vertexai/firebase_vertexai/example/android/settings.gradle b/packages/firebase_vertexai/firebase_vertexai/example/android/settings.gradle new file mode 100644 index 000000000000..1d6d19b7f8ec --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/android/settings.gradle @@ -0,0 +1,26 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.10" apply false +} + +include ":app" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/assets/images/cat.jpg b/packages/firebase_vertexai/firebase_vertexai/example/assets/images/cat.jpg new file mode 100644 index 000000000000..8d2069e6c979 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/assets/images/cat.jpg differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/assets/images/scones.jpg b/packages/firebase_vertexai/firebase_vertexai/example/assets/images/scones.jpg new file mode 100644 index 000000000000..ce689588e871 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/assets/images/scones.jpg differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/.gitignore b/packages/firebase_vertexai/firebase_vertexai/example/ios/.gitignore new file mode 100644 index 000000000000..7a7f9873ad7d --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/AppFrameworkInfo.plist b/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000000..7c5696400627 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/Debug.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000000..ec97fc6f3021 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/Release.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000000..c4855bfe2000 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Podfile b/packages/firebase_vertexai/firebase_vertexai/example/ios/Podfile new file mode 100644 index 000000000000..d97f17e223fb --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.pbxproj b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..184f7769bf30 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,732 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3414F5B6C6F086F6373F1948 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5F1FA05866A2D0FCA3287B20 /* GoogleService-Info.plist */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 901FEC83A38129064032C578 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94CE5BFCDF90764354BB6740 /* Pods_Runner.framework */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + B7B3CA2D70F15615E1B8E5D8 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 154D9627A1C14A5ACE0B7B0D /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 154D9627A1C14A5ACE0B7B0D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 232D95ECCEC6F04B9CEC8925 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 560CA017EC76D8AAE2E21549 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 5F1FA05866A2D0FCA3287B20 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 8ACDC47C7E9AF1A1B9595598 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 94CE5BFCDF90764354BB6740 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A85D07EF8959748E1D3E564B /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + B0B22A9E291076BD22BA9F10 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + E1D0571EA0792087F8F27457 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0F5F3CD1ED7DB09B81C92173 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B7B3CA2D70F15615E1B8E5D8 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 901FEC83A38129064032C578 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 3C3B3E8596675CC144D1BD5B /* Pods */ = { + isa = PBXGroup; + children = ( + E1D0571EA0792087F8F27457 /* Pods-Runner.debug.xcconfig */, + 232D95ECCEC6F04B9CEC8925 /* Pods-Runner.release.xcconfig */, + 560CA017EC76D8AAE2E21549 /* Pods-Runner.profile.xcconfig */, + A85D07EF8959748E1D3E564B /* Pods-RunnerTests.debug.xcconfig */, + 8ACDC47C7E9AF1A1B9595598 /* Pods-RunnerTests.release.xcconfig */, + B0B22A9E291076BD22BA9F10 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 5F1FA05866A2D0FCA3287B20 /* GoogleService-Info.plist */, + 3C3B3E8596675CC144D1BD5B /* Pods */, + A50BECFB61A452F592070BAA /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + A50BECFB61A452F592070BAA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 94CE5BFCDF90764354BB6740 /* Pods_Runner.framework */, + 154D9627A1C14A5ACE0B7B0D /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + F5C7CFE0E232B64D613F0623 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + 0F5F3CD1ED7DB09B81C92173 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + F51794D56D63ACA383D5C2E4 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 123ADD1BD119276C98000FAF /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + 3414F5B6C6F086F6373F1948 /* GoogleService-Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 123ADD1BD119276C98000FAF /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + F51794D56D63ACA383D5C2E4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + F5C7CFE0E232B64D613F0623 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A85D07EF8959748E1D3E564B /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8ACDC47C7E9AF1A1B9595598 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B0B22A9E291076BD22BA9F10 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..919434a6254f --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000000..d5bcd6878b4e --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/AppDelegate.swift b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000000..70693e4a8c12 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000000..d36b1fab2d9d --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 000000000000..dc9ada4725e9 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 000000000000..7353c41ecf9c Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 000000000000..797d452e4589 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 000000000000..6ed2d933e112 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 000000000000..4cd7b0099ca8 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 000000000000..fe730945a01f Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 000000000000..321773cd857a Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 000000000000..797d452e4589 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 000000000000..502f463a9bc8 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 000000000000..0ec303439225 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 000000000000..0ec303439225 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 000000000000..e9f5fea27c70 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 000000000000..84ac32ae7d98 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 000000000000..8953cba09064 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 000000000000..0467bf12aa4d Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 000000000000..0bedcf2fd467 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 000000000000..9da19eacad3b Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 000000000000..9da19eacad3b Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 000000000000..9da19eacad3b Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000000..89c2725b70f1 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000000..f2e259c7c939 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Base.lproj/Main.storyboard b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000000..f3c28516fb38 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Info.plist b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Info.plist new file mode 100644 index 000000000000..5458fc4188bf --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Runner-Bridging-Header.h b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000000..308a2a560b42 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/ios/firebase_app_id_file.json b/packages/firebase_vertexai/firebase_vertexai/example/ios/firebase_app_id_file.json new file mode 100644 index 000000000000..59a23a1a01cc --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/ios/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:651313571784:ios:2f1472905da3e8e9b1c2fd", + "FIREBASE_PROJECT_ID": "vertex-ai-example-ef5a2", + "GCM_SENDER_ID": "651313571784" +} \ No newline at end of file diff --git a/packages/firebase_vertexai/firebase_vertexai/example/lib/main.dart b/packages/firebase_vertexai/firebase_vertexai/example/lib/main.dart new file mode 100644 index 000000000000..fa38bc930385 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/lib/main.dart @@ -0,0 +1,491 @@ +// Copyright 2024 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. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:firebase_vertexai/firebase_vertexai.dart'; +import 'package:firebase_core/firebase_core.dart'; + +void main() { + runApp(const GenerativeAISample()); +} + +class GenerativeAISample extends StatelessWidget { + const GenerativeAISample({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter + Vertex AI', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed( + brightness: Brightness.dark, + seedColor: const Color.fromARGB(255, 171, 222, 244), + ), + useMaterial3: true, + ), + home: const ChatScreen(title: 'Flutter + Vertex AI'), + ); + } +} + +class ChatScreen extends StatefulWidget { + const ChatScreen({super.key, required this.title}); + + final String title; + + @override + State createState() => _ChatScreenState(); +} + +class _ChatScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: const ChatWidget(), + ); + } +} + +class ChatWidget extends StatefulWidget { + const ChatWidget({ + super.key, + }); + + @override + State createState() => _ChatWidgetState(); +} + +class _ChatWidgetState extends State { + late final GenerativeModel _model; + late final GenerativeModel _functionCallModel; + late final ChatSession _chat; + final ScrollController _scrollController = ScrollController(); + final TextEditingController _textController = TextEditingController(); + final FocusNode _textFieldFocus = FocusNode(); + final List<({Image? image, String? text, bool fromUser})> _generatedContent = + <({Image? image, String? text, bool fromUser})>[]; + bool _loading = false; + + @override + void initState() { + super.initState(); + + initFirebase().then((value) { + _model = FirebaseVertexAI.instance.generativeModel( + model: 'gemini-1.5-pro-preview-0409', + ); + _functionCallModel = FirebaseVertexAI.instance.generativeModel( + model: 'gemini-1.5-pro-preview-0409', + tools: [ + Tool(functionDeclarations: [exchangeRateTool]), + ], + ); + _chat = _model.startChat(); + }); + } + + Future> findExchangeRate( + Map arguments, + ) async => + // This hypothetical API returns a JSON such as: + // {"base":"USD","date":"2024-04-17","rates":{"SEK": 0.091}} + { + 'date': arguments['currencyDate'], + 'base': arguments['currencyFrom'], + 'rates': {arguments['currencyTo']! as String: 0.091}, + }; + + final exchangeRateTool = FunctionDeclaration( + 'findExchangeRate', + 'Returns the exchange rate between currencies on given date.', + Schema( + SchemaType.object, + properties: { + 'currencyDate': Schema( + SchemaType.string, + description: 'A date in YYYY-MM-DD format or ' + 'the exact value "latest" if a time period is not specified.', + ), + 'currencyFrom': Schema( + SchemaType.string, + description: 'The currency code of the currency to convert from, ' + 'such as "USD".', + ), + 'currencyTo': Schema( + SchemaType.string, + description: 'The currency code of the currency to convert to, ' + 'such as "USD".', + ), + }, + ), + ); + + Future initFirebase() async { + await Firebase.initializeApp(); + } + + void _scrollDown() { + WidgetsBinding.instance.addPostFrameCallback( + (_) => _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: const Duration( + milliseconds: 750, + ), + curve: Curves.easeOutCirc, + ), + ); + } + + @override + Widget build(BuildContext context) { + final textFieldDecoration = InputDecoration( + contentPadding: const EdgeInsets.all(15), + hintText: 'Enter a prompt...', + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + Radius.circular(14), + ), + borderSide: BorderSide( + color: Theme.of(context).colorScheme.secondary, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: const BorderRadius.all( + Radius.circular(14), + ), + borderSide: BorderSide( + color: Theme.of(context).colorScheme.secondary, + ), + ), + ); + + return Padding( + padding: const EdgeInsets.all(8), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView.builder( + controller: _scrollController, + itemBuilder: (context, idx) { + var content = _generatedContent[idx]; + return MessageWidget( + text: content.text, + image: content.image, + isFromUser: content.fromUser, + ); + }, + itemCount: _generatedContent.length, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 25, + horizontal: 15, + ), + child: Row( + children: [ + Expanded( + child: TextField( + autofocus: true, + focusNode: _textFieldFocus, + decoration: textFieldDecoration, + controller: _textController, + onSubmitted: _sendChatMessage, + ), + ), + const SizedBox.square( + dimension: 15, + ), + IconButton( + tooltip: 'tokenCount Test', + onPressed: !_loading + ? () async { + await _testCountToken(); + } + : null, + icon: Icon( + Icons.numbers, + color: _loading + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.primary, + ), + ), + IconButton( + tooltip: 'function calling Test', + onPressed: !_loading + ? () async { + await _testFunctionCalling(); + } + : null, + icon: Icon( + Icons.functions, + color: _loading + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.primary, + ), + ), + IconButton( + tooltip: 'image prompt', + onPressed: !_loading + ? () async { + await _sendImagePrompt(_textController.text); + } + : null, + icon: Icon( + Icons.image, + color: _loading + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.primary, + ), + ), + if (!_loading) + IconButton( + onPressed: () async { + await _sendChatMessage(_textController.text); + }, + icon: Icon( + Icons.send, + color: Theme.of(context).colorScheme.primary, + ), + ) + else + const CircularProgressIndicator(), + ], + ), + ), + ], + ), + ); + } + + Future _sendImagePrompt(String message) async { + setState(() { + _loading = true; + }); + try { + ByteData catBytes = await rootBundle.load('assets/images/cat.jpg'); + ByteData sconeBytes = await rootBundle.load('assets/images/scones.jpg'); + final content = [ + Content.multi([ + TextPart(message), + // The only accepted mime types are image/*. + DataPart('image/jpeg', catBytes.buffer.asUint8List()), + DataPart('image/jpeg', sconeBytes.buffer.asUint8List()), + ]), + ]; + _generatedContent.add( + ( + image: Image.asset('assets/images/cat.jpg'), + text: message, + fromUser: true + ), + ); + _generatedContent.add( + ( + image: Image.asset('assets/images/scones.jpg'), + text: null, + fromUser: true + ), + ); + + var response = await _model.generateContent(content); + var text = response.text; + _generatedContent.add((image: null, text: text, fromUser: false)); + + if (text == null) { + _showError('No response from API.'); + return; + } else { + setState(() { + _loading = false; + _scrollDown(); + }); + } + } catch (e) { + _showError(e.toString()); + setState(() { + _loading = false; + }); + } finally { + _textController.clear(); + setState(() { + _loading = false; + }); + _textFieldFocus.requestFocus(); + } + } + + Future _sendChatMessage(String message) async { + setState(() { + _loading = true; + }); + + try { + _generatedContent.add((image: null, text: message, fromUser: true)); + var response = await _chat.sendMessage( + Content.text(message), + ); + var text = response.text; + _generatedContent.add((image: null, text: text, fromUser: false)); + + if (text == null) { + _showError('No response from API.'); + return; + } else { + setState(() { + _loading = false; + _scrollDown(); + }); + } + } catch (e) { + _showError(e.toString()); + setState(() { + _loading = false; + }); + } finally { + _textController.clear(); + setState(() { + _loading = false; + }); + _textFieldFocus.requestFocus(); + } + } + + Future _testFunctionCalling() async { + setState(() { + _loading = true; + }); + final chat = _functionCallModel.startChat(); + const prompt = 'How much is 50 US dollars worth in Swedish krona?'; + + // Send the message to the generative model. + var response = await chat.sendMessage(Content.text(prompt)); + + final functionCalls = response.functionCalls.toList(); + // When the model response with a function call, invoke the function. + if (functionCalls.isNotEmpty) { + final functionCall = functionCalls.first; + final result = switch (functionCall.name) { + // Forward arguments to the hypothetical API. + 'findExchangeRate' => await findExchangeRate(functionCall.args), + // Throw an exception if the model attempted to call a function that was + // not declared. + _ => throw UnimplementedError( + 'Function not implemented: ${functionCall.name}', + ) + }; + // Send the response to the model so that it can use the result to generate + // text for the user. + response = await chat + .sendMessage(Content.functionResponse(functionCall.name, result)); + } + // When the model responds with non-null text content, print it. + if (response.text case final text?) { + _generatedContent.add((image: null, text: text, fromUser: false)); + setState(() { + _loading = false; + }); + } + } + + Future _testCountToken() async { + setState(() { + _loading = true; + }); + + const prompt = 'tell a short story'; + var response = await _model.countTokens([Content.text(prompt)]); + print( + 'token: ${response.totalTokens}, billable characters: ${response.totalBillableCharacters}', + ); + + setState(() { + _loading = false; + }); + } + + void _showError(String message) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Something went wrong'), + content: SingleChildScrollView( + child: SelectableText(message), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('OK'), + ), + ], + ); + }, + ); + } +} + +class MessageWidget extends StatelessWidget { + final Image? image; + final String? text; + final bool isFromUser; + + const MessageWidget({ + super.key, + this.image, + this.text, + required this.isFromUser, + }); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: + isFromUser ? MainAxisAlignment.end : MainAxisAlignment.start, + children: [ + Flexible( + child: Container( + constraints: const BoxConstraints(maxWidth: 600), + decoration: BoxDecoration( + color: isFromUser + ? Theme.of(context).colorScheme.primaryContainer + : Theme.of(context).colorScheme.surfaceVariant, + borderRadius: BorderRadius.circular(18), + ), + padding: const EdgeInsets.symmetric( + vertical: 15, + horizontal: 20, + ), + margin: const EdgeInsets.only(bottom: 8), + child: Column( + children: [ + if (text case final text?) MarkdownBody(data: text), + if (image case final image?) image, + ], + ), + ), + ), + ], + ); + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/.gitignore b/packages/firebase_vertexai/firebase_vertexai/example/macos/.gitignore new file mode 100644 index 000000000000..746adbb6b9e1 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Flutter/Flutter-Debug.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000000..4b81f9b2d200 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Flutter/Flutter-Release.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000000..5caa9d1579e4 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Podfile b/packages/firebase_vertexai/firebase_vertexai/example/macos/Podfile new file mode 100644 index 000000000000..b52666a10389 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/project.pbxproj b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..98b78d959253 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,805 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 1E1464098F5197FB1E35FDA1 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E05DB31CC6D204C7C78D127 /* Pods_RunnerTests.framework */; }; + 20C13FC2C906153EF4A40292 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 08B0491E23641E5BA5DD096C /* GoogleService-Info.plist */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 3D1CF19370CB8E26E5C667A5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4DAA18FE8B79A454BF3F8CB /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08B0491E23641E5BA5DD096C /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; + 0E05DB31CC6D204C7C78D127 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3A40C9AE19ACEC6C433878E9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 587C61AFC0E2B0BF5340F8E8 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 5C2B5E4F1CE100E1FA5D9DC5 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 766A2E414AFDFA56243527A6 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 816B0EE72BF94FC5261D04E6 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A2911B8EF91B3925874FDE6A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + C4DAA18FE8B79A454BF3F8CB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E1464098F5197FB1E35FDA1 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D1CF19370CB8E26E5C667A5 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 08B0491E23641E5BA5DD096C /* GoogleService-Info.plist */, + BE277C424FC00920BE07E371 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + BE277C424FC00920BE07E371 /* Pods */ = { + isa = PBXGroup; + children = ( + A2911B8EF91B3925874FDE6A /* Pods-Runner.debug.xcconfig */, + 816B0EE72BF94FC5261D04E6 /* Pods-Runner.release.xcconfig */, + 766A2E414AFDFA56243527A6 /* Pods-Runner.profile.xcconfig */, + 3A40C9AE19ACEC6C433878E9 /* Pods-RunnerTests.debug.xcconfig */, + 587C61AFC0E2B0BF5340F8E8 /* Pods-RunnerTests.release.xcconfig */, + 5C2B5E4F1CE100E1FA5D9DC5 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C4DAA18FE8B79A454BF3F8CB /* Pods_Runner.framework */, + 0E05DB31CC6D204C7C78D127 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 33B83C0D35C3606AED8215FE /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + E10F886575A4AF9F1D3D5C5B /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 1D3525FBE401B81EB0265948 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + 20C13FC2C906153EF4A40292 /* GoogleService-Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 1D3525FBE401B81EB0265948 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33B83C0D35C3606AED8215FE /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + E10F886575A4AF9F1D3D5C5B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3A40C9AE19ACEC6C433878E9 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 587C61AFC0E2B0BF5340F8E8 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5C2B5E4F1CE100E1FA5D9DC5 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000000..b2775746f883 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/AppDelegate.swift b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/AppDelegate.swift new file mode 100644 index 000000000000..d53ef6437726 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000000..a2ec33f19f11 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 000000000000..82b6f9d9a33e Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 000000000000..13b35eba55c6 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 000000000000..0a3f5fa40fb3 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 000000000000..bdb57226d5f2 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 000000000000..f083318e09ca Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 000000000000..326c0e72c9d8 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 000000000000..2f1632cfddf3 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Base.lproj/MainMenu.xib b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 000000000000..80e867a4e06b --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/AppInfo.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000000..92fb3cd54e84 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.example + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved. diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Debug.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000000..36b0fd9464f4 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Release.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000000..dff4f49561c8 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Warnings.xcconfig b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000000..42bcbf4780b1 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/DebugProfile.entitlements b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000000..8e61fa50fdbb --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + com.apple.security.network.client + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Info.plist b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Info.plist new file mode 100644 index 000000000000..4789daa6a443 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/MainFlutterWindow.swift b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 000000000000..3cc05eb23491 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Release.entitlements b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Release.entitlements new file mode 100644 index 000000000000..852fa1a4728a --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/macos/firebase_app_id_file.json b/packages/firebase_vertexai/firebase_vertexai/example/macos/firebase_app_id_file.json new file mode 100644 index 000000000000..f4a21e85e553 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/macos/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:651313571784:ios:722e4f9cad0b9e5db1c2fd", + "FIREBASE_PROJECT_ID": "vertex-ai-example-ef5a2", + "GCM_SENDER_ID": "651313571784" +} \ No newline at end of file diff --git a/packages/firebase_vertexai/firebase_vertexai/example/pubspec.yaml b/packages/firebase_vertexai/firebase_vertexai/example/pubspec.yaml new file mode 100644 index 000000000000..f00aa68d2131 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/pubspec.yaml @@ -0,0 +1,40 @@ +name: vertex_ai_example +description: "Example project to show how to use the Vertex AI SDK." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +version: 1.0.0+1 + +environment: + sdk: '>=3.2.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.6 + firebase_core: ^2.27.0 + firebase_vertexai: ^0.0.1 + flutter: + sdk: flutter + flutter_markdown: ^0.6.20 + +dev_dependencies: + flutter_lints: ^3.0.0 + flutter_test: + sdk: flutter + +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + assets: + - assets/images/ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/web/favicon.png b/packages/firebase_vertexai/firebase_vertexai/example/web/favicon.png new file mode 100644 index 000000000000..8aaa46ac1ae2 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/web/favicon.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-192.png b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-192.png new file mode 100644 index 000000000000..b749bfef0747 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-192.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-512.png b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-512.png new file mode 100644 index 000000000000..88cfd48dff11 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-512.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-maskable-192.png b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-maskable-192.png new file mode 100644 index 000000000000..eb9b4d76e525 Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-maskable-192.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-maskable-512.png b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-maskable-512.png new file mode 100644 index 000000000000..d69c56691fbd Binary files /dev/null and b/packages/firebase_vertexai/firebase_vertexai/example/web/icons/Icon-maskable-512.png differ diff --git a/packages/firebase_vertexai/firebase_vertexai/example/web/index.html b/packages/firebase_vertexai/firebase_vertexai/example/web/index.html new file mode 100644 index 000000000000..45cf2ca304e4 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + + + + + diff --git a/packages/firebase_vertexai/firebase_vertexai/example/web/manifest.json b/packages/firebase_vertexai/firebase_vertexai/example/web/manifest.json new file mode 100644 index 000000000000..096edf8fe4cd --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/firebase_vertexai.dart b/packages/firebase_vertexai/firebase_vertexai/lib/firebase_vertexai.dart new file mode 100644 index 000000000000..21251bf1336b --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/firebase_vertexai.dart @@ -0,0 +1,36 @@ +// Copyright 2024 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. + +library firebase_vertexai; + +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:firebase_app_check/firebase_app_check.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart' + show FirebasePluginPlatform; +import 'package:google_generative_ai/google_generative_ai.dart' as google_ai; +// ignore: implementation_imports, tightly coupled packages +import 'package:google_generative_ai/src/model.dart' as google_ai_model; + +import 'src/vertex_version.dart'; + +part 'src/firebase_vertexai.dart'; +part 'src/vertex_api.dart'; +part 'src/vertex_chat.dart'; +part 'src/vertex_content.dart'; +part 'src/vertex_function_calling.dart'; +part 'src/vertex_model.dart'; diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/src/firebase_vertexai.dart b/packages/firebase_vertexai/firebase_vertexai/lib/src/firebase_vertexai.dart new file mode 100644 index 000000000000..f72df7a4a144 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/src/firebase_vertexai.dart @@ -0,0 +1,121 @@ +// Copyright 2024 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. + +part of firebase_vertexai; + +const _defaultLocation = 'us-central1'; + +/// Default timeout duration, 30 minutes in millisecond +const int defaultTimeout = 1800000; + +/// The entrypoint for [FirebaseVertexAI]. +class FirebaseVertexAI extends FirebasePluginPlatform { + FirebaseVertexAI._( + {required this.app, + required this.options, + required this.location, + this.appCheck}) + : super(app.name, 'plugins.flutter.io/firebase_vertexai'); + + /// The [FirebaseApp] for this current [FirebaseVertexAI] instance. + FirebaseApp app; + + /// The optional [FirebaseAppCheck] for this current [FirebaseVertexAI] instance. + /// https://firebase.google.com/docs/app-check + FirebaseAppCheck? appCheck; + + /// Configuration parameters for sending requests to the backend. + RequestOptions options; + + /// The service location for this [FirebaseVertexAI] instance. + String location; + + static final Map _cachedInstances = {}; + + /// Returns an instance using the default [FirebaseApp]. + static FirebaseVertexAI get instance { + return FirebaseVertexAI.instanceFor( + app: Firebase.app(), + ); + } + + /// Returns an instance using a specified [FirebaseApp]. + /// + /// If [app] is not provided, the default Firebase app will be used. + /// If pass in [appCheck], request session will get protected from abusing. + static FirebaseVertexAI instanceFor({ + FirebaseApp? app, + FirebaseAppCheck? appCheck, + RequestOptions? options, + String? location, + }) { + app ??= Firebase.app(); + + if (_cachedInstances.containsKey(app.name)) { + return _cachedInstances[app.name]!; + } + + options ??= + RequestOptions(timeout: const Duration(milliseconds: defaultTimeout)); + + location ??= _defaultLocation; + + FirebaseVertexAI newInstance = FirebaseVertexAI._( + app: app, options: options, location: location, appCheck: appCheck); + _cachedInstances[app.name] = newInstance; + + return newInstance; + } + + /// Create a [GenerativeModel] backed by the generative model named [model]. + /// + /// The [model] argument can be a model name (such as `'gemini-pro'`) or a + /// model code (such as `'models/gemini-pro'`). + /// There is no creation time check for whether the `model` string identifies + /// a known and supported model. If not, attempts to generate content + /// will fail. + /// + /// The optional [safetySettings] and [generationConfig] can be used to + /// control and guide the generation. See [SafetySetting] and + /// [GenerationConfig] for details. + GenerativeModel generativeModel( + {required String model, + List? safetySettings, + GenerationConfig? generationConfig, + Content? systemInstruction, + List? tools, + ToolConfig? toolConfig}) { + return GenerativeModel._( + model: model, + app: app, + appCheck: appCheck, + location: location, + safetySettings: safetySettings, + generationConfig: generationConfig, + systemInstruction: systemInstruction, + tools: tools, + toolConfig: toolConfig); + } +} + +/// Options for request to backend. +class RequestOptions { + /// [timeout] duration for the request. + RequestOptions({ + required this.timeout, + }); + + /// Timeout for the request, default to 30 minutes, in milliseconds. + final Duration timeout; +} diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_api.dart b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_api.dart new file mode 100644 index 000000000000..15b48f3e22ae --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_api.dart @@ -0,0 +1,1014 @@ +// Copyright 2024 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. + +part of firebase_vertexai; + +/// Response for Count Tokens +final class CountTokensResponse { + /// Constructor + CountTokensResponse(this.totalTokens, {this.totalBillableCharacters}); + factory CountTokensResponse._fromGoogleAICountTokensResponse( + google_ai.CountTokensResponse countTokensResponse) { + // comment out the functionality until the GoogleAI SDK updated to 0.3.4 + // if (countTokensResponse.extraFields != null) { + // return CountTokensResponse( + // countTokensResponse.totalTokens, + // totalBillableCharacters: + // countTokensResponse.extraFields?['totalBillableCharacters'] as int?, + // ); + // } else { + // return CountTokensResponse(countTokensResponse.totalTokens); + // } + return CountTokensResponse(countTokensResponse.totalTokens); + } + + /// The number of tokens that the `model` tokenizes the `prompt` into. + /// + /// Always non-negative. + final int totalTokens; + + /// The number of characters that the `model` could bill at. + /// + /// Always non-negative. + final int? totalBillableCharacters; +} + +/// Response from the model; supports multiple candidates. +final class GenerateContentResponse { + /// Constructor + GenerateContentResponse(this.candidates, this.promptFeedback); + + factory GenerateContentResponse._fromGoogleAIGenerateContentResponse( + google_ai.GenerateContentResponse generateContentResponse) => + GenerateContentResponse( + generateContentResponse.candidates + .map(Candidate._fromGoogleAICandidate) + .toList(), + generateContentResponse.promptFeedback != null + ? PromptFeedback._fromGoogleAIPromptFeedback( + generateContentResponse.promptFeedback!) + : null); + + /// Candidate responses from the model. + final List candidates; + + /// Returns the prompt's feedback related to the content filters. + final PromptFeedback? promptFeedback; + + /// Converts this response to a [GenerateContentResponse]. + + // ignore: unused_element + google_ai.GenerateContentResponse _toGoogleAIGenerateContentResponse() => + google_ai.GenerateContentResponse( + candidates + .map( + (candidate) => candidate._toGoogleAICandidate(), + ) + .toList(), + promptFeedback?._toGoogleAIPromptFeedback()); + + /// The text content of the first part of the first of [candidates], if any. + /// + /// If the prompt was blocked, or the first candidate was finished for a reason + /// of [FinishReason.recitation] or [FinishReason.safety], accessing this text + /// will throw a [GenerativeAIException]. + /// + /// If the first candidate's content starts with a text part, this value is + /// that text. + /// + /// If there are no candidates, or if the first candidate does not start with + /// a text part, this value is `null`. + String? get text { + return switch (candidates) { + [] => switch (promptFeedback) { + PromptFeedback( + :final blockReason, + :final blockReasonMessage, + ) => + // TODO: Add a specific subtype for this exception? + throw google_ai.GenerativeAIException('Response was blocked' + '${blockReason != null ? ' due to $blockReason' : ''}' + '${blockReasonMessage != null ? ': $blockReasonMessage' : ''}'), + _ => null, + }, + [ + Candidate( + finishReason: (FinishReason.recitation || FinishReason.safety) && + final finishReason, + :final finishMessage, + ), + ... + ] => + throw google_ai.GenerativeAIException( + // ignore: prefer_interpolation_to_compose_strings + 'Candidate was blocked due to $finishReason' + + (finishMessage != null && finishMessage.isNotEmpty + ? ': $finishMessage' + : ''), + ), + [Candidate(content: Content(parts: [TextPart(:final text)])), ...] => + text, + [Candidate(), ...] => null, + }; + } + + /// The function call parts of the first candidate in [candidates], if any. + /// + /// Returns an empty list if there are no candidates, or if the first + /// candidate has no [FunctionCall] parts. There is no error thrown if the + /// prompt or response were blocked. + Iterable get functionCalls => + candidates.firstOrNull?.content.parts.whereType() ?? + const []; +} + +/// Response for Embed Content. +final class EmbedContentResponse { + /// Constructor + EmbedContentResponse(this.embedding); + factory EmbedContentResponse._fromGoogleAIEmbedContentResponse( + google_ai.EmbedContentResponse embedContentResponse) => + EmbedContentResponse(ContentEmbedding._fromGoogleAIContentEmbedding( + embedContentResponse.embedding)); + + /// The embedding generated from the input content. + final ContentEmbedding embedding; + + /// Converts this response to a [EmbedContentResponse]. + // ignore: unused_element + google_ai.EmbedContentResponse _toGoogleAIEmbedContentResponse() => + google_ai.EmbedContentResponse(embedding._toGoogleAIContentEmbedding()); +} + +/// Response for Embed Content in batch. +final class BatchEmbedContentsResponse { + /// Constructor + BatchEmbedContentsResponse(this.embeddings); + + factory BatchEmbedContentsResponse._fromGoogleAIBatchEmbedContentsResponse( + google_ai.BatchEmbedContentsResponse embedContentResponse) => + BatchEmbedContentsResponse(embedContentResponse.embeddings + .map(ContentEmbedding._fromGoogleAIContentEmbedding) + .toList()); + + /// The embeddings generated from the input content for each request, in the + /// same order as provided in the batch request. + final List embeddings; +} + +/// Request for Embed Content. +final class EmbedContentRequest { + /// Constructor + EmbedContentRequest(this.content, {this.taskType, this.title, this.model}); + + /// The content to embed. + final Content content; + + /// The type of task to perform. + final TaskType? taskType; + + /// The title of the content. + final String? title; + + /// The model to use. + final String? model; + + /// Converts this request to a json object. + Object toJson({String? defaultModel}) => { + 'content': content.toJson(), + if (taskType case final taskType?) 'taskType': taskType.toJson(), + if (title != null) 'title': title, + if (model ?? defaultModel case final model?) 'model': model, + }; + + /// Converts this response to a [EmbedContentResponse]. + // ignore: unused_element + google_ai.EmbedContentRequest _toGoogleAIEmbedContentRequest() => + google_ai.EmbedContentRequest(content._toGoogleAIContent(), + taskType: taskType?._toGoogleAITaskType(), + title: title, + model: model); +} + +/// An embedding, as defined by a list of values. +final class ContentEmbedding { + /// Constructor + ContentEmbedding(this.values); + factory ContentEmbedding._fromGoogleAIContentEmbedding( + google_ai.ContentEmbedding contentEmbedding) => + ContentEmbedding(contentEmbedding.values); + + /// The embedding values. + final List values; + + /// Converts this embedding to a [google_ai.ContentEmbedding]. + google_ai.ContentEmbedding _toGoogleAIContentEmbedding() => + google_ai.ContentEmbedding(values); +} + +/// Feedback metadata of a prompt specified in a [GenerativeModel] request. +final class PromptFeedback { + /// Constructor + PromptFeedback(this.blockReason, this.blockReasonMessage, this.safetyRatings); + factory PromptFeedback._fromGoogleAIPromptFeedback( + google_ai.PromptFeedback promptFeedback) => + PromptFeedback( + promptFeedback.blockReason != null + ? BlockReason._fromGoogleAIBlockReason(promptFeedback.blockReason!) + : null, + promptFeedback.blockReasonMessage, + promptFeedback.safetyRatings + .map(SafetyRating._fromGoogleAISafetyRating) + .toList(), + ); + + /// If set, the prompt was blocked and no candidates are returned. + /// + /// Rephrase your prompt. + final BlockReason? blockReason; + + /// Message for the block reason. + final String? blockReasonMessage; + + /// Ratings for safety of the prompt. + /// + /// There is at most one rating per category. + final List safetyRatings; + + /// Converts this feedback to a [google_ai.PromptFeedback]. + google_ai.PromptFeedback _toGoogleAIPromptFeedback() => + google_ai.PromptFeedback( + blockReason?._toGoogleAIBlockReason(), + blockReasonMessage, + safetyRatings + .map((safetyRating) => safetyRating._toGoogleAISafetyRating()) + .toList(), + ); +} + +/// Response candidate generated from a [GenerativeModel]. +final class Candidate { + // TODO: token count? + /// Constructor + Candidate(this.content, this.safetyRatings, this.citationMetadata, + this.finishReason, this.finishMessage); + factory Candidate._fromGoogleAICandidate(google_ai.Candidate candidate) => + Candidate( + Content._fromGoogleAIContent(candidate.content), + candidate.safetyRatings + ?.map(SafetyRating._fromGoogleAISafetyRating) + .toList(), + candidate.citationMetadata != null + ? CitationMetadata._fromGoogleAICitationMetadata( + candidate.citationMetadata!) + : null, + candidate.finishReason != null + ? FinishReason._fromGoogleAIFinishReason(candidate.finishReason!) + : null, + candidate.finishMessage); + + /// Generated content returned from the model. + final Content content; + + /// List of ratings for the safety of a response candidate. + /// + /// There is at most one rating per category. + final List? safetyRatings; + + /// Citation information for model-generated candidate. + /// + /// This field may be populated with recitation information for any text + /// included in the [content]. These are passages that are "recited" from + /// copyrighted material in the foundational LLM's training data. + final CitationMetadata? citationMetadata; + + /// The reason why the model stopped generating tokens. + /// + /// If empty, the model has not stopped generating the tokens. + final FinishReason? finishReason; + + /// Message for finish reason. + final String? finishMessage; + + google_ai.Candidate _toGoogleAICandidate() => google_ai.Candidate( + content._toGoogleAIContent(), + safetyRatings?.map((s) => s._toGoogleAISafetyRating()).toList(), + citationMetadata?._toGoogleAICitationMetadata(), + finishReason?._toGoogleAIFinishReason(), + finishMessage, + ); +} + +/// Safety rating for a piece of content. +/// +/// The safety rating contains the category of harm and the harm probability +/// level in that category for a piece of content. Content is classified for +/// safety across a number of harm categories and the probability of the harm +/// classification is included here. +final class SafetyRating { + /// Constructor + SafetyRating(this.category, this.probability); + factory SafetyRating._fromGoogleAISafetyRating( + google_ai.SafetyRating safetyRating) => + SafetyRating( + HarmCategory._fromGoogleAIHarmCategory(safetyRating.category), + HarmProbability._fromGoogleAIHarmProbability( + safetyRating.probability)); + + /// The category for this rating. + final HarmCategory category; + + /// The probability of harm for this content. + final HarmProbability probability; + + /// Converts this rating to a [google_ai.SafetyRating]. + google_ai.SafetyRating _toGoogleAISafetyRating() => google_ai.SafetyRating( + category._toGoogleAIHarmCategory(), + probability._toGoogleAIHarmProbability()); +} + +/// The reason why a prompt was blocked. +enum BlockReason { + /// Default value to use when a blocking reason isn't set. + /// + /// Never used as the reason for blocking a prompt. + unspecified('BLOCK_REASON_UNSPECIFIED'), + + /// Prompt was blocked due to safety reasons. + /// + /// You can inspect `safetyRatings` to see which safety category blocked the + /// prompt. + safety('SAFETY'), + + /// Prompt was blocked due to other unspecified reasons. + other('OTHER'); + + const BlockReason(this._jsonString); + static BlockReason _parseValue(String jsonObject) { + return switch (jsonObject) { + 'BLOCK_REASON_UNSPECIFIED' => BlockReason.unspecified, + 'SAFETY' => BlockReason.safety, + 'OTHER' => BlockReason.other, + _ => throw FormatException('Unhandled BlockReason format', jsonObject), + }; + } + + static BlockReason _fromGoogleAIBlockReason( + google_ai.BlockReason googleAIBlockReason) { + return switch (googleAIBlockReason) { + google_ai.BlockReason.unspecified => BlockReason.unspecified, + google_ai.BlockReason.safety => BlockReason.safety, + google_ai.BlockReason.other => BlockReason.other, + }; + } + + /// Converts this blocking reason to a [google_ai.BlockReason]. + + google_ai.BlockReason _toGoogleAIBlockReason() { + return switch (this) { + BlockReason.unspecified => google_ai.BlockReason.unspecified, + BlockReason.safety => google_ai.BlockReason.safety, + BlockReason.other => google_ai.BlockReason.other + }; + } + + final String _jsonString; + + /// Convert to json format + String toJson() => _jsonString; + + @override + String toString() => name; +} + +/// The category of a rating. +/// +/// These categories cover various kinds of harms that developers may wish to +/// adjust. +enum HarmCategory { + /// Harm category is not specified. + unspecified('HARM_CATEGORY_UNSPECIFIED'), + + /// Malicious, intimidating, bullying, or abusive comments targeting another + /// individual. + harassment('HARM_CATEGORY_HARASSMENT'), + + /// Negative or harmful comments targeting identity and/or protected + /// attributes. + hateSpeech('HARM_CATEGORY_HATE_SPEECH'), + + /// Contains references to sexual acts or other lewd content. + sexuallyExplicit('HARM_CATEGORY_SEXUALLY_EXPLICIT'), + + /// Promotes or enables access to harmful goods, services, and activities. + dangerousContent('HARM_CATEGORY_DANGEROUS_CONTENT'); + + const HarmCategory(this._jsonString); + factory HarmCategory._fromGoogleAIHarmCategory( + google_ai.HarmCategory harmCategory) { + return switch (harmCategory) { + google_ai.HarmCategory.unspecified => HarmCategory.unspecified, + google_ai.HarmCategory.harassment => HarmCategory.harassment, + google_ai.HarmCategory.hateSpeech => HarmCategory.hateSpeech, + google_ai.HarmCategory.sexuallyExplicit => HarmCategory.sexuallyExplicit, + google_ai.HarmCategory.dangerousContent => HarmCategory.dangerousContent, + }; + } + static HarmCategory _parseValue(Object jsonObject) { + return switch (jsonObject) { + 'HARM_CATEGORY_UNSPECIFIED' => HarmCategory.unspecified, + 'HARM_CATEGORY_HARASSMENT' => HarmCategory.harassment, + 'HARM_CATEGORY_HATE_SPEECH' => HarmCategory.hateSpeech, + 'HARM_CATEGORY_SEXUALLY_EXPLICIT' => HarmCategory.sexuallyExplicit, + 'HARM_CATEGORY_DANGEROUS_CONTENT' => HarmCategory.dangerousContent, + _ => throw FormatException('Unhandled HarmCategory format', jsonObject), + }; + } + + @override + String toString() => name; + + final String _jsonString; + + /// Convert to json format. + String toJson() => _jsonString; + + /// Converts this harm category to a [google_ai.HarmCategory]. + + google_ai.HarmCategory _toGoogleAIHarmCategory() { + return switch (this) { + HarmCategory.unspecified => google_ai.HarmCategory.unspecified, + HarmCategory.harassment => google_ai.HarmCategory.harassment, + HarmCategory.hateSpeech => google_ai.HarmCategory.hateSpeech, + HarmCategory.sexuallyExplicit => google_ai.HarmCategory.sexuallyExplicit, + HarmCategory.dangerousContent => google_ai.HarmCategory.dangerousContent, + }; + } +} + +/// The probability that a piece of content is harmful. +/// +/// The classification system gives the probability of the content being unsafe. +/// This does not indicate the severity of harm for a piece of content. +enum HarmProbability { + /// Probability is unspecified. + unspecified('UNSPECIFIED'), + + /// Content has a negligible probability of being unsafe. + negligible('NEGLIGIBLE'), + + /// Content has a low probability of being unsafe. + low('LOW'), + + /// Content has a medium probability of being unsafe. + medium('MEDIUM'), + + /// Content has a high probability of being unsafe. + high('HIGH'); + + const HarmProbability(this._jsonString); + + factory HarmProbability._fromGoogleAIHarmProbability( + google_ai.HarmProbability harmProbability) { + return switch (harmProbability) { + google_ai.HarmProbability.unspecified => HarmProbability.unspecified, + google_ai.HarmProbability.negligible => HarmProbability.negligible, + google_ai.HarmProbability.low => HarmProbability.low, + google_ai.HarmProbability.medium => HarmProbability.medium, + google_ai.HarmProbability.high => HarmProbability.high, + }; + } + static HarmProbability _parseValue(Object jsonObject) { + return switch (jsonObject) { + 'UNSPECIFIED' => HarmProbability.unspecified, + 'NEGLIGIBLE' => HarmProbability.negligible, + 'LOW' => HarmProbability.low, + 'MEDIUM' => HarmProbability.medium, + 'HIGH' => HarmProbability.high, + _ => + throw FormatException('Unhandled HarmProbability format', jsonObject), + }; + } + + google_ai.HarmProbability _toGoogleAIHarmProbability() { + return switch (this) { + HarmProbability.unspecified => google_ai.HarmProbability.unspecified, + HarmProbability.negligible => google_ai.HarmProbability.negligible, + HarmProbability.low => google_ai.HarmProbability.low, + HarmProbability.medium => google_ai.HarmProbability.medium, + HarmProbability.high => google_ai.HarmProbability.high, + }; + } + + final String _jsonString; + + /// Convert to json format. + String toJson() => _jsonString; + + @override + String toString() => name; +} + +/// Source attributions for a piece of content. +final class CitationMetadata { + /// Constructor + CitationMetadata(this.citationSources); + factory CitationMetadata._fromGoogleAICitationMetadata( + google_ai.CitationMetadata citationMetadata) => + CitationMetadata(citationMetadata.citationSources + .map(CitationSource._fromGoogleAICitationSource) + .toList()); + + /// Citations to sources for a specific response. + final List citationSources; + + google_ai.CitationMetadata _toGoogleAICitationMetadata() => + google_ai.CitationMetadata( + citationSources.map((e) => e._toGoogleAICitationSource()).toList()); +} + +/// Citation to a source for a portion of a specific response. +final class CitationSource { + /// Constructor + CitationSource(this.startIndex, this.endIndex, this.uri, this.license); + factory CitationSource._fromGoogleAICitationSource( + google_ai.CitationSource source) => + CitationSource( + source.startIndex, source.endIndex, source.uri, source.license); + + /// Start of segment of the response that is attributed to this source. + /// + /// Index indicates the start of the segment, measured in bytes. + final int? startIndex; + + /// End of the attributed segment, exclusive. + final int? endIndex; + + /// URI that is attributed as a source for a portion of the text. + final Uri? uri; + + /// License for the GitHub project that is attributed as a source for segment. + /// + /// License info is required for code citations. + final String? license; + + google_ai.CitationSource _toGoogleAICitationSource() => + google_ai.CitationSource(startIndex, endIndex, uri, license); +} + +/// Reason why a model stopped generating tokens. +enum FinishReason { + /// Default value to use when a finish reason isn't set. + /// + /// Never used as the reason for finishing. + unspecified('UNSPECIFIED'), + + /// Natural stop point of the model or provided stop sequence. + stop('STOP'), + + /// The maximum number of tokens as specified in the request was reached. + maxTokens('MAX_TOKENS'), + + /// The candidate content was flagged for safety reasons. + safety('SAFETY'), + + /// The candidate content was flagged for recitation reasons. + recitation('RECITATION'), + + /// Unknown reason. + other('OTHER'); + + const FinishReason(this._jsonString); + + factory FinishReason._fromGoogleAIFinishReason( + google_ai.FinishReason finishReason) { + return switch (finishReason) { + google_ai.FinishReason.unspecified => FinishReason.unspecified, + google_ai.FinishReason.stop => FinishReason.stop, + google_ai.FinishReason.maxTokens => FinishReason.maxTokens, + google_ai.FinishReason.safety => FinishReason.safety, + google_ai.FinishReason.recitation => FinishReason.recitation, + google_ai.FinishReason.other => FinishReason.other, + }; + } + + google_ai.FinishReason _toGoogleAIFinishReason() { + return switch (this) { + FinishReason.unspecified => google_ai.FinishReason.unspecified, + FinishReason.stop => google_ai.FinishReason.stop, + FinishReason.maxTokens => google_ai.FinishReason.maxTokens, + FinishReason.safety => google_ai.FinishReason.safety, + FinishReason.recitation => google_ai.FinishReason.recitation, + FinishReason.other => google_ai.FinishReason.other, + }; + } + + final String _jsonString; + + /// Convert to json format + String toJson() => _jsonString; + + static FinishReason _parseValue(Object jsonObject) { + return switch (jsonObject) { + 'UNSPECIFIED' => FinishReason.unspecified, + 'STOP' => FinishReason.stop, + 'MAX_TOKENS' => FinishReason.maxTokens, + 'SAFETY' => FinishReason.safety, + 'RECITATION' => FinishReason.recitation, + 'OTHER' => FinishReason.other, + _ => throw FormatException('Unhandled FinishReason format', jsonObject), + }; + } + + @override + String toString() => name; +} + +/// Safety setting, affecting the safety-blocking behavior. +/// +/// Passing a safety setting for a category changes the allowed probability that +/// content is blocked. +final class SafetySetting { + /// Constructor + SafetySetting(this.category, this.threshold); + // ignore: unused_element + factory SafetySetting._fromGoogleAISafetySetting( + google_ai.SafetySetting setting) => + SafetySetting( + HarmCategory._fromGoogleAIHarmCategory(setting.category), + HarmBlockThreshold._fromGoogleAIHarmBlockThreshold( + setting.threshold)); + + /// The category for this setting. + final HarmCategory category; + + /// Controls the probability threshold at which harm is blocked. + final HarmBlockThreshold threshold; + + google_ai.SafetySetting _toGoogleAISafetySetting() => google_ai.SafetySetting( + category._toGoogleAIHarmCategory(), + threshold._toGoogleAIHarmBlockThreshold()); + + /// Convert to json format. + Object toJson() => + {'category': category.toJson(), 'threshold': threshold.toJson()}; +} + +/// Probability of harm which causes content to be blocked. +/// +/// When provided in [SafetySetting.threshold], a predicted harm probability at +/// or above this level will block content from being returned. +enum HarmBlockThreshold { + /// Threshold is unspecified, block using default threshold. + unspecified('HARM_BLOCK_THRESHOLD_UNSPECIFIED'), + + /// Block when medium or high probability of unsafe content. + low('BLOCK_LOW_AND_ABOVE'), + + /// Block when medium or high probability of unsafe content. + medium('BLOCK_MEDIUM_AND_ABOVE'), + + /// Block when high probability of unsafe content. + high('BLOCK_ONLY_HIGH'), + + /// Always show regardless of probability of unsafe content. + none('BLOCK_NONE'); + + const HarmBlockThreshold(this._jsonString); + factory HarmBlockThreshold._fromGoogleAIHarmBlockThreshold( + google_ai.HarmBlockThreshold threshold) { + return switch (threshold) { + google_ai.HarmBlockThreshold.unspecified => + HarmBlockThreshold.unspecified, + google_ai.HarmBlockThreshold.low => HarmBlockThreshold.low, + google_ai.HarmBlockThreshold.medium => HarmBlockThreshold.medium, + google_ai.HarmBlockThreshold.high => HarmBlockThreshold.high, + google_ai.HarmBlockThreshold.none => HarmBlockThreshold.none, + }; + } + // ignore: unused_element + static HarmBlockThreshold _parseValue(Object jsonObject) { + return switch (jsonObject) { + 'HARM_BLOCK_THRESHOLD_UNSPECIFIED' => HarmBlockThreshold.unspecified, + 'BLOCK_LOW_AND_ABOVE' => HarmBlockThreshold.low, + 'BLOCK_MEDIUM_AND_ABOVE' => HarmBlockThreshold.medium, + 'BLOCK_ONLY_HIGH' => HarmBlockThreshold.high, + 'BLOCK_NONE' => HarmBlockThreshold.none, + _ => throw FormatException( + 'Unhandled HarmBlockThreshold format', jsonObject), + }; + } + + final String _jsonString; + + google_ai.HarmBlockThreshold _toGoogleAIHarmBlockThreshold() { + return switch (this) { + HarmBlockThreshold.unspecified => + google_ai.HarmBlockThreshold.unspecified, + HarmBlockThreshold.low => google_ai.HarmBlockThreshold.low, + HarmBlockThreshold.medium => google_ai.HarmBlockThreshold.medium, + HarmBlockThreshold.high => google_ai.HarmBlockThreshold.high, + HarmBlockThreshold.none => google_ai.HarmBlockThreshold.none, + }; + } + + @override + String toString() => name; + + /// Convert to json format. + Object toJson() => _jsonString; +} + +/// Configuration options for model generation and outputs. +final class GenerationConfig { + /// Constructor + GenerationConfig( + {this.candidateCount, + this.stopSequences = const [], + this.maxOutputTokens, + this.temperature, + this.topP, + this.topK}); + + // ignore: unused_element + factory GenerationConfig._fromGoogleAIGenerationConfig( + google_ai.GenerationConfig config) => + GenerationConfig( + candidateCount: config.candidateCount, + stopSequences: config.stopSequences, + maxOutputTokens: config.maxOutputTokens, + temperature: config.temperature, + topP: config.topP, + topK: config.topK); + + /// Number of generated responses to return. + /// + /// This value must be between [1, 8], inclusive. If unset, this will default + /// to 1. + final int? candidateCount; + + /// The set of character sequences (up to 5) that will stop output generation. + /// + /// If specified, the API will stop at the first appearance of a stop + /// sequence. The stop sequence will not be included as part of the response. + final List stopSequences; + + /// The maximum number of tokens to include in a candidate. + /// + /// If unset, this will default to output_token_limit specified in the `Model` + /// specification. + final int? maxOutputTokens; + + /// Controls the randomness of the output. + /// + /// Note: The default value varies by model. + /// + /// Values can range from `[0.0, infinity]`, inclusive. A value temperature + /// must be greater than 0.0. + final double? temperature; + + /// The maximum cumulative probability of tokens to consider when sampling. + /// + /// The model uses combined Top-k and nucleus sampling. Tokens are sorted + /// based on their assigned probabilities so that only the most likely tokens + /// are considered. Top-k sampling directly limits the maximum number of + /// tokens to consider, while Nucleus sampling limits number of tokens based + /// on the cumulative probability. + /// + /// Note: The default value varies by model. + final double? topP; + + /// The maximum number of tokens to consider when sampling. + /// + /// The model uses combined Top-k and nucleus sampling. Top-k sampling + /// considers the set of `top_k` most probable tokens. Defaults to 40. + /// + /// Note: The default value varies by model. + final int? topK; + + /// Convert to json format + Map toJson() => { + if (candidateCount case final candidateCount?) + 'candidateCount': candidateCount, + if (stopSequences.isNotEmpty) 'stopSequences': stopSequences, + if (maxOutputTokens case final maxOutputTokens?) + 'maxOutputTokens': maxOutputTokens, + if (temperature case final temperature?) 'temperature': temperature, + if (topP case final topP?) 'topP': topP, + if (topK case final topK?) 'topK': topK, + }; + + google_ai.GenerationConfig _toGoogleAIGenerationConfig() => + google_ai.GenerationConfig( + candidateCount: candidateCount, + stopSequences: stopSequences, + maxOutputTokens: maxOutputTokens, + temperature: temperature, + topP: topP, + topK: topK); +} + +/// Type of task for which the embedding will be used. +enum TaskType { + /// Unset value, which will default to one of the other enum values. + unspecified('TASK_TYPE_UNSPECIFIED'), + + /// Specifies the given text is a query in a search/retrieval setting. + retrievalQuery('RETRIEVAL_QUERY'), + + /// Specifies the given text is a document from the corpus being searched. + retrievalDocument('RETRIEVAL_DOCUMENT'), + + /// Specifies the given text will be used for STS. + semanticSimilarity('SEMANTIC_SIMILARITY'), + + /// Specifies that the given text will be classified. + classification('CLASSIFICATION'), + + /// Specifies that the embeddings will be used for clustering. + clustering('CLUSTERING'); + + const TaskType(this._jsonString); + // ignore: unused_element + factory TaskType._fromGoogleAITaskType(google_ai.TaskType type) { + return switch (type) { + google_ai.TaskType.unspecified => TaskType.unspecified, + google_ai.TaskType.retrievalQuery => TaskType.retrievalQuery, + google_ai.TaskType.retrievalDocument => TaskType.retrievalDocument, + google_ai.TaskType.semanticSimilarity => TaskType.semanticSimilarity, + google_ai.TaskType.classification => TaskType.classification, + google_ai.TaskType.clustering => TaskType.clustering, + }; + } + + // ignore: unused_element + static TaskType _parseValue(Object jsonObject) { + return switch (jsonObject) { + 'TASK_TYPE_UNSPECIFIED' => TaskType.unspecified, + 'RETRIEVAL_QUERY' => TaskType.retrievalQuery, + 'RETRIEVAL_DOCUMENT' => TaskType.retrievalDocument, + 'SEMANTIC_SIMILARITY' => TaskType.semanticSimilarity, + 'CLASSIFICATION' => TaskType.classification, + 'CLUSTERING' => TaskType.clustering, + _ => throw FormatException('Unhandled TaskType format', jsonObject), + }; + } + + final String _jsonString; + + /// Convert to json format + Object toJson() => _jsonString; + google_ai.TaskType _toGoogleAITaskType() { + return switch (this) { + TaskType.unspecified => google_ai.TaskType.unspecified, + TaskType.retrievalQuery => google_ai.TaskType.retrievalQuery, + TaskType.retrievalDocument => google_ai.TaskType.retrievalDocument, + TaskType.semanticSimilarity => google_ai.TaskType.semanticSimilarity, + TaskType.classification => google_ai.TaskType.classification, + TaskType.clustering => google_ai.TaskType.clustering, + }; + } +} + +/// Parse to [GenerateContentResponse] from json object. +GenerateContentResponse parseGenerateContentResponse(Object jsonObject) { + return switch (jsonObject) { + {'candidates': final List candidates} => GenerateContentResponse( + candidates.map(_parseCandidate).toList(), + switch (jsonObject) { + {'promptFeedback': final promptFeedback?} => + _parsePromptFeedback(promptFeedback), + _ => null + }), + {'promptFeedback': final promptFeedback?} => + GenerateContentResponse([], _parsePromptFeedback(promptFeedback)), + _ => throw FormatException( + 'Unhandled GenerateContentResponse format', jsonObject) + }; +} + +/// Parse to [CountTokensResponse] from json object. +CountTokensResponse parseCountTokensResponse(Object jsonObject) { + return switch (jsonObject) { + {'totalTokens': final int totalTokens} => CountTokensResponse(totalTokens), + _ => + throw FormatException('Unhandled CountTokensResponse format', jsonObject) + }; +} + +/// Parse to [EmbedContentResponse] from json object. +EmbedContentResponse parseEmbedContentResponse(Object jsonObject) { + return switch (jsonObject) { + {'embedding': final Object embedding} => + EmbedContentResponse(_parseContentEmbedding(embedding)), + _ => + throw FormatException('Unhandled EmbedContentResponse format', jsonObject) + }; +} + +Candidate _parseCandidate(Object? jsonObject) { + if (jsonObject is! Map) { + throw FormatException('Unhandled Candidate format', jsonObject); + } + + return Candidate( + jsonObject.containsKey('content') + ? parseContent(jsonObject['content'] as Object) + : Content(null, []), + switch (jsonObject) { + {'safetyRatings': final List safetyRatings} => + safetyRatings.map(_parseSafetyRating).toList(), + _ => null + }, + switch (jsonObject) { + {'citationMetadata': final Object citationMetadata} => + _parseCitationMetadata(citationMetadata), + _ => null + }, + switch (jsonObject) { + {'finishReason': final Object finishReason} => + FinishReason._parseValue(finishReason), + _ => null + }, + switch (jsonObject) { + {'finishMessage': final String finishMessage} => finishMessage, + _ => null + }, + ); +} + +PromptFeedback _parsePromptFeedback(Object jsonObject) { + return switch (jsonObject) { + { + 'safetyRatings': final List safetyRatings, + } => + PromptFeedback( + switch (jsonObject) { + {'blockReason': final String blockReason} => + BlockReason._parseValue(blockReason), + _ => null, + }, + switch (jsonObject) { + {'blockReasonMessage': final String blockReasonMessage} => + blockReasonMessage, + _ => null, + }, + safetyRatings.map(_parseSafetyRating).toList()), + _ => throw FormatException('Unhandled PromptFeedback format', jsonObject), + }; +} + +SafetyRating _parseSafetyRating(Object? jsonObject) { + return switch (jsonObject) { + { + 'category': final Object category, + 'probability': final Object probability + } => + SafetyRating(HarmCategory._parseValue(category), + HarmProbability._parseValue(probability)), + _ => throw FormatException('Unhandled SafetyRating format', jsonObject), + }; +} + +ContentEmbedding _parseContentEmbedding(Object? jsonObject) { + return switch (jsonObject) { + {'values': final List values} => ContentEmbedding([ + ...values.cast(), + ]), + _ => throw FormatException('Unhandled ContentEmbedding format', jsonObject), + }; +} + +CitationMetadata _parseCitationMetadata(Object? jsonObject) { + return switch (jsonObject) { + {'citationSources': final List citationSources} => + CitationMetadata(citationSources.map(_parseCitationSource).toList()), + _ => throw FormatException('Unhandled CitationMetadata format', jsonObject), + }; +} + +CitationSource _parseCitationSource(Object? jsonObject) { + if (jsonObject is! Map) { + throw FormatException('Unhandled CitationSource format', jsonObject); + } + + final uriString = jsonObject['uri'] as String?; + + return CitationSource( + jsonObject['startIndex'] as int?, + jsonObject['endIndex'] as int?, + uriString != null ? Uri.parse(uriString) : null, + jsonObject['license'] as String?, + ); +} diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_chat.dart b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_chat.dart new file mode 100644 index 000000000000..af2cc2a14212 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_chat.dart @@ -0,0 +1,106 @@ +// // Copyright 2024 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. + +part of firebase_vertexai; + +/// A back-and-forth chat with a generative model. +/// +/// Records messages sent and received in [history]. The history will always +/// record the content from the first candidate in the +/// [GenerateContentResponse], other candidates may be available on the returned +/// response. +final class ChatSession { + /// Creates a new chat session with the provided model. + + ChatSession._(this._history, List? _safetySettings, + GenerationConfig? _generationConfig, GenerativeModel _model) + : _googleAIChatSession = _model._googleAIModel.startChat( + history: _history.map((e) => e._toGoogleAIContent()).toList(), + safetySettings: _safetySettings != null + ? _safetySettings + .map((setting) => setting._toGoogleAISafetySetting()) + .toList() + : [], + generationConfig: + GenerativeModel._googleAIGenerationConfig(_generationConfig)); + final List _history; + + final google_ai.ChatSession _googleAIChatSession; + + /// The content that has been successfully sent to, or received from, the + /// generative model. + /// + /// If there are outstanding requests from calls to [sendMessage] or + /// [sendMessageStream], these will not be reflected in the history. + /// Messages without a candidate in the response are not recorded in history, + /// including the message sent to the model. + Iterable get history => _history.skip(0); + + /// Sends [message] to the model as a continuation of the chat [history]. + /// + /// Prepends the history to the request and uses the provided model to + /// generate new content. + /// + /// When there are no candidates in the response, the [message] and response + /// are ignored and will not be recorded in the [history]. + /// + /// Waits for any ongoing or pending requests to [sendMessage] or + /// [sendMessageStream] to complete before generating new content. + /// Successful messages and responses for ongoing or pending requests will + /// be reflected in the history sent for this message. + Future sendMessage(Content message) async { + return _googleAIChatSession + .sendMessage(message._toGoogleAIContent()) + .then(GenerateContentResponse._fromGoogleAIGenerateContentResponse); + } + + /// Continues the chat with a new [message]. + /// + /// Sends [message] to the model as a continuation of the chat [history] and + /// reads the response in a stream. + /// Prepends the history to the request and uses the provided model to + /// generate new content. + /// + /// When there are no candidates in any response in the stream, the [message] + /// and responses are ignored and will not be recorded in the [history]. + /// + /// Waits for any ongoing or pending requests to [sendMessage] or + /// [sendMessageStream] to complete before generating new content. + /// Successful messages and responses for ongoing or pending requests will + /// be reflected in the history sent for this message. + /// + /// Waits to read the entire streamed response before recording the message + /// and response and allowing pending messages to be sent. + Stream sendMessageStream(Content message) { + return _googleAIChatSession + .sendMessageStream(message._toGoogleAIContent()) + .map(GenerateContentResponse._fromGoogleAIGenerateContentResponse); + } +} + +/// [StartChatExtension] on [GenerativeModel] +extension StartChatExtension on GenerativeModel { + /// Starts a [ChatSession] that will use this model to respond to messages. + /// + /// ```dart + /// final chat = model.startChat(); + /// final response = await chat.sendMessage(Content.text('Hello there.')); + /// print(response.text); + /// ``` + ChatSession startChat( + {List? history, + List? safetySettings, + GenerationConfig? generationConfig}) => + ChatSession._(history ?? [], safetySettings, generationConfig, this); +} diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_content.dart b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_content.dart new file mode 100644 index 000000000000..34636f3c7ab9 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_content.dart @@ -0,0 +1,193 @@ +// Copyright 2024 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. + +part of firebase_vertexai; + +/// The base structured datatype containing multi-part content of a message. +final class Content { + /// Constructor + Content(this.role, this.parts); + factory Content._fromGoogleAIContent(google_ai.Content content) => + Content(content.role, content.parts.map(Part._fromGoogleAIPart).toList()); + + /// The producer of the content. + /// + /// Must be either 'user' or 'model'. Useful to set for multi-turn + /// conversations, otherwise can be left blank or unset. + final String? role; + + /// Ordered `Parts` that constitute a single message. + /// + /// Parts may have different MIME types. + final List parts; + + /// Return a [Content] with [TextPart]. + static Content text(String text) => Content('user', [TextPart(text)]); + + /// Return a [Content] with [DataPart]. + static Content data(String mimeType, Uint8List bytes) => + Content('user', [DataPart(mimeType, bytes)]); + + /// Return a [Content] with multiple [Part]s. + static Content multi(Iterable parts) => Content('user', [...parts]); + + /// Return a [Content] with multiple [Part]s from the model. + static Content model(Iterable parts) => Content('model', [...parts]); + + /// Return a [Content] with [FunctionResponse]. + static Content functionResponse( + String name, Map? response) => + Content('function', [FunctionResponse(name, response)]); + + /// Return a [Content] with [TextPart] of system instruction. + static Content system(String instructions) => + Content('system', [TextPart(instructions)]); + + /// Convert the [Content] to json format. + Map toJson() => { + if (role case final role?) 'role': role, + 'parts': parts.map((p) => p.toJson()).toList() + }; + google_ai.Content _toGoogleAIContent() => + google_ai.Content(role, parts.map((p) => p.toPart()).toList()); +} + +/// Parse the [Content] from json object. +Content parseContent(Object jsonObject) { + return switch (jsonObject) { + {'parts': final List parts} => Content( + switch (jsonObject) { + {'role': final String role} => role, + _ => null, + }, + parts.map(_parsePart).toList()), + _ => throw FormatException('Unhandled Content format', jsonObject), + }; +} + +Part _parsePart(Object? jsonObject) { + return switch (jsonObject) { + {'text': final String text} => TextPart(text), + { + 'functionCall': { + 'name': final String name, + 'args': final Map args + } + } => + FunctionCall(name, args), + { + 'functionResponse': {'name': String _, 'response': Map _} + } => + throw UnimplementedError('FunctionResponse part not yet supported'), + {'inlineData': {'mimeType': String _, 'data': String _}} => + throw UnimplementedError('inlineData content part not yet supported'), + _ => throw FormatException('Unhandled Part format', jsonObject), + }; +} + +/// A datatype containing media that is part of a multi-part [Content] message. +sealed class Part { + factory Part._fromGoogleAIPart(google_ai.Part part) => switch (part) { + google_ai.TextPart textPart => TextPart(textPart.text), + google_ai.DataPart dataPart => + DataPart(dataPart.mimeType, dataPart.bytes), + google_ai.FilePart() => throw UnimplementedError(), + google_ai.FunctionCall functionCall => + FunctionCall(functionCall.name, functionCall.args), + google_ai.FunctionResponse functionResponse => + FunctionResponse(functionResponse.name, functionResponse.response), + }; + + /// Convert the [Part] content to json format. + Object toJson(); + + /// Convert the [Part] content to [google_ai.Part]. + google_ai.Part toPart(); +} + +/// A [Part] with the text content. +final class TextPart implements Part { + /// Constructor + TextPart(this.text); + + /// The text content of the [Part] + final String text; + @override + Object toJson() => {'text': text}; + @override + google_ai.Part toPart() => google_ai.TextPart(text); +} + +/// A [Part] with the byte content of a file. +final class DataPart implements Part { + /// Constructor + DataPart(this.mimeType, this.bytes); + + /// File type of the [DataPart]. + /// https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/send-multimodal-prompts#media_requirements + final String mimeType; + + /// Data contents in bytes. + final Uint8List bytes; + @override + Object toJson() => { + 'inlineData': {'data': base64Encode(bytes), 'mimeType': mimeType} + }; + @override + google_ai.Part toPart() => google_ai.DataPart(mimeType, bytes); +} + +/// A predicted `FunctionCall` returned from the model that contains +/// a string representing the `FunctionDeclaration.name` with the +/// arguments and their values. +final class FunctionCall implements Part { + /// Constructor + FunctionCall(this.name, this.args); + + /// The name of the function to call. + final String name; + + /// The function parameters and values. + final Map args; + + @override + // TODO: Do we need the wrapper object? + Object toJson() => { + 'functionCall': {'name': name, 'args': args} + }; + @override + google_ai.Part toPart() => google_ai.FunctionCall(name, args); +} + +/// The response class for [FunctionCall] +final class FunctionResponse implements Part { + /// Constructor + FunctionResponse(this.name, this.response); + + /// The name of the function that was called. + final String name; + + /// The function response. + /// + /// The values must be JSON compatible types; `String`, `num`, `bool`, `List` + /// of JSON compatibles types, or `Map` from String to JSON compatible types. + final Map? response; + + @override + Object toJson() => { + 'functionResponse': {'name': name, 'response': response} + }; + @override + google_ai.Part toPart() => google_ai.FunctionResponse(name, response); +} diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_function_calling.dart b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_function_calling.dart new file mode 100644 index 000000000000..e6ccb372ef91 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_function_calling.dart @@ -0,0 +1,293 @@ +// Copyright 2024 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. + +part of firebase_vertexai; + +/// Tool details that the model may use to generate a response. +/// +/// A `Tool` is a piece of code that enables the system to interact with +/// external systems to perform an action, or set of actions, outside of +/// knowledge and scope of the model. +final class Tool { + /// Constructor + Tool({this.functionDeclarations}); + + /// A list of `FunctionDeclarations` available to the model that can be used + /// for function calling. + /// + /// The model or system does not execute the function. Instead the defined + /// function may be returned as a [FunctionCall] with arguments to the client + /// side for execution. The next conversation turn may contain a + /// [FunctionResponse] + /// with the role "function" generation context for the next model turn. + final List? functionDeclarations; + + /// Convert to json object. + Map toJson() => { + if (functionDeclarations case final functionDeclarations?) + 'functionDeclarations': + functionDeclarations.map((f) => f.toJson()).toList(), + }; + + google_ai.Tool _toGoogleAITool() => google_ai.Tool( + functionDeclarations: functionDeclarations + ?.map((f) => f._toGoogleAIToolFunctionDeclaration()) + .toList(), + ); +} + +/// Structured representation of a function declaration as defined by the +/// [OpenAPI 3.03 specification](https://spec.openapis.org/oas/v3.0.3). +/// +/// Included in this declaration are the function name and parameters. This +/// FunctionDeclaration is a representation of a block of code that can be used +/// as a `Tool` by the model and executed by the client. +final class FunctionDeclaration { + /// Constructor + FunctionDeclaration(this.name, this.description, this.parameters); + + /// The name of the function. + /// + /// Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum + /// length of 63. + final String name; + + /// A brief description of the function. + final String description; + + /// The definition of an input or output data types. + final Schema? parameters; + + /// Convert to json object. + Map toJson() => { + 'name': name, + 'description': description, + if (parameters case final parameters?) 'parameters': parameters.toJson() + }; + + google_ai.FunctionDeclaration _toGoogleAIToolFunctionDeclaration() => + google_ai.FunctionDeclaration( + name, + description, + parameters?._toGoogleAIToolSchema(), + ); +} + +/// Config for tools to use with model. +final class ToolConfig { + /// Constructor + ToolConfig({this.functionCallingConfig}); + + /// Config for function calling. + final FunctionCallingConfig? functionCallingConfig; + + /// Convert to json object. + Map toJson() => { + if (functionCallingConfig case final config?) + 'functionCallingConfig': config.toJson(), + }; + google_ai.ToolConfig _toGoogleAIToolConfig() => google_ai.ToolConfig( + functionCallingConfig: + functionCallingConfig?._toGoogleAIFunctionCallingConfig(), + ); +} + +/// Configuration specifying how the model should use the functions provided as +/// tools. +final class FunctionCallingConfig { + /// Constructor + FunctionCallingConfig({this.mode, this.allowedFunctionNames}); + + /// The mode in which function calling should execute. + /// + /// If null, the default behavior will match [FunctionCallingMode.auto]. + final FunctionCallingMode? mode; + + /// A set of function names that, when provided, limits the functions the + /// model will call. + /// + /// This should only be set when the Mode is [FunctionCallingMode.any]. + /// Function names should match [FunctionDeclaration.name]. With mode set to + /// `any`, model will predict a function call from the set of function names + /// provided. + final Set? allowedFunctionNames; + + /// Convert to json object. + Object toJson() => { + if (mode case final mode?) 'mode': mode.toJson(), + if (allowedFunctionNames case final allowedFunctionNames?) + 'allowedFunctionNames': allowedFunctionNames.toList(), + }; + + google_ai.FunctionCallingConfig _toGoogleAIFunctionCallingConfig() => + google_ai.FunctionCallingConfig( + mode: mode?._toGoogleAIFunctionCallingMode(), + allowedFunctionNames: allowedFunctionNames?.toSet(), + ); +} + +/// The mode in which the model should use the functions provided as tools. +enum FunctionCallingMode { + /// The mode with default model behavior. + /// + /// Model decides to predict either a function call or a natural language + /// response. + auto, + + /// A mode where the Model is constrained to always predicting a function + /// call only. + any, + + /// A mode where the model will not predict any function call. + /// + /// Model behavior is same as when not passing any function declarations. + none; + + /// Convert to json object. + String toJson() => switch (this) { + auto => 'AUTO', + any => 'ANY', + none => 'NONE', + }; + + google_ai.FunctionCallingMode _toGoogleAIFunctionCallingMode() => + switch (this) { + auto => google_ai.FunctionCallingMode.auto, + any => google_ai.FunctionCallingMode.any, + none => google_ai.FunctionCallingMode.none, + }; +} + +/// The definition of an input or output data types. +/// +/// These types can be objects, but also primitives and arrays. +/// Represents a select subset of an +/// [OpenAPI 3.0 schema object](https://spec.openapis.org/oas/v3.0.3#schema). +final class Schema { + // TODO: Add named constructors for the types? + /// Constructor + Schema( + this.type, { + this.format, + this.description, + this.nullable, + this.enumValues, + this.items, + this.properties, + this.requiredProperties, + }); + + /// The type of this value. + SchemaType type; + + /// The format of the data. + /// + /// This is used only for primitive datatypes. + /// + /// Supported formats: + /// for [SchemaType.number] type: float, double + /// for [SchemaType.integer] type: int32, int64 + /// for [SchemaType.string] type: enum. See [enumValues] + String? format; + + /// A brief description of the parameter. + /// + /// This could contain examples of use. + /// Parameter description may be formatted as Markdown. + String? description; + + /// Whether the value mey be null. + bool? nullable; + + /// Possible values if this is a [SchemaType.string] with an enum format. + List? enumValues; + + /// Schema for the elements if this is a [SchemaType.array]. + Schema? items; + + /// Properties of this type if this is a [SchemaType.object]. + Map? properties; + + /// The keys from [properties] for properties that are required if this is a + /// [SchemaType.object]. + List? requiredProperties; + + /// Convert to json object. + Map toJson() => { + 'type': type.toJson(), + if (format case final format?) 'format': format, + if (description case final description?) 'description': description, + if (nullable case final nullable?) 'nullable': nullable, + if (enumValues case final enumValues?) 'enum': enumValues, + if (items case final items?) 'items': items.toJson(), + if (properties case final properties?) + 'properties': { + for (final MapEntry(:key, :value) in properties.entries) + key: value.toJson() + }, + if (requiredProperties case final requiredProperties?) + 'required': requiredProperties + }; + + google_ai.Schema _toGoogleAIToolSchema() => google_ai.Schema( + type._toGoogleAIToolSchemaType(), + format: format, + description: description, + nullable: nullable, + enumValues: enumValues, + items: items?._toGoogleAIToolSchema(), + properties: properties + ?.map((key, value) => MapEntry(key, value._toGoogleAIToolSchema())), + requiredProperties: requiredProperties); +} + +/// The value type of a [Schema]. +enum SchemaType { + /// string type. + string, + + /// number type + number, + + /// integer type + integer, + + /// boolean type + boolean, + + /// array type + array, + + /// object type + object; + + /// Convert to json object. + String toJson() => switch (this) { + string => 'STRING', + number => 'NUMBER', + integer => 'INTEGER', + boolean => 'BOOLEAN', + array => 'ARRAY', + object => 'OBJECT', + }; + + google_ai.SchemaType _toGoogleAIToolSchemaType() => switch (this) { + string => google_ai.SchemaType.string, + number => google_ai.SchemaType.number, + integer => google_ai.SchemaType.integer, + boolean => google_ai.SchemaType.boolean, + array => google_ai.SchemaType.array, + object => google_ai.SchemaType.object, + }; +} diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_model.dart b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_model.dart new file mode 100644 index 000000000000..790e97c388df --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_model.dart @@ -0,0 +1,233 @@ +// Copyright 2024 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. + +// ignore_for_file: use_late_for_private_fields_and_variables + +part of firebase_vertexai; + +const _baseUrl = 'firebaseml.googleapis.com'; +const _apiVersion = 'v2beta'; + +/// A multimodel generative model (like Gemini). +/// +/// Allows generating content, creating embeddings, and counting the number of +/// tokens in a piece of content. +final class GenerativeModel { + /// Create a [GenerativeModel] backed by the generative model named [model]. + /// + /// The [model] argument can be a model name (such as `'gemini-pro'`) or a + /// model code (such as `'models/gemini-pro'`). + /// There is no creation time check for whether the `model` string identifies + /// a known and supported model. If not, attempts to generate content + /// will fail. + /// + /// The optional [safetySettings] and [generationConfig] can be used to + /// control and guide the generation. See [SafetySetting] and + /// [GenerationConfig] for details. + /// + GenerativeModel._({ + required String model, + required String location, + required FirebaseApp app, + FirebaseAppCheck? appCheck, + List? safetySettings, + GenerationConfig? generationConfig, + List? tools, + Content? systemInstruction, + ToolConfig? toolConfig, + }) : _firebaseApp = app, + _googleAIModel = google_ai_model.createModelWithBaseUri( + model: _normalizeModelName(model), + apiKey: app.options.apiKey, + baseUri: _vertexUri(app, location), + requestHeaders: _appCheckToken(appCheck), + safetySettings: safetySettings != null + ? safetySettings + .map((setting) => setting._toGoogleAISafetySetting()) + .toList() + : [], + generationConfig: generationConfig?._toGoogleAIGenerationConfig(), + systemInstruction: systemInstruction?._toGoogleAIContent(), + tools: tools != null + ? tools.map((tool) => tool._toGoogleAITool()).toList() + : [], + toolConfig: toolConfig?._toGoogleAIToolConfig(), + ); + final FirebaseApp _firebaseApp; + final google_ai_model.GenerativeModel _googleAIModel; + + static const _modelsPrefix = 'models/'; + static String _normalizeModelName(String modelName) => + modelName.startsWith(_modelsPrefix) + ? modelName.substring(_modelsPrefix.length) + : modelName; + + static Uri _vertexUri(FirebaseApp app, String location) { + var projectId = app.options.projectId; + return Uri.https( + _baseUrl, + '/$_apiVersion/projects/$projectId/locations/$location/publishers/google', + ); + } + + static google_ai.GenerationConfig _convertGenerationConfig( + GenerationConfig? config, FirebaseApp app) { + if (config == null) { + return google_ai.GenerationConfig(); + } else { + return config._toGoogleAIGenerationConfig(); + } + } + + static FutureOr> Function() _appCheckToken( + FirebaseAppCheck? appCheck) { + return () async { + Map headers = {}; + // Override the client name in Google AI SDK + headers['x-goog-api-client'] = 'gl-dart/flutter fire/$packageVersion'; + if (appCheck != null) { + final token = await appCheck.getToken(); + if (token != null) { + headers['X-Firebase-AppCheck'] = token; + } + } + return headers; + }; + } + + static google_ai.GenerationConfig? _googleAIGenerationConfig( + GenerationConfig? config) { + return config?._toGoogleAIGenerationConfig(); + } + + /// Generates content responding to [prompt]. + /// + /// Sends a "generateContent" API request for the configured model, + /// and waits for the response. + /// + /// Example: + /// ```dart + /// final response = await model.generateContent([Content.text(prompt)]); + /// print(response.text); + /// ``` + Future generateContent(Iterable prompt, + {List? safetySettings, + GenerationConfig? generationConfig}) async { + Iterable googlePrompt = + prompt.map((content) => content._toGoogleAIContent()); + List googleSafetySettings = safetySettings != null + ? safetySettings + .map((setting) => setting._toGoogleAISafetySetting()) + .toList() + : []; + return _googleAIModel + .generateContent(googlePrompt, + safetySettings: googleSafetySettings, + generationConfig: + _convertGenerationConfig(generationConfig, _firebaseApp)) + .then(GenerateContentResponse._fromGoogleAIGenerateContentResponse); + } + + /// Generates a stream of content responding to [prompt]. + /// + /// Sends a "streamGenerateContent" API request for the configured model, + /// and waits for the response. + /// + /// Example: + /// ```dart + /// final responses = await model.generateContent([Content.text(prompt)]); + /// await for (final response in responses) { + /// print(response.text); + /// } + /// ``` + Stream generateContentStream( + Iterable prompt, + {List? safetySettings, + GenerationConfig? generationConfig}) { + return _googleAIModel + .generateContentStream( + prompt.map((content) => content._toGoogleAIContent()), + safetySettings: safetySettings != null + ? safetySettings + .map((setting) => setting._toGoogleAISafetySetting()) + .toList() + : [], + generationConfig: generationConfig?._toGoogleAIGenerationConfig()) + .map(GenerateContentResponse._fromGoogleAIGenerateContentResponse); + } + + /// Counts the total number of tokens in [contents]. + /// + /// Sends a "countTokens" API request for the configured model, + /// and waits for the response. + /// + /// Example: + /// ```dart + /// final promptContent = [Content.text(prompt)]; + /// final totalTokens = + /// (await model.countTokens(promptContent)).totalTokens; + /// if (totalTokens > maxPromptSize) { + /// print('Prompt is too long!'); + /// } else { + /// final response = await model.generateContent(promptContent); + /// print(response.text); + /// } + /// ``` + Future countTokens(Iterable contents) async { + return _googleAIModel + .countTokens(contents.map((e) => e._toGoogleAIContent())) + .then(CountTokensResponse._fromGoogleAICountTokensResponse); + } + + /// Creates an embedding (list of float values) representing [content]. + /// + /// Sends a "embedContent" API request for the configured model, + /// and waits for the response. + /// + /// Example: + /// ```dart + /// final promptEmbedding = + /// (await model.embedContent([Content.text(prompt)])).embedding.values; + /// ``` + Future embedContent(Content content, + {TaskType? taskType, String? title}) async { + return _googleAIModel + .embedContent(content._toGoogleAIContent(), + taskType: taskType?._toGoogleAITaskType(), title: title) + .then(EmbedContentResponse._fromGoogleAIEmbedContentResponse); + } + + /// Creates embeddings (list of float values) representing each content in + /// [requests]. + /// + /// Sends a "batchEmbedContents" API request for the configured model. + /// + /// Example: + /// ```dart + /// final requests = [ + /// EmbedContentRequest(Content.text(first)), + /// EmbedContentRequest(Content.text(second)) + /// ]; + /// final promptEmbeddings = + /// (await model.embedContent(requests)).embedding.values; + /// ``` + Future batchEmbedContents( + Iterable requests) async { + return _googleAIModel + .batchEmbedContents( + requests.map((e) => e._toGoogleAIEmbedContentRequest())) + .then( + BatchEmbedContentsResponse._fromGoogleAIBatchEmbedContentsResponse); + } +} diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_version.dart b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_version.dart new file mode 100644 index 000000000000..abeed350f9a9 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/lib/src/vertex_version.dart @@ -0,0 +1,16 @@ +// Copyright 2024 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. + +/// version number for the package, should be align with pubspec.yaml. +const packageVersion = '0.0.1'; diff --git a/packages/firebase_vertexai/firebase_vertexai/pubspec.yaml b/packages/firebase_vertexai/firebase_vertexai/pubspec.yaml new file mode 100644 index 000000000000..1d33a3016bbc --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/pubspec.yaml @@ -0,0 +1,23 @@ +name: firebase_vertexai +description: "Firebase Vertex AI SDK." +version: 0.0.1 +homepage: https://firebase.google.com/docs/vertex-ai/get-started?platform=flutter + +environment: + sdk: '>=3.2.0 <4.0.0' + flutter: ">=3.16.0" + +dependencies: + firebase_app_check: ^0.2.1+16 + firebase_core: ^2.26.0 + firebase_core_platform_interface: ^5.0.0 + flutter: + sdk: flutter + google_generative_ai: ^0.3.3 + +dev_dependencies: + flutter_lints: ^3.0.0 + flutter_test: + sdk: flutter + mockito: ^5.0.0 + plugin_platform_interface: ^2.1.3 diff --git a/packages/firebase_vertexai/firebase_vertexai/test/firebase_vertexai_test.dart b/packages/firebase_vertexai/firebase_vertexai/test/firebase_vertexai_test.dart new file mode 100644 index 000000000000..0c8946d8f00f --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/test/firebase_vertexai_test.dart @@ -0,0 +1,82 @@ +// Copyright 2024 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. + +import 'package:firebase_app_check/firebase_app_check.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_vertexai/firebase_vertexai.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'vertex_mock.dart'; + +void main() { + setupFirebaseVertexAIMocks(); + // ignore: unused_local_variable + late FirebaseApp app; + // ignore: unused_local_variable + late FirebaseAppCheck appCheck; + late FirebaseApp customApp; + late FirebaseAppCheck customAppCheck; + + group('FirebaseVertexAI Tests', () { + late FirebaseApp app; + + setUpAll(() async { + // Initialize Firebase + app = await Firebase.initializeApp(); + customApp = await Firebase.initializeApp( + name: 'custom-app', + options: Firebase.app().options, + ); + appCheck = FirebaseAppCheck.instance; + customAppCheck = FirebaseAppCheck.instanceFor(app: customApp); + }); + + test('Singleton behavior', () { + final instance1 = FirebaseVertexAI.instance; + final instance2 = FirebaseVertexAI.instanceFor(app: app); + expect(identical(instance1, instance2), isTrue); + }); + + test('Instance creation with defaults', () { + final vertexAI = FirebaseVertexAI.instanceFor(app: app); + expect(vertexAI.app, equals(app)); + expect(vertexAI.location, equals('us-central1')); + expect(vertexAI.options.timeout.inMilliseconds, equals(defaultTimeout)); + }); + + test('Instance creation with custom', () { + final vertexAI = FirebaseVertexAI.instanceFor( + app: customApp, + appCheck: customAppCheck, + location: 'custom-location'); + expect(vertexAI.app, equals(customApp)); + expect(vertexAI.appCheck, equals(customAppCheck)); + expect(vertexAI.location, equals('custom-location')); + }); + + test('generativeModel creation', () { + final vertexAI = FirebaseVertexAI.instance; + + final model = vertexAI.generativeModel( + model: 'gemini-pro', + generationConfig: GenerationConfig(maxOutputTokens: 1024), + systemInstruction: Content.system('You are a helpful assistant.'), + ); + + expect(model, isA()); + }); + + // ... other tests (e.g., with different parameters) + }); +} diff --git a/packages/firebase_vertexai/firebase_vertexai/test/vertex_content_test.dart b/packages/firebase_vertexai/firebase_vertexai/test/vertex_content_test.dart new file mode 100644 index 000000000000..033fb4f06af0 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/test/vertex_content_test.dart @@ -0,0 +1,176 @@ +// Copyright 2024 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. + +import 'dart:typed_data'; + +import 'package:firebase_vertexai/firebase_vertexai.dart'; // Your library +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_generative_ai/google_generative_ai.dart' as google_ai; + +// Mock google_ai classes (if needed) +// ... + +void main() { + group('Content tests', () { + test('constructor', () { + final content = Content( + 'user', [TextPart('Test'), DataPart('image/png', Uint8List(0))]); + expect(content.role, 'user'); + expect(content.parts[0], isA()); + expect((content.parts[0] as TextPart).text, 'Test'); + expect(content.parts[1], isA()); + expect((content.parts[1] as DataPart).mimeType, 'image/png'); + expect((content.parts[1] as DataPart).bytes.length, 0); + }); + + test('text()', () { + final content = Content('user', [TextPart('Test')]); + expect(content.role, 'user'); + expect(content.parts[0], isA()); + }); + + test('data()', () { + final content = Content('user', [DataPart('image/png', Uint8List(0))]); + expect(content.parts[0], isA()); + }); + + test('multi()', () { + final content = Content( + 'user', [TextPart('Test'), DataPart('image/png', Uint8List(0))]); + expect(content.parts.length, 2); + expect(content.parts[0], isA()); + expect(content.parts[1], isA()); + }); + + test('toJson', () { + final content = Content( + 'user', [TextPart('Test'), DataPart('image/png', Uint8List(0))]); + final json = content.toJson(); + expect(json['role'], 'user'); + expect((json['parts']! as List).length, 2); + expect((json['parts']! as List)[0]['text'], 'Test'); + expect( + (json['parts']! as List)[1]['inlineData']['mimeType'], 'image/png'); + expect((json['parts']! as List)[1]['inlineData']['data'].length, 0); + // ... verify json structure + }); + + test('parseContent', () { + final json = { + 'role': 'user', + 'parts': [ + {'text': 'Hello'}, + ] + }; + final content = parseContent(json); + expect(content.role, 'user'); + expect(content.parts.length, 1); + expect(content.parts[0], isA()); + expect(reason: 'TextPart', (content.parts[0] as TextPart).text, 'Hello'); + // ... verify content + }); + + // ... additional tests for edge cases (e.g., null role, empty parts list) + }); + + group('Part tests', () { + test('TextPart toJson', () { + final part = TextPart('Test'); + final json = part.toJson(); + expect((json as Map)['text'], 'Test'); + // ... verify json structure + }); + + test('TextPart toPart', () { + final part = TextPart('Test'); + final newPart = part.toPart(); + expect(newPart, isA()); + expect((newPart as google_ai.TextPart).text, 'Test'); + }); + + test('DataPart toJson', () { + final part = DataPart('image/png', Uint8List(0)); + final json = part.toJson(); + expect((json as Map)['inlineData']['mimeType'], 'image/png'); + expect(json['inlineData']['data'], ''); + // ... verify json structure + }); + + test('DataPart toPart', () { + final part = DataPart('image/png', Uint8List(0)); + final newPart = part.toPart(); + expect(newPart, isA()); + expect((newPart as google_ai.DataPart).mimeType, 'image/png'); + expect(newPart.bytes.length, 0); + }); + + test('FunctionCall toJson', () { + final part = FunctionCall('myFunction', { + 'arguments': [ + {'text': 'Test'} + ] + }); + final json = part.toJson(); + expect((json as Map)['functionCall']['name'], 'myFunction'); + expect(json['functionCall']['args'].length, 1); + expect(json['functionCall']['args']['arguments'].length, 1); + expect(json['functionCall']['args']['arguments'][0]['text'], 'Test'); + // ... verify json structure + }); + + test('FunctionCall toPart', () { + final part = FunctionCall('myFunction', { + 'arguments': [ + {'text': 'Test'} + ] + }); + final newPart = part.toPart(); + expect(newPart, isA()); + expect((newPart as google_ai.FunctionCall).name, 'myFunction'); + expect(newPart.args.length, 1); + expect((newPart.args['arguments']! as List).length, 1); + expect((newPart.args['arguments']! as List)[0]['text'], 'Test'); + }); + + test('FunctionResponse toJson', () { + final part = FunctionResponse('myFunction', { + 'inlineData': { + 'mimeType': 'application/octet-stream', + 'data': Uint8List(0) + } + }); + final json = part.toJson(); + expect((json as Map)['functionResponse']['name'], 'myFunction'); + expect(json['functionResponse']['response']['inlineData']['mimeType'], + 'application/octet-stream'); + expect(json['functionResponse']['response']['inlineData']['data'], + Uint8List(0)); + + // ... verify json structure + }); + + test('FunctionResponse toPart', () { + final part = FunctionResponse('myFunction', { + 'inlineData': { + 'mimeType': 'application/octet-stream', + 'data': Uint8List(0) + } + }); + final newPart = part.toPart(); + expect(newPart, isA()); + expect((newPart as google_ai.FunctionResponse).name, 'myFunction'); + expect(newPart.response?.length, 1); + }); + }); +} diff --git a/packages/firebase_vertexai/firebase_vertexai/test/vertex_mock.dart b/packages/firebase_vertexai/firebase_vertexai/test/vertex_mock.dart new file mode 100644 index 000000000000..5e8faec08656 --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/test/vertex_mock.dart @@ -0,0 +1,72 @@ +// Copyright 2024 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. + +import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +class MockFirebaseAppVertexAI implements TestFirebaseCoreHostApi { + @override + Future initializeApp( + String appName, + PigeonFirebaseOptions initializeAppRequest, + ) async { + return PigeonInitializeResponse( + name: appName, + options: initializeAppRequest, + pluginConstants: {}, + ); + } + + @override + Future> initializeCore() async { + return [ + PigeonInitializeResponse( + name: defaultFirebaseAppName, + options: PigeonFirebaseOptions( + apiKey: '123', + projectId: '123', + appId: '123', + messagingSenderId: '123', + ), + pluginConstants: {}, + ) + ]; + } + + @override + Future optionsFromResource() async { + return PigeonFirebaseOptions( + apiKey: '123', + projectId: '123', + appId: '123', + messagingSenderId: '123', + ); + } +} + +void setupFirebaseVertexAIMocks() { + TestWidgetsFlutterBinding.ensureInitialized(); + + TestFirebaseCoreHostApi.setup(MockFirebaseAppVertexAI()); +} + +// FirebaseVertexAIPlatform Mock +class MockFirebaseVertexAI extends Mock + with + // ignore: prefer_mixin, plugin_platform_interface needs to migrate to use `mixin` + MockPlatformInterfaceMixin { + MockFirebaseVertexAI(); +}