こんにちは、ゲームソリューション部のsoraです。
今回は、FlutterでDALL·E 3をAPI経由で使用してみたことについて書いていきます。
実装した画面
生成したい画像の指示を入力して、DALL·E 3のAPIを実行して画像を生成するシンプルなアプリです。
前提
OpenAIにてAPIキーを作成して、利用可能なクレジットを準備しておいてください。
クレジットを準備しなくてもAPIキーは作成できますが、クレジットが0の状態で使用してもエラーになります。
状態管理には、Riverpod(flutter_riverpod)を使用しています。
flutter_riverpod | Flutter package
コードの解説
コードは以下です。
今回はテストのため、ファイル分けせずに全てmain.dart
に書いています。
main.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
class Response extends Notifier<String> {
@override
String build(){
return '';
}
void clear() {
state = '';
}
void modify(String url) {
state = url;
}
}
final responseProvider = NotifierProvider<Response, String>(() {
return Response();
});
// DALL·E 3 API実行
Future<void> apiRequest(String message, WidgetRef ref) async {
String responseUrl;
final providerNotifier = ref.watch(responseProvider.notifier);
// 取得したAPIキーを入れる
const apiKey = '{OpenAIのAPIキー}';
const domain = 'api.openai.com';
const path = 'v1/images/generations';
// モデルの指定
const model = 'dall-e-3';
// APIリクエスト
http.Response response = await http.post(
Uri.https(domain, path),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'Bearer $apiKey',
},
body: jsonEncode(<String, dynamic>{
// モデル
"model": model,
// 指示メッセージ
"prompt": message,
// 生成枚数
"n" : 1,
// 画像サイズ
"size": "1024x1024",
// クオリティ
"quality": "standard"
}),
);
if (response.statusCode == 200) {
String responseData = utf8.decode(response.bodyBytes).toString();
final responseJsonData = jsonDecode(responseData);
responseUrl = responseJsonData['data'][0]['url'];
providerNotifier.modify(responseUrl);
} else {
throw Exception('Failed to load sentence');
}
}
void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.lightBlueAccent),
useMaterial3: true,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends ConsumerWidget {
MyHomePage({super.key});
final _messageController = TextEditingController();
@override
Widget build(BuildContext context, WidgetRef ref) {
final providerValue = ref.watch(responseProvider);
final providerNotifier = ref.watch(responseProvider.notifier);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('DALL·E 3 test'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
padding: const EdgeInsets.only(
left: 25,
right: 25,
),
child: TextField(
controller: _messageController,
maxLines: 1,
decoration: const InputDecoration(
hintText: 'メッセージを入力',
hintStyle: TextStyle(color: Colors.black54),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: const Text('AI画像生成実行'),
onPressed: (){
var msg = _messageController.text.trim();
if(msg.isEmpty){
_messageController.clear();
return;
}
providerNotifier.clear();
apiRequest(msg, ref);
},
),
]
),
const SizedBox(height: 30),
Container(
padding: const EdgeInsets.only(
left: 25,
right: 25,
),
// 生成された画像の表示
child: providerValue == ''
? const Text('')
: Image.network(providerValue),
),
],
),
),
);
}
}
DALL·E 3 API実行
OpenAIのAPIキーやモデルを指定して、POSTメソッドでリクエストを投げます。
それぞれのパラメータについては、コメントで記載しています。
ステータスコードが200だった場合は、レスポンスとして生成された画像のURLを取得できるため、そのURLを使用して表示しています。
ちなみに、APIキーについて、テストのためそのまま記述するコードになっていますが、本来であれば暗号化したりサーバ側で扱うようにしてください。
main.dart
// 取得したAPIキーを入れる
const apiKey = '{OpenAIのAPIキー}';
const domain = 'api.openai.com';
const path = 'v1/images/generations';
// モデルの指定
const model = 'dall-e-3';
// APIリクエスト
http.Response response = await http.post(
Uri.https(domain, path),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'Bearer $apiKey',
},
body: jsonEncode(<String, dynamic>{
// モデル
"model": model,
// 指示メッセージ
"prompt": message,
// 生成枚数
"n" : 1,
// 画像サイズ
"size": "1024x1024",
// クオリティ
"quality": "standard"
}),
);
if (response.statusCode == 200) {
String responseData = utf8.decode(response.bodyBytes).toString();
final responseJsonData = jsonDecode(responseData);
// レスポンスの中からURLを抜き出す
responseUrl = responseJsonData['data'][0]['url'];
providerNotifier.modify(responseUrl);
} else {
throw Exception('Failed to load sentence');
}
最後に
今回は、FlutterでDALL·E 3をAPI経由で使用してみたことを記事にしました。
どなたかの参考になると幸いです。