OpenAIのGPT-4oを使って、音声と画像からDjangoコードを生成させてみた
OpenAIのGPT-4oを使って、音声と画像からDjangoコードを生成させてみた
はじめに
こんにちは!
前回は、以下の記事でAzureOpenAIのGPT-4oを使った簡単な検証を行ってみましたが、今回は、OpenAIのGPT-4oのAPIを使って、ローカルで動くマルチモーダルなアプリを作ってみました。
アプリの概要
下図のように画像と音声による指示出しで、アウトプットを出力させるようなマルチモーダルアプリにしてみました。
取り込む画像は、「Windowsマーク+Shift+S」で範囲指定して画面キャプチャしておくと、自動でアプリがクリップボード領域から画像データを取得するという仕組みにしてみました。
まず、インプットに使う画像を用意します。
「生成AIのプロンプトを管理するDjangoアプリを開発する」というお題で、今回は以下のようなフロー図(mermaidフロー図)を生成AIに作成していもらいました。
このフロー図と、音声による指示出しをテキスト変換した情報をGPT-4oに与えてアウトプット(Djangoコード)を出力させるといった感じです。
実際に動かしてみたデモ動画
指示出しの音声が入ってませんが、音声で「このフローズを満たすPythonのDjangoコードを作成してください」としゃべって指示だししています。
使用したライブラリとAPI
このアプリでは以下の機能を利用しています。
ライブラリ/API | 説明 |
---|---|
eel | PythonとHTML/JS/CSSを使ってデスクトップアプリを作るためのライブラリ |
pyaudio | Pythonでオーディオ入力を扱うためのライブラリ |
webrtcvad | 音声アクティビティ検出(VAD)を行うためのライブラリ |
PIL | 画像処理を行うためのライブラリ |
OpenAI Whisper API | 音声をテキストに変換するためのAPI |
OpenAI GPT-4 API | OpenAIの最新の大規模言語モデル(2024/6/2時点) |
実装の流れ
- eelを使ってデスクトップアプリの基本構成を作成
- pyaudioとwebrtcvadを使ってユーザーの音声入力を録音し、無音区間を検出して録音を停止
- 録音された音声をOpenAI Whisper APIを使ってテキストに変換
- PILを使ってクリップボードから画像を取得し、base64エンコードして画像データを準備
- 音声から変換されたテキストと画像データをOpenAI GPT-4o APIに送信し、回答を得る
- 生成された回答をeelを通してフロントエンドに表示
実験結果
インプットは先ほどのフロー図と、音声で「このフローズを満たすPythonのDjangoコードを作成してください」と指示だししてみました。
以下が実際に回答された全内容ですが、モデル、ビュー、フォーム、テンプレート、URLパターン等、最低限必要と思われるベースのコードとしては結構いい感じに提案してくれています。
そのまま動かすとエラーが出てところどころ修正は必要ですが、1から作るより爆速で開発できますね。
このボリュームのコードが30秒かからず出てくるわけですから、凄い時代になったなーと感じます。
===============================
ここから下が生成された回答内容
================================
このフロー図に基づいて、Djangoプロジェクトを作成するための基本的なコードを提供します。以下のコードは、ユーザー認証、プロンプトの作成、検索、 編集、削除、お気に入り追加、評価などの機能を含んでいます。
1. プロジェクトのセットアップ
まず、Djangoプロジェクトを作成します。
django-admin startproject myproject
cd myproject
django-admin startapp prompts
settings.py
の設定
2. INSTALLED_APPS
にprompts
アプリを追加します。
INSTALLED_APPS = [
...
'prompts',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
3. モデルの作成
prompts/models.py
にモデルを定義します。
from django.db import models
from django.contrib.auth.models import User
class Prompt(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Favorite(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
prompt = models.ForeignKey(Prompt, on_delete=models.CASCADE)
class Rating(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
prompt = models.ForeignKey(Prompt, on_delete=models.CASCADE)
score = models.IntegerField()
4. URLの設定
prompts/urls.py
を作成し、ビューをマッピングします。
from django.urls import path
from . import views
urlpatterns = [
path('', views.dashboard, name='dashboard'),
path('login/', views.login_view, name='login'),
path('prompt/<int:prompt_id>/', views.view_prompt, name='view_prompt'),
path('prompt/new/', views.create_prompt, name='create_prompt'),
path('prompt/<int:prompt_id>/edit/', views.edit_prompt, name='edit_prompt'),
path('prompt/<int:prompt_id>/delete/', views.delete_prompt, name='delete_prompt'),
path('prompt/<int:prompt_id>/favorite/', views.add_favorite, name='add_favorite'),
path('prompt/<int:prompt_id>/rate/', views.rate_prompt, name='rate_prompt'),
]
5. ビューの作成
prompts/views.py
にビューを定義します。
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login
from .models import Prompt, Favorite, Rating
from .forms import PromptForm, RatingForm
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('dashboard')
return render(request, 'prompts/login.html')
@login_required
def dashboard(request):
prompts = Prompt.objects.filter(owner=request.user)
return render(request, 'prompts/dashboard.html', {'prompts': prompts})
@login_required
def create_prompt(request):
if request.method == 'POST':
form = PromptForm(request.POST)
if form.is_valid():
prompt = form.save(commit=False)
prompt.owner = request.user
prompt.save()
return redirect('dashboard')
else:
form = PromptForm()
return render(request, 'prompts/create_prompt.html', {'form': form})
@login_required
def view_prompt(request, prompt_id):
prompt = get_object_or_404(Prompt, id=prompt_id)
is_owner = prompt.owner == request.user
return render(request, 'prompts/view_prompt.html', {'prompt': prompt, 'is_owner': is_owner})
@login_required
def edit_prompt(request, prompt_id):
prompt = get_object_or_404(Prompt, id=prompt_id)
if request.user != prompt.owner:
return redirect('dashboard')
if request.method == 'POST':
form = PromptForm(request.POST, instance=prompt)
if form.is_valid():
form.save()
return redirect('dashboard')
else:
form = PromptForm(instance=prompt)
return render(request, 'prompts/edit_prompt.html', {'form': form})
@login_required
def delete_prompt(request, prompt_id):
prompt = get_object_or_404(Prompt, id=prompt_id)
if request.user == prompt.owner:
prompt.delete()
return redirect('dashboard')
@login_required
def add_favorite(request, prompt_id):
prompt = get_object_or_404(Prompt, id=prompt_id)
Favorite.objects.get_or_create(user=request.user, prompt=prompt)
return redirect('view_prompt', prompt_id=prompt_id)
@login_required
def rate_prompt(request, prompt_id):
prompt = get_object_or_404(Prompt, id=prompt_id)
if request.method == 'POST':
form = RatingForm(request.POST)
if form.is_valid():
rating = form.save(commit=False)
rating.user = request.user
rating.prompt = prompt
rating.save()
return redirect('view_prompt', prompt_id=prompt_id)
else:
form = RatingForm()
return render(request, 'prompts/rate_prompt.html', {'form': form})
6. フォームの作成
prompts/forms.py
にフォームを定義します。
from django import forms
from .models import Prompt, Rating
class PromptForm(forms.ModelForm):
class Meta:
model = Prompt
fields = ['title', 'content']
class RatingForm(forms.ModelForm):
class Meta:
model = Rating
fields = ['score']
7. テンプレートの作成
prompts/templates/prompts/
ディレクトリに以下のテンプレートファイルを作成し ます。
login.html
<form method="post">
{% csrf_token %}
<label for="username">Username:</label>
<input type="text" name="username" id="username">
<label for="password">Password:</label>
<input type="password" name="password" id="password">
<button type="submit">Login</button>
</form>
dashboard.html
<h1>Dashboard</h1>
<a href="{% url 'create_prompt' %}">Create New Prompt</a>
<ul>
{% for prompt in prompts %}
<li><a href="{% url 'view_prompt' prompt.id %}">{{ prompt.title }}</a></li>
{% endfor %}
</ul>
create_prompt.html
<h1>Create New Prompt</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
view_prompt.html
<h1>{{ prompt.title }}</h1>
<p>{{ prompt.content }}</p>
{% if is_owner %}
<a href="{% url 'edit_prompt' prompt.id %}">Edit</a>
<a href="{% url 'delete_prompt' prompt.id %}">Delete</a>
{% else %}
<a href="{% url 'add_favorite' prompt.id %}">Add to Favorites</a>
<a href="{% url 'rate_prompt' prompt.id %}">Rate</a>
{% endif %}
edit_prompt.html
<h1>Edit Prompt</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
rate_prompt.html
<h1>Rate Prompt</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
8. マイグレーションの実行
最後に、データベースのマイグレーションを実行します。
python manage.py makemigrations
python manage.py migrate
9. サーバーの起動
python manage.py runserver
これで、フロー図に基づいたDjangoアプリケーションが完成しました。ユーザーはロ グインし、プロンプトを作成、編集、削除、お気に入り追加、評価することができます。
===============================
ここまでが生成された回答内容
================================
GPT-4oの可能性
GPT-4oの登場によって、マルチモーダルな生成AIの活用が一段と加速しそうだなと感じさせられました。
現時点ではまだ一般公開されてませんが、GPT-4o自体には音声を扱える機能も搭載されているようなので、音声機能がリリースされれば、今回のようにわざわざWhisper APIを使って音声をテキストに変換するような処理を繰み込まなくても直接音声をインプットできるようになるんじゃないかなーと思っています。
実務レベルで使えそうな精度に近づいている気がするので、今後は音声と画像の組み合わせのようなマルチモーダルなインターフェースの活用が増えていきそうですね。
Discussion