はじめに
皆さんこんにちは。
QiitaのイベントでCodeAGIというものを使用しています。
長々と4回に分割してきた「CodeAGIを使おう!」シリーズですが、前回の投稿までで設計書と定義書を作成しプロジェクトも作成まで行いました。
今回は最終回として、これまで作成したものを使用して実際にCodeAGIのプロジェクトに設計書・定義書を読み込ませコードの自動生成までを行いたいと思います!!
使用したデータは以下に挙げておきます。
読み込むデータについて
過去の投稿(設計書、定義書)などで投稿しましたが、CodeAGIを使用するにあたって以下の3か所で作成した設計書を読み込む必要があります
※画像イメージ指定は「デザイン生成 α version」ということで実験的にリリースされている機能のようです。
実験的のためJavaプロジェクトのみに対応しているようです。
また生成AIはOpenAIのgpt-4-vision-preview
にて解析を行っており、その他の生成 AIでは行えないようです。
自分はPythonを使用しており、生成AIモデルはgpt-4o
なので画像生成機能は用いていないので、読み込みは行いませんでした。
テーブル定義書指定
テーブル定義書指定では作成するデータテーブルの定義書を入力します。
公式サイトでテンプレート及びサンプルをダウンロードできるので、それを参考にテーブル定義書を作成します。
- テーブル定義書指定を選択するとドラッグ&ドロップか追加ボタンから作成したエクセルファイルを読み込むことができるので、作成した
テーブル設計書.xlsx
を読み込みます。 - 入力したテーブル設計書はCodeAGI上の「指定データ確認」で確認することができる
機能設計書指定
機能設計書指定では作成するプログラムの振る舞いやデータの関連などを指定します。
どのボタンが押された、どのようなアクションが実行された際にどのようなふるまいをするか、どのようにデータを受け渡すかなどを文章で指定します。
-
機能設計書指定から機能選択を選択する。(頭痛が痛い🤣)
-
初回は選択できる機能がないはずなので、新規作成を行う
-
画面やバッチの機能などの定義書が書かれた機能設計書をドラッグ&ドロップか追加ボタンで読み込む
- この時、選択した機能種別において最低限必要な定義書を指定する必要がある。詳しくは下記表を参考にしてください
-
入力した機能設計書はCodeAGI上の「指定データ確認」で確認することができる
機能種別 | 機能種別と必要な定義書及びアーキテクチャ |
---|---|
![]() |
![]() |
画面イメージ指定
自分の環境では対応していないので割愛
共通仕様書指定
マニュアルを読んだのですが、結局どのようなことを書けばよいかが理解できず作成せず。ただ、共通仕様書指定を行わなくてもコードの生成は可能であったので必須ではなさそう。
マニュアルより、共通仕様書指定に読み込ませる定義書は以下のような内容とのこと。
共通部品指定
こちらも使用しなかったので割愛。
ここで指定する内容はCodeAGIアプリによると以下の内容とのこと。
用意されている入力内容は以下の通り。
自社製ログライブラリ等があればそれを教えることができそうです。
コード生成
ここまで来たらお待ちかねのコード生成です。
まずは、指定データ確認で入力したデータがすべて読まれているかを確認しプログラム生成を選択します。
しばらく待つとコードが生成されます。
生成プログラム確認&ファイル出力から生成されたプログラムの確認及びファイルに保存を行います。
生成されたコードは以下の通り。
models.py
from django.db import models
# ユーザーモデル
class User(models.Model):
user_id = models.AutoField(primary_key=True, db_column='USER_ID')
user_name = models.CharField(max_length=32, db_column='USER_NAME')
password = models.CharField(max_length=32, db_column='PASSWORD')
class Meta:
db_table = 'ユーザー'
# プロジェクトモデル
class Project(models.Model):
project_id = models.AutoField(primary_key=True, db_column='PROJECT_ID')
project_name = models.CharField(max_length=50, db_column='PROJECT_NAME')
purpose = models.CharField(max_length=300, db_column='PURPOSE', blank=True, null=True)
class Meta:
db_table = 'プロジェクト'
# タスクモデル
class Task(models.Model):
task_id = models.AutoField(primary_key=True, db_column='TASK_ID')
project = models.ForeignKey(Project, on_delete=models.CASCADE, db_column='PROJECT_ID')
task_name = models.CharField(max_length=50, db_column='TASK_NAME')
contents = models.CharField(max_length=1000, db_column='CONTENTS', default='タスク内容')
register = models.ForeignKey(User, related_name='registered_tasks', on_delete=models.CASCADE, db_column='REGISTER_ID')
assign = models.ForeignKey(User, related_name='assigned_tasks', on_delete=models.SET_NULL, null=True, blank=True, db_column='ASSIGN_ID')
status = models.CharField(max_length=10, db_column='STATUS', default='未開始', choices=[('未開始', '未開始'), ('実行中', '実行中'), ('完了済み', '完了済み'), ('保留中', '保留中')])
start_day = models.DateField(db_column='START_DAY', blank=True, null=True)
end_day = models.DateField(db_column='END_DAY', blank=True, null=True)
class Meta:
db_table = 'タスク'
urls.py
from django.urls import path
from .views import LoginView, RegisterView, ProjectListView, ProjectDetailView, TaskDetailView
urlpatterns = [
# ログイン画面のURLパターン
path('login/', LoginView.as_view(), name='login'),
# 新規登録画面のURLパターン
path('register/', RegisterView.as_view(), name='register'),
# プロジェクト一覧画面のURLパターン
path('projects/', ProjectListView.as_view(), name='project_list'),
# プロジェクト詳細画面のURLパターン
path('projects/<int:project_id>/', ProjectDetailView.as_view(), name='project_detail'),
# タスク詳細画面のURLパターン
path('tasks/<int:task_id>/', TaskDetailView.as_view(), name='task_detail'),
]
views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views import View
from django.contrib import messages
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from .models import Project, Task
# ログイン画面のビュー
class LoginView(View):
template_name = 'login.html'
def get(self, request):
return render(request, self.template_name)
def post(self, request):
user_name = request.POST.get('USER_NAME')
password = request.POST.get('PASSWORD')
if not user_name or not password:
messages.error(request, 'ユーザー名またはパスワードが入力されていません')
return render(request, self.template_name)
if len(password) < 6:
messages.error(request, 'パスワードが短すぎます')
return render(request, self.template_name)
user = authenticate(request, username=user_name, password=password)
if user is not None:
login(request, user)
return redirect('project_list')
else:
messages.error(request, 'ユーザー情報が正しくありません')
return render(request, self.template_name)
# 新規登録画面のビュー
class RegisterView(View):
template_name = 'register.html'
def get(self, request):
return render(request, self.template_name)
def post(self, request):
user_name = request.POST.get('USER_NAME')
password = request.POST.get('PASSWORD')
if not user_name or not password:
messages.error(request, 'ユーザー名またはパスワードが入力されていません')
return render(request, self.template_name)
if len(password) < 6:
messages.error(request, 'パスワードが短すぎます')
return render(request, self.template_name)
if User.objects.filter(username=user_name).exists():
messages.error(request, 'ユーザーは既に登録されています')
return render(request, self.template_name)
user = User.objects.create_user(username=user_name, password=password)
user.save()
messages.success(request, 'ユーザー登録が完了しました')
return redirect('login')
# プロジェクト一覧画面のビュー
class ProjectListView(View):
template_name = 'project_list.html'
def get(self, request):
user = request.user
projects = Project.objects.filter(project_user__user_id=user.id).order_by('project_id')
project_data = []
for project in projects:
project_members = project.project_user_set.count()
remaining_tasks = project.task_set.exclude(status='完了済み').count()
project_data.append({
'project_id': project.project_id,
'project_name': project.project_name,
'project_members': project_members,
'remaining_tasks': remaining_tasks
})
return render(request, self.template_name, {'projects': project_data})
# プロジェクト詳細画面のビュー
class ProjectDetailView(View):
template_name = 'project_detail.html'
def get(self, request, project_id):
project = get_object_or_404(Project, pk=project_id)
tasks = project.task_set.order_by('task_id')
return render(request, self.template_name, {'project': project, 'tasks': tasks})
# タスク詳細画面のビュー
class TaskDetailView(View):
template_name = 'task_detail.html'
def get(self, request, task_id):
task = get_object_or_404(Task, pk=task_id)
return render(request, self.template_name, {'task': task})
def post(self, request, task_id):
task = get_object_or_404(Task, pk=task_id)
task.task_name = request.POST.get('TASK_NAME', task.task_name)
task.contents = request.POST.get('TASK_DESCRIPTION', task.contents)
task.assign_id = request.POST.get('ASSIGN', task.assign_id)
task.status = request.POST.get('STATUS', task.status)
task.start_day = request.POST.get('START_DAY', task.start_day)
task.end_day = request.POST.get('END_DAY', task.end_day)
task.save()
messages.success(request, 'タスクが更新されました')
return redirect('task_detail', task_id=task_id)
admin.py
from django.contrib import admin
from .models import User, Project, Task
# ユーザーモデルの管理クラス
class UserAdmin(admin.ModelAdmin):
list_display = ('user_name',)
# プロジェクトモデルの管理クラス
class ProjectAdmin(admin.ModelAdmin):
list_display = ('project_name',)
# タスクモデルの管理クラス
class TaskAdmin(admin.ModelAdmin):
list_display = ('task_name', 'status')
# 管理サイトへのモデルの登録
admin.site.register(User, UserAdmin)
admin.site.register(Project, ProjectAdmin)
admin.site.register(Task, TaskAdmin)
apps.py
from django.apps import AppConfig
class MainConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'main'
login.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ログイン</title>
</head>
<body>
<h1>ログイン</h1>
<form method="post">
{% csrf_token %}
<label for="user_name">ユーザー名</label>
<input type="text" id="user_name" name="USER_NAME" maxlength="32" required>
<br>
<label for="password">パスワード</label>
<input type="password" id="password" name="PASSWORD" maxlength="32" required>
<br>
<button type="submit">ログイン</button>
</form>
<a href="{% url 'register' %}">新規登録</a>
</body>
</html>
register.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>新規登録</title>
</head>
<body>
<h1>新規登録</h1>
<form method="post">
{% csrf_token %}
<label for="user_name">ユーザー名</label>
<input type="text" id="user_name" name="USER_NAME" maxlength="32" required>
<br>
<label for="password">パスワード</label>
<input type="password" id="password" name="PASSWORD" maxlength="32" required>
<br>
<button type="submit">登録</button>
</form>
<a href="{% url 'login' %}">ログイン画面へ戻る</a>
</body>
</html>
project_list.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>プロジェクト一覧</title>
</head>
<body>
<h1>プロジェクト一覧</h1>
<table>
<thead>
<tr>
<th>プロジェクトID</th>
<th>プロジェクト名</th>
<th>プロジェクトメンバー</th>
<th>残タスク数</th>
</tr>
</thead>
<tbody>
{% for project in projects %}
<tr>
<td>{{ project.project_id }}</td>
<td><a href="{% url 'project_detail' project.project_id %}">{{ project.project_name }}</a></td>
<td>{{ project.project_members }}</td>
<td>{{ project.remaining_tasks }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button onclick="location.href='{% url 'add_project' %}'">プロジェクト追加</button>
</body>
</html>
project_detail.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>プロジェクト詳細</title>
</head>
<body>
<h1>プロジェクト: {{ project.project_name }}</h1>
<table>
<thead>
<tr>
<th>タスク名</th>
<th>担当者</th>
<th>状態</th>
</tr>
</thead>
<tbody>
{% for task in tasks %}
<tr>
<td><a href="{% url 'task_detail' task.task_id %}">{{ task.task_name }}</a></td>
<td>{{ task.assign.user_name }}</td>
<td>{{ task.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button onclick="location.href='{% url 'add_task' project.project_id %}'">タスク追加</button>
</body>
</html>
task_detail.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>タスク詳細</title>
</head>
<body>
<h1>タスク: {{ task.task_name }}</h1>
<form method="post">
{% csrf_token %}
<label for="task_name">タスク名</label>
<input type="text" id="task_name" name="TASK_NAME" value="{{ task.task_name }}" required>
<br>
<label for="task_description">内容</label>
<textarea id="task_description" name="TASK_DESCRIPTION">{{ task.contents }}</textarea>
<br>
<label for="assign">担当者</label>
<select id="assign" name="ASSIGN">
{% for user in users %}
<option value="{{ user.id }}" {% if user.id == task.assign_id %}selected{% endif %}>{{ user.user_name }}</option>
{% endfor %}
</select>
<br>
<label for="status">状態</label>
<select id="status" name="STATUS">
<option value="未開始" {% if task.status == '未開始' %}selected{% endif %}>未開始</option>
<option value="実行中" {% if task.status == '実行中' %}selected{% endif %}>実行中</option>
<option value="完了済み" {% if task.status == '完了済み' %}selected{% endif %}>完了済み</option>
<option value="保留中" {% if task.status == '保留中' %}selected{% endif %}>保留中</option>
</select>
<br>
<label for="start_day">開始日</label>
<input type="date" id="start_day" name="START_DAY" value="{{ task.start_day }}">
<br>
<label for="end_day">終了日</label>
<input type="date" id="end_day" name="END_DAY" value="{{ task.end_day }}">
<br>
<button type="submit">保存</button>
</form>
</body>
</html>
所感
生成されたコードを確認してみた所感としては、完ぺきではないにしても、アクション定義書に記述した振る舞いが自動生成されています。
ただ一部指定した振る舞いが実現できていなかったり部分はあり、ここは定義書の作成の工夫次第でどうにかなる内容だと思います。
自分が感じた欠点は、データテーブルを適切に生成することができておらず不満を感じました。
(ユーザーとプロジェクトをつなぐPROJECT_
USER`が生成されたmodels.pyにはなかった)
画面遷移やアクションの振る舞い、データの受け渡しは文章で書くことになるので自然言語特有のあいまいさがあり足りない部分が出てしまうのはわかりますが、データテーブルはかなり厳密に書いているので完ぺきに生成できていてほしかったです。
また、今回生成されたコードはそれ単体では動かず、自分で作成したDjangoプロジェクトにマージして使用する必要があります。
生成されたコードをただコピペするだけではなく、すでにある.pyファイルへのマージや必要なフォルダ構成に修正するなど手間があります。
生成されたコードの確認がもう少し楽にできる方法があればよかったなと思います。
CodeAGIを業務に使うには
今回使ってみて、コードの自動生成はすごく便利だと思いました。
ただ、テーブル定義書と機能設計書を入れないとコード生成できない仕様となっており、ある程度固まったものを入れないとコード生成にたどり着けないので、例えばもっと小さな粒度でのコード生成を試せるとよかったなと思います。
たとえば、テーブル定義書からmodels.py
を生成するのみの機能や、アクション定義書からふるまい(関数)生成などもっと簡単に使用できれば業務のイテレーション開発時の時短につながると感じました。
さいごに
今回作成していて気づきましたが、アプリ内のロゴを確認すると(共通部品指定で添付した画像等)、6月15日前後に入れたCodeAGIはβバージョンのようですが、マニュアルにはβの記述がありませんでした。
今回はβを使用していますが、αバージョンで作られたマニュアルを見ながら使用していていたので、βバージョンではできる機能が増えているかもしれません。
使用してみて全体的に思ったことですが、サンプルやマニュアルの用語や文章が統一されておらず、全体的に理解が難しかったです。
さらに用意しなくてはいけない内容以外に多くQiitaのお題程度で個人で使用するにはハードルが高いなと感じました。
ただ、定義書を作ってしまえば自動で簡単に、すぐにコードができとても感動しました。
企業で使用する際は要件定義書や仕様書がすでにあるものかと思いますので、コード生成の自動化に一役買ってくれそうに思います。