🤖

社内ロボット開発企画の紹介

2024/07/24に公開

はじめに

はじめまして。データアナリティクスラボ株式会社 データソリューション事業部の力岡と申します。普段はデータサイエンティストとして、データ分析や機械学習モデルの構築、生成AIアプリの開発などを行っています。

今回は、社内で進めているロボット開発企画についてご紹介します。本記事では、技術的内容というよりも、社内の取り組みに焦点を当てて、紹介していきたいと思います。

ロボット開発企画とは

一言でいうと、最近話題の生成AI技術をロボットに組み込み、実際に勉強してみようという企画です。

通常、生成AIはChatGPTのように画面上で文字を入力して使用することが多いですが、現在はマルチモーダル化が急速に進んでおり、エージェントとして多岐にわたるタスクを遂行できる能力の開発が期待されています。この技術の進化に伴い、画面上だけで完結する処理だけでなく、物理的な存在を介した技術展開が盛んになると予想し、早いうちからこのような技術に触れ、世の中で必要とされる技術に対する感度を高めることを目的としてロボット開発企画を立案しました。

役員や上長への企画プレゼンを行い、承認を得た後、社内で協力者を募り、企画をスタートしました。

企画概要

本企画では、Raspberry Piという小型コンピュータを使って、音声チャット機能を開発を試みました。具体的には、Raspberry Piにカメラ、マイク、スピーカーを取り付けることで、Amazon Alexaのような音声認識と対話機能を実現しようとしています。

使用するハードウェア

  • Raspberry Pi:小型で低コストのコンピュータ。プログラミングや電子工作に広く使われている。
  • カメラ:画像をキャプチャするために使用。これにより、画像処理が可能になる。
  • マイク:音声を入力するために使用。ユーザーの音声指示を認識し、処理ができる。
  • スピーカー:音声出力を行うために使用。ユーザーに対する音声応答を行う。

機能の実装について

ロボットに実装した機能について説明します。基本的な流れとしては、マイクとカメラで取得したデータをOpenAIのAPIで処理し、その結果得られた音声データをスピーカーで出力するという仕組みになっています。システムの全体像は以下の通りです。

利用しているOpenAIのAPIは以下の3つです。API料金がかかりますが、手軽に実装できるため、興味のある方はぜひ調べてみてください。参考程度ですが、OpenAIのAPIを利用するプログラムも共有します。

  • gpt-4o:入力されたテキストに基づいて、適切な応答を生成するAPI
  • Whisper:音声をテキストに変換する音声認識API
  • TTS:テキストを音声に変換するAPI
プログラム
openai_wrapper.py
import os
import base64
import requests
from typing import Dict
from openai import OpenAI
from datetime import datetime
from picamera2 import Picamera2
from settings import OPENAI_API_KEY, IMAGES_DIR, AUDIO_DIR


# 初期設定
picam2 = Picamera2()
openai_client = OpenAI(api_key=OPENAI_API_KEY)


def ask_gpt_4o(messages: list) -> str:
    """
    GPT-4oを用いて、質問応答を行う.

    Args:
        content (str): 対話用プロンプト
        messages (list): メッセージリスト
    Returns:
        str: GPT-4oの生成テキスト
    """

    completion = openai_client.chat.completions.create(
        model="gpt-4o",
        messages=messages
    )

    return completion.choices[0].message.content


def make_audio_data(input_data: str, file_name=AUDIO_DIR+"speech.mp3"):
    """
    テキストデータからmp3形式のオーディオファイルを作成する.

    Args:
        input_data (str): オーディオファイルにするテキスト
        file_name (str): 保存するファイル名
    """

    response = openai_client.audio.speech.create(
        model="tts-1",
        voice="echo",
        input=input_data,
    )
    response.stream_to_file(file_name)


def transcript_whisper(audio_name: str):
    """
    音声データをテキスト化する.

    Args:
        audio_name (str): 音声データのファイル名
    Returns:
        str: 音声データのテキスト化データ
    """

    transcript = openai_client.audio.transcriptions.create(
        model="whisper-1",
        file=open(audio_name, "rb"),
        language="ja"
    )

    return transcript.text


