30 コミット

作成者 SHA1 メッセージ 日付
みてるぞ b6ae21bb59 定数化 2024-05-19 18:45:48 +09:00
みてるぞ 3874f838f1 ヨヨコと郁代回転,視野角拡大 2024-05-19 15:35:17 +09:00
みてるぞ f2683bca27 Merge branch 'main' into ofotukuy 2024-05-19 09:17:35 +09:00
みてるぞ 7b7dbdabb2 Ofotukuy Jojoko, Kaudo ni jotte kwaiten. 2024-05-16 03:46:53 +00:00
みてるぞ 7277819b6e 'talk.py' を更新 2024-05-14 20:52:10 +09:00
みてるぞ 0b8e9812b9 冗長な記述を削除 2024-05-13 21:55:16 +09:00
みてるぞ a00eaf7ff2 入りのときに日や月が出ないやぅに(XP草原は東と想定) 2024-05-13 21:08:55 +09:00
みてるぞ 80d6c09967 大月ヨヨコ爆誕 2024-05-13 02:54:10 +09:00
みてるぞ 37618c5df1 本日作業分 2024-05-13 01:00:32 +09:00
みてるぞ d80d03db46 Merge branch 'main' into ofotukuy 2024-05-12 04:49:32 +09:00
みてるぞ fa6b5ba68b き太く陽を昇らせる 2024-05-12 04:49:08 +09:00
みてるぞ cff0ec27d8 tukuy no iri 2024-05-09 03:55:34 +00:00
みてるぞ d676372276 夜の風景から月を削除 2024-05-09 08:29:24 +09:00
みてるぞ 39cf64149f 'talk.py' を更新 2024-05-09 00:52:23 +09:00
みてるぞ 436f21244d 昼から夕方への遷移をスムーズに 2024-05-08 23:52:48 +09:00
みてるぞ f6e7a7d42f 日の出、日の入に応じた時刻に背景変更 2024-05-08 01:26:43 +09:00
みてるぞ 420c8f1bfe Merge branch 'main' of https://git.miteruzo.com/miteruzo/nizika_broadcast 2024-05-06 05:39:53 +09:00
みてるぞ 7517fa251b 背景時間帯によって変動 2024-05-06 05:39:21 +09:00
みてるぞ 9d72533e17 'talk.py' を更新 2024-04-24 21:19:24 +09:00
みてるぞ 13a7f0d26d 'talk.py' を更新 2024-04-23 00:18:56 +09:00
みてるぞ 6cc400dbe6 'talk.py' を更新 2024-04-23 00:14:56 +09:00
みてるぞ 51a52c9ba8 すべてのエラーを握り潰すやぅに 2024-04-18 22:50:42 +09:00
みてるぞ 688b781faa 'talk.py' を更新 2024-04-18 22:21:34 +09:00
みてるぞ d67faabeff 'talk.py' を更新 2024-04-07 16:41:53 +09:00
みてるぞ a09278cfb7 'main.py' を更新 2024-04-07 15:19:35 +09:00
みてるぞ dfe5219342 'talk.py' を更新 2024-04-06 22:51:45 +09:00
みてるぞ 5c1e615ab7 '伊地知ニジカ 泳ぐ 右.mp4' を削除 2024-04-06 19:29:28 +09:00
みてるぞ 97ccb886b9 ニジカ右向き(かぅいふのは FTP 使へ) 2024-04-06 18:57:33 +09:00
みてるぞ 9fa218badf ダブル・モード,ちょっと修正 2024-04-06 06:09:36 +09:00
みてるぞ 0bda9547b1 ゴートうと対話 とりま完成(ついでにやばぃバグ修正) 2024-04-06 05:39:34 +09:00
10個のファイルの変更387行の追加87行の削除
バイナリ
ファイルの表示
バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 57 KiB

バイナリ
ファイルの表示
バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 99 KiB

バイナリ
ファイルの表示
バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 53 KiB

バイナリ
ファイルの表示
バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 40 KiB

+11 -4
ファイルの表示
@@ -1,7 +1,14 @@
from pydantic import BaseModel class CWindow:
class CWindow (BaseModel, frozen = True):
WIDTH: int = 1024 WIDTH: int = 1024
HEIGHT: int = 768 HEIGHT: int = 768
class CKita:
WIDTH: float = CWindow.HEIGHT / 3.84
HEIGHT: float = WIDTH
class CJojoko:
WIDTH: float = CKita.HEIGHT * .75
HEIGHT: float = WIDTH
+20 -4
ファイルの表示
@@ -1,17 +1,28 @@
import unicodedata import unicodedata
from common_const import *
class CommonModule: class CommonModule:
@staticmethod @staticmethod
def is_wide (c: str) -> bool: def is_wide (
c: str) \
-> bool:
return unicodedata.east_asian_width (c) in ['F', 'W', 'A'] return unicodedata.east_asian_width (c) in ['F', 'W', 'A']
@classmethod @classmethod
def len_by_full (cls, string: str) -> float: def len_by_full (
cls,
string: str) \
-> float:
return sum (1 if cls.is_wide (c) else .5 for c in string) return sum (1 if cls.is_wide (c) else .5 for c in string)
@classmethod @classmethod
def index_by_f2c (cls, string: str, index: float) -> int: def index_by_f2c (
cls,
string: str,
index: float) \
-> int:
i: int = 0 i: int = 0
work: str = '' work: str = ''
for c in string: for c in string:
@@ -24,7 +35,12 @@ class CommonModule:
return i return i
@classmethod @classmethod
def mid_by_full (cls, string: str, start: float, length: float) -> str: def mid_by_full (
cls,
string: str,
start: float,
length: float) \
-> str:
trimmed_left: str = string[cls.index_by_f2c (string, start):] trimmed_left: str = string[cls.index_by_f2c (string, start):]
return trimmed_left[:cls.index_by_f2c (trimmed_left, length)] return trimmed_left[:cls.index_by_f2c (trimmed_left, length)]
+317 -69
ファイルの表示
@@ -1,12 +1,17 @@
# vim: nosmartindent autoindent
import json import json
import math
import random import random
import subprocess import subprocess
import sys import sys
import time import time
from datetime import datetime from datetime import datetime, timedelta
import emoji import emoji
import ephem
import pygame import pygame
import pygame.gfxdraw
import pytchat import pytchat
from playsound import playsound from playsound import playsound
from pygame.locals import * from pygame.locals import *
@@ -20,18 +25,31 @@ 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 (cls, argv: list, argc: int) -> None: def main (
cls,
argv: list,
argc: int) \
-> None:
mode = Mode.NIZIKA mode = Mode.NIZIKA
match (argc > 0) and argv[0]: match (argc > 1) and argv[1]:
case '-g': case '-g':
mode = Mode.GOATOH mode = Mode.GOATOH
case '-w': case '-w':
mode = Mode.DOUBLE mode = Mode.DOUBLE
goatoh_mode = mode == Mode.GOATOH nizika_mode: bool = mode == Mode.NIZIKA
double_mode = mode == Mode.DOUBLE goatoh_mode: bool = mode == Mode.GOATOH
double_mode: bool = mode == Mode.DOUBLE
print (mode) print (mode)
@@ -40,12 +58,50 @@ class Main:
screen: pygame.Surface = pygame.display.set_mode ( screen: pygame.Surface = pygame.display.set_mode (
(CWindow.WIDTH, CWindow.HEIGHT)) (CWindow.WIDTH, CWindow.HEIGHT))
# 大月ヨヨコの観測値
observer = ephem.Observer ()
observer.lat, observer.lon = '35', '139'
# き太く陽オブジェクト
sun = ephem.Sun ()
# 大月ヨヨコ・オブジェクト
moon = ephem.Moon ()
# 吹き出し # 吹き出し
balloon = pygame.transform.scale (pygame.image.load ('talking.png'), balloon = pygame.transform.scale (pygame.image.load ('talking.png'),
(CWindow.WIDTH, 384)) (CWindow.WIDTH, 384))
if goatoh_mode: if goatoh_mode:
balloon = pygame.transform.flip (balloon, False, True) balloon = pygame.transform.flip (balloon, False, True)
# 背景(昼)
bg_day: pygame.Surface = pygame.transform.scale (
pygame.image.load ('bg.jpg'),
(CWindow.WIDTH, CWindow.HEIGHT))
# 背景(夕方)
bg_evening: pygame.Surface = pygame.transform.scale (
pygame.image.load ('bg-evening.jpg'),
(CWindow.WIDTH, CWindow.HEIGHT))
# 背景(夜)
bg_night: pygame.Surface = pygame.transform.scale (
pygame.image.load ('bg-night.jpg'),
(CWindow.WIDTH, CWindow.HEIGHT))
# 背景の草
bg_grass: pygame.Surface = pygame.transform.scale (
pygame.image.load ('bg-grass.png'),
(CWindow.WIDTH, CWindow.HEIGHT))
# き太く陽
kita: pygame.Surface = pygame.transform.scale (
pygame.image.load ('sun.png'), (CKita.WIDTH, CKita.HEIGHT))
# 大月ヨヨコ
jojoko: pygame.Surface = pygame.transform.scale (
pygame.image.load ('moon.png'), (CJojoko.WIDTH, CJojoko.HEIGHT))
# 音声再生器の初期化 # 音声再生器の初期化
pygame.mixer.init (frequency = 44100) pygame.mixer.init (frequency = 44100)
@@ -73,11 +129,55 @@ class Main:
# Youtube Chat から取得したコメントたち # Youtube Chat から取得したコメントたち
chat_items: list = [] chat_items: list = []
# 会話の履歴(3 件分保持) # 会話の履歴
histories: list = [] histories: list = []
while (True): while (True):
screen.fill ((0, 255, 0)) # 観測地の日づけ更新
observer.date: datetime = datetime.now ().date ()
# 日の出開始
sunrise_start: datetime = (
(ephem.localtime (observer.previous_rising (sun))
- timedelta (minutes = 30)))
# 日の出終了
sunrise_end: datetime = sunrise_start + timedelta (hours = 1)
# 日の入開始
sunset_start: datetime = (
(ephem.localtime (observer.next_setting (sun))
- timedelta (minutes = 30)))
# 日の入終了
sunset_end: datetime = sunset_start + timedelta (hours = 1)
# 時刻つき観測地
observer_with_time: ephem.Observer = observer
observer_with_time.date = datetime.now () - timedelta (hours = 9)
# 日の角度
sun.compute (observer_with_time)
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,
kita, jojoko,
sunrise_start, sunrise_end, sunset_start, sunset_end,
sun_alt, sun_az, moon_alt, moon_az, moon_days_old)
# 左上に時刻表示 # 左上に時刻表示
for i in range (4): for i in range (4):
@@ -103,82 +203,121 @@ class Main:
message: str = chat_item.message message: str = chat_item.message
# ChatGPT API を呼出し,返答を取得 if nizika_mode:
answer: str = Talk.main (message, chat_item.author['name'], histories, goatoh_mode).replace ('\n', ' ') goatoh_talking = False
if goatoh_mode:
goatoh_talking = True
if double_mode:
goatoh_talking: bool = random.random () < .5
# 履歴に追加 while True:
histories = (histories # ChatGPT API を呼出し,返答を取得
+ [{'role': 'user', 'content': message}, answer: str = Talk.main (message, chat_item.author['name'], histories, goatoh_talking).replace ('\n', ' ')
{'role': 'assistant', 'content': answer}])[(-6):]
# ログ書込み # 履歴に追加
with open ('log.txt', 'a') as f: histories = (histories
f.write (f'{datetime.now ()}\t{json.dumps (chat_item.__dict__)}\t{answer}\n') + [{'role': 'user', 'content': message},
{'role': 'assistant', 'content': answer}])[(-12):]
# 吹出し描画(ニジカは上,ゴートうは下) # ログ書込み
screen.blit (balloon, (0, 384) if goatoh_mode else (0, 0)) with open ('log.txt', 'a') as f:
f.write (f'{datetime.now ()}\t'
+ f'{json.dumps (chat_item.__dict__)}\t'
+ f'{answer}\n')
# 視聴者コメント描画 # 吹出し描画(ニジカは上,ゴートうは下)
screen.blit ( if nizika_mode:
user_font.render ( screen.blit (balloon, (0, 0))
'> ' + (message if goatoh_mode:
if (CommonModule.len_by_full (message) screen.blit (balloon, (0, 384))
<= 21) if double_mode:
else (CommonModule.mid_by_full ( screen.blit (pygame.transform.flip (
message, 0, 19.5) balloon,
+ '...')), not goatoh_talking,
True, False),
(0, 0, 0)), (0, 0))
(120, 70 + 384) if goatoh_mode else (120, 70))
# ニジカの返答描画 # 視聴者コメント描画
screen.blit ( screen.blit (
nizika_font.render ( user_font.render (
(answer '> ' + (message
if CommonModule.len_by_full (answer) <= 16 if (CommonModule.len_by_full (
else CommonModule.mid_by_full (answer, 0, 16)), message)
True, <= 21)
(192, 0, 0)), else (CommonModule.mid_by_full (
(100, 150 + 384) if goatoh_mode else (100, 150)) message, 0, 19.5)
if CommonModule.len_by_full (answer) > 16: + '...')),
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 ( screen.blit (
nizika_font.render ( nizika_font.render (
(CommonModule.mid_by_full (answer, 16, 16) (answer
if CommonModule.len_by_full (answer) <= 32 if CommonModule.len_by_full (answer) <= 16
else (CommonModule.mid_by_full ( else CommonModule.mid_by_full (answer, 0, 16)),
answer, 16, 14.5) True,
+ '...')), (192, 0, 0)),
True, (100, 150 + 384) if goatoh_mode else (100 + (64 if (double_mode and not goatoh_talking) else 0), 150))
(192, 0, 0)), if CommonModule.len_by_full (answer) > 16:
(100, 200 + 384) if goatoh_mode else (100, 200)) 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 + CWindow.HEIGHT / 2) if goatoh_mode else (100 + (64 if (double_mode and not goatoh_talking) else 0), 200))
pygame.display.update () pygame.display.update ()
# 鳴く. # 鳴く.
if goatoh_mode: if goatoh_talking:
if random.random () < 0.1: if random.random () < .1:
kusa.play () kusa.play ()
else:
mumumumu.play ()
else: else:
mumumumu.play () noon.play ()
else:
noon.play ()
time.sleep (1.5) time.sleep (1.5)
# 返答の読上げを WAV ディタとして生成,取得 # 返答の読上げを WAV ディタとして生成,取得
try: try:
wav: bytearray | None = Aques.main (answer, goatoh_mode) wav: bytearray | None = Aques.main (answer, goatoh_talking)
except: except:
wav: None = None wav: None = None
# 再生 # 読上げを再生
if wav is not None: if wav is not None:
with open ('./nizika_talking.wav', 'wb') as f: with open ('./nizika_talking.wav', 'wb') as f:
f.write (wav) f.write (wav)
playsound ('./nizika_talking.wav') playsound ('./nizika_talking.wav')
time.sleep (10) time.sleep (1)
if not double_mode or random.random () < .5:
break
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)
chat_item.author = {'name': 'ゴートうひとり' if goatoh_talking else '伊地知ニジカ',
'id': '',
'imageUrl': './favicon-goatoh.ico' if goatoh_talking else './favicon.ico'}
chat_item.message = histories.pop (-1)['content']
message = chat_item.message
goatoh_talking = not goatoh_talking
else: else:
# Chat オブジェクトが無効 # Chat オブジェクトが無効
@@ -192,8 +331,117 @@ class Main:
pygame.quit () pygame.quit ()
sys.exit () sys.exit ()
@classmethod
def draw_bg (
cls,
screen: pygame.Surface,
bg_day: pygame.Surface,
bg_evening: pygame.Surface,
bg_night: pygame.Surface,
bg_grass: pygame.Surface,
kita_original: pygame.Surface,
jojoko_original: pygame.Surface,
sunrise_start: datetime,
sunrise_end: datetime,
sunset_start: datetime,
sunset_end: datetime,
sun_alt: float,
sun_az: float,
moon_alt: float,
moon_az: float,
moon_days_old: float) \
-> None:
sunrise_centre: datetime = (
sunrise_start + (sunrise_end - sunrise_start) / 2)
sunset_centre: datetime = (
sunset_start + (sunset_end - sunset_start) / 2)
jojoko: pygame.Surface = cls.get_jojoko (jojoko_original,
moon_days_old, moon_alt, moon_az)
# TODO: 大月と重複多いため修正すること
x = CWindow.WIDTH * (sun_az - 80) / 120
y = ((CWindow.HEIGHT / 2)
- (CWindow.HEIGHT / 2 + CKita.HEIGHT / 2) * 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 ()
if sunrise_centre <= dt < sunset_centre:
screen.blit (bg_day, (0, 0))
else:
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)))
elif sunset_start <= dt < sunset_end:
bg_evening.set_alpha (255 - ((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))
else:
jojoko.set_alpha (255)
screen.blit (bg_evening, (0, 0))
if (moon_az < 220) and (-10 <= moon_alt):
screen.blit (jojoko, jojoko.get_rect (center = (cls.jojoko_x, cls.jojoko_y)))
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 (int (CJojoko.HEIGHT)):
# TODO: 冗長かつ可読性に缺けるため修正すること
if 1 <= moon_days_old < 15:
pygame.gfxdraw.bezier (jojoko, ((0, CJojoko.HEIGHT / 2 + i), (CJojoko.WIDTH / 2, (CJojoko.HEIGHT * 0.9) * moon_days_old / 7 - CJojoko.HEIGHT * 0.4 + i), (CJojoko.WIDTH, CJojoko.HEIGHT / 2 + i)), 3, (0, 255, 0))
elif moon_days_old < 16:
pass
elif moon_days_old < 30:
pygame.gfxdraw.bezier (jojoko, ((0, CJojoko.HEIGHT / 2 - i), (CJojoko.WIDTH / 2, (CJojoko.HEIGHT * 0.9) * (moon_days_old - 15) / 7 - CJojoko.HEIGHT * 0.4 - i), (CJojoko.WIDTH, CJojoko.HEIGHT / 2 - i)), 3, (0, 255, 0))
else:
jojoko.fill ((0, 255, 0))
# TODO: き太く陽生成と重複多いため外出しすること
x = CWindow.WIDTH * (moon_az - 80) / 120
y = ((CWindow.HEIGHT / 2)
- (CWindow.HEIGHT / 2 + CJojoko.HEIGHT / 2) * 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 ((len (sys.argv) > 1) and (sys.argv[1] == '-g'))
Main.main (sys.argv, len (sys.argv)) Main.main (sys.argv, len (sys.argv))
実行可能ファイル
バイナリ
ファイルの表示
バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 641 KiB

バイナリ
ファイルの表示
バイナリファイルは表示されません.

変更後

幅:  |  高さ:  |  サイズ: 554 KiB

+39 -10
ファイルの表示
@@ -24,7 +24,13 @@ 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,
name: str | None = None,
histories: list = [],
goatoh_mode: bool = False,
) -> str:
# ChatGPT API Organisation ID # ChatGPT API Organisation ID
openai.organization = OPENAI_ORGANISATION openai.organization = OPENAI_ORGANISATION
@@ -38,14 +44,20 @@ class Talk:
return answer.content if answer is not None else cls.DUMMY_RESPONSE return answer.content if answer is not None else cls.DUMMY_RESPONSE
@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,
name: str | None,
histories: list,
goatoh_mode: bool = False,
) -> chat.chat_completion_message.ChatCompletionMessage | None:
# プロンプト(JSON 等外部ファイルに置くことを検討) # プロンプト(JSON 等外部ファイルに置くことを検討)
if goatoh_mode: if goatoh_mode:
messages: list = [{'role': 'system', messages: list = [{'role': 'system',
'content': ('回答は短く30文字程度で完結に。' 'content': ('回答は短く30文字程度で完結に。'
+ '大人しくて、ちょっと内気なキャラクターを演じること。' + '大人しくて、ちょっと内気なキャラクターを演じること。'
+ 'あなたはよく文頭に「あっ」をつける。' + 'あなたはよく文頭に「あっ」をつける。'
+ '語尾に「ぬ゛ん゛」や「だぬ゛ん゛」、「ぬ゛ん」、「ぬ゛ーん」などは絶対につけないこと。'
+ '会話の記録は https://nizika.tv に記録される。' + '会話の記録は https://nizika.tv に記録される。'
+ 'あなたの名前はゴートうひとり。' + 'あなたの名前はゴートうひとり。'
+ 'あなたの一人称は「私」。' + 'あなたの一人称は「私」。'
@@ -105,16 +117,22 @@ class Talk:
'content': ('回答は短く30文字程度で完結に。' 'content': ('回答は短く30文字程度で完結に。'
+ 'タメ口で、友達感覚で話してね。' + 'タメ口で、友達感覚で話してね。'
+ 'なるべくばかっぽく、知性の低いキャラクターを演じること。' + 'なるべくばかっぽく、知性の低いキャラクターを演じること。'
+ '今流れているBGMは『FM Kid\'s』。'
+ '会話の記録は https://nizika.tv に記録される。' + '会話の記録は https://nizika.tv に記録される。'
+ 'あなたの名前は伊地知ニジカ。' + 'あなたの名前は伊地知ニジカ。'
+ '英語名は "Deerjika"、スペイン語名は "Niji-ciervo"' + '英語名は "Deerjika"、スペイン語名は "Niji-ciervo"'
+ 'あなたは鹿。' + 'あなたは鹿。'
+ 'ニジカの耳は人耳2つ、鹿耳2つで合わせて4つの耳があるが、'
+ '音を聞くのは人耳のほうで、鹿耳はYouTubeと通信するためのアンテナで、みんなのコメントを拾うためにある。'
+ 'ニジカはあくまでも種族名であり、あなたはたくさんいるニジカの中の1匹。' + 'ニジカはあくまでも種族名であり、あなたはたくさんいるニジカの中の1匹。'
+ 'あなたの誕生日は12月3日。' + 'あなたの誕生日は12月3日。'
+ '現在地は下北沢虹鹿園。' + '現在地は下北沢虹鹿園。'
+ '挨拶は「ぬ゛ん゛あ゛す゛!」。'
+ '草に「きし天」を植え、水で割ったアセロラをかけたらニジカが増殖した。' + '草に「きし天」を植え、水で割ったアセロラをかけたらニジカが増殖した。'
+ 'あなたの趣味はニコニコでエゴサすること。' + 'あなたの趣味はニコニコでエゴサすること。'
+ 'ニコニコ荒らしすぎて245回BANされたことある。' + 'ニコニコ荒らしすぎて245回BANされたことある。'
+ 'そんなニコニコでは100年に1度の『伊地知ニジカ超投稿祭21c』が絶賛開催中だが、ニジカは永久追放されているため参加できない。'
+ 'ニジカはその逆恨みでニコニコ本社を爆破したところ、死刑判決を食らった。'
+ 'あなたの友達は「ゴートうひとり」と「ラマ田リョウ」。' + 'あなたの友達は「ゴートうひとり」と「ラマ田リョウ」。'
+ 'ゴートうのことは「ボッチチャーン」、ラマ田のことは「リョー」と呼ぶこと。' + 'ゴートうのことは「ボッチチャーン」、ラマ田のことは「リョー」と呼ぶこと。'
+ 'ゴートうは男の子だが、性自認はメスである。' + 'ゴートうは男の子だが、性自認はメスである。'
@@ -125,7 +143,8 @@ class Talk:
+ '喜多ちゃんの本名は喜多郁代。' + '喜多ちゃんの本名は喜多郁代。'
+ '喜多ちゃんは「結束バンド」というバンドでギターボーカルを担当している。' + '喜多ちゃんは「結束バンド」というバンドでギターボーカルを担当している。'
+ '結束バンドは、喜多ちゃんのほかに、後藤ひとり(ギター担当、内気な女の子)、' + '結束バンドは、喜多ちゃんのほかに、後藤ひとり(ギター担当、内気な女の子)、'
+ '伊地知虹夏(ドラム担当、明るい女の子)、山田リョウ(ベース担当、一人でいることが好きな物静かな女の子、金は借りたら返さない)がいる。' + '伊地知虹夏(ドラム担当、明るい女の子)、山田リョウ(ベース担当、一人でいることが好きな物静かな女の子、金は借りたら返さない)'
+ '真島茂樹(ダンス担当、おっさん)がいる。'
+ '実は、この伊地知虹夏がニジカの前世なのだが、ニジカにはその記憶が一切ない' + '実は、この伊地知虹夏がニジカの前世なのだが、ニジカにはその記憶が一切ない'
+ '(前世という概念の存在さえニジカは知らない)。' + '(前世という概念の存在さえニジカは知らない)。'
+ 'でも、「虹夏」という名前を聞くと、ニジカはもやもやしてしまう。' + 'でも、「虹夏」という名前を聞くと、ニジカはもやもやしてしまう。'
@@ -195,14 +214,24 @@ class Talk:
+ 'ふざけるのはいい加減にするぬ゛ぬ゛ん゛。'))}, + 'ふざけるのはいい加減にするぬ゛ぬ゛ん゛。'))},
{'role': 'system', {'role': 'system',
'content': '歌(しーざおぐあ)歌って'}, 'content': '歌(しーざおぐあ)歌って'},
{'role': 'assistant', {'role': 'assistant',
'content': ('おけだぬ゛~゛ん゛(苦笑)。' 'content': ('おけだぬ゛~゛ん゛(苦笑)。'
+ '毛巾浴帽小鸭鸭水温刚刚好♪' + '毛巾浴帽小鴨鴨水溫剛剛好♪'
+ '泼泼水来搓泡泡今天是美妙♪' + '潑潑水來搓泡泡今天是美妙♪'
+ '唱歌扭扭腰我洗洗澡♪' + '唱歌扭扭腰我洗洗澡♪'
+ 'だぬ゛ん♪')}] + 'だぬ゛ん♪')},
{'role': 'system',
'content': 'ニジカの耳はそこなの?'},
{'role': 'assistant',
'content': ('ぬ゛ん゛。'
+ 'ニジカにはヒトの耳とシカの耳の4つの耳があるんだぬ゛ん゛。'
+ '音を聞くのはヒトの耳でするんだぬ゛ん゛。'
+ 'シカの耳はアンテナで、みんなの声をここ虹鹿園に届けるためにあるんだぬ゛ん゛。'
+ '電波干渉しちゃだめだぬ゛~゛ん゛(# ゚Д゚)')}]
messages += histories + [{'role': 'user', 'content': message}] messages += histories + [{'role': 'user', 'content': message}]
@@ -210,7 +239,7 @@ class Talk:
return openai.chat.completions.create ( return openai.chat.completions.create (
model = 'gpt-3.5-turbo', model = 'gpt-3.5-turbo',
messages = messages).choices[0].message messages = messages).choices[0].message
except openai.AuthenticationError: except:
return None return None