#30 おやつタイム対応(ブルスカ連携はまだ)

このコミットが含まれているのは:
2024-12-02 16:01:04 +09:00
コミット 719ae99273
11個のファイルの変更157行の追加179行の削除
ファイルの表示
+2 -1
ファイルの表示
@@ -1,5 +1,6 @@
import subprocess
from ctypes import *
from ctypes import ARRAY # type: ignore
from ctypes import POINTER, byref, c_int, c_ubyte, cast, cdll
class Aques:
-1
ファイルの表示
@@ -5,4 +5,3 @@ OPENAI_ORGANISATION: str = 'org-XXXXXXXXXXXXXXXXXXXXXXXX'
# API Key
OPENAI_API_KEY: str = 'sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
-82
ファイルの表示
@@ -1,82 +0,0 @@
Traceback (most recent call last):
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_exceptions.py", line 10, in map_exceptions
yield
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_backends/sync.py", line 126, in read
return self._sock.recv(max_bytes)
File "/usr/lib/python3.10/ssl.py", line 1288, in recv
return self.read(buflen)
File "/usr/lib/python3.10/ssl.py", line 1161, in read
return self._sslobj.read(len)
TimeoutError: The read operation timed out
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 66, in map_httpcore_exceptions
yield
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 228, in handle_request
resp = self._pool.handle_request(req)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py", line 268, in handle_request
raise exc
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py", line 251, in handle_request
response = connection.handle_request(request)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/connection.py", line 103, in handle_request
return self._connection.handle_request(request)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/http2.py", line 185, in handle_request
raise exc
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/http2.py", line 148, in handle_request
status, headers = self._receive_response(
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/http2.py", line 292, in _receive_response
event = self._receive_stream_event(request, stream_id)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/http2.py", line 333, in _receive_stream_event
self._receive_events(request, stream_id)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/http2.py", line 361, in _receive_events
events = self._read_incoming_data(request)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/http2.py", line 452, in _read_incoming_data
raise exc
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_sync/http2.py", line 438, in _read_incoming_data
data = self._network_stream.read(self.READ_NUM_BYTES, timeout)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_backends/sync.py", line 124, in read
with map_exceptions(exc_map):
File "/usr/lib/python3.10/contextlib.py", line 153, in __exit__
self.gen.throw(typ, value, traceback)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions
raise to_exc(exc) from exc
httpcore.ReadTimeout: The read operation timed out
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/miteruzo/Downloads/nizika_broadcast/main.py", line 117, in <module>
Main.main ()
File "/home/miteruzo/Downloads/nizika_broadcast/main.py", line 106, in main
live_chat = pytchat.create (video_id = YOUTUBE_ID)
File "/home/miteruzo/.local/lib/python3.10/site-packages/pytchat/core/__init__.py", line 7, in create
return PytchatCore(_vid, **kwargs)
File "/home/miteruzo/.local/lib/python3.10/site-packages/pytchat/core/pytchat.py", line 96, in __init__
self._setup()
File "/home/miteruzo/.local/lib/python3.10/site-packages/pytchat/core/pytchat.py", line 106, in _setup
channel_id=util.get_channelid(self._client, self._video_id),
File "/home/miteruzo/.local/lib/python3.10/site-packages/pytchat/util/__init__.py", line 103, in get_channelid
resp = client.get("https://www.youtube.com/embed/{}".format(quote(video_id)), headers=config.headers)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_client.py", line 1041, in get
return self.request(
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_client.py", line 814, in request
return self.send(request, auth=auth, follow_redirects=follow_redirects)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_client.py", line 901, in send
response = self._send_handling_auth(
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_client.py", line 929, in _send_handling_auth
response = self._send_handling_redirects(
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_client.py", line 966, in _send_handling_redirects
response = self._send_single_request(request)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_client.py", line 1002, in _send_single_request
response = transport.handle_request(request)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 227, in handle_request
with map_httpcore_exceptions():
File "/usr/lib/python3.10/contextlib.py", line 153, in __exit__
self.gen.throw(typ, value, traceback)
File "/home/miteruzo/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 83, in map_httpcore_exceptions
raise mapped_exc(message) from exc
httpx.ReadTimeout: The read operation timed out
-30
ファイルの表示
@@ -1,30 +0,0 @@
Traceback (most recent call last):
File "/home/miteruzo/Downloads/nizika_broadcast/main.py", line 136, in <module>
Main.main ((len (sys.argv) > 1) and (sys.argv[1] == '-g'))
File "/home/miteruzo/Downloads/nizika_broadcast/main.py", line 60, in main
answer: str = Talk.main (message, chat_item.author['name'], histories, goatoh_mode).replace ('\n', ' ')
File "/home/miteruzo/Downloads/nizika_broadcast/talk.py", line 23, in main
= cls.__get_message (message, name, histories, goatoh_mode)
File "/home/miteruzo/Downloads/nizika_broadcast/talk.py", line 196, in __get_message
return openai.chat.completions.create (
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_utils/_utils.py", line 301, in wrapper
return func(*args, **kwargs)
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/resources/chat/completions.py", line 598, in create
return self._post(
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_base_client.py", line 1096, in post
return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_base_client.py", line 856, in request
return self._request(
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_base_client.py", line 894, in _request
return self._retry_request(
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_base_client.py", line 966, in _retry_request
return self._request(
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_base_client.py", line 894, in _request
return self._retry_request(
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_base_client.py", line 966, in _retry_request
return self._request(
File "/home/miteruzo/.local/lib/python3.10/site-packages/openai/_base_client.py", line 908, in _request
raise self._make_status_error_from_response(err.response) from None
openai.InternalServerError: Error code: 500 - {'error': {'message': 'The server had an error processing your request. Sorry about that! You can retry your request, or contact us through our help center at help.openai.com if you keep seeing this error. (Please include the request ID req_ca732fde8fe201933c96c403d44db7e5 in your email.)', 'type': 'server_error', 'param': None, 'code': None}}
+110 -64
ファイルの表示
@@ -9,19 +9,20 @@ import time
from datetime import datetime, timedelta
import emoji
import ephem
import ephem # type: ignore
import pygame
import pygame.gfxdraw
import pytchat
import pytchat # type: ignore
from playsound import playsound
from pygame.locals import *
from youtube import *
import play_movie
from aques import Aques
from common_const import *
from common_module import CommonModule
from mode import Mode
from talk import Talk
from youtube import *
class Main:
@@ -39,7 +40,7 @@ class Main:
argv: list,
argc: int) \
-> None:
mode = Mode.NIZIKA
mode: Mode = Mode.NIZIKA
match (argc > 1) and argv[1]:
case '-g':
mode = Mode.GOATOH
@@ -108,6 +109,12 @@ class Main:
# ニジカの “ぬ゛ぅ゛ぅ゛ぅ゛ん゛”
noon = pygame.mixer.Sound ('noon.wav')
# “あっ!”
deerjika_oh = pygame.mixer.Sound ('oh.wav')
# おやつタイムのテーマ
snack_time_sound = pygame.mixer.Sound ('snack_time.wav')
# ゴートうの “ムムムム”
mumumumu = pygame.mixer.Sound ('mumumumu.wav')
@@ -132,9 +139,12 @@ class Main:
# 会話の履歴
histories: list = []
# おやつ記録
has_snack = False
while True:
# 観測地の日づけ更新
observer.date: datetime = datetime.now ().date ()
observer.date = datetime.now ().date ()
# 日の出開始
sunrise_start: datetime = (
@@ -189,7 +199,7 @@ class Main:
# Chat オブジェクトが有効
# Chat 取得
chat_items: list = live_chat.get ().items
chat_items = live_chat.get ().items
if chat_items:
# 溜まってゐる Chat からランダムに 1 つ抽出
@@ -208,7 +218,7 @@ class Main:
if goatoh_mode:
goatoh_talking = True
if double_mode:
goatoh_talking: bool = random.random () < .5
goatoh_talking = random.random () < .5
while True:
# ChatGPT API を呼出し,返答を取得
@@ -225,54 +235,9 @@ class Main:
+ f'{json.dumps (chat_item.__dict__)}\t'
+ f'{answer}\n')
# 吹出し描画(ニジカは上,ゴートうは下)
if nizika_mode:
screen.blit (balloon, (0, 0))
if goatoh_mode:
screen.blit (balloon, (0, 384))
if double_mode:
screen.blit (pygame.transform.flip (
balloon,
not goatoh_talking,
False),
(0, 0))
# 視聴者コメント描画
screen.blit (
user_font.render (
'> ' + (message
if (CommonModule.len_by_full (
message)
<= 21)
else (CommonModule.mid_by_full (
message, 0, 19.5)
+ '...')),
True,
(0, 0, 0)),
(120, 70 + 384) if goatoh_mode else (120 + (64 if (double_mode and not goatoh_talking) else 0), 70))
# ニジカの返答描画
screen.blit (
nizika_font.render (
(answer
if CommonModule.len_by_full (answer) <= 16
else CommonModule.mid_by_full (answer, 0, 16)),
True,
(192, 0, 0)),
(100, 150 + 384) if goatoh_mode else (100 + (64 if (double_mode and not goatoh_talking) else 0), 150))
if CommonModule.len_by_full (answer) > 16:
screen.blit (
nizika_font.render (
(CommonModule.mid_by_full (answer, 16, 16)
if CommonModule.len_by_full (answer) <= 32
else (CommonModule.mid_by_full (
answer, 16, 14.5)
+ '...')),
True,
(192, 0, 0)),
(100, 200 + 384) if goatoh_mode else (100 + (64 if (double_mode and not goatoh_talking) else 0), 200))
pygame.display.update ()
cls.draw_talking (screen, balloon, user_font, nizika_font,
message, answer, mode,
mode == 3 and goatoh_talking)
# 鳴く.
if goatoh_talking:
@@ -286,10 +251,11 @@ class Main:
time.sleep (1.5)
# 返答の読上げを WAV ディタとして生成,取得
wav: bytearray | None
try:
wav: bytearray | None = Aques.main (answer, goatoh_talking)
wav = Aques.main (answer, goatoh_talking)
except:
wav: None = None
wav = None
# 読上げを再生
if wav is not None:
@@ -324,13 +290,93 @@ class Main:
# 再生成
live_chat = pytchat.create (video_id = YOUTUBE_ID)
if has_snack and datetime.now ().hour == 14:
has_snack = False
pygame.display.update ()
if (not has_snack) and datetime.now ().hour == 15:
has_snack = True
deerjika_oh.play ()
time.sleep (0.6)
snack_time_sound.play ()
play_movie.main (screen, 'snack_time.mp4')
query = 'おやつタイムだ!!!!'
cls.draw_bg (screen, bg_day, bg_evening, bg_night, bg_grass,
kita, jojoko,
sunrise_start, sunrise_end, sunset_start, sunset_end,
sun_alt, sun_az, moon_alt, moon_az, moon_days_old)
cls.draw_talking (screen, balloon, user_font, nizika_font,
query, Talk.main (query).replace ('\n', ' '))
noon.play ()
time.sleep (1.5)
for event in pygame.event.get ():
if event.type == QUIT:
pygame.quit ()
sys.exit ()
@staticmethod
def draw_talking (
screen: pygame.Surface,
balloon: pygame.Surface,
user_font: pygame.font.Font,
nizika_font: pygame.font.Font,
query: str,
answer: str,
mode: Mode = Mode.NIZIKA,
flip: bool = False,
) -> None:
# 吹出し描画(ニジカは上,ゴートうは下)
nizika_mode = False
goatoh_mode = False
double_mode = False
match mode:
case Mode.NIZIKA:
screen.blit (balloon, (0, 0))
nizika_mode = True
case Mode.GOATOH:
screen.blit (balloon, (0, 384))
goatoh_mode = True
case Mode.DOUBLE:
screen.blit (pygame.transform.flip (balloon, flip, False), (0, 0))
double_mode = True
# 視聴者コメント描画
screen.blit (
user_font.render (
('> ' + (query
if (CommonModule.len_by_full (query) <= 21)
else (CommonModule.mid_by_full (query, 0, 19.5) + '...'))),
True, (0, 0, 0)),
((120, 70 + 384)
if goatoh_mode
else (120 + (64 if (double_mode and flip) else 0), 70)))
# ニジカの返答描画
screen.blit (
nizika_font.render (
(answer
if CommonModule.len_by_full (answer) <= 16
else CommonModule.mid_by_full (answer, 0, 16)),
True,
(192, 0, 0)),
(100, 150 + 384) if goatoh_mode else (100 + (64 if (double_mode and flip) else 0), 150))
if CommonModule.len_by_full (answer) > 16:
screen.blit (
nizika_font.render (
(CommonModule.mid_by_full (answer, 16, 16)
if CommonModule.len_by_full (answer) <= 32
else (CommonModule.mid_by_full (
answer, 16, 14.5)
+ '...')),
True,
(192, 0, 0)),
(100, 200 + 384) if goatoh_mode else (100 + (64 if (double_mode and flip) else 0), 200))
pygame.display.update ()
@classmethod
def draw_bg (
cls,
@@ -349,8 +395,8 @@ class Main:
sun_az: float,
moon_alt: float,
moon_az: float,
moon_days_old: float) \
-> None:
moon_days_old: float,
) -> None:
sunrise_centre: datetime = (
sunrise_start + (sunrise_end - sunrise_start) / 2)
sunset_centre: datetime = (
@@ -379,16 +425,16 @@ class Main:
screen.blit (bg_night, (0, 0))
if sunrise_start <= dt < sunrise_end:
bg_evening.set_alpha (255 - ((abs (dt - sunrise_centre) * 510)
/ (sunrise_end - sunrise_centre)))
bg_evening.set_alpha (255 - int ((abs (dt - sunrise_centre) * 510)
/ (sunrise_end - sunrise_centre)))
elif sunset_start <= dt < sunset_end:
bg_evening.set_alpha (255 - ((abs (dt - sunset_centre) * 510)
/ (sunset_end - sunset_centre)))
bg_evening.set_alpha (255 - int ((abs (dt - sunset_centre) * 510)
/ (sunset_end - sunset_centre)))
else:
bg_evening.set_alpha (0)
if sunrise_start <= dt < sunset_end:
jojoko.set_alpha (255 - 255 / 15 * abs (moon_days_old - 15))
jojoko.set_alpha (255 - int (255 / 15 * abs (moon_days_old - 15)))
else:
jojoko.set_alpha (255)
バイナリ
ファイルの表示
バイナリファイルは表示されません.
+44
ファイルの表示
@@ -0,0 +1,44 @@
import cv2
import pygame
import sys
def main (
screen: pygame.Surface,
video_path: str,
) -> None:
# OpenCV で動画を読み込む
cap = cv2.VideoCapture (video_path)
if not cap.isOpened ():
return
# screen の幅、高さ
(width, height) = screen.get_size ()
fps = cap.get (cv2.CAP_PROP_FPS)
clock = pygame.time.Clock ()
while cap.isOpened ():
# 動画のフレームを読み込む
(ret, frame) = cap.read ()
if not ret:
break
# OpenCV の BGR フォーマットを RGB に変換
frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB)
# Numpy 配列を Pygame サーフェスに変換
frame_surface = pygame.surfarray.make_surface (frame)
frame_surface = pygame.transform.rotate (frame_surface, -90)
frame_surface = pygame.transform.flip (frame_surface, True, False)
frame_surface = pygame.transform.scale (frame_surface, (width, height))
# フレームを描画
screen.blit (frame_surface, (0, 0))
pygame.display.update ()
# FPS に応じて待機
clock.tick (fps)
cap.release ()
バイナリ
ファイルの表示
バイナリファイルは表示されません.
バイナリ
ファイルの表示
バイナリファイルは表示されません.
+1 -1
ファイルの表示
@@ -15,7 +15,7 @@ from openai.types.chat import (ChatCompletionAssistantMessageParam,
ChatCompletionUserMessageParam)
from openai.types.chat.chat_completion_message import ChatCompletionMessage
from .connection import OPENAI_API_KEY, OPENAI_ORGANISATION # type: ignore
from connection import OPENAI_API_KEY, OPENAI_ORGANISATION # type: ignore
class Talk: