diff --git a/samples/dart/bin/guessing_game.dart b/samples/dart/bin/guessing_game.dart new file mode 100644 index 0000000..13bfea9 --- /dev/null +++ b/samples/dart/bin/guessing_game.dart @@ -0,0 +1,140 @@ +// 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:io'; + +import 'package:args/args.dart'; +import 'package:google_generative_ai/google_generative_ai.dart'; + +Future> _generateWords(String apiKey, String subject) async { + final config = GenerationConfig(candidateCount: 1, temperature: 1.0); + final model = GenerativeModel( + model: 'gemini-pro', + apiKey: apiKey, + generationConfig: config, + requestOptions: RequestOptions(apiVersion: 'v1beta'), + ); + final content = [Content.text('Create and record a list of 20 $subject.')]; + + final response = await model.generateContent( + content, + tools: [ + Tool(functionDeclarations: [ + FunctionDeclaration( + 'recordWords', + 'Stores a list of words for a guessing game.', + Schema(SchemaType.object, properties: { + 'words': Schema(SchemaType.array, + items: Schema(SchemaType.string, + description: + 'A single word that a player will need to guess.')) + })) + ]) + ], + toolConfig: ToolConfig( + functionCallingConfig: + FunctionCallingConfig(mode: FunctionCallingMode.any)), + ); + final functionCall = response.functionCalls.first; + return [ + for (final word in functionCall.args['words'] as List) word as String + ]; +} + +Future> _generateHints( + String apiKey, List words) async { + final config = GenerationConfig(candidateCount: 1, temperature: 0.5); + final model = GenerativeModel( + model: 'gemini-pro', + apiKey: apiKey, + generationConfig: config, + requestOptions: RequestOptions(apiVersion: 'v1beta'), + ); + final content = [ + Content.text( + 'Create and record a list of descriptions for these words: $words. ' + 'The descriptions should be in the same order as the words. ' + 'The descriptions cannot use the word itself. ' + 'The descriptions should make it easy to guess the word. ' + 'Each description should be 3 words long.') + ]; + + final response = await model.generateContent(content, + tools: [ + Tool(functionDeclarations: [ + FunctionDeclaration( + 'recordDescriptions', + 'Stores a list of word descriptions for a guessing game.', + Schema(SchemaType.object, properties: { + 'descriptions': Schema(SchemaType.array, + items: Schema(SchemaType.string, + description: + 'A 3 word description of some other hidden word.')) + })) + ]) + ], + toolConfig: ToolConfig( + functionCallingConfig: + FunctionCallingConfig(mode: FunctionCallingMode.any))); + final hints = response.functionCalls.first.args['descriptions'] as List; + return [for (int i = 0; i < hints.length; ++i) (words[i], hints[i])]; +} + +bool guessWord(String word, String hint) { + stdout.writeln(hint); + stdout.write('What am I? '); + + while (true) { + final guess = stdin.readLineSync(); + if (guess == null) { + stdout.writeln('You missed me, I am $word'); + exit(0); + } + if (guess.trim().toUpperCase() == word.toUpperCase()) { + return true; + } + if (guess.isEmpty) { + stdout.writeln('You missed me, I am $word'); + return false; + } + stdout.write('Nope! What am I? '); + } +} + +Future main(List args) async { + final apiKey = Platform.environment['GOOGLE_API_KEY']; + if (apiKey == null) { + stderr.writeln(r'No $GOOGLE_API_KEY environment variable'); + exit(1); + } + + final parser = ArgParser(); + parser.addOption('subject', + defaultsTo: 'common nouns', help: 'the theme of the quiz'); + final parsedArgs = parser.parse(args); + + final words = await _generateWords(apiKey, parsedArgs['subject']); + words.shuffle(); + final hints = await _generateHints(apiKey, words); + + final start = DateTime.now(); + var got = 0; + while (hints.isNotEmpty) { + final (word, prompt) = hints.removeLast(); + if (guessWord(word, prompt)) got += 1; + } + final end = DateTime.now(); + stdout.writeln('Got $got of ${words.length} in ' + '${end.difference(start).inSeconds} seconds'); +} diff --git a/samples/dart/pubspec.yaml b/samples/dart/pubspec.yaml index 46788f1..3328ea5 100644 --- a/samples/dart/pubspec.yaml +++ b/samples/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: ^3.0.0 dependencies: + args: ^2.4.2 path: ^1.9.0 # Note: best practice here is to use a caret version constraint. We use `any` # here just for the purpose of the samples.