ニジカのスカトロ,ニジカトロ. https://bsky.app/profile/deerjika-bot.bsky.social
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.py 4.3 KiB

3 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. from datetime import datetime, timedelta
  2. import time
  3. import sys
  4. from atproto import Client, models
  5. from ai.talk import Talk
  6. import account
  7. def check_notifications (
  8. client: Client,
  9. ) -> list:
  10. (uris, last_seen_at) = ([], client.get_current_time_iso ())
  11. for notification in (client.app.bsky.notification.list_notifications ()
  12. .notifications):
  13. if not notification.is_read:
  14. if notification.reason in ['mention', 'reply']:
  15. uris += [notification.uri]
  16. elif notification.reason == 'follow':
  17. client.follow (notification.author.did)
  18. client.app.bsky.notification.update_seen ({ 'seen_at': last_seen_at })
  19. return uris
  20. def get_thread_contents (
  21. client: Client,
  22. uri: str,
  23. parent_height: int,
  24. ) -> list:
  25. response = (client.get_post_thread (uri = uri,
  26. parent_height = parent_height)
  27. .thread)
  28. records = []
  29. while response is not None:
  30. records += [{ 'strong_ref': models.create_strong_ref (response.post),
  31. 'did': response.post.author.did,
  32. 'handle': response.post.author.handle,
  33. 'name': response.post.author.display_name,
  34. 'datetime': response.post.record.created_at,
  35. 'text': response.post.record.text,
  36. 'embed': response.post.record.embed }]
  37. response = response.parent
  38. return records
  39. def main () -> None:
  40. client = Client (base_url = 'https://bsky.social')
  41. client.login (account.USER_ID, account.PASSWORD)
  42. last_posted_at = datetime.now () - timedelta (hours = 6)
  43. has_got_snack_time = False
  44. while True:
  45. now = datetime.now ()
  46. for uri in check_notifications (client):
  47. records = get_thread_contents (client, uri, 20)
  48. if len (records) > 0:
  49. answer = Talk.main ((records[0]['text']
  50. if (records[0]['embed'] is None
  51. or not hasattr (records[0]['embed'],
  52. 'images'))
  53. else [
  54. { 'type': 'text', 'text': records[0]['text'] },
  55. { 'type': 'image_url', 'image_url': {
  56. 'url': f"https://cdn.bsky.app/img/feed_fullsize/plain/{ records[0]['did'] }/{ records[0]['embed'].images[0].image.ref.link }" } }]),
  57. records[0]['name'],
  58. [*map (lambda record: {
  59. 'role': ('assistant'
  60. if (record['handle']
  61. == account.USER_ID)
  62. else 'user'),
  63. 'content':
  64. record['text']},
  65. reversed (records[1:]))])
  66. client.send_post (answer,
  67. reply_to = models.AppBskyFeedPost.ReplyRef (
  68. parent = records[0]['strong_ref'],
  69. root = records[-1]['strong_ref']))
  70. if now.hour == 14 and has_got_snack_time:
  71. has_got_snack_time = False
  72. if now.hour == 15 and not has_got_snack_time:
  73. with open ('./assets/snack-time.jpg', 'rb') as f:
  74. image = models.AppBskyEmbedImages.Image (
  75. alt = 'おやつタイムだ!!!!',
  76. image = client.com.atproto.repo.upload_blob (f).blob)
  77. client.send_post (Talk.main ('おやつタイムだ!!!!'),
  78. embed = models.app.bsky.embed.images.Main (
  79. images = [image]))
  80. last_posted_at = now
  81. has_got_snack_time = True
  82. if now - last_posted_at >= timedelta (hours = 6):
  83. client.send_post (Talk.main ('今どうしてる?'))
  84. last_posted_at = now
  85. time.sleep (60)
  86. if __name__ == '__main__':
  87. main (*sys.argv[1:])