| 
																	
																	
																	
																 | 
																@@ -1,6 +1,7 @@ | 
															
														
														
													
														
															
																 | 
																 | 
																from __future__ import annotations | 
																 | 
																 | 
																from __future__ import annotations | 
															
														
														
													
														
															
																 | 
																 | 
																
  | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																import asyncio | 
																 | 
																 | 
																import asyncio | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																import random | 
															
														
														
													
														
															
																 | 
																 | 
																from datetime import date, datetime, time, timedelta | 
																 | 
																 | 
																from datetime import date, datetime, time, timedelta | 
															
														
														
													
														
															
																 | 
																 | 
																from typing import TypedDict, cast | 
																 | 
																 | 
																from typing import TypedDict, cast | 
															
														
														
													
														
															
																 | 
																 | 
																
  | 
																 | 
																 | 
																
  | 
															
														
														
													
												
													
														
															
																| 
																	
																	
																	
																		
																	
																 | 
																@@ -9,7 +10,9 @@ from bs4 import BeautifulSoup | 
															
														
														
													
														
															
																 | 
																 | 
																from requests.exceptions import Timeout | 
																 | 
																 | 
																from requests.exceptions import Timeout | 
															
														
														
													
														
															
																 | 
																 | 
																
  | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																import queries_to_answers as q2a | 
																 | 
																 | 
																import queries_to_answers as q2a | 
															
														
														
													
														
															
																 | 
																 | 
																from db.models import Video, VideoHistory | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																from db.models import Comment, Video, VideoHistory | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																from nizika_ai.consts import Character, GPTModel, QueryType | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																from nizika_ai.models import Query | 
															
														
														
													
														
															
																 | 
																 | 
																
  | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																KIRIBAN_VIEWS_COUNTS: list[int] = sorted ({ *range (1_000, 10_000, 1_000), | 
																 | 
																 | 
																KIRIBAN_VIEWS_COUNTS: list[int] = sorted ({ *range (1_000, 10_000, 1_000), | 
															
														
														
													
														
															
																 | 
																 | 
																                                            *range (10_000, 1_000_001, 10_000), | 
																 | 
																 | 
																                                            *range (10_000, 1_000_001, 10_000), | 
															
														
														
													
												
													
														
															
																| 
																	
																		
																	
																	
																		
																	
																	
																 | 
																@@ -44,28 +47,16 @@ async def report_kiriban ( | 
															
														
														
													
														
															
																 | 
																 | 
																        (views_count, video_info, uploaded_at) = ( | 
																 | 
																 | 
																        (views_count, video_info, uploaded_at) = ( | 
															
														
														
													
														
															
																 | 
																 | 
																                kiriban_list.pop (random.randint (0, len (kiriban_list) - 1))) | 
																 | 
																 | 
																                kiriban_list.pop (random.randint (0, len (kiriban_list) - 1))) | 
															
														
														
													
														
															
																 | 
																 | 
																        since_posted = datetime.now () - uploaded_at | 
																 | 
																 | 
																        since_posted = datetime.now () - uploaded_at | 
															
														
														
													
														
															
																 | 
																 | 
																        uri = f"https://www.nicovideo.jp/watch/{ video_info['contentId'] }" | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																        (title, description, thumbnail) = fetch_embed_info (uri) | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																        try: | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																            upload = client.com.atproto.repo.upload_blob ( | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																                    io.BytesIO (requests.get (thumbnail, | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																                                              timeout = 60).content)) | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																            thumb = upload.blob | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																        except Timeout: | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																            thumb = None | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																        comments = nico.get_comments (video_info['contentId']) | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        video_code = video_info['contentId'] | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        uri = f"https://www.nicovideo.jp/watch/{ video_code }" | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        (title, description, _) = fetch_embed_info (uri) | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        comments = fetch_comments (video_code) | 
															
														
														
													
														
															
																 | 
																 | 
																        popular_comments = sorted (comments, | 
																 | 
																 | 
																        popular_comments = sorted (comments, | 
															
														
														
													
														
															
																 | 
																 | 
																                                   key      = lambda c: c.nico_count, | 
																 | 
																 | 
																                                   key      = lambda c: c.nico_count, | 
															
														
														
													
														
															
																 | 
																 | 
																                                   reverse  = True)[:10] | 
																 | 
																 | 
																                                   reverse  = True)[:10] | 
															
														
														
													
														
															
																 | 
																 | 
																        latest_comments = sorted (comments, | 
																 | 
																 | 
																        latest_comments = sorted (comments, | 
															
														
														
													
														
															
																 | 
																 | 
																                                  key       = lambda c: c.posted_at, | 
																 | 
																 | 
																                                  key       = lambda c: c.posted_at, | 
															
														
														
													
														
															
																 | 
																 | 
																                                  reverse   = True)[:10] | 
																 | 
																 | 
																                                  reverse   = True)[:10] | 
															
														
														
													
														
															
																 | 
																 | 
																        embed_external = models.AppBskyEmbedExternal.Main ( | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																                external = models.AppBskyEmbedExternal.External ( | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																                    title       = title, | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																                    description = description, | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																                    thumb       = thumb, | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																                    uri         = uri)) | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																        prompt = f"{ since_posted.days }日と{ since_posted.seconds }秒前にニコニコに投稿された『{ video_info['title'] }』という動画が{ views_count }再生を突破しました。\n" | 
																 | 
																 | 
																        prompt = f"{ since_posted.days }日と{ since_posted.seconds }秒前にニコニコに投稿された『{ video_info['title'] }』という動画が{ views_count }再生を突破しました。\n" | 
															
														
														
													
														
															
																 | 
																 | 
																        prompt += f"コメント数は{ len (comments) }件です。\n" | 
																 | 
																 | 
																        prompt += f"コメント数は{ len (comments) }件です。\n" | 
															
														
														
													
														
															
																 | 
																 | 
																        if video_info['tags']: | 
																 | 
																 | 
																        if video_info['tags']: | 
															
														
														
													
												
													
														
															
																| 
																	
																	
																	
																		
																	
																 | 
																@@ -78,10 +69,19 @@ async def report_kiriban ( | 
															
														
														
													
														
															
																 | 
																 | 
																```html | 
																 | 
																 | 
																```html | 
															
														
														
													
														
															
																 | 
																 | 
																{ video_info['description'] } | 
																 | 
																 | 
																{ video_info['description'] } | 
															
														
														
													
														
															
																 | 
																 | 
																``` | 
																 | 
																 | 
																``` | 
															
														
														
													
														
															
																 | 
																 | 
																このことについて、ニジカちゃんからのお祝いメッセージを下さい。 | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																ただし、そのメッセージ内には再生数の数値とその多さに応じたリアクションを添えてください。 | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																また、ぜひ投稿からこの再生数に至るまでにかかった時間や、つけられたタグ、コメントに対して思いを馳せてください。 | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																好きなコメントがあったら教えてね。""" | 
																 | 
																 | 
																 | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																このことについて、何かお祝いメッセージを下さい。 | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																ただし、そのメッセージ内には再生数の数値を添えてください。 | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																また、つけられたタグ、コメントからどのような動画か想像し、説明してください。""" | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query = Query () | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.user_id = None | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.target_character = Character.DEERJIKA.value | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.content = prompt | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.query_type = QueryType.KIRIBAN.value | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.model = GPTModel.GPT3_TURBO.value | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.sent_at = datetime.now () | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.answered = False | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.transfer_data = { 'video_code': video_code } | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        query.save () | 
															
														
														
													
														
															
																 | 
																 | 
																        # 待ち時間計算 | 
																 | 
																 | 
																        # 待ち時間計算 | 
															
														
														
													
														
															
																 | 
																 | 
																        dt = datetime.now () | 
																 | 
																 | 
																        dt = datetime.now () | 
															
														
														
													
														
															
																 | 
																 | 
																        d = dt.date () | 
																 | 
																 | 
																        d = dt.date () | 
															
														
														
													
												
													
														
															
																| 
																	
																		
																	
																	
																		
																	
																	
																 | 
																@@ -195,6 +195,53 @@ def create_bs_from_url ( | 
															
														
														
													
														
															
																 | 
																 | 
																    return BeautifulSoup (req.text, 'hecoml.parser') | 
																 | 
																 | 
																    return BeautifulSoup (req.text, 'hecoml.parser') | 
															
														
														
													
														
															
																 | 
																 | 
																
  | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																
  | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																def fetch_embed_info ( | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        url:    str, | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																) -> tuple[str, str, str]: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    title:          str = '' | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    description:    str = '' | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    thumbnail:      str = '' | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    try: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        res = requests.get (url, timeout = 60) | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    except Timeout: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        return ('', '', '') | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    if res.status_code != 200: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        return ('', '', '') | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    soup = BeautifulSoup (res.text, 'html.parser') | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    tmp = soup.find ('title') | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    if tmp is not None: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        title = tmp.text | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    tmp = soup.find ('meta', attrs = { 'name': 'description' }) | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    if tmp is not None and hasattr (tmp, 'get'): | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        try: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																            description = cast (str, tmp.get ('content')) | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        except Exception: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																            pass | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    tmp = soup.find ('meta', attrs = { 'name': 'thumbnail' }) | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    if tmp is not None and hasattr (tmp, 'get'): | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        try: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																            thumbnail = cast (str, tmp.get ('content')) | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        except Exception: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																            pass | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    return (title, description, thumbnail) | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																def fetch_comments ( | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        video_code: str, | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																) -> list[Comment]: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    video = Video.where ('code', video_code).first () | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    if video is None: | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																        return [] | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																    return video.comments | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																 | 
																 | 
																 | 
																
  | 
															
														
														
													
														
															
																 | 
																 | 
																async def report_nico ( | 
																 | 
																 | 
																async def report_nico ( | 
															
														
														
													
														
															
																 | 
																 | 
																) -> None: | 
																 | 
																 | 
																) -> None: | 
															
														
														
													
														
															
																 | 
																 | 
																    ... | 
																 | 
																 | 
																    ... | 
															
														
														
													
												
													
														
															
																| 
																	
																		
																	
																	
																	
																 | 
																
  |