グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



話題の『ChatGPT o1』をコーディングに使ってみた(ChatGPT 4oとの比較)

昨今ではもう世間に定着してきたChatGPTですが、2024年9月12日に新しいAIモデルの『ChatGPT o1』がリリースされました。

https://openai.com/index/introducing-openai-o1-preview/

今回のモデルに関しては思考プロセスが洗練され、問題に反応する前にじっくり考える時間を取るようになり、 複雑なコードを正確に生成してデバックすることに優れているようです。

今回は、『ChatGPT o1』を使ってみて、以前のモデルと比較してみたいと思います。

実際に使ってみた

以下のプロンプトを入力して、以前のモデル『ChatGPT 4o』と新しいモデルである『ChatGPT o1』を使ってコーディングさせてみます。

あなたは「TypeScript」を専門とするフロントエンドのエンジニアです。
以下の要件でコードを作成してください。

# 要件
- タスクの追加
 - ユーザーは、新しいタスクをリストに追加できる。
 - タスクには、タイトルと任意で詳細説明を入力できる。
- タスクの表示
 - 追加されたタスクはリスト形式で表示される。
 - 各タスクには、タイトル、ステータス(未完了/完了)、および作成日が表示される。
- タスクの削除
 - ユーザーは不要になったタスクをリストから削除できる。
- タスクのステータス変更
 - ユーザーは、タスクを「完了」または「未完了」に変更できる。
 - 完了済みのタスクは別のスタイル(例: 打ち消し線や色の変更)で表示される。

ChatGPT 4o

まずはコードを確認してみます。

import React, { useState } from 'react';

interface Task {
  id: number;
  title: string;
  description?: string;
  isCompleted: boolean;
  createdAt: Date;
}

const App: React.FC = () => {
  const [tasks, setTasks] = useState<Task[]>([]);
  const [newTaskTitle, setNewTaskTitle] = useState('');
  const [newTaskDescription, setNewTaskDescription] = useState('');

  const addTask = () => {
    if (newTaskTitle.trim() === '') return;

    const newTask: Task = {
      id: tasks.length + 1,
      title: newTaskTitle,
      description: newTaskDescription,
      isCompleted: false,
      createdAt: new Date(),
    };
    setTasks([...tasks, newTask]);
    setNewTaskTitle('');
    setNewTaskDescription('');
  };

  const deleteTask = (id: number) => {
    setTasks(tasks.filter(task => task.id !== id));
  };

  const toggleTaskStatus = (id: number) => {
    setTasks(
      tasks.map(task =>
        task.id === id ? { ...task, isCompleted: !task.isCompleted } : task
      )
    );
  };

  return (
    <div className="app">
      <h1>タスク管理アプリ</h1>

      <div>
        <input
          type="text"
          placeholder="タスクタイトル"
          value={newTaskTitle}
          onChange={e => setNewTaskTitle(e.target.value)}
        />
        <textarea
          placeholder="タスクの詳細説明 (任意)"
          value={newTaskDescription}
          onChange={e => setNewTaskDescription(e.target.value)}
        />
        <button onClick={addTask}>タスクを追加</button>
      </div>

      <ul>
        {tasks.map(task => (
          <li key={task.id} style={{ textDecoration: task.isCompleted ? 'line-through' : 'none' }}>
            <h2>{task.title}</h2>
            {task.description && <p>{task.description}</p>}
            <p>作成日: {task.createdAt.toLocaleDateString()}</p>
            <button onClick={() => toggleTaskStatus(task.id)}>
              {task.isCompleted ? '未完了にする' : '完了にする'}
            </button>
            <button onClick={() => deleteTask(task.id)}>削除</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default App;
/* 全体のレイアウト */
body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
  margin: 0;
  padding: 20px;
}

.app {
  max-width: 600px;
  margin: 0 auto;
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

h1 {
  text-align: center;
  color: #333;
}

/* タスク追加フォーム */
input[type="text"],
textarea {
  width: 100%;
  padding: 10px;
  margin: 10px 0;
  border: 1px solid #ccc;
  border-radius: 5px;
  font-size: 16px;
}

button {
  padding: 10px 15px;
  background-color: #28a745;
  color: #fff;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 16px;
  margin-right: 10px;
}

button:hover {
  background-color: #218838;
}

/* タスクリスト */
ul {
  list-style-type: none;
  padding: 0;
}

li {
  background-color: #f9f9f9;
  margin: 10px 0;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
}

li h2 {
  margin: 0;
  font-size: 18px;
  color: #333;
}

li p {
  margin: 5px 0;
  color: #666;
}

/* 完了したタスクのスタイル */
li.completed {
  background-color: #d4edda;
  border-color: #c3e6cb;
  text-decoration: line-through;
  color: #6c757d;
}

li.completed h2 {
  color: #155724;
}

li.completed p {
  color: #6c757d;
}

/* タスクの操作ボタン */
li button {
  align-self: flex-start;
  margin-top: 10px;
}

li button:first-of-type {
  background-color: #007bff;
}

li button:first-of-type:hover {
  background-color: #0056b3;
}

li button:last-of-type {
  background-color: #dc3545;
}

li button:last-of-type:hover {
  background-color: #c82333;
}

コーディングに関しては、特に問題はなさそうです。

では、実際に出力してみましょう。

デザインに関しては、背景色が付いていたり、影が付いているなど思ったよりもちゃんとしています。
しかし、テキストボックスとテキストエリアの要素が親コンポーネントの padding を突き抜けているのは少し気になってしまいますね。

続いて、実際にアプリケーションの動作を確認してみます。

こちらの要件を満たした実装になっていますが、タスクを完了済みにするとボタンまで打ち消し線されていたり、少しツッコミどころがあるのはご愛嬌といったところなのでしょうか。

以前のモデルとは言えど、さすがChatGPTと言った仕上がりになっていました。

ChatGPT o1

さて、続けてこちらも確認していきましょう。
まずは出力コードから

// src/App.tsx

import React, { useState, ChangeEvent, FormEvent } from 'react';
import './App.css';

// タスクの型定義
interface Task {
  id: number;
  title: string;
  description?: string;
  isCompleted: boolean;
  createdAt: Date;
}

const App: React.FC = () => {
  const [tasks, setTasks] = useState<Task[]>([]);
  const [title, setTitle] = useState<string>('');
  const [description, setDescription] = useState<string>('');

  // タスク追加ハンドラー
  const handleAddTask = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (title.trim() === '') {
      alert('タイトルを入力してください');
      return;
    }
    const newTask: Task = {
      id: Date.now(),
      title,
      description,
      isCompleted: false,
      createdAt: new Date(),
    };
    setTasks([newTask, ...tasks]);
    setTitle('');
    setDescription('');
  };

  // タスク削除ハンドラー
  const handleDeleteTask = (id: number) => {
    if (window.confirm('本当にこのタスクを削除しますか?')) {
      setTasks(tasks.filter(task => task.id !== id));
    }
  };

  // タスクステータス変更ハンドラー
  const handleToggleStatus = (id: number) => {
    setTasks(
      tasks.map(task =>
        task.id === id ? { ...task, isCompleted: !task.isCompleted } : task
      )
    );
  };

  return (
    <div className="container">
      <h1>タスク管理アプリ</h1>
      <form onSubmit={handleAddTask} className="task-form">
        <div>
          <label htmlFor="title">タイトル<span className="required">*</span>:</label>
          <input
            type="text"
            id="title"
            value={title}
            onChange={(e: ChangeEvent<HTMLInputElement>) => setTitle(e.target.value)}
            required
          />
        </div>
        <div>
          <label htmlFor="description">詳細説明:</label>
          <textarea
            id="description"
            value={description}
            onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setDescription(e.target.value)}
          ></textarea>
        </div>
        <button type="submit">タスクを追加</button>
      </form>

      <h2>タスクリスト</h2>
      {tasks.length === 0 ? (
        <p>タスクがありません。</p>
      ) : (
        <ul className="task-list">
          {tasks.map(task => (
            <li key={task.id} className={task.isCompleted ? 'completed' : ''}>
              <div className="task-header">
                <h3>{task.title}</h3>
                <div>
                  <button onClick={() => handleToggleStatus(task.id)}>
                    {task.isCompleted ? '未完了にする' : '完了にする'}
                  </button>
                  <button onClick={() => handleDeleteTask(task.id)}>削除</button>
                </div>
              </div>
              {task.description && <p>{task.description}</p>}
              <small>作成日: {task.createdAt.toLocaleString()}</small>
              <span className="status">
                ステータス: {task.isCompleted ? '完了' : '未完了'}
              </span>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default App;
/* src/App.css */

.container {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.task-form {
  margin-bottom: 30px;
}

.task-form div {
  margin-bottom: 15px;
}

.task-form label {
  display: block;
  margin-bottom: 5px;
}

.task-form .required {
  color: red;
}

.task-form input,
.task-form textarea {
  width: 100%;
  padding: 8px;
  box-sizing: border-box;
}

.task-form button {
  padding: 10px 20px;
  font-size: 16px;
}

.task-list {
  list-style: none;
  padding: 0;
}

.task-list li {
  background: #f9f9f9;
  margin-bottom: 15px;
  padding: 15px;
  border-radius: 5px;
  position: relative;
}

.task-list li.completed {
  background: #d4edda;
  text-decoration: line-through;
  color: #6c757d;
}

.task-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.task-header h3 {
  margin: 0;
}

.task-header button {
  margin-left: 10px;
  padding: 5px 10px;
}

.status {
  display: block;
  margin-top: 10px;
  font-weight: bold;
}

パッと見た感じですが、しっかりコーディングされていますね。

では、実際に出力してみます。

デザインに関してはとてもシンプルで見やすいですね。
また、ChatGPT 4o の出力結果のような若干のスタイルの崩れも見られません。

続いて、実際にアプリケーションの動作を確認してみます。

実装面に関しても、要件に沿った機能が搭載されており、かつ ChatGPT 4o のようにボタンまで打ち消し線を反映させることはありませんでした。
また完了、未完了で色を分けるよう小洒落た実装もされていて、結構凄いです。

要件に書いていませんでしたが、必須バリデーションエラーもあるということで文句はないですね。

まとめ

以前のモデルも優れていると感じていましたが、『ChatGPT o1』はさらに大幅に進化しており、非常に驚かされました。
また、前述していませんでしたが、出力までの処理時間も『o1』の方が格段に速くなっていました。 さらに、要件の微妙なニュアンスの理解や、必須バリデーションなどの追加機能の実装においても、 まるで人間の思考に近い精度を実現していました。

ぜひ皆様も『ChatGPT o1』をお試しいただき、最先端AIの凄さを実感してみてください。

この記事を書いた人

2G
2G
システムエンジニアへの夢をあきらめきれず、建築業界からIT業界へ転職。
アーティス入社後はフロントエンドエンジニアとして、webアプリケーションサービスの開発に従事している。趣味は、ラーメン屋巡り。
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします