少し前にRaspberryPi ZEROWを使ってchatgptと連携させて会話できるものを作成しました。↓
これを応用して、AI会話と音楽再生ができる持ち運び可能なminiコンポを作ってみました。
内容的には上記のものに外装を作って液晶つけただけのようなもんなので全く持って大したことは無いのですが、せっかくだしここでまとめておこうと思います。
コンセプト
超小型のコンポをイメージした持ち運べる音楽再生機。
それだけでは物足りないのでchatgptで会話機能を盛り込み「chatgptで会話できるポータブルminiコンポ」とする。
。。それでも物足りないのでLEDテープで光らせて誤魔化す事とする。。(今後予定)
構成
・RaspberryPi ZEROW
・WM8960 Hi-Fi サウンドカード オーディオ HAT
・128*160 ILI9341 display
gpioにボタンを付けてchatgptとmusicモードの切り替えを行うつもりでしたが、なぜかプログラムが上手く動かなかったのでボタンの実装はあきらめました。
chatgptのプログラムを強制終了させると、musicモードが立ち上がるようにしました。
musicモードは、単にスマホとペアリングさせてスマホの音源を再生させているだけです。(というかLCDにmusicと表示させているだけ。。)
プログラム
chatgpt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
import pyaudio import struct import math import audioop import wave import time import os import io from google.cloud import speech import openai from google.cloud import texttospeech from gtts import gTTS import pygame.mixer from adafruit_rgb_display.rgb import color565 from adafruit_rgb_display.ili9341 import ILI9341 import random from busio import SPI from digitalio import DigitalInOut import board import time from PIL import Image, ImageDraw, ImageFont import adafruit_rgb_display.ili9341 as ili9341 # Pin Configuration cs_pin = DigitalInOut(board.D8) dc_pin = DigitalInOut(board.D24) rst_pin = DigitalInOut(board.D25) # Set up SPI bus spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO) # Create the ILI9341 display: display = ILI9341( spi, cs=cs_pin, dc=dc_pin, rst=rst_pin, width=128, height=160, rotation=180, baudrate=24000000 ) WIDTH = 128 HEIGHT = 160 font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 24) text_width, text_height = font.getsize("chatgpt") image = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0)) draw = ImageDraw.Draw(image) draw.text(((WIDTH - text_width) // 2, (HEIGHT - text_height) // 2),"chatgpt", font=font, fill=(255, 255, 255)) display.image(image.transpose(Image.FLIP_TOP_BOTTOM)) pygame.mixer.init() openai.api_key = "key" os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '****.json' # Instantiates a client client = speech.SpeechClient() ### 音声データを指定 speech_file = 'output.wav' chunk = 1024 FORMAT = pyaudio.paInt16 CHANNELS = 1 RATE = 44100 INPUT_DEVICE_INDEX = 0 THRESHOLD = 700 SILENCE_LIMIT = 3 RECORD_SECONDS = 5 WAVE_OUTPUT_FILENAME = "output.wav" p = pyaudio.PyAudio() def get_rms(block): """ Returns the root mean square of the audio block. """ return audioop.rms(block, 2) def get_audio_input_device(p, input_device_index, channels=1, rate=44100, frames_per_buffer=1024): stream = p.open(format=pyaudio.paInt16, channels=channels, rate=rate, input=True, input_device_index=input_device_index, frames_per_buffer=frames_per_buffer) return stream def ask_gpt(text): response = openai.Completion.create( engine="davinci", # 使用する言語モデルを指定する prompt=text, max_tokens=1024, # 応答の長さを指定する n=1, # 応答の候補数を指定する stop=None, # 応答の終了条件を指定する ) return response.choices[0].text.strip() # text to speech関数(引数:変換テキスト、対応言語、出力ファイル名) def text_to_speech(text, language, name): # gTTSインスタンスの作成 text2speech = gTTS(text, # 音声変換するテキスト lang=language, # 対応言語(ja:日本語) ) # 音声変換したデータをファイルに保存 text2speech.save(name + ".mp3") return True stream = get_audio_input_device(p, INPUT_DEVICE_INDEX, CHANNELS, RATE, chunk) is_recording = False silence_counter = 0 frames = [] #frames = [bytes(frame) for frame in frames] type = "nane" t_end = time.time() t_time = 3 text = "" while True: try: block = stream.read(chunk, exception_on_overflow=False) amplitude = get_rms(block) if not is_recording: if amplitude > THRESHOLD: is_recording = True print("Recording started") frames = [] elif is_recording: if amplitude > THRESHOLD: silence_counter = 0 # Record audio block frames.append(block) type = "on" print("rokuon") else: if type == "on": cdown = time.time() #for i in range(0, int(RATE / chunk * RECORD_SECONDS)): while True: if time.time() < cdown + 3 and amplitude < THRESHOLD: #data = stream.read(block) block = stream.read(chunk, exception_on_overflow=False) frames.append(block) #t_end = time.time() #t_time = 3 #if time.time() < t_end + t_time: #frames.append(block) #print("kuuhaku") else: #print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa") break #time.sleep(3) type = "off" silence_counter += 1 if silence_counter > (RATE / chunk) * SILENCE_LIMIT: is_recording = False silence_counter = 0 print("Recording stopped") # Save recorded audio to file wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') wf.setnchannels(CHANNELS) wf.setsampwidth(p.get_sample_size(FORMAT)) wf.setframerate(RATE) #print(frames) #frames = [struct.pack('h', s) for s in frames] wf.writeframes(b''.join(frames)) wf.close() frames = [] #print("nnnnnnnnnnnnaaaaaaaaaaaaaaaaaaasssssssssssssiiiiiiiiii") # 音声ファイルを読み込む with wave.open("output.wav", "rb") as f: frames = f.readframes(f.getnframes()) sample_rate = f.getframerate() sample_width = f.getsampwidth() channels = f.getnchannels() print("wait....") ### rb(read binary)でデータを読み込む with io.open(speech_file, 'rb') as f: content = f.read() ### RecognitionAudioにデータを渡す audio = speech.RecognitionAudio(content=content) config = speech.RecognitionConfig( ### encodeでエラーが出たのでENCODING_UNSPECIFIEDに変更 encoding=speech.RecognitionConfig.AudioEncoding.ENCODING_UNSPECIFIED, sample_rate_hertz=44100, language_code="ja-JP", ) ### 音声を抽出 response = client.recognize(config=config, audio=audio) ### 抽出結果をprintで表示 for result in response.results: if "{}".format(result.alternatives[0].transcript) == "": text = "" frames = [] break print("Transcript: {}".format(result.alternatives[0].transcript)) text = "{}".format(result.alternatives[0].transcript) # ChatGPTにテキストを送信して回答を受け取る if text != "": #answer = ask_gpt("what your name?") response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[ #{"role": "system", "content": "日本語で返事してください"}, {"role": "user", "content": text} ] ) #print(type(response)) print("response" + response.choices[0]["message"]["content"].strip()) text = response.choices[0]["message"]["content"].strip() #print(response) #print(answer) #ChatGPTの回答を音声データに変換してファイルに保存する language = "ja" # 保存ファイル名 name = "gTTS_Text2Speech" # 関数実行 text_to_speech(text, language, name) #with wave.open("output.wav", "wb") as f: # f.setnchannels(channels) # f.setsampwidth(sample_width) # f.setframerate(sample_rate) #print("Done.") # Cloud Text-to-Speech APIのクライアントを初期化する #client = texttospeech.TextToSpeechClient() # 音楽ファイルの読み込み pygame.mixer.music.load("gTTS_Text2Speech.mp3") # 音楽再生 pygame.mixer.music.play(0) while True: if(pygame.mixer.music.get_busy()!=True): break time.sleep(0.2) pygame.mixer.music.stop() text = "" # 回答を音声データに変換する #input_text = messages # 元のテキストと回答を結合する #synthesis_input = texttospeech.SynthesisInput(text=input_text) #voice = texttospeech.VoiceSelectionParams( # language_code="ja-JP", # name="ja-JP-Wavenet-A", # ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL, #) #audio_config = texttospeech.AudioConfig( # audio_encoding=texttospeech.AudioEncoding.LINEAR16, # sample_rate_hertz=sample_rate, #) #response = client.synthesize_speech( # input=synthesis_input, voice=voice, audio_config=audio_config #) # 回答を音声ファイルに保存する #with wave.open("output.wav", "wb") as f: #f.setnchannels(channels) #f.setsampwidth(sample_width) #f.setframerate(sample_rate) #f.writeframes(response.audio_content) print("Done.") #frames = [] # Debug: Print amplitude #print(f"Amplitude: {amplitude}") #print(type) except KeyboardInterrupt: font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 24) text_width, text_height = font.getsize("music") image = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0)) draw = ImageDraw.Draw(image) draw.text(((WIDTH - text_width) // 2, (HEIGHT - text_height) // 2),"music", font=font, fill=(255, 255, 255)) display.image(image.transpose(Image.FLIP_TOP_BOTTOM)) time/sleep(3) break stream.stop_stream() p.terminate() |
music
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
from adafruit_rgb_display.rgb import color565 from adafruit_rgb_display.ili9341 import ILI9341 import random from busio import SPI from digitalio import DigitalInOut import board import time from PIL import Image, ImageDraw, ImageFont import adafruit_rgb_display.ili9341 as ili9341 import RPi.GPIO as GPIO # RPi.GPIOモジュールを使用 import time GPIO.setmode(GPIO.BCM) GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # Pin Configuration cs_pin = DigitalInOut(board.D8) dc_pin = DigitalInOut(board.D24) rst_pin = DigitalInOut(board.D25) # Set up SPI bus spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO) # Create the ILI9341 display: display = ILI9341( spi, cs=cs_pin, dc=dc_pin, rst=rst_pin, width=128, height=160, rotation=180, baudrate=24000000 ) WIDTH = 128 HEIGHT = 160 # テキストが画面に収まる場合はそのまま表示 font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 24) text_width, text_height = font.getsize("music") image = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0)) draw = ImageDraw.Draw(image) draw.text(((WIDTH - text_width) // 2, (HEIGHT - text_height) // 2),"music", font=font, fill=(255, 255, 255)) display.image(image.transpose(Image.FLIP_TOP_BOTTOM)) GPIO.cleanup() |
外装
液晶部がもっと上手い事隠せんかったんかと突っ込みたくなりますがもう次の作品を作りたいのでこれで良しとします。
完成
こんなもんばっかりつくってます!
それでも良ければ是非フォロー&拡散してくださいね!!