見出し画像

1人でもすいか割りがやりたいのでAIに指示してもらう動画で使ったコードをそのまま公開するやつ

三珠さくまるです。おそらくVtuberです。

https://www.youtube.com/watch?v=G1FKCXi0-oI

動画勢の動画リレーに参加しました。

そのときに書いたAIにWebカメラから見た状況からAIにすいか割りの支持をさせるコードを公開します。ちゃんと書いた割りに、カットしちゃって、見せ場、特になかったからなぁ……お好きに使っていいですが、自己責任でお願いします。

import cv2
import openai
import time
import os
from pathlib import Path
from playsound import playsound
from datetime import datetime
import tkinter as tk
from tkinter import ttk
import sounddevice as sd
import base64
import requests

# OpenAI APIキーを設定
api_key = "ここにAPI KEYをいれるぜ"
openai.API_KEY = api_key

def list_cameras():
    """利用可能なカメラデバイスをリストアップする関数"""
    index = 0
    arr = []
    while True:
        cap = cv2.VideoCapture(index)
        if not cap.read()[0]:
            break
        else:
            arr.append(f"Camera {index}")
        cap.release()
        index += 1
    if not arr:
        arr.append("None")
    return arr

def list_audio_devices():
    """利用可能なオーディオデバイスをリストアップする関数"""
    devices = sd.query_devices()
    output_devices = [device['name'] for device in devices if device['max_output_channels'] > 0]
    return output_devices

def capture_image(camera_index=0):
    """カメラから画像をキャプチャする関数"""
    cap = cv2.VideoCapture(camera_index)
    if not cap.isOpened():
        print("カメラを開くことができません")
        return None
    
    ret, frame = cap.read()
    if not ret:
        print("画像をキャプチャできません")
        return None
    
    cap.release()
    return frame

def encode_image(image_path):
    """画像をBase64にエンコードする関数"""
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode('utf-8')

def send_image_to_openai(image_path):
    """画像をOpenAI APIに送信し、指示を取得する関数"""
    base64_image = encode_image(image_path)
    
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}"
    }
    
    payload = {
        "model": "gpt-4o",
        "messages": [
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": (
                            "あなたはスイカ割の指示役です。これはスイカ割りをしている人です。"
                            "彼は目隠しをしていて、どっちを向いているかはわかっていません"
                            "彼がスイカに近づけるよう右を向くや進むや左を向くや1つだけ命令してください。棒を振り落とせば割れる場合、そう指示を出してください。"
                            "5秒後、また指示を出してもらうようにお願いしますので、待っていてください"
                        )
                    },
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": f"data:image/jpeg;base64,{base64_image}"
                        }
                    }
                ]
            }
        ],
        "max_tokens": 300
    }
    
    response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
    response_json = response.json()
    
    return response_json['choices'][0]['message']['content']

def generate_speech_from_text(text, model="tts-1", voice="nova"):
    """テキストから音声を生成し、ファイルに保存する関数"""
    client = openai.Client(api_key=api_key)  # APIキーを渡す
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    speech_file_path = Path.cwd()/f"Speech_{timestamp}.mp3"
    
    response = client.audio.speech.create(
        model=model,
        voice=voice,
        input=text
    )
    
    response.stream_to_file(speech_file_path)
    return speech_file_path

def play_audio(file_path):
    """MP3ファイルを再生する関数"""
    playsound(file_path)

def save_log(log_data, log_file="log.txt"):
    """ログデータを保存する関数"""
    with open(log_file, "a") as f:
        f.write(log_data + "\n")

def save_image(image, filename):
    """画像をファイルに保存する関数"""
    cv2.imwrite(filename, image)

def start_process(camera_index, speaker_name, interval=5):
    """メインのプロセスを開始する関数"""
    # スピーカーのテスト音声再生
    print("スピーカーのテストを行います...")
    time.sleep(3)
    play_audio(Path.cwd() / "test.mp3")
    
    # 1分後にStart.mp3を再生
    print("1分後にStart.mp3を再生します...")
    time.sleep(30)
    play_audio(Path.cwd() / "start.mp3")
    
    start_time = time.time()
    
    while True:
        image = capture_image(camera_index)
        if image is None:
            continue
        
        # 画像ファイル名を生成して保存
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        image_filename = f"captured_{timestamp}.jpg"
        save_image(image, image_filename)
        
        # OpenAIに画像を送信して指示を取得
        instruction = send_image_to_openai(image_filename)
        print("指示:", instruction)
        
        # 指示のログを保存
        log_data = f"{timestamp}: {instruction}"
        save_log(log_data)
        
        # 指示を音声に変換して再生
        speech_file = generate_speech_from_text(instruction)
        play_audio(speech_file)

        time.sleep(interval)

def main():
    # Tkinterウィンドウの初期化
    root = tk.Tk()
    root.title("カメラとスピーカーの選択")
    
    cameras = list_cameras()
    audio_devices = list_audio_devices()
    
    camera_var = tk.StringVar(value=cameras[0] if cameras else "None")
    speaker_var = tk.StringVar(value=audio_devices[0] if audio_devices else "Default")
    
    # カメラ選択プルダウンメニュー
    tk.Label(root, text="カメラデバイスを選択してください:").pack()
    camera_menu = ttk.Combobox(root, textvariable=camera_var, values=cameras)
    camera_menu.pack()
    
    # スピーカー選択プルダウンメニュー
    tk.Label(root, text="スピーカーを選択してください:").pack()
    speaker_menu = ttk.Combobox(root, textvariable=speaker_var, values=audio_devices)
    speaker_menu.pack()
    
    def on_start():
        camera_index = cameras.index(camera_var.get())
        speaker_name = speaker_var.get()
        root.destroy()  # GUIを閉じる
        start_process(camera_index, speaker_name)
    
    # スタートボタン
    start_button = tk.Button(root, text="開始", command=on_start)
    start_button.pack()
    
    root.mainloop()

if __name__ == "__main__":
    main()

使い方:あんまわかんない人が使うのには向いてないぜ!!
start.mp3とtest.mp3をいい感じのところに入れて、一応、API Key(Open AI)を入力して、カメラとスピーカーを選択すれば使えます。
ぶっちゃけ、カメラの画像を定期的にChatGPTに送って、その返答をスピーカー出力してるという仕組みなので、インストラクションの部分とかインターバルの時間を弄ればなんにでも使えます!!!

たまにコード公開するので
チャンネル登録とかよろしく!以上!!


いいなと思ったら応援しよう!