home

OpenAIの画像生成APIをFlutterから呼んで画像を生成してみる

2023-02-10T00:48:09+09:00

前提

今回はこちらの記事を参考にさせていただきました!

上記記事ではChatGPTを使用しているのですが、同じAPIを使うのではなく、画像生成APIを使って画像を生成してみます。

環境

  • macOS: 12.6
  • Android Studio Dolphin | 2021.3.1 Patch 1
  • flutter: 3.6.0-0.1.pre
  • Dart: 2.19.0

OpenAIの画像生成APIについて

リクエストの仕方によっていくつか使用方法があります。
今回は文字列を送信して、それを元に生成した画像のURLを返却してもらいます。

以下はリンク先のマニュアルに記載されている、curlでリクエストする方法です。

curl https://api.openai.com/v1/images/generations \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "prompt": "a white siamese cat",
    "n": 1,
    "size": "1024x1024"
  }'

$OPENAI_API_KEYが必要となるため取得します。

  1. まずこちらから会員登録してください。メールアドレスの他に、GoogleアカウントまたはMicrosoftアカウントが使用できます。

  2. 右上のアイコンを押してView API Keysメニューを開きます。

  3. Create New Secretボタンを押せばAPIキーを生成することができます。

ちなみにUsageページを見ると無料でAPIを使用できる期間等を見ることができます。使いすぎないようにご注意ください。

手順

Flutterプロジェクトを作成

まずは適当にプロジェクトを作成してください。

pubspec.ymlにdependenciesを追加

今回はdioというパッケージを使用します。HTTP通信を行うために利用します。

pubspec.yml
dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  dio: ^4.0.6 # この行を追加

IDEによっては自動でダウンロードしてくれますが、そうでない場合はプロジェクトのルートディレクトリ配下でコマンドを叩いてください。

console
flutter pub get

ファイルを作成

アプリのメインロジック。ただ画像生成ページを呼んでいるだけです。

main.dart
import 'package:flutter/material.dart';
import 'package:open_api/open_api/image_generation_api_page.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const ImageGenerationAPIPage(),
    );
  }
}

画像生成ページです。
ボタンは送信ボタンのようなアイコンを使用してみました。

image_generation_api_page.dart
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

class ImageGenerationAPIPage extends StatefulWidget {
  const ImageGenerationAPIPage({Key? key}) : super(key: key);

  @override
  _ImageGenerationAPIPageState createState() => _ImageGenerationAPIPageState();
}

class _ImageGenerationAPIPageState extends State<ImageGenerationAPIPage> {
  var imageUrl = '';
  var textForGenerationImageController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Image Generation'),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: Image.network(imageUrl)),
          TextField(
            autofocus: true,
            style: const TextStyle(
              fontSize: 20.0,
              color: Colors.black,
            ),
            controller: textForGenerationImageController,
            decoration: const InputDecoration(
              border: InputBorder.none,
              hintText: 'Type text to generate image!',
            ),
          ),
          IconButton(onPressed: () async {
            String url = await generateImageFromText(textForGenerationImageController.text);
            setState(() {
              imageUrl = url;
            });
          }, icon: const Icon(Icons.send)),
        ],
      ),
    );
  }

  Future<String> generateImageFromText(String text) async {
    String apiKey = 'XXXXXXXXXXXXXXXXXXXX'; // ここをAPIキーに差し替え
    var dio = Dio();
    dio.options.headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer $apiKey'};

    try {
      Response response = await dio.post(
        'https://api.openai.com/v1/images/generations',
        data: {
          'prompt': text,
          'n': 1,
          'size': '1024x1024',
        },
      );
      var generatedImageUrl = response.data['data'][0]['url'];
      print('generatedImageUrl:' + generatedImageUrl);
      return generatedImageUrl;
    } catch (e) {
      print(e);
      return e.toString();
    }
  }
}

レスポンスではAPIが生成した画像へのURLが返却されます。それをsetStateメソッドでStateful Widgetのメンバ変数にセットすることで、画像を表示します。

最初は画像へのURLがないのでエラーになっています。

「a white cat」と入力して送信ボタンを押します。
しばらくすると画像が表示されます。

もう一回押すと違う猫ちゃんが…!!

さいごに

利用すること自体は他の一般的なAPIとあまり変わりはないようです。
ただ生成できるものがすごいので、色々なサービスに組み込んだり、アイディア出しにも使ったりできそうです。
例えばCMでお馴染みの(古い?)「蛍のいる渋谷」を見てみましょう。

人と蛍が共存している感じがありますね…!

自己紹介

サムネイル

y5347M

バックエンドエンジニアをしています。