2024/07/31第6回FlutterGakkai
AWSAmplifyとBedrockを
活用した生成AIアプリの開発
KDDIアジャイル開発センター株式会社 平井友樹
自己紹介
平井友樹(TomokiHirai)@AllJokin
KDDIアジャイル開発センター株式会社/KDDI株式会社
エンジニアとしてアジャイルの内製開発支援を担当
React,Flutter,AWS,GCPなど
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 1
生成AI
テキスト生成 画像生成
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 2
Flutterx生成AI
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 3
google_generative_ai
Googleの生成AIであるGeminiをFlutterから簡単に呼び出すためのライブラリ。
UsingtheGoogleAISDKforDart(Flutter)tocalltheGoogleAIGeminiAPIdirectlyfromyourappisrecommendedforprototyping
only.
→商用では非推奨なので使えない…。APIKeyを管理するためのバックエンドを構築がめんどくさい…。
import 'package:google_generative_ai/google_generative_ai.dart';
const apiKey = ...;
void main() async {
final model = GenerativeModel(
model: 'gemini-1.5-flash-latest',
apiKey: apiKey,
);
final prompt = 'Write a story about a magic backpack.';
final content = [Content.text(prompt)];
final response = await model.generateContent(content);
};
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 4
AWSAmplifyとAmazonBedrock
を使おう!
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 5
AWSAmplify(Gen2)
フルスタックのWebアプリケーションやモバイルアプリケーションを素早く構築、デプロイするためのツール
Typescriptによるバックエンド定義
開発者ごとのクラウドサンドボックス環境
Gitブランチと連携した自動デプロイ
AWSCDKによるバックエンドのカスタマイズ
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 6
Typescriptによるバックエンド定義
Typescriptによるリソース定義によってGraphQLスキーマとDynamoDBのテーブルを自動生成
GraphQLスキーマ定義
DynamoDBテーブル
id content
1 test
2 test
import { type ClientSchema, a, defineData }
from '@aws-amplify/backend';
const schema = a.schema({
Todo: a.model({
content: a.string(),
}).authorization(allow => [allow.owner()]),
});
export type Schema = ClientSchema<typeof schema>;
export const data = defineData({
schema,
authorizationModes: {
defaultAuthorizationMode: 'userPool',
},
});
type Todo {
id: ID!
content: String!
}
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 7
サンドボックス環境
開発者ごとに独立したサンドボックス環境を利用可能。変更後のデプロイも高速。
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 8
AmazonBedrock
AWSが提供する生成AIサービス
様々な生成AIモデルをサーバレスなAPIで呼び出すことができる
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 9
作成したサンプルアプリケーション
料理の写真をFlutterアプリで撮影し、生成AIで料理名とカロリーを推定する
https://github.com/tm-hirai/flutter_amplify_bedrock
https://qiita.com/allJokin/items/dd1a267bdce88a79d0cc
AWS Cloud
User
{
"food": カレー,
"calorie": 800
}
AWS Amplify
Amazon Bedrock
AWS AppSync AWS Lambda
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 10
バックエンド実装
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 11
生成AIを呼び出すバックエンドの作成
フロントエンドから送信された料理画像を生成AIで処理し、カロリーを推定するバックエンドを作成
Amplifyのファイル構成に従い、以下のファイルを作成する
使用するサービスは以下の3つ。
AppSync:サーバーレスでマネージドなGraphQLサーバー
Lambda:Node.js、Python、Rubyなどをサーバーレスに実行できるFaas(FunctionasaService)
Bedrock:生成AIサービス
amplify/
data/
calorieCalculation.ts Lambda関数の定義
resource.ts スキーマの定義
backend.ts バックエンドの定義
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 12
Lambda関数の実装
Lambda関数で実行されるTypescriptのコード。Base64形式の画像をBedrockに送信する。
export const handler: Schema["calorieCalculation"]["functionHandler"] =
async (event,_ ) => {
const client = new BedrockRuntimeClient({ region: "us-east-1" });
// base64形式の画像
const base64String = event.arguments.base64String;
const input = {
modelId: process.env.MODEL_ID,
contentType: "application/json",
accept: "application/json",
body: prompt, // 次スライドに記載
} as InvokeModelCommandInput;
const command = new InvokeModelCommand(input);
const response = await client.send(command);
const data = JSON.parse(Buffer.from(response.body)
.toString());
return data.content[0].text;
};
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 13
Bedrockに送信するプロンプト
日本語より英語の方がトークン数(課金単位)が少なくて低コストなので、英語で作成
システムプロンプト
入力画像
命令文
system: "You are a calorie analysis expert capable of estimating the calories of any dish shown in an image."
{ type: "image", source: {type: "base64", media_type: "image/jpeg", data: base64String} }
{
type: "text",
text: `Estimate calories of the food in this image.
Use JSON format with "food" (dish name in Japanese) and "calorie" (in kcal) as keys.
Do not output anything other than JSON.
<example>
{ "food": "寿司", "calorie": 300 }
</example>`
}
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 14
スキーマ定義
Lambda関数の設定とGraphQLスキーマ定義する。フロントから呼び出す際の引数や返り値、認証方式などを定義する。
export const MODEL_ID = "anthropic.claude-3-sonnet-20240229-v1:0";
// Lambdaの定義
export const calorieCalculationFunction = defineFunction({
entry: "./calorieCalculation.ts",
environment: { MODEL_ID, },
runtime: 20,
timeoutSeconds: 10,
});
const schema = a.schema({
calorieCalculation: a
.query().arguments({ base64String: a.string().required() }).returns(a.string())
.authorization((allow) => [allow.publicApiKey()])
.handler(a.handler.function(calorieCalculationFunction)),
});
export type Schema = ClientSchema<typeof schema>;
export const data = defineData({
schema,
authorizationModes: { defaultAuthorizationMode: "apiKey", apiKeyAuthorizationMode: { expiresInDays: 30 } },
});
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 15
バックエンド定義
defineBackend によってバックエンドが生成される。
import { defineBackend } from "@aws-amplify/backend";
import { data, MODEL_ID, calorieCalculationFunction } from "./data/resource";
import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
export const backend = defineBackend({
data,
calorieCalculationFunction,
});
// LambdaからBedrockを呼び出すための権限を付与
backend.calorieCalculationFunction.resources.lambda.addToRolePolicy(
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["bedrock:InvokeModel"],
resources: [`arn:aws:bedrock:us-east-1::foundation-model/${MODEL_ID}`],
})
);
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 16
デプロイ
以下のコマンドでサンドボックス環境にデプロイ可能。GraphQLスキーマとフロントの設定ファイルが生成される。
アプリ側で読み込むdartファイル GraphQLのスキーマ
npx ampx sandbox --outputs-format dart --outputs-out-dir lib --outputs-version 0
const amplifyConfig = '''{
"UserAgent": "@aws-amplify/client-config/1.0.4",
"Version": "1.0",
"api": {
"plugins": {
"awsAPIPlugin": {
"data": {
"endpointType": "GraphQL",
"endpoint": "https://xxx.appsync-api.
ap-northeast-1.amazonaws.com/graphql",
"region": "ap-northeast-1",
"authorizationType": "API_KEY",
"apiKey": "xxx"
}
}}}}''';
type Query {
calorieCalculation(base64String: String!):
String @aws_iam @aws_api_key
}
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 17
Flutterアプリ実装
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 18
アプリの概要
1. カメラで写真を撮影
2. 撮影した画像を加工
3. 画像をアップロード
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 19
1.カメラで写真を撮影
camera パッケージを使ってカメラ機能を実装
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 利用可能なカメラの取得
final cameras = await availableCameras();
runApp(MyApp(
cameras: cameras,
));
}
// コントローラー初期化
void initState() {
super.initState();
controller = CameraController(widget.cameras[0],
ResolutionPreset.max, enableAudio: false);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
Widget build(BuildContext context) {
// プレビューウィジット
return CameraPreview(controller);
}
// 撮影
controller.takePicture().then((XFile file) async {});
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 20
2.撮影した画像を加工
1. 端末によって縦横比が異なるので、正方形に切り取る
2. 解像度が高いとコストが大きいので、500x500にリサイズする
①画像ファイルを
正⽅形に整形
②500x500に
リサイズ
元画像 正⽅形画像
500x500
tokens = (width px * height px)/750
画像サイズ トークン数 コスト/1枚 コスト/1000枚
200x200 約54 約$0.00016 約$0.16
500x500 約333 約$0.001 約$1
1000x1000 約1334 約$0.004 約$4.00
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 21
2.撮影した画像を加工
image パッケージを使って500x500の画像を作成する
copyCrop :画像を切り取る
copyResize :画像のサイズを変更する
final cmd = img.Command()
..image(image)
..copyCrop(x: 0, y: 0, width: image.width, height: image.width)
..copyResize(width: 500, height: 500);
final processedImage = await cmd.getImageThread();
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 22
3.画像をアップロードして推定結果を受け取る
base64形式の画像を引数に設定してGraphQLのリクエストを実行する
const graphQLDocument = '''
query calorieCalculation($base64String: String!) {
calorieCalculation(base64String: $base64String)
}
''';
// imageのオブジェクトをjpg形式でbase64エンコード
final base64String = base64Encode(img.encodeJpg(_image!));
final request = GraphQLRequest<String>(
document: graphQLDocument,
variables: <String, String>{
"base64String": base64String
},
authorizationMode: APIAuthorizationType.apiKey);
/// API実行
final response = await Amplify.API.query(request: request).response;
Map<String, dynamic> jsonMap = json.decode(response.data!);
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 23
デモ
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 24
まとめ
AWSAmplifyxAmazonBedrockで
簡単に生成AIアプリケーションを作成可能
ぜひ試してみてください!
KDDI Agile Development Center Corporation
KDDIアジャイル開発センター株式会社 25

More Related Content

PDF
Storytelling For The Web: Integrate Storytelling in your Design Process
PDF
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
PDF
How to Leverage AI to Boost Employee Wellness - Lydia Di Francesco - SocialHR...
PDF
2024 Trend Updates: What Really Works In SEO & Content Marketing
PDF
2024 State of Marketing Report – by Hubspot
PDF
Everything You Need To Know About ChatGPT
PDF
Product Design Trends in 2024 | Teenage Engineerings
PDF
How Race, Age and Gender Shape Attitudes Towards Mental Health
Storytelling For The Web: Integrate Storytelling in your Design Process
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
How to Leverage AI to Boost Employee Wellness - Lydia Di Francesco - SocialHR...
2024 Trend Updates: What Really Works In SEO & Content Marketing
2024 State of Marketing Report – by Hubspot
Everything You Need To Know About ChatGPT
Product Design Trends in 2024 | Teenage Engineerings
How Race, Age and Gender Shape Attitudes Towards Mental Health
Ad

AWS AmplifyとBedrockを活用した生成AIアプリの開発@第6回 FlutterGakkai