0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CopilotKitを使ってToDoアプリにAI Copilot機能をつける

Posted at

はじめに

Dev.toを眺めていたら、アプリケーション内にAI Copilot機能を早く簡単に構築できるツールを見つけたので試してみます。

そのツールの名前がCopilotKitです!

CopilotKitで主にできることは以下です。(公式サイトから)

image.png
image.png

今回は、公式サイトにある、ToDoアプリにAI Copilot機能を追加するチュートリアルを実施してみます。

👇成果物の例
image.png

image.png

image.png

image.png

環境構築

まずは、Copilot機能を追加するためのToDoアプリを用意して、それぞれセットアップをします。

ToDoアプリのセットアップ

① リポジトリのクローン

git clone -b base-start-here https://github.com/CopilotKit/example-todos-app.git
cd example-todos-app

② 依存性のインストール

npm install

③ ローカルで起動

npm run dev

http://localhost:3000 にアクセスするとToDoアプリが起動しているはずです。
まだただのToDoアプリです。

CopilotKitのセットアップ

① 依存性のインストール

npm install @copilotkit/react-core @copilotkit/react-ui
  • @copilotkit/react-core: CopilotKitのコアライブラリで、CopilotKitプロバイダーや便利なフックが含まれています
  • @copilotkit/react-ui: CopilotKitのUIライブラリで、サイドバー、チャットポップアップ、テキストエリアなどのCopilotKit UIコンポーネントが含まれています

② CopilotKitプロバイダの導入
CopilotKitを使用するためにはアプリケーションをCopilotKitプロバイダでラップする必要があります。
その際、Copilot CloudのAPIキーが必要なので、取得して <your-copilot-cloud-public-api-key> の部分に設定してくださいね。
Copilot Cloud APIキー

app\layout.tsx
image.png

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { Suspense } from "react";
import { CopilotKit } from "@copilotkit/react-core";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "CopilotKit Todos",
  description: "A simple todo app using CopilotKit",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <CopilotKit publicApiKey="ck_pub_8874a2eb5442ba759e9d72c59245a77f">
          <Suspense>{children}</Suspense>
        </CopilotKit>
      </body>
    </html>
  );
}

③ Chat Popupの導入
ポップアップチャットの機能を追加します。
app\page.tsx
image.png

"use client";

import { TasksList } from "@/components/TasksList";
import { TasksProvider } from "@/lib/hooks/use-tasks";
import { CopilotPopup } from "@copilotkit/react-ui"; 
import "@copilotkit/react-ui/styles.css"; 
 
export default function Home() {
  return (
    <>
      <TasksProvider>
        <TasksList />
      </TasksProvider>
      <CopilotPopup />
    </>
  );
}

とても簡単ですね。

再度、http://localhost:3000 にアクセスするとページの右下にチャットのポップアップボタンが表示されていると思います。

今回はポップアップチャット <CopilotPopup/ > を使用しましたが、その他にも<CopilotSidebar /><CopilotChat /> などもあります。

<CopilotSidebar /> の場合の画面
image.png

ここまでの状態ですと、ToDoアプリ画面にポップアップが表示され、AIと会話できるだけです。
この後は、自然言語でアプリの状態を操作する実装を追加していきます。

AI Copilot機能の追加

Copilot Readable State

AIを使用してアプリの状態を操作する前に、AI側にアプリの状態を知ってもらう必要があります。
こちらのToDoアプリでは lib/hooks/use-tasks.tsxファイル 内でタスクの管理やタスクの追加・更新・削除メソッドを定義しています。

  • タスクの状態変数(tasks
  • タスクの追加メソッド(addTask
  • タスクの更新メソッド(setTaskStatus
  • タスクの削除メソッド(deleteTask

このファイル内に新しく useCopilotReadable フックを定義していきます。
lib\hooks\use-tasks.tsx
image.png

  • descriptionプロパティにはアプリの状態を知ってもらうためにAIへ渡したデータの意味を記載します
  • value プロパティには状態全体(ここではタスクの状態)をJSON文字列として指定しています

これでAI Copilotは何のタスクがあるか把握できるようになりました。

試しに、タスクは何個ある?と聞いてみてください!

Copilot Actions

最後はCopilot Actionsです。
AI Copilotとタスク管理メソッドを紐づけましょう。
タスクを追加するaddTask メソッド、タスクを更新するsetTaskStatus メソッド、タスクを削除する deleteTask メソッドそれぞれに対して useCopilotAction を定義しましょう。

lib\hooks\use-tasks.tsx
image.png

image.png

lib\hooks\use-tasks.tsxの最終的なコード

import { createContext, useContext, useState, ReactNode } from "react";
import { defaultTasks } from "../default-tasks";
import { Task, TaskStatus } from "../tasks.types";

import { useCopilotReadable, useCopilotAction } from "@copilotkit/react-core";

let nextId = defaultTasks.length + 1;

type TasksContextType = {
  tasks: Task[];
  addTask: (title: string) => void;
  setTaskStatus: (id: number, status: TaskStatus) => void;
  deleteTask: (id: number) => void;
};

const TasksContext = createContext<TasksContextType | undefined>(undefined);

export const TasksProvider = ({ children }: { children: ReactNode }) => {
  const [tasks, setTasks] = useState<Task[]>(defaultTasks);

  useCopilotReadable({
    description: "The state of the todo list",
    value: JSON.stringify(tasks),
  });

  useCopilotAction({
    name: "addTask",
    description: "Adds a task to the todo list",
    parameters: [
      {
        name: "title",
        type: "string",
        description: "The title of the task",
        required: true,
      },
    ],
    handler: ({ title }) => {
      addTask(title);
      console.log("Created");
    },
  });

  useCopilotAction({
    name: "deleteTask",
    description: "Deletes a task from the todo list",
    parameters: [
      {
        name: "id",
        type: "number",
        description: "The id of the task",
        required: true,
      },
    ],
    handler: ({ id }) => {
      deleteTask(id);
    },
  });

  useCopilotAction({
    name: "setTaskStatus",
    description: "Sets the status of a task",
    parameters: [
      {
        name: "id",
        type: "number",
        description: "The id of the task",
        required: true,
      },
      {
        name: "status",
        type: "string",
        description: "The status of the task",
        enum: Object.values(TaskStatus),
        required: true,
      },
    ],
    handler: ({ id, status }) => {
      setTaskStatus(id, status);
    },
  });

  const addTask = (title: string) => {
    setTasks([...tasks, { id: nextId++, title, status: TaskStatus.todo }]);
  };

  const setTaskStatus = (id: number, status: TaskStatus) => {
    setTasks(
      tasks.map((task) =>
        task.id === id ? { ...task, status } : task
      )
    );
  };

  const deleteTask = (id: number) => {
    setTasks(tasks.filter((task) => task.id !== id));
  };
  
  return (
    <TasksContext.Provider value={{ tasks, addTask, setTaskStatus, deleteTask }}>
      {children}
    </TasksContext.Provider>
  );
};

export const useTasks = () => {
  const context = useContext(TasksContext);
  if (context === undefined) {
    throw new Error("useTasks must be used within a TasksProvider");
  }
  return context;
};

この useCopilotAction がアプリケーションをとても便利なものにしてくれます。

  • name プロパティはメソッド名を指定しておきます
  • description は先ほどと同じように何をしているのか簡単な記載です
  • handleruseCopilotAction がトリガーされたときに呼び出される関数です
    • タスクの追加・更新・削除はここで実行されます

これでToDoアプリにAI Copilot機能をつけることができました。

試しに、タスクの追加や更新、削除などを自然言語で実施してみてください!

私が初めてこの機能を触ったときは結構感動しました。
今回はテキストで自然言語を入力してアプリを操作できるようになりましたが、将来的には自然言語を発声してアプリを操作できるようになるととても便利ですよね。
今後、このようなAI Nativeなアプリケーションはどんどん増えていくと思いますので、成果物だけでも体感してみてください!

実装前のコード
実装後のコード

さいごに

これ以上にも、公式サイトからいくつかアイデアが提供されています。

  • useCopilotChatSuggestions フックを使用して、Copilotに提案を追加する
  • チャットウィンドウに最初のアシスタントメッセージを追加する
  • テキスト入力ホルダーにオートコンプリートを実装する

参考になれば嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?