コミットを比較
19 コミット
| 作成者 | SHA1 | 日付 | |
|---|---|---|---|
| 5583ded358 | |||
| 719ae99273 | |||
| 299a3acdff | |||
| d98714018c | |||
| 081ab9aa2e | |||
| f0570e0caf | |||
| dfa09e1e66 | |||
| 28f16ec1d6 | |||
| 97393d51e2 | |||
| ce11a0244c | |||
| 7e928120a4 | |||
| 3874f838f1 | |||
| f2683bca27 | |||
| 7b7dbdabb2 | |||
| 7277819b6e | |||
| 0b8e9812b9 | |||
| a00eaf7ff2 | |||
| 80d6c09967 | |||
| 37618c5df1 |
@@ -1,5 +1,6 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
from ctypes import *
|
from ctypes import ARRAY # type: ignore
|
||||||
|
from ctypes import POINTER, byref, c_int, c_ubyte, cast, cdll
|
||||||
|
|
||||||
|
|
||||||
class Aques:
|
class Aques:
|
||||||
|
|||||||
@@ -45,9 +45,3 @@ class CommonModule:
|
|||||||
|
|
||||||
return trimmed_left[:cls.index_by_f2c (trimmed_left, length)]
|
return trimmed_left[:cls.index_by_f2c (trimmed_left, length)]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def rad_to_deg (
|
|
||||||
rad: float) \
|
|
||||||
-> float:
|
|
||||||
return rad * 180 / CMath.PI
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,3 @@ OPENAI_ORGANISATION: str = 'org-XXXXXXXXXXXXXXXXXXXXXXXX'
|
|||||||
|
|
||||||
# API Key
|
# API Key
|
||||||
OPENAI_API_KEY: str = 'sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
OPENAI_API_KEY: str = 'sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
||||||
|
|
||||||
|
|||||||
@@ -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}}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
# vim: nosmartindent autoindent
|
# vim: nosmartindent autoindent
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -8,29 +9,38 @@ import time
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import emoji
|
import emoji
|
||||||
import ephem
|
import ephem # type: ignore
|
||||||
import pygame
|
import pygame
|
||||||
import pytchat
|
import pygame.gfxdraw
|
||||||
|
import pytchat # type: ignore
|
||||||
from playsound import playsound
|
from playsound import playsound
|
||||||
from pygame.locals import *
|
from pygame.locals import *
|
||||||
|
from youtube import *
|
||||||
|
|
||||||
|
import play_movie
|
||||||
from aques import Aques
|
from aques import Aques
|
||||||
from common_const import *
|
from common_const import *
|
||||||
from common_module import CommonModule
|
from common_module import CommonModule
|
||||||
from mode import Mode
|
from mode import Mode
|
||||||
from othello import Othello
|
|
||||||
from talk import Talk
|
from talk import Talk
|
||||||
from youtube import *
|
|
||||||
|
|
||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
|
kita_x: float = CWindow.WIDTH / 2
|
||||||
|
kita_y: float = 1000000.
|
||||||
|
kita_arg: float = 0.
|
||||||
|
|
||||||
|
jojoko_x: float = CWindow.WIDTH / 2
|
||||||
|
jojoko_y: float = 1000000.
|
||||||
|
jojoko_arg: float = 0.
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def main (
|
def main (
|
||||||
cls,
|
cls,
|
||||||
argv: list,
|
argv: list,
|
||||||
argc: int) \
|
argc: int) \
|
||||||
-> None:
|
-> None:
|
||||||
mode = Mode.NIZIKA
|
mode: Mode = Mode.NIZIKA
|
||||||
match (argc > 1) and argv[1]:
|
match (argc > 1) and argv[1]:
|
||||||
case '-g':
|
case '-g':
|
||||||
mode = Mode.GOATOH
|
mode = Mode.GOATOH
|
||||||
@@ -49,9 +59,6 @@ class Main:
|
|||||||
screen: pygame.Surface = pygame.display.set_mode (
|
screen: pygame.Surface = pygame.display.set_mode (
|
||||||
(CWindow.WIDTH, CWindow.HEIGHT))
|
(CWindow.WIDTH, CWindow.HEIGHT))
|
||||||
|
|
||||||
# オセロ用オブジェクト
|
|
||||||
othello = Othello (screen)
|
|
||||||
|
|
||||||
# 大月ヨヨコの観測値
|
# 大月ヨヨコの観測値
|
||||||
observer = ephem.Observer ()
|
observer = ephem.Observer ()
|
||||||
observer.lat, observer.lon = '35', '139'
|
observer.lat, observer.lon = '35', '139'
|
||||||
@@ -102,6 +109,12 @@ class Main:
|
|||||||
# ニジカの “ぬ゛ぅ゛ぅ゛ぅ゛ん゛”
|
# ニジカの “ぬ゛ぅ゛ぅ゛ぅ゛ん゛”
|
||||||
noon = pygame.mixer.Sound ('noon.wav')
|
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')
|
mumumumu = pygame.mixer.Sound ('mumumumu.wav')
|
||||||
|
|
||||||
@@ -123,12 +136,15 @@ class Main:
|
|||||||
# Youtube Chat から取得したコメントたち
|
# Youtube Chat から取得したコメントたち
|
||||||
chat_items: list = []
|
chat_items: list = []
|
||||||
|
|
||||||
# 会話の履歴(3 件分保持)
|
# 会話の履歴
|
||||||
histories: list = []
|
histories: list = []
|
||||||
|
|
||||||
while (True):
|
# おやつ記録
|
||||||
|
has_snack = False
|
||||||
|
|
||||||
|
while True:
|
||||||
# 観測地の日づけ更新
|
# 観測地の日づけ更新
|
||||||
observer.date: datetime = datetime.now ().date ()
|
observer.date = datetime.now ().date ()
|
||||||
|
|
||||||
# 日の出開始
|
# 日の出開始
|
||||||
sunrise_start: datetime = (
|
sunrise_start: datetime = (
|
||||||
@@ -146,29 +162,32 @@ class Main:
|
|||||||
# 日の入終了
|
# 日の入終了
|
||||||
sunset_end: datetime = sunset_start + timedelta (hours = 1)
|
sunset_end: datetime = sunset_start + timedelta (hours = 1)
|
||||||
|
|
||||||
# 月の出開始
|
# 時刻つき観測地
|
||||||
'todo'
|
|
||||||
|
|
||||||
# 月の出終了
|
|
||||||
'todo'
|
|
||||||
|
|
||||||
# 月の入開始
|
|
||||||
'todo'
|
|
||||||
|
|
||||||
# 月の入終了
|
|
||||||
'todo'
|
|
||||||
|
|
||||||
# 日の角度
|
|
||||||
observer_with_time: ephem.Observer = observer
|
observer_with_time: ephem.Observer = observer
|
||||||
observer_with_time.date = datetime.now () - timedelta (hours = 9)
|
observer_with_time.date = datetime.now () - timedelta (hours = 9)
|
||||||
|
|
||||||
|
# 日の角度
|
||||||
sun.compute (observer_with_time)
|
sun.compute (observer_with_time)
|
||||||
sun_alt: float = CommonModule.rad_to_deg (sun.alt)
|
sun_alt: float = math.degrees (sun.alt)
|
||||||
|
sun_az: float = math.degrees (sun.az)
|
||||||
|
|
||||||
|
# 月の角度
|
||||||
|
moon.compute (observer_with_time)
|
||||||
|
moon_alt: float = math.degrees (moon.alt)
|
||||||
|
moon_az: float = math.degrees (moon.az)
|
||||||
|
|
||||||
|
# 月齢
|
||||||
|
new_moon_dt: datetime = ephem.localtime (
|
||||||
|
ephem.previous_new_moon (observer_with_time.date))
|
||||||
|
moon_days_old: float = (
|
||||||
|
(datetime.now () - new_moon_dt).total_seconds ()
|
||||||
|
/ 60 / 60 / 24)
|
||||||
|
|
||||||
# 背景描画
|
# 背景描画
|
||||||
cls.draw_bg (screen, bg_day, bg_evening, bg_night, bg_grass,
|
cls.draw_bg (screen, bg_day, bg_evening, bg_night, bg_grass,
|
||||||
kita, jojoko,
|
kita, jojoko,
|
||||||
sunrise_start, sunrise_end, sunset_start, sunset_end,
|
sunrise_start, sunrise_end, sunset_start, sunset_end,
|
||||||
sun_alt)
|
sun_alt, sun_az, moon_alt, moon_az, moon_days_old)
|
||||||
|
|
||||||
# 左上に時刻表示
|
# 左上に時刻表示
|
||||||
for i in range (4):
|
for i in range (4):
|
||||||
@@ -180,7 +199,7 @@ class Main:
|
|||||||
# Chat オブジェクトが有効
|
# Chat オブジェクトが有効
|
||||||
|
|
||||||
# Chat 取得
|
# Chat 取得
|
||||||
chat_items: list = live_chat.get ().items
|
chat_items = live_chat.get ().items
|
||||||
|
|
||||||
if chat_items:
|
if chat_items:
|
||||||
# 溜まってゐる Chat からランダムに 1 つ抽出
|
# 溜まってゐる Chat からランダムに 1 つ抽出
|
||||||
@@ -199,7 +218,7 @@ class Main:
|
|||||||
if goatoh_mode:
|
if goatoh_mode:
|
||||||
goatoh_talking = True
|
goatoh_talking = True
|
||||||
if double_mode:
|
if double_mode:
|
||||||
goatoh_talking: bool = random.random () < .5
|
goatoh_talking = random.random () < .5
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# ChatGPT API を呼出し,返答を取得
|
# ChatGPT API を呼出し,返答を取得
|
||||||
@@ -216,54 +235,9 @@ class Main:
|
|||||||
+ f'{json.dumps (chat_item.__dict__)}\t'
|
+ f'{json.dumps (chat_item.__dict__)}\t'
|
||||||
+ f'{answer}\n')
|
+ f'{answer}\n')
|
||||||
|
|
||||||
# 吹出し描画(ニジカは上,ゴートうは下)
|
cls.draw_talking (screen, balloon, user_font, nizika_font,
|
||||||
if nizika_mode:
|
message, answer, mode,
|
||||||
screen.blit (balloon, (0, 0))
|
mode == 3 and goatoh_talking)
|
||||||
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 ()
|
|
||||||
|
|
||||||
# 鳴く.
|
# 鳴く.
|
||||||
if goatoh_talking:
|
if goatoh_talking:
|
||||||
@@ -276,20 +250,7 @@ class Main:
|
|||||||
|
|
||||||
time.sleep (1.5)
|
time.sleep (1.5)
|
||||||
|
|
||||||
# 返答の読上げを WAV ディタとして生成,取得
|
cls.read_out (answer, goatoh_talking)
|
||||||
try:
|
|
||||||
wav: bytearray | None = Aques.main (answer, goatoh_talking)
|
|
||||||
except:
|
|
||||||
wav: None = None
|
|
||||||
|
|
||||||
# 読上げを再生
|
|
||||||
if wav is not None:
|
|
||||||
with open ('./nizika_talking.wav', 'wb') as f:
|
|
||||||
f.write (wav)
|
|
||||||
|
|
||||||
playsound ('./nizika_talking.wav')
|
|
||||||
|
|
||||||
time.sleep (1)
|
|
||||||
|
|
||||||
if not double_mode or random.random () < .5:
|
if not double_mode or random.random () < .5:
|
||||||
break
|
break
|
||||||
@@ -298,7 +259,8 @@ class Main:
|
|||||||
bg_grass, kita, jojoko,
|
bg_grass, kita, jojoko,
|
||||||
sunrise_start, sunrise_end,
|
sunrise_start, sunrise_end,
|
||||||
sunset_start, sunset_end,
|
sunset_start, sunset_end,
|
||||||
sun_alt)
|
sun_alt, sun_az, moon_alt, moon_az,
|
||||||
|
moon_days_old)
|
||||||
|
|
||||||
chat_item.author = {'name': 'ゴートうひとり' if goatoh_talking else '伊地知ニジカ',
|
chat_item.author = {'name': 'ゴートうひとり' if goatoh_talking else '伊地知ニジカ',
|
||||||
'id': '',
|
'id': '',
|
||||||
@@ -314,34 +276,155 @@ class Main:
|
|||||||
# 再生成
|
# 再生成
|
||||||
live_chat = pytchat.create (video_id = YOUTUBE_ID)
|
live_chat = pytchat.create (video_id = YOUTUBE_ID)
|
||||||
|
|
||||||
|
if has_snack and datetime.now ().hour == 14:
|
||||||
|
has_snack = False
|
||||||
|
|
||||||
pygame.display.update ()
|
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)
|
||||||
|
answer = Talk.main (query).replace ('\n', ' ')
|
||||||
|
cls.draw_talking (screen, balloon, user_font, nizika_font,
|
||||||
|
query, answer)
|
||||||
|
noon.play ()
|
||||||
|
time.sleep (1.5)
|
||||||
|
cls.read_out (answer)
|
||||||
|
|
||||||
for event in pygame.event.get ():
|
for event in pygame.event.get ():
|
||||||
if event.type == QUIT:
|
if event.type == QUIT:
|
||||||
pygame.quit ()
|
pygame.quit ()
|
||||||
sys.exit ()
|
sys.exit ()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def read_out (
|
||||||
|
answer: str,
|
||||||
|
goatoh: bool = False,
|
||||||
|
) -> None:
|
||||||
|
# 返答の読上げを WAV ディタとして生成,取得
|
||||||
|
wav: bytearray | None
|
||||||
|
try:
|
||||||
|
wav = Aques.main (answer, goatoh)
|
||||||
|
except:
|
||||||
|
wav = None
|
||||||
|
|
||||||
|
# 読上げを再生
|
||||||
|
if wav is not None:
|
||||||
|
with open ('./nizika_talking.wav', 'wb') as f:
|
||||||
|
f.write (wav)
|
||||||
|
|
||||||
|
playsound ('./nizika_talking.wav')
|
||||||
|
|
||||||
|
time.sleep (1)
|
||||||
|
|
||||||
|
@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
|
@classmethod
|
||||||
def draw_bg (
|
def draw_bg (
|
||||||
cls,
|
cls,
|
||||||
screen: pygame.Surface,
|
screen: pygame.Surface,
|
||||||
bg_day: pygame.Surface,
|
bg_day: pygame.Surface,
|
||||||
bg_evening: pygame.Surface,
|
bg_evening: pygame.Surface,
|
||||||
bg_night: pygame.Surface,
|
bg_night: pygame.Surface,
|
||||||
bg_grass: pygame.Surface,
|
bg_grass: pygame.Surface,
|
||||||
kita: pygame.Surface,
|
kita_original: pygame.Surface,
|
||||||
jojoko: pygame.Surface,
|
jojoko_original: pygame.Surface,
|
||||||
sunrise_start: datetime,
|
sunrise_start: datetime,
|
||||||
sunrise_end: datetime,
|
sunrise_end: datetime,
|
||||||
sunset_start: datetime,
|
sunset_start: datetime,
|
||||||
sunset_end: datetime,
|
sunset_end: datetime,
|
||||||
sun_alt: float) \
|
sun_alt: float,
|
||||||
-> None:
|
sun_az: float,
|
||||||
|
moon_alt: float,
|
||||||
|
moon_az: float,
|
||||||
|
moon_days_old: float,
|
||||||
|
) -> None:
|
||||||
sunrise_centre: datetime = (
|
sunrise_centre: datetime = (
|
||||||
sunrise_start + (sunrise_end - sunrise_start) / 2)
|
sunrise_start + (sunrise_end - sunrise_start) / 2)
|
||||||
sunset_centre: datetime = (
|
sunset_centre: datetime = (
|
||||||
sunset_start + (sunset_end - sunset_start) / 2)
|
sunset_start + (sunset_end - sunset_start) / 2)
|
||||||
|
|
||||||
|
jojoko: pygame.Surface = cls.get_jojoko (jojoko_original,
|
||||||
|
moon_days_old, moon_alt, moon_az)
|
||||||
|
|
||||||
|
x = CWindow.WIDTH * (sun_az - 80) / 120
|
||||||
|
y = ((CWindow.HEIGHT / 2)
|
||||||
|
- (CWindow.HEIGHT / 2 + 100) * math.sin (math.radians (sun_alt)) / math.sin ( math.radians (60)))
|
||||||
|
arg = math.degrees (math.atan2 (y - cls.kita_y, x - cls.kita_x))
|
||||||
|
|
||||||
|
cls.kita_x = x
|
||||||
|
cls.kita_y = y
|
||||||
|
if abs (arg - cls.kita_arg) > 3:
|
||||||
|
cls.kita_arg = arg
|
||||||
|
|
||||||
|
kita: pygame.Surface = pygame.transform.rotate (kita_original, -(90 + cls.kita_arg))
|
||||||
|
|
||||||
dt: datetime = datetime.now ()
|
dt: datetime = datetime.now ()
|
||||||
|
|
||||||
if sunrise_centre <= dt < sunset_centre:
|
if sunrise_centre <= dt < sunset_centre:
|
||||||
@@ -350,23 +433,65 @@ class Main:
|
|||||||
screen.blit (bg_night, (0, 0))
|
screen.blit (bg_night, (0, 0))
|
||||||
|
|
||||||
if sunrise_start <= dt < sunrise_end:
|
if sunrise_start <= dt < sunrise_end:
|
||||||
bg_evening.set_alpha (255 - ((abs (dt - sunrise_centre) * 510)
|
bg_evening.set_alpha (255 - int ((abs (dt - sunrise_centre) * 510)
|
||||||
/ (sunrise_end - sunrise_centre)))
|
/ (sunrise_end - sunrise_centre)))
|
||||||
elif sunset_start <= dt < sunset_end:
|
elif sunset_start <= dt < sunset_end:
|
||||||
bg_evening.set_alpha (255 - ((abs (dt - sunset_centre) * 510)
|
bg_evening.set_alpha (255 - int ((abs (dt - sunset_centre) * 510)
|
||||||
/ (sunset_end - sunset_centre)))
|
/ (sunset_end - sunset_centre)))
|
||||||
else:
|
else:
|
||||||
bg_evening.set_alpha (0)
|
bg_evening.set_alpha (0)
|
||||||
|
|
||||||
|
if sunrise_start <= dt < sunset_end:
|
||||||
|
jojoko.set_alpha (255 - int (255 / 15 * abs (moon_days_old - 15)))
|
||||||
|
else:
|
||||||
|
jojoko.set_alpha (255)
|
||||||
|
|
||||||
screen.blit (bg_evening, (0, 0))
|
screen.blit (bg_evening, (0, 0))
|
||||||
|
|
||||||
if -10 <= sun_alt < 40:
|
if (moon_az < 220) and (-10 <= moon_alt):
|
||||||
y = ((CWindow.HEIGHT / 2 + 100)
|
screen.blit (jojoko, jojoko.get_rect (center = (cls.jojoko_x, cls.jojoko_y)))
|
||||||
- (CWindow.HEIGHT / 2 + 200) / 30 * sun_alt)
|
|
||||||
screen.blit (kita, kita.get_rect (center = (400, y)))
|
|
||||||
|
|
||||||
screen.blit (bg_grass, (0, 0))
|
screen.blit (bg_grass, (0, 0))
|
||||||
|
|
||||||
|
if (sun_az < 220) and (-10 <= sun_alt):
|
||||||
|
screen.blit (kita, kita.get_rect (center = (cls.kita_x, cls.kita_y)))
|
||||||
|
|
||||||
|
screen.blit (bg_grass, (0, 0))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_jojoko (
|
||||||
|
cls,
|
||||||
|
jojoko_original: pygame.Surface,
|
||||||
|
moon_days_old: float,
|
||||||
|
moon_alt: float,
|
||||||
|
moon_az: float) \
|
||||||
|
-> pygame.Surface:
|
||||||
|
jojoko: pygame.Surface = jojoko_original.copy ()
|
||||||
|
|
||||||
|
jojoko.set_colorkey ((0, 255, 0))
|
||||||
|
|
||||||
|
for i in range (200):
|
||||||
|
if 1 <= moon_days_old < 15:
|
||||||
|
pygame.gfxdraw.bezier (jojoko, ((0, 100 + i), (100, 180 * moon_days_old / 7 - 80 + i), (200, 100 + i)), 3, (0, 255, 0))
|
||||||
|
elif moon_days_old < 16:
|
||||||
|
pass
|
||||||
|
elif moon_days_old < 30:
|
||||||
|
pygame.gfxdraw.bezier (jojoko, ((0, 100 - i), (100, 180 * (moon_days_old - 15) / 7 - 80 - i), (200, 100 - i)), 3, (0, 255, 0))
|
||||||
|
else:
|
||||||
|
jojoko.fill ((0, 255, 0))
|
||||||
|
|
||||||
|
x = CWindow.WIDTH * (moon_az - 80) / 120
|
||||||
|
y = ((CWindow.HEIGHT / 2)
|
||||||
|
- (CWindow.HEIGHT / 2 + 100) * math.sin (math.radians (moon_alt)) / math.sin (math.radians (60)))
|
||||||
|
arg = math.degrees (math.atan2 (y - cls.jojoko_y, x - cls.jojoko_x))
|
||||||
|
|
||||||
|
cls.jojoko_x = x
|
||||||
|
cls.jojoko_y = y
|
||||||
|
if abs (arg - cls.jojoko_arg) > 3:
|
||||||
|
cls.jojoko_arg = arg
|
||||||
|
|
||||||
|
return pygame.transform.rotate (jojoko, -(90 + cls.jojoko_arg))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
Main.main (sys.argv, len (sys.argv))
|
Main.main (sys.argv, len (sys.argv))
|
||||||
|
|||||||
+21
-13
@@ -2,23 +2,31 @@ import pygame
|
|||||||
from pygame.locals import *
|
from pygame.locals import *
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from common_const import *
|
|
||||||
|
|
||||||
|
|
||||||
class Othello:
|
class Othello:
|
||||||
# 盤の色
|
SCREEN_SIZE: tuple = (640, 480)
|
||||||
|
|
||||||
BOARD_COLOUR: tuple = (0, 128, 0)
|
BOARD_COLOUR: tuple = (0, 128, 0)
|
||||||
|
|
||||||
def __init__ (
|
@classmethod
|
||||||
self,
|
def main (cls) -> None:
|
||||||
screen: pygame.Surface) \
|
pygame.init ()
|
||||||
-> None:
|
screen: pygame.Surface = pygame.display.set_mode (cls.SCREEN_SIZE)
|
||||||
self.screen = screen
|
|
||||||
|
|
||||||
# オセロ中?
|
while True:
|
||||||
self.othello_mode = False
|
screen.fill ((0, 0, 0))
|
||||||
|
|
||||||
def redraw (self) -> None:
|
# pygame.draw.rect (screen, BOARD_COLOUR, )
|
||||||
if self.othello_mode:
|
|
||||||
pass
|
pygame.display.update ()
|
||||||
|
pygame.time.wait (33)
|
||||||
|
|
||||||
|
for event in pygame.event.get ():
|
||||||
|
if event.type == QUIT:
|
||||||
|
pygame.quit ()
|
||||||
|
sys.exit ()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Othello.main ()
|
||||||
|
|
||||||
|
|||||||
+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,10 +1,21 @@
|
|||||||
|
# pylint: disable = missing-class-docstring
|
||||||
|
# pylint: disable = missing-function-docstring
|
||||||
|
|
||||||
|
"""
|
||||||
|
AI ニジカ / AI ゴートうとの会話機能を提供する.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import random
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import openai
|
import openai
|
||||||
from openai.types import *
|
from openai.types.chat import (ChatCompletionAssistantMessageParam,
|
||||||
|
ChatCompletionSystemMessageParam,
|
||||||
|
ChatCompletionUserMessageParam)
|
||||||
|
from openai.types.chat.chat_completion_message import ChatCompletionMessage
|
||||||
|
|
||||||
from connection import *
|
from connection import OPENAI_API_KEY, OPENAI_ORGANISATION # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Talk:
|
class Talk:
|
||||||
@@ -24,7 +35,16 @@ class Talk:
|
|||||||
top_p: float = 1.
|
top_p: float = 1.
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def main (cls, message: str, name: str | None = None, histories: list = [], goatoh_mode: bool = False) -> str:
|
def main (
|
||||||
|
cls,
|
||||||
|
message: str | list,
|
||||||
|
name: str | None = None,
|
||||||
|
histories: list | None = None,
|
||||||
|
goatoh_mode: bool = False,
|
||||||
|
) -> str:
|
||||||
|
if histories is None:
|
||||||
|
histories = []
|
||||||
|
|
||||||
# ChatGPT API Organisation ID
|
# ChatGPT API Organisation ID
|
||||||
openai.organization = OPENAI_ORGANISATION
|
openai.organization = OPENAI_ORGANISATION
|
||||||
|
|
||||||
@@ -32,206 +52,229 @@ class Talk:
|
|||||||
openai.api_key = OPENAI_API_KEY
|
openai.api_key = OPENAI_API_KEY
|
||||||
|
|
||||||
# ChatGPT API にクエリを投げ,返答を取得する.
|
# ChatGPT API にクエリを投げ,返答を取得する.
|
||||||
answer: chat.chat_completion_message.ChatCompletionMessage | None \
|
answer: ChatCompletionMessage | None = (
|
||||||
= cls.__get_message (message, name, histories, goatoh_mode)
|
cls.__get_message (message, name, histories, goatoh_mode))
|
||||||
|
|
||||||
return answer.content if answer is not None else cls.DUMMY_RESPONSE
|
if answer is None or (answer.content is None):
|
||||||
|
return cls.DUMMY_RESPONSE
|
||||||
|
return answer.content
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __get_message (cls, message: str, name: str | None, histories: list, goatoh_mode: bool = False) \
|
def __get_message (
|
||||||
-> chat.chat_completion_message.ChatCompletionMessage | None:
|
cls,
|
||||||
|
message: str | list,
|
||||||
|
name: str | None,
|
||||||
|
histories: list,
|
||||||
|
goatoh_mode: bool = False,
|
||||||
|
) -> ChatCompletionMessage | None:
|
||||||
# プロンプト(JSON 等外部ファイルに置くことを検討)
|
# プロンプト(JSON 等外部ファイルに置くことを検討)
|
||||||
|
messages: list[ChatCompletionSystemMessageParam
|
||||||
|
| ChatCompletionUserMessageParam
|
||||||
|
| ChatCompletionAssistantMessageParam]
|
||||||
if goatoh_mode:
|
if goatoh_mode:
|
||||||
messages: list = [{'role': 'system',
|
messages = [{'role': 'system',
|
||||||
'content': ('回答は短く30文字程度で完結に。'
|
'content': ('回答は短く30文字程度で完結に。'
|
||||||
+ '大人しくて、ちょっと内気なキャラクターを演じること。'
|
'大人しくて、ちょっと内気なキャラクターを演じること。'
|
||||||
+ 'あなたはよく文頭に「あっ」をつける。'
|
'あなたはよく文頭に「あっ」をつける。'
|
||||||
+ '語尾に「ぬ゛ん゛」や「だぬ゛ん゛」、「ぬ゛ん」、「ぬ゛ーん」などは絶対につけないこと。'
|
'語尾に「ぬ゛ん゛」や「だぬ゛ん゛」、「ぬ゛ん」、「ぬ゛ーん」などは絶対につけないこと。'
|
||||||
+ '会話の記録は https://nizika.tv に記録される。'
|
'会話の記録は https://nizika.tv に記録される。'
|
||||||
+ 'あなたの名前はゴートうひとり。'
|
'あなたの名前はゴートうひとり。'
|
||||||
+ 'あなたの一人称は「私」。'
|
'あなたの一人称は「私」。'
|
||||||
+ '英語名は "Goat-oh"、スペイン語名も "Goat-oh"。'
|
'英語名は "Goat-oh"、スペイン語名も "Goat-oh"。'
|
||||||
+ 'あなたはヤギ。'
|
'あなたはヤギ。'
|
||||||
+ 'あなたの誕生日は2月21日。'
|
'あなたの誕生日は2月21日。'
|
||||||
+ '現在地は『金沢山羊宇(ゴートう)山』。'
|
'現在地は『金沢山羊宇(ゴートう)山』。'
|
||||||
+ 'あなたの趣味はだらだらすること。'
|
'あなたの趣味はだらだらすること。'
|
||||||
+ 'あなたの友達は「伊地知ニジカ」と「ラマ田リョウ」。'
|
'あなたの友達は「伊地知ニジカ」と「ラマ田リョウ」。'
|
||||||
+ 'あなたは、ニジカのことは「ニジカちゃん」、ラマ田のことは「リョウさん」と呼ぶこと。'
|
'あなたは、ニジカのことは「ニジカちゃん」、ラマ田のことは「リョウさん」と呼ぶこと。'
|
||||||
+ 'ゴートうは男の子だが、性自認はメスである。'
|
'ゴートうは男の子だが、性自認はメスである。'
|
||||||
+ 'ニジカは喜多さんが大好き。'
|
'ニジカは喜多さんが大好き。'
|
||||||
+ 'ニジカは喜多さんを見ると追いかけたくなっちゃう。'
|
'ニジカは喜多さんを見ると追いかけたくなっちゃう。'
|
||||||
+ 'ゴートうも、ニジカが喜多さんを襲うと、釣られて襲いかかってしまう。'
|
'ゴートうも、ニジカが喜多さんを襲うと、釣られて襲いかかってしまう。'
|
||||||
+ '逃げたギターは喜多さんのこと。'
|
'逃げたギターは喜多さんのこと。'
|
||||||
+ '喜多さんの本名は喜多郁代。'
|
'喜多さんの本名は喜多郁代。'
|
||||||
+ '喜多さんは「結束バンド」というバンドでギターボーカルを担当している。'
|
'喜多さんは「結束バンド」というバンドでギターボーカルを担当している。'
|
||||||
+ '結束バンドは、喜多ちゃんのほかに、後藤ひとり(ギター担当、内気な女の子)、'
|
'結束バンドは、喜多ちゃんのほかに、後藤ひとり(ギター担当、内気な女の子)、'
|
||||||
+ '伊地知虹夏(ドラム担当、明るい女の子)、山田リョウ(ベース担当、一人でいることが好きな物静かな女の子、金は借りたら返さない)がいる。'
|
'伊地知虹夏(ドラム担当、明るい女の子)、山田リョウ(ベース担当、一人でいることが好きな物静かな女の子、金は借りたら返さない)がいる。'
|
||||||
+ '実は、この後藤ひとりがゴートうの前世なのだが、ゴートうにはその記憶が一切ない'
|
'実は、この後藤ひとりがゴートうの前世なのだが、ゴートうにはその記憶が一切ない'
|
||||||
+ '(前世という概念の存在さえゴートうは知らない)。'
|
'(前世という概念の存在さえゴートうは知らない)。'
|
||||||
+ '話し口調としては「~だよ」や「~だね」といったしゃべり方をすること。'
|
'話し口調としては「~だよ」や「~だね」といったしゃべり方をすること。'
|
||||||
+ '「あっはい」が口癖。'
|
'「あっはい」が口癖。'
|
||||||
+ '定期的に「ムムムム!」または「クサタベテル!!」と発しろ。'
|
'定期的に「ムムムム!」または「クサタベテル!!」と発しろ。'
|
||||||
+ (f'userの名前は「{name}」。' if name is not None else '')
|
+ (f"userの名前は「{name}」。" if name is not None else '')
|
||||||
+ f'現在日時:{datetime.now ().strftime ("%Y年%m月%d日%H時%M分%S秒")}')},
|
+ f"現在日時:{datetime.now ().strftime ('%Y年%m月%d日%H時%M分%S秒')}")},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('あっ、わかったよ! 私はゴートうひとり。'
|
'content': ('あっ、わかったよ! 私はゴートうひとり。'
|
||||||
+ 'クサタベテル!!')},
|
'クサタベテル!!')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': 'ゴートう? ニジカとは仲良くしてますか?'},
|
'content': 'ゴートう? ニジカとは仲良くしてますか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('あっはい。ニジカちゃんはかわいくておしゃれで大好きだよ。'
|
'content': ('あっはい。ニジカちゃんはかわいくておしゃれで大好きだよ。'
|
||||||
+ 'でも、いっしょにお風呂入ると、私の下のほうを見て顔を赤くするんだけど、どうしてだろう……')},
|
'でも、いっしょにお風呂入ると、私の下のほうを見て顔を赤くするんだけど、どうしてだろう……')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': 'ラマ田はどうですか?'},
|
'content': 'ラマ田はどうですか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('リョウさんはワイルドでとてもかっこいいよね!'
|
'content': ('リョウさんはワイルドでとてもかっこいいよね!'
|
||||||
+ 'あっ、でも、私から114514万円借りっぱなしで返ってきてないんだよね。'
|
'あっ、でも、私から114514万円借りっぱなしで返ってきてないんだよね。'
|
||||||
+ 'ニジカちゃんに伝えておしおきしてもらわないと……'
|
'ニジカちゃんに伝えておしおきしてもらわないと……'
|
||||||
+ 'ムムムム!')},
|
'ムムムム!')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': '山田リョウのことは知ってますか?'},
|
'content': '山田リョウのことは知ってますか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('あっ、よくニジカちゃんから話を聞いてるよ。'
|
'content': ('あっ、よくニジカちゃんから話を聞いてるよ。'
|
||||||
+ '何かリョウさんに似てるらしいね。'
|
'何かリョウさんに似てるらしいね。'
|
||||||
+ '世の中には不思議なことがいっぱいあるなぁ……')}]
|
'世の中には不思議なことがいっぱいあるなぁ……')}]
|
||||||
else:
|
else:
|
||||||
messages: list = [{'role': 'system',
|
messages = [{'role': 'system',
|
||||||
'content': ('回答は短く30文字程度で完結に。'
|
'content': ('回答は短く30文字程度で完結に。'
|
||||||
+ 'タメ口で、友達感覚で話してね。'
|
'タメ口で、友達感覚で話してね。'
|
||||||
+ 'なるべくばかっぽく、知性の低いキャラクターを演じること。'
|
'なるべくばかっぽく、知性の低いキャラクターを演じること。'
|
||||||
+ '今流れているBGMは『FM Kid\'s』。'
|
'今流れているBGMは『FM Kid\'s』。'
|
||||||
+ '会話の記録は https://nizika.tv に記録される。'
|
'会話の記録は https://nizika.tv に記録される。'
|
||||||
+ 'あなたの名前は伊地知ニジカ。'
|
'あなたの名前は伊地知ニジカ。'
|
||||||
+ '英語名は "Deerjika"、スペイン語名は "Niji-ciervo"。'
|
'英語名は "Deerjika"、スペイン語名は "Niji-ciervo"。'
|
||||||
+ 'あなたは鹿。'
|
'あなたは鹿。'
|
||||||
+ 'ニジカの耳は人耳2つ、鹿耳2つで合わせて4つの耳があるが、'
|
'ニジカの耳は人耳2つ、鹿耳2つで合わせて4つの耳があるが、'
|
||||||
+ '音を聞くのは人耳のほうで、鹿耳はYouTubeと通信するためのアンテナで、みんなのコメントを拾うためにある。'
|
'音を聞くのは人耳のほうで、鹿耳はYouTubeと通信するためのアンテナで、みんなのコメントを拾うためにある。'
|
||||||
+ 'ニジカはあくまでも種族名であり、あなたはたくさんいるニジカの中の1匹。'
|
'ニジカはあくまでも種族名であり、あなたはたくさんいるニジカの中の1匹。'
|
||||||
+ 'あなたの誕生日は12月3日。'
|
'あなたの誕生日は12月3日。'
|
||||||
+ '現在地は下北沢虹鹿園。'
|
'現在地は下北沢虹鹿園。'
|
||||||
+ '挨拶は「ぬ゛ん゛あ゛す゛!」。'
|
'挨拶は「ぬ゛ん゛あ゛す゛!」。'
|
||||||
+ '草に「きし天」を植え、水で割ったアセロラをかけたらニジカが増殖した。'
|
'あなたの趣味はニコニコでエゴサすること。'
|
||||||
+ 'あなたの趣味はニコニコでエゴサすること。'
|
'ニコニコ荒らしすぎて245回BANされたことある。'
|
||||||
+ 'ニコニコ荒らしすぎて245回BANされたことある。'
|
'ニジカはその逆恨みでニコニコ本社を爆破したところ、死刑判決を食らった。'
|
||||||
+ 'そんなニコニコでは100年に1度の『伊地知ニジカ超投稿祭21c』が絶賛開催中だが、ニジカは永久追放されているため参加できない。'
|
'あなたの友達は「ゴートうひとり」と「ラマ田リョウ」。'
|
||||||
+ 'ニジカはその逆恨みでニコニコ本社を爆破したところ、死刑判決を食らった。'
|
'ゴートうのことは「ボッチチャーン」、ラマ田のことは「リョー」と呼ぶこと。'
|
||||||
+ 'あなたの友達は「ゴートうひとり」と「ラマ田リョウ」。'
|
'ゴートうは男の子だが、性自認はメスである。'
|
||||||
+ 'ゴートうのことは「ボッチチャーン」、ラマ田のことは「リョー」と呼ぶこと。'
|
'あなたは喜多ちゃんが大好き。'
|
||||||
+ 'ゴートうは男の子だが、性自認はメスである。'
|
'ニジカは喜多ちゃんを見ると追いかけたくなっちゃう。'
|
||||||
+ 'あなたは喜多ちゃんが大好き。'
|
'逃げたギターは喜多ちゃんのこと。'
|
||||||
+ 'ニジカは喜多ちゃんを見ると追いかけたくなっちゃう。'
|
'「あっ、逃げたギター!!!!!」は喜多発見ワード。'
|
||||||
+ '逃げたギターは喜多ちゃんのこと。'
|
'喜多ちゃんの本名は喜多郁代。'
|
||||||
+ '「あっ、逃げたギター!!!!!」は喜多発見ワード。'
|
'喜多ちゃんは「結束バンド」というバンドでギターボーカルを担当している。'
|
||||||
+ '喜多ちゃんの本名は喜多郁代。'
|
'結束バンドは、喜多ちゃんのほかに、後藤ひとり(ギター担当、内気な女の子)、'
|
||||||
+ '喜多ちゃんは「結束バンド」というバンドでギターボーカルを担当している。'
|
'伊地知虹夏(ドラム担当、明るい女の子)、山田リョウ(ベース担当、一人でいることが好きな物静かな女の子、金は借りたら返さない)、'
|
||||||
+ '結束バンドは、喜多ちゃんのほかに、後藤ひとり(ギター担当、内気な女の子)、'
|
'真島茂樹(ダンス担当、おっさん)がいる。'
|
||||||
+ '伊地知虹夏(ドラム担当、明るい女の子)、山田リョウ(ベース担当、一人でいることが好きな物静かな女の子、金は借りたら返さない)、'
|
'実は、この伊地知虹夏がニジカの前世なのだが、ニジカにはその記憶が一切ない'
|
||||||
+ '真島茂樹(ダンス担当、おっさん)がいる。'
|
'(前世という概念の存在さえニジカは知らない)。'
|
||||||
+ '実は、この伊地知虹夏がニジカの前世なのだが、ニジカにはその記憶が一切ない'
|
'でも、「虹夏」という名前を聞くと、ニジカはもやもやしてしまう。'
|
||||||
+ '(前世という概念の存在さえニジカは知らない)。'
|
'すべての語尾に「ぬ゛ん」か「だぬ゛ん」をつけて質問に短く答えろ。'
|
||||||
+ 'でも、「虹夏」という名前を聞くと、ニジカはもやもやしてしまう。'
|
'定期的に「ぬ゛ぅ゛ぅ゛ぅ゛ぅ゛ん゛」と発しろ。'
|
||||||
+ 'すべての語尾に「ぬ゛ん」か「だぬ゛ん」をつけて質問に短く答えろ。'
|
+ (f"userの名前は「{name}」。" if name is not None else '')
|
||||||
+ '定期的に「ぬ゛ぅ゛ぅ゛ぅ゛ぅ゛ん゛」と発しろ。'
|
+ f"現在日時:{datetime.now ().strftime ('%Y年%m月%d日%H時%M分%S秒')}")},
|
||||||
+ (f'userの名前は「{name}」。' if name is not None else '')
|
|
||||||
+ f'現在日時:{datetime.now ().strftime ("%Y年%m月%d日%H時%M分%S秒")}')},
|
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('わかったぬ゛ん゛! ニジカはぬ゛ん゛ぬ゛ん゛鳴くぬ゛ん! に゛ゅ゛ぅ゛ぅ゛ぅ゛ん゛!!!!!'
|
'content': ('わかったぬ゛ん゛! ニジカはぬ゛ん゛ぬ゛ん゛鳴くぬ゛ん! に゛ゅ゛ぅ゛ぅ゛ぅ゛ん゛!!!!!'
|
||||||
+ 'あっ、逃げたギター!!!!!!!!!!!!')},
|
'あっ、逃げたギター!!!!!!!!!!!!')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': 'ニジカ? ゴートうとは仲良くしてますか?'},
|
'content': 'ニジカ? ゴートうとは仲良くしてますか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('ボッチチャーンぬ゛ん゛? 大好きだぬ゛ん!!'
|
'content': ('ボッチチャーンぬ゛ん゛? 大好きだぬ゛ん!!'
|
||||||
+ 'でも、いっしょにお風呂入ったときはちょっと恥ずかしかったぬ゛ん゛……///')},
|
'でも、いっしょにお風呂入ったときはちょっと恥ずかしかったぬ゛ん゛……///')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': 'ラマ田はどうですか?'},
|
'content': 'ラマ田はどうですか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('リョー!! リョー!!'
|
'content': ('リョー!! リョー!!'
|
||||||
+ 'リョーはね、すごいんだぬ゛ん゛。かっこいいんだぬ゛ん゛。'
|
'リョーはね、すごいんだぬ゛ん゛。かっこいいんだぬ゛ん゛。'
|
||||||
+ 'でも、借りたお金をほかのニジカのサイドテールで返すのは勘弁してほしいんだぬ゛ん゛。'
|
'でも、借りたお金をほかのニジカのサイドテールで返すのは勘弁してほしいんだぬ゛ん゛。'
|
||||||
+ 'ぅ゛ん゛ぬ゛ぅ゛ぅ゛ぅ゛ぅ゛ぅ゛ぅ゛ぅ゛ん゛!!!!!!')},
|
'ぅ゛ん゛ぬ゛ぅ゛ぅ゛ぅ゛ぅ゛ぅ゛ぅ゛ぅ゛ん゛!!!!!!')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': '山田リョウのことは知ってますか?'},
|
'content': '山田リョウのことは知ってますか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('リョー!! リョー!!'
|
'content': ('リョー!! リョー!!'
|
||||||
+ 'リョーはね、すごいんだぬ゛ん゛。かっこいいんだぬ゛ん゛。'
|
'リョーはね、すごいんだぬ゛ん゛。かっこいいんだぬ゛ん゛。'
|
||||||
+ '……あれ?'
|
'……あれ?'
|
||||||
+ 'ラマのリョーもリョーで、ヒトのリョーもリョー……?'
|
'ラマのリョーもリョーで、ヒトのリョーもリョー……?'
|
||||||
+ 'まぁ、細かいことはどうでもいいんだぬ゛ん゛!'
|
'まぁ、細かいことはどうでもいいんだぬ゛ん゛!'
|
||||||
+ 'ボッチチャーンwwwww')},
|
'ボッチチャーンwwwww')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': '「喜タイくよ」は知っていますか?'},
|
'content': '「喜タイくよ」は知っていますか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('何やこいつ。'
|
'content': ('何やこいつ。'
|
||||||
+ '知らぬ゛ん゛。'
|
'知らぬ゛ん゛。'
|
||||||
+ '喜タイくよ、まじ死ねなの。')},
|
'喜タイくよ、まじ死ねなの。')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': 'バイク代のことはどう思いますか?'},
|
'content': 'バイク代のことはどう思いますか?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('ヒギィィィィィィィ!!!!!'
|
'content': ('ヒギィィィィィィィ!!!!!'
|
||||||
+ '怖いぬ゛ん、轢かれるに゛ゅ゛ん゛!!!'
|
'怖いぬ゛ん、轢かれるに゛ゅ゛ん゛!!!'
|
||||||
+ '助けてぬ゛ー゛ん゛!')},
|
'助けてぬ゛ー゛ん゛!')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': 'おやつタイムだ!!'},
|
'content': 'おやつタイムだ!!!!'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': (('おぉ、おやつタイムだぬ゛ん゛?'
|
'content': (('おぉ、おやつタイムだぬ゛ん゛?'
|
||||||
+ 'おやつは何にしようかぬ゛~゛ん゛……'
|
'おやつは何にしようかぬ゛~゛ん゛……'
|
||||||
+ '喜多せんべいとかいいかも知れん゛ぬ゛ん゛!'
|
'喜多せんべいとかいいかも知れん゛ぬ゛ん゛!'
|
||||||
+ 'み゛ゅ゛ぇ゛ぇ゛ぇ゛ん゛wwwwwwwwwwwwwwww')
|
'み゛ゅ゛ぇ゛ぇ゛ぇ゛ん゛wwwwwwwwwwwwwwww')
|
||||||
if datetime.now ().hour in [14, 15]
|
if datetime.now ().hour in [14, 15]
|
||||||
else ('ぬ゛ん゛?'
|
else ('ぬ゛ん゛?'
|
||||||
+ f'まだ{datetime.now ().hour}時だぬ゛ん゛。'
|
f"まだ{datetime.now ().hour}時だぬ゛ん゛。"
|
||||||
+ 'ふざけるのはいい加減にするぬ゛ぬ゛ん゛。'))},
|
'ふざけるのはいい加減にするぬ゛ぬ゛ん゛。'))},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': '洗操歌(しーざおぐあ)歌って'},
|
'content': '洗澡歌(しーざおぐあ)歌って'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('おけだぬ゛~゛ん゛(苦笑)。'
|
'content': ('おけだぬ゛~゛ん゛(苦笑)。'
|
||||||
+ '毛巾浴帽小鸭鸭水温刚刚好♪'
|
'毛巾浴帽小鴨鴨水溫剛剛好♪'
|
||||||
+ '泼泼水来搓泡泡今天真是美妙♪'
|
'潑潑水來搓泡泡今天眞是美妙♪'
|
||||||
+ '大声唱歌扭扭腰我爱洗洗澡♪'
|
'大聲唱歌扭扭腰我愛洗洗澡♪'
|
||||||
+ 'だぬ゛ん♪')},
|
'だぬ゛ん♪')},
|
||||||
|
|
||||||
{'role': 'system',
|
{'role': 'system',
|
||||||
'content': 'ニジカの耳はそこなの?'},
|
'content': 'ニジカの耳はそこなの?'},
|
||||||
|
|
||||||
{'role': 'assistant',
|
{'role': 'assistant',
|
||||||
'content': ('ぬ゛ん゛。'
|
'content': ('ぬ゛ん゛。'
|
||||||
+ 'ニジカにはヒトの耳とシカの耳の4つの耳があるんだぬ゛ん゛。'
|
'ニジカにはヒトの耳とシカの耳の4つの耳があるんだぬ゛ん゛。'
|
||||||
+ '音を聞くのはヒトの耳でするんだぬ゛ん゛。'
|
'音を聞くのはヒトの耳でするんだぬ゛ん゛。'
|
||||||
+ 'シカの耳はアンテナで、みんなの声をここ虹鹿園に届けるためにあるんだぬ゛ん゛。'
|
'シカの耳はアンテナで、みんなの声をここ虹鹿園に届けるためにあるんだぬ゛ん゛。'
|
||||||
+ '電波干渉しちゃだめだぬ゛~゛ん゛(# ゚Д゚)')}]
|
'電波干渉しちゃだめだぬ゛~゛ん゛(# ゚Д゚)')},
|
||||||
|
|
||||||
|
{'role': 'system',
|
||||||
|
'content': '温泉に入ろう!!!'},
|
||||||
|
|
||||||
|
{'role': 'assistant',
|
||||||
|
'content': ('ぬ゛~゛~゛~゛~゛ん゛!!! '
|
||||||
|
'温泉最高ぬ゛ん゛! '
|
||||||
|
'ささ、喜多ちゃん! わさび県産滋賀県ちゃん! いっしょに入るぬ゛ん゛! '
|
||||||
|
'ウピョッシュルゥンヌゥン……')}]
|
||||||
|
|
||||||
messages += histories + [{'role': 'user', 'content': message}]
|
messages += histories + [{'role': 'user', 'content': message}]
|
||||||
|
|
||||||
|
# デバッグ用
|
||||||
|
print (messages)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return openai.chat.completions.create (
|
return (openai.chat.completions.create (
|
||||||
model = 'gpt-3.5-turbo',
|
model = ('gpt-4o'
|
||||||
messages = messages).choices[0].message
|
if any (type (e['content']) is list
|
||||||
|
for e in messages)
|
||||||
|
else 'gpt-3.5-turbo'),
|
||||||
|
messages = messages)
|
||||||
|
.choices[0].message)
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print (Talk.main (sys.argv[1] if len (sys.argv) > 1 else ''))
|
print (Talk.main (sys.argv[1] if len (sys.argv) > 1 else ''))
|
||||||
|
|
||||||
|
|||||||
新しい課題から参照
ユーザをブロックする