AWSでWhisperのREST APIを開発した話


# はじめに
AWSを利用してOpenAIが開発した音声認識モデル「Whisper」のAPIを開発しリリースしました。開発にあたってどういう設計になったか、どういう工夫をしたかを本記事にて公開します。
AWS上でAPIを開発したい方の手助けになれば幸いです。

# Whisper APIについて

サイト: [https://www.portlink-apis.com/](https://www.portlink-apis.com/)
![Screenshot 2023-03-05 at 18.58.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/3da3425d-0a37-6302-ca0e-aaa752511911.png)

「whisper.api」はOpenAIが開発した音声認識モデル「Whisper」をAPIとして提供しているサービスです。
誰でもREST APIを用いて音声の書き起こしが利用できます。Whisperのモデルの中でも一番高精度なlarge-v2モデルを使用できます。
将来的に従量課金制にする予定ですが、現在はベータ版のため無料で利用できます。ぜひ一度使ってみてください。
API Token取得後、SwaggerUIから簡単に試せるのでぜひ一度使ってみてください。

![swagger_transcribe.361cab5ddf88393a806f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/4ca4f2a2-61d5-b9d1-a829-b2bdbec2ece3.png)


```
curl -X 'POST' \
  'https://whisper.portlink-apis.com/transcribe?model=tiny&speed=1&language=english' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <YOUR API ACCESS TOKEN>' \
  -H 'Content-Type: multipart/form-data' \
  -F 'file=@speech-en-001.mp3;type=audio/mpeg'
```


# 設計

APIを設計する上で必要なのは以下の三つでした。
- APIトークンを提供するためのフロントエンド
- ユーザーに提供するAPI
- Whisperを使って推論を行う推論用API

これらを考慮した結果、以下のような設計図にしました。

![Screenshot 2023-03-05 at 18.05.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/8dd7f7dd-6015-1539-8a21-dc6acda1b4ec.png)

### コードベースでのクラウド環境の構築
設計する上で一番重要視したのがクラウドのバックエンド環境をコードベースにすることでした。
そのためフロントエンドとユーザーに提供するAPIをAmplifyで構築しています。Amplifyでは対話型CLIを用いてCognitoやECS,DynamoDBなどのバックエンド環境が簡単に構築できました。

```
$ amplify init  // amplify作成
$ amplify checkout env dev   // 環境の切り替え
$ amplify add <auth|api|function>  // 各種リソースの作成
$ amplify push  // デプロイ
```

推論用APIはAmplify単体では構築できなかったためCloud Develplment Kit(CDK)を用いています。
CDKでユーザーの音声ファイルを一時的に保存するS3や推論用APIとなるSagemaker非同期推論のエンドポイントを構築しています。
```
$ cdk init
$ cdk deploy <リソース名>
$ cdk destroy <リソース名>
```

### Serverless Container
Amplifyの応用的な使い方としてAPIのアプリケーションにLambdaなどのfunctionを使うのではなく、Dockerを使ったServerless Containerを使用しています。Serverless ContainerはAmplifyではAdvancedな使い方で独自のDocker containerをデプロイできるようになります。

Lambdaを使う手もありますが、Lambda layerでの依存ライブラリやソースコードの管理、ローカルでの開発のしずらさなどが難点として感じていました。Dockerを使えるのであれば環境変数や依存ライブラリなどを同じコンテナ内で管理できますし、ローカルの開発用APIとしても扱いやすいという利点があります。

Serverless Container以下のコマンドで使えるようになります。
```
$ amplify configure project
? Do you want to enable container-based deployments? (y/N) // yを選択

$ amplify add api
Which service would you like to use
- API Gateway + AWS Fargate (Container-based)
```

## Frontend
フロントエンドではユーザー登録やAPIトークンの発行、ドキュメントなどを提供しています。
Reactを用いて作成しており、AmplifyのHostingを使ってGitHubにpushすると同時にCICDが走ってデプロイするようにしました。

![Screenshot 2023-03-05 at 18.58.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/3da3425d-0a37-6302-ca0e-aaa752511911.png)

## Backend
Backendのユーザー向けAPIは先ほども述べたようにServerless Containerを使用しています。
言語はPythonで、APIフレームワークとしてFastAPIを使用しました。

Serverless Containerを使うことでローカルでもクラウドと同じ環境が用意できるという利点があります。また、FastAPIでは自動でSwaggerUIを作成してくれるので開発としてもユーザーに提供するUIとしても非常に便利です。

## API 
推論APIはGPUを使ったバッチ処理や大規模モデルの利用、スケーリングなど様々なことを考慮する必要があり、それらを一から用意すると非常に面倒です。
当初はAWS BatchやECSを用いて構築しようと思いましたがモデルの共有等で難しさを感じたため、Sagemakerの非同期推論エンドポイントを使いました。非同期推論エンドポイントではS3内に保存したモデルを指定すれば自動的に/opt/ml/modelディレクトリにモデルをマウントしてくれるためモデルを簡単に扱うことができます。


Sagemaker EndpointのCDK Stack例
```
interface SageMakerEndPointStackProps extends cdk.StackProps {
  endpointConfigName: string
}

export class SageMakerEndPointStack extends cdk.Stack {
  endpointName: string
  constructor(scope: Construct, id: string, props: SageMakerEndPointStackProps) {
    super(scope, id, props);
    const env = this.node.tryGetContext('env') // staging

    this.endpointName = `whisper-api-inference-endpoint-${env}`
    const cfnEndpoint = new sagemaker.CfnEndpoint(this, `WhisperApiInferenceSagemakeEndpoint-${env}1`, {
      endpointName: this.endpointName,
      endpointConfigName: props.endpointConfigName,
    });
  }
}
```

# 終わりに
以上がAWS上でWhisperのAPIを構築するための設計と工夫した点です。
まだまだAWSの知識が浅く、推論APIのスケーリングや従量課金などまだまだ考慮できていない点はありますが、今後少しずつ実装していきたいと思います。