見出し画像

ずんだもんに目を与えて実況させようとした話

ゲームは一人でするのも楽しいですが、やはりみんなでワイワイやるゲームは格別です。
しかし悲しいかな、人間そう上手く都合が合いません…
もし日常的に一緒にゲームできる人が居る方は大事になすってください。

そこで無敵のAIの出番!!!
AIくんに実況してもらって、掛け合いを楽しむ、そういう事ができれば一人でも寂しくない!!!!!

というわけで、もはや浸透した感もある `gpt-4-vision-preview` の使ってみた記事になります。
最終的に出来たものはこちら



視野を設定(キャプチャ画面を作成)

まずは視野を設定します。
正直他はAPIを繋げこむだけなので、そこまで大変ではないのですが、
このスクショ枠が諸々うまく動かなくて大変でした。

まだ整理出来てないですが、スクショ部分だけだとこんな感じ
(投稿したらハイライトされるらしい…信じよう)

# draggable_window.py

import tkinter as tk
from PIL import ImageGrab
import time
import os
from datetime import datetime
import threading
import json
from screeninfo import get_monitors
from tts_api import VoiceVoxTTS
from image_analys import ImageAnalysisAPI

class DraggableWindow:
    def __init__(self, root, api_url="http://localhost:50021"):
        self.root = root
        self.root.attributes('-alpha', 0.1)  # 完全に透明
        self.root.attributes('-topmost', True)  # 最前面表示
        self.save_directory = "captured_screenshots"
        self.tts = VoiceVoxTTS(api_url)
        self.image_api = ImageAnalysisAPI() 

    def get_current_monitor(self):
        # 現在のウィンドウ位置に基づいて現在のモニターを取得
        x, y = self.root.winfo_x(), self.root.winfo_y()
        for m in get_monitors():
            if m.x <= x <= m.x + m.width and m.y <= y <= m.y + m.height:
                return m
        return None  # モニターが見つからない場合

    def capture_screen(self, window, interval=10):
        while True:
            self.tts.wait_until_playback_finishes()  # TTSの再生が終了するまで待つ

            current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
            output_path = os.path.join(self.save_directory, f"screenshot_{current_time}.png")

            monitor = self.get_current_monitor()
            if not monitor:
                continue  # モニターが見つからない場合はスキップ

            # モニターの解像度に基づいて座標計算
            x = max(self.root.winfo_rootx(), monitor.x)
            y = max(self.root.winfo_rooty(), monitor.y)
            w = min(self.root.winfo_width(), monitor.width)
            h = min(self.root.winfo_height(), monitor.height)

            print(x, y, x + w, y + h)
            screenshot = ImageGrab.grab(bbox=(x, y, x + w, y + h))
            screenshot.save(output_path)
            print(f"スクリーンショットを保存しました: {output_path}")
            self.speak(output_path)
            time.sleep(interval)

    def speak(self, output_path):
        # 画像のテキスト化
        text = self.image_api.analyze_image(output_path)

        # TTSでの音声再生
        self.tts.text_to_speech(text)

常に最前面に透過したウィンドウをおいて、
その範囲内を一定時間ごとにスクショするだけのコードです。

スクショするときの座標計算がサブモニタとの兼ね合いでズレてたり、
画面の枠をフレキシブルにしようとして結局ウィンドウ従来の機能を使ったほうが良いなとなったり紆余曲折ありました。

声を付与(TTSを組み込み)

localにVOICEVOXのDockerを立てて、そこにテキストを投げ込んで読ませています。
結構処理が重たそうだったので、ストリーミングとかGPU利用とかにしてみたほうが良さそう。要改善ポイントです。


開眼(GPT-4Vへの接続)

いよいよ本題の、GPTへの接続!
ですが、大した手間はかからず、APIにエイヤと画像を投げてあげるだけです。

こんな感じ

 response = self.client.chat.completions.create(
            model="gpt-4-vision-preview",
            messages=[
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": "What’s in this image?Responses must be in Japanese."},
                        *map(lambda x: {"image": x, "resize": 512}, base64Frames),
                    ],
                }
            ],
            max_tokens=300,
        )
content = response.choices[0].message.content

所感

こうした生まれたのが冒頭の動画のずんだもんなわけですが、
一緒に実況を楽しむにはいくつかの課題がまだあります。

まず第一に顔がない。
キャラクターとしてこれは致命的。
このためにUnityを色々触ってましたが、うまくエラーが取れずに断念…
今月どこかでリベンジしたい…

そして第二に応答が遅い
レスポンスを見てると、4Vはそこそこ早そうなので、TTSをもう少し高速化してやれば良さそう。

最後に、キャラクターが弱い。
現時点ではただのChatGPT4Vなので、面白みが無いです。
実況らしいプロンプトを仕込んだりしてその辺のキャラメイクをいい感じにしておきたいところ…

この記事が気に入ったらサポートをしてみませんか?