def ask_gpt_4v(content: str) -> str:
    """
    GPT-4 visionのプロンプト制御を行う.

    Args:
        content (str): 対話用プロンプト
    Returns:
        str: GPT-4 visionの生成テキスト
    """

    def _take_picture() -> Dict:
        config = picam2.create_still_configuration()
        picam2.configure(config)
        picam2.start()
        now = datetime.now().strftime('%Y%m%d%H%M%S%f')
        picam2.capture_file(os.path.join(IMAGES_DIR, f'{now}_image.jpg'))
        picam2.stop()

    def _get_latest_image_path() -> str:
        image_file_list = os.listdir(IMAGES_DIR)
        image_file_list = [image_file for image_file in image_file_list if image_file.endswith('jpg')]
        image_file_list.sort(reverse=True)
        return os.path.join(IMAGES_DIR, image_file_list[0])

    def _encode_image(image_file_path: str) -> str:
        with open(image_file_path, 'rb') as image_file:
            return base64.b64encode(image_file.read()).decode('utf-8')

    _take_picture()
    image_path = _get_latest_image_path()
    base64_image = _encode_image(image_path)

    payload = {
        'model': 'gpt-4-turbo',
        'messages': [
            {
                'role': 'user', 'content': [
                    {'type': 'text', 'text': content},
                    {'type': 'image_url', 'image_url': {'url': f'data:image/jpeg;base64,{base64_image}'}}
                ]
            }
        ],
        'max_tokens': 300
    }
 
    url = 'https://api.openai.com/v1/chat/completions'
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f"Bearer {OPENAI_API_KEY}"
    }

    response = requests.post(url=url, headers=headers, json=payload)
    response = response.json()

    return response['choices'][0]['message']['content']

作業の様子

隔週でメンバーが集まり、定時後に開発を進めました。雑談しながらワイワイとプログラミングするのは楽しかったです。また、センサーの取り付けでは半田付けなども行いました!(電気工事士の資格を持つメンバーがおり、安全に気をつけて実施しました👨‍🔧)


完成した機能の紹介

画像対話機能と統計・AIクイズ生成機能の2つの機能を開発しましたので、紹介します。試験段階であるため、応答スピードや回答品質など改善の余地はありますが、試せるレベル感にはなっているかと思います。

画像対話機能

音声入力とともに写真を撮影し、その写真について回答してくれる機能です。Tシャツに書かれた「Data Analysis Labo」という文字まで読み取れているのはすごいですね。かなりのマルチモーダル性能です。
https://youtu.be/rMmHLRvV7oI

統計・AIクイズ生成機能

生成AIを利用して、統計・AIに関するクイズを作成し、回答の正誤を判断してくれる機能です。途中の選択肢の発音がややおかしいです。TTSモデルはまだ日本語の発音が得意ではなさそうですね。
https://youtu.be/jX30PT8PsA0

まとめ

以上が、ロボット開発企画の紹介となります。APIをうまく活用することで、計算能力の低いマイコンでも生成AIを利用した機能を実装することが可能となります。今後も新機能の計画や新規開発メンバーの募集を予定しており、さらなる挑戦を続けていきたいと思っています!

さいごに

このように弊社は、自分や会社のためになることを自由に企画して取り組める、自由な社風が特徴です。この他にも、社員一人ひとりが主体的にアイデアを出し、様々な企画が社内で推進されています。

もし、このような社風に共感を感じて、「興味があるので話を聞いてみたい」という方や「新たなメンバーとして、スタートアップ企業を成長させる取り組みに参加したい」という方は、ぜひ採用サイトからご連絡ください。

おまけ

企画に必要な機材は、役員と一緒に秋葉原まで買いに行きました。役員がこのような企画に積極的に参加してくれるのは、スタートアップ企業ならではの魅力じゃないかと思います。秋月商店や千石電商などをみんなで楽しく周りました!

DAL Tech Blog

Discussion