顔認識して天気を答える
Weather map api で現在地の天気を取得し
Voicevox へ curl で送って音声を作成し
Pygame でしゃべるまではできたので
次にこれを関数にしてkao.pyで実行するようにする
まずはubuntuへ転送して実験する
1 2 | pip install pygame pip install --upgrade deepl |
で足りないものを入れる
そして
1 | scp weather_* snowpool@192.168.1.69: /home/snowpool/aw10s/ |
でコピーして
1 | python weather_voice.py |
を実行するとubuntu でもできた
次に、このweather_voide.pyのコードを関数にする
現在の天気を取得するコードは
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 | import requests import json from datetime import datetime import deepl def get_weather_forecast(latitude, longitude, API_key, deepl_auth_key): # DeepL Translatorのインスタンスを生成 translator = deepl.Translator(deepl_auth_key) # OpenWeather APIのURL url = "https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude=hourly,minutely&units=metric&lang=ja&appid={API_key}" url = url. format (lat=latitude, lon=longitude, API_key=API_key) # APIリクエスト response = requests.get(url) jsondata = response.json() # 今日の日付を取得 today = datetime.now(). date () # 今日の天気予報を探す for daily_forecast in jsondata[ "daily" ]: date = datetime.fromtimestamp(daily_forecast[ "dt" ]). date () if date == today: min_temp = daily_forecast[ "temp" ][ "min" ] max_temp = daily_forecast[ "temp" ][ "max" ] weather = daily_forecast[ "weather" ][0][ "main" ] description = daily_forecast[ "weather" ][0][ "description" ] break # 天気をdeeplで日本語に翻訳 weather_japanese = translator.translate_text(weather, target_lang= "JA" ).text # 今日の天気予報をまとめる today_weather_repo = f "今日の天気は{weather_japanese}、予想最高気温は{max_temp}度、予想最低気温は{min_temp}度です" return today_weather_repo # 関数を使用して天気予報を取得 latitude = "緯度" longitude = "経度" API_key = "open weather map APIキー" deepl_auth_key = "deepLのAPIキー" weather_report = get_weather_forecast(latitude, longitude, API_key, deepl_auth_key) # 天気予報をテキストファイルに保存 with open ( 'weather.txt' , 'w' ) as file : file .write(weather_report) |
これは
weather_forecast.py
にまとめてある
次に
weather_voice.py
をほかで呼べるように関数にする
現状は
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 | import subprocess import pygame import time from weather_forecast import get_weather_forecast # 天気予報を取得してファイルに保存 latitude = "緯度" longitude = "経度" API_key = "open weather map API キー" deepl_auth_key = "deepLのAPIキー" weather_report = get_weather_forecast(latitude, longitude, API_key, deepl_auth_key) with open ( 'weather.txt' , 'w' ) as file : file .write(weather_report) # JSONファイルを作成するためのcurlコマンド command_json = [ "curl" , "-s" , "-X" , "POST" , "192.168.1.69:50021/audio_query?speaker=1" , "--get" , "--data-urlencode" , "text@weather.txt" ] # 音声ファイルを作成するためのcurlコマンド command_audio = [ "curl" , "-s" , "-H" , "Content-Type: application/json" , "-X" , "POST" , "-d" , "@query.json" , "192.168.1.69:50021/synthesis?speaker=1" ] # 最初のコマンドを実行してJSONファイルを作成 with open ( 'query.json' , 'w' ) as file : subprocess.run(command_json, stdout= file ) # 第二のコマンドを実行して音声ファイルを作成 with open ( 'test_audio.wav' , 'wb' ) as file : subprocess.run(command_audio, stdout= file ) # Pygameの初期化 pygame.init() pygame.mixer.init() # WAVファイルを読み込む sound = pygame.mixer.Sound( "test_audio.wav" ) # 再生 sound.play() # 再生が終了するまで待機 while pygame.mixer.get_busy(): time . sleep (0.1) |
これを関数にする
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 | import subprocess import pygame import time from weather_forecast import get_weather_forecast def generate_and_play_weather_report(latitude, longitude, API_key, deepl_auth_key): # 天気予報を取得してファイルに保存 weather_report = get_weather_forecast(latitude, longitude, API_key, deepl_auth_key) with open ( 'weather.txt' , 'w' ) as file : file .write(weather_report) # JSONファイルを作成するためのcurlコマンド command_json = [ "curl" , "-s" , "-X" , "POST" , "192.168.1.69:50021/audio_query?speaker=1" , "--get" , "--data-urlencode" , "text@weather.txt" ] # 音声ファイルを作成するためのcurlコマンド command_audio = [ "curl" , "-s" , "-H" , "Content-Type: application/json" , "-X" , "POST" , "-d" , "@query.json" , "192.168.1.69:50021/synthesis?speaker=1" ] # JSONファイルと音声ファイルを作成 with open ( 'query.json' , 'w' ) as file : subprocess.run(command_json, stdout= file ) with open ( 'test_audio.wav' , 'wb' ) as file : subprocess.run(command_audio, stdout= file ) # Pygameで音声ファイルを再生 pygame.init() pygame.mixer.init() sound = pygame.mixer.Sound( "test_audio.wav" ) sound.play() while pygame.mixer.get_busy(): time . sleep (0.1) |
変更点を確認しておく
インポート部分は変化なし
1 2 3 4 5 6 7 8 9 10 11 | import subprocess import pygame import time from weather_forecast import get_weather_forecast # 天気予報を取得してファイルに保存 latitude = "34.745755" longitude = "137.91146" API_key = "open weather map のAPIキー" deepl_auth_key = "deepLのAPIキー" |
の部分を削除しkao.pyへ移動させる
また
1 | import weather_voice |
をkao,oyへ追加
そしてprintぶんの下へ
1 | weather_voice.generate_and_play_weather_report(latitude, longitude, API_key, deepl_auth_key) |
を追記して保存
実験のため
VNC接続して実行
ubuntuで
1 | tigervncserver -xstartup /usr/bin/gnome-session -geometry 800x600 -localhost no :1 |
を実行後
Mac の場合
Finder から
移動 > サーバーに接続で
1 | vnc: //192 .168.1.69:5901 |
で接続
これで実験すると顔認識した時に今日の天気を教えてくれるようになった
次は画面表示せずに処理するようにコードを書き換える
これは単純にishowの画面表示部分と
認識した部分を枠で囲む部分を削除するだけでOK
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 | import cv2 import time import weather_voice # 天気予報を取得してファイルに保存 latitude = "緯度" longitude = "経度" API_key = "open weather map APIキー" deepl_auth_key = "deepLのAPIキー" # Haar Cascade分類器の読み込み face_cascade = cv2.CascadeClassifier( 'haarcascade_frontalface_default.xml' ) eye_cascade = cv2.CascadeClassifier( 'haarcascade_eye.xml' ) # Webカメラの設定 cap = cv2.VideoCapture(0) # 0番目のカメラを使用する場合 # 最後の顔検出時刻 lastTime = None # メインループ while True: # カメラからのフレームの取得 ret, frame = cap. read () # フレームのグレースケール化 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 顔の検出 faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) # 検出された顔に対する処理 for (x, y, w, h) in faces: # 検出自の処理(検出から1分たったら再度イベント動かす if lastTime is None or time .perf_counter() - lastTime > 60: # 検出時刻更新 lastTime = time .perf_counter() print( "人間発見、警戒せよw" ) weather_voice.generate_and_play_weather_report(latitude, longitude, API_key, deepl_auth_key) #画像を表示する場合 #cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2) #roi_gray = gray[y:y+h, x:x+w] #roi_color = frame[y:y+h, x:x+w] # 以下は目もマークする場合 # eyes = eye_cascade.detectMultiScale(roi_gray) # for (ex, ey, ew, eh) in eyes: # cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (255, 0, 0), 2) # 結果の表示 #cv2.imshow('Facial Feature Detection', frame) # 終了のキー入力 if cv2.waitKey(1) & 0xFF == ord( 'q' ): break # 後処理 cap.release() cv2.destroyAllWindows() |
とすればOK
あとは終了する方法が
Ctrl +c 以外にないので
他に終了させる方法があるか考える
それとスペック不足のためか
顔認識してから音声が出るまでに時間がかかる
とりあえず不要部分を削除したのが
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 | import cv2 import time import weather_voice # 天気予報を取得してファイルに保存 latitude = "34.745755" longitude = "137.91146" API_key = "1082c12d65462d76f7dd1b7ef93c7849" deepl_auth_key = "5f169e4d-3701-9eff-08fc-bf6065b64c8f:fx" # Haar Cascade分類器の読み込み face_cascade = cv2.CascadeClassifier( 'haarcascade_frontalface_default.xml' ) eye_cascade = cv2.CascadeClassifier( 'haarcascade_eye.xml' ) # Webカメラの設定 cap = cv2.VideoCapture(0) # 0番目のカメラを使用する場合 # 最後の顔検出時刻 lastTime = None # メインループ while True: # カメラからのフレームの取得 ret, frame = cap. read () # フレームのグレースケール化 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 顔の検出 faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) # 検出された顔に対する処理 for (x, y, w, h) in faces: # 検出自の処理(検出から1分たったら再度イベント動かす if lastTime is None or time .perf_counter() - lastTime > 60: # 検出時刻更新 lastTime = time .perf_counter() print( "今日の天気を顔認識したのでお知らせ" ) weather_voice.generate_and_play_weather_report(latitude, longitude, API_key, deepl_auth_key) # 後処理 cap.release() cv2.destroyAllWindows() |
次にセキュリティのため
1 | vim config.ini |
でファイルを作り
1 2 3 | [API_KEYS] OPENWEATHER_API_KEY = open weather map API キー DEEPL_AUTH_KEY = deepLのAPIキー |
というようにしてキーを設定ファイルから読み込むようにする
なおキーを”” で囲むとバグるので注意
あとは
Pythonスクリプトでconfigparserモジュールを使用して設定ファイルから情報を読み込む
1 2 3 4 5 6 7 8 | import configparser # 設定ファイルを読み込む config = configparser.ConfigParser() config. read ( 'config.ini' ) # APIキーを取得 API_key = config[ 'API_KEYS' ][ 'OPENWEATHER_API_KEY' ] deepl_auth_key = config[ 'API_KEYS' ][ 'DEEPL_AUTH_KEY' ] |
これを使うようにコードを変更する
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 | import cv2 import time import configparser import weather_voice # 天気予報を取得してファイルに保存 latitude = "緯度" longitude = "経度" # 設定ファイルを読み込む config = configparser.ConfigParser() config. read ( 'config.ini' ) # APIキーを取得 API_key = config[ 'API_KEYS' ][ 'OPENWEATHER_API_KEY' ] deepl_auth_key = config[ 'API_KEYS' ][ 'DEEPL_AUTH_KEY' ] # Haar Cascade分類器の読み込み face_cascade = cv2.CascadeClassifier( 'haarcascade_frontalface_default.xml' ) eye_cascade = cv2.CascadeClassifier( 'haarcascade_eye.xml' ) # Webカメラの設定 cap = cv2.VideoCapture(0) # 0番目のカメラを使用する場合 # 最後の顔検出時刻 lastTime = None # メインループ while True: # カメラからのフレームの取得 ret, frame = cap. read () # フレームのグレースケール化 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 顔の検出 faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) # 検出された顔に対する処理 for (x, y, w, h) in faces: # 検出自の処理(検出から1分たったら再度イベント動かす if lastTime is None or time .perf_counter() - lastTime > 60: # 検出時刻更新 lastTime = time .perf_counter() print( "今日の天気を顔認識したのでお知らせ" ) weather_voice.generate_and_play_weather_report(latitude, longitude, API_key, deepl_auth_key) # 後処理 cap.release() cv2.destroyAllWindows() |
とりあえずこれで完成
どのみちバックグランドで動作させるので
停止方法は保留
あとは GitHub へコードをアップする