📖

geminiで英語例文を作成

2024/03/04に公開

こんにちは。タオルです。

geminiで英語テキストを渡したら例文を返すロジックを作りました。
英語テキストの取得はdatamuseからしています。

get_page.dart
import 'package:flutter/material.dart';
import 'package:tango/Repository/datamuse_repository.dart';
import 'package:tango/repository/gemini_repository.dart';

import 'ocr_page.dart';
import 'setting_page.dart';

class AsyncValue<T> {
  final T? _data;
  final bool _isLoading;
  final Object? _error;

  const AsyncValue.data(this._data)
      : _isLoading = false,
        _error = null;

  const AsyncValue.loading()
      : _data = null,
        _isLoading = true,
        _error = null;

  const AsyncValue.error(this._error)
      : _data = null,
        _isLoading = false;

  bool get isLoading => _isLoading;
  T? get data => _data;
  Object? get error => _error;

  Widget when({
    required Widget Function(T? data) data,
    required Widget Function() loading,
    required Widget Function(Object? error, StackTrace? stack) error,
  }) {
    if (_isLoading) return loading();
    if (_error != null) return error(_error, null);
    return data(_data);
  }
}

class GetPage extends StatefulWidget {
  const GetPage({super.key});

  
  _GetPageState createState() => _GetPageState();
}

class _GetPageState extends State<GetPage> {
  final TextEditingController _controller = TextEditingController();
  final DatamuseRepository _wordRepository = DatamuseRepository();
  final GeminiRepository _geminiRepository = GeminiRepository();
  AsyncValue<List<String>?> _answerState = AsyncValue.data(null);
  List<String> _suggestions = [];

  Future<void> _getSuggestions(String datamuseQuery) async {
    final suggestions = await _wordRepository.getSuggestions(datamuseQuery);
    setState(() {
      _suggestions = suggestions;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Gotcha'),
        actions: [
          IconButton(
              onPressed: () {
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => const OcrPage()));
              },
              icon: const Icon(Icons.camera)),
          IconButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const SettingPage()),
                );
              },
              icon: const Icon(Icons.settings)),
        ],
      ),
      body: Center(
        child: Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: TextField(
                controller: _controller,
                decoration: const InputDecoration(
                  hintText: '英単語を入力してください',
                ),
                onChanged: (value) => _getSuggestions(value),
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: _suggestions.length,
                itemBuilder: (context, index) {
                  final String suggestion = _suggestions[index];
                  return ListTile(
                    title: Text(suggestion),
                    onTap: () {
                      final presenter = ExampleSentencePresenter(
                          geminiRepository: _geminiRepository);
                      // タップされた単語(suggestion)を引数として渡します。
                      presenter.createAndShowExampleSentence(
                          suggestion, context);
                    },
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class LoadingDialog {
  static void show(BuildContext context, {String? message}) {
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return AlertDialog(
          content: Row(
            children: [
              const CircularProgressIndicator(),
              const SizedBox(width: 24),
              Text(message ?? '読み込み中...'),
            ],
          ),
          contentPadding: const EdgeInsets.all(20.0),
        );
      },
    );
  }

  static void hide(BuildContext context) {
    if (Navigator.of(context).mounted) {
      Navigator.of(context).pop();
    }
  }
}

class ResultDialog {
  static void show(BuildContext context, String title, String content) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: Text(content),
          actions: <Widget>[
            TextButton(
              child: const Text('閉じる'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }
}

class ExampleSentencePresenter {
  final GeminiRepository geminiRepository;

  ExampleSentencePresenter({required this.geminiRepository});

  Future<void> createAndShowExampleSentence(
      String post, BuildContext context) async {
    LoadingDialog.show(context);

    final createAnswer = await geminiRepository.createExampleSentence(post);

    LoadingDialog.hide(context);

    if (createAnswer != null) {
      _showResultDialog(context, '生成された例文', createAnswer);
    } else {
      _showResultDialog(context, 'エラー', '例文を生成できませんでした。');
    }
  }

  void _showResultDialog(BuildContext context, String title, String content) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: Text(content),
          actions: <Widget>[
            TextButton(
              child: const Text('閉じる'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }
}
gemini_repository
import 'package:google_generative_ai/google_generative_ai.dart';

class GeminiRepository {
  static const apiKey = 'xxxxxxxxxxxxxxx';

  Future<String?> getText(String prompt) async {
    final model = GenerativeModel(
      model: 'gemini-pro',
      apiKey: apiKey,
    );

    final content = [
      Content.text(prompt),
    ];

    final response = await model.generateContent(content);
    return response.text;
  }

  // 以下のメソッドを追加
  Future<String?> createExampleSentence(String post) async {
    final prompt = '''
    以下の単語から、よく使われる例文を一つ教えてください。
    ---
    $post
    ---
    ''';

    final createAnswer = await getText(prompt);
    return createAnswer;
  }
}
datamuse_repository
import 'package:http/http.dart' as http;
import 'dart:convert';

class DatamuseRepository {
  Future<List<String>> getSuggestions(String datamuseQuery) async {
    Uri uri = Uri.https('api.datamuse.com', '/sug', {'s': datamuseQuery});
    http.Response response = await http.get(uri);
    final List<dynamic> data = json.decode(response.body);
    return data.map((e) => e['word'] as String).toList();
  }
}

Discussion