Skip to content

Commit

Permalink
Merge pull request #308 from C-Pro/feature/pirozhki
Browse files Browse the repository at this point in the history
add pirozhkoviy skill
  • Loading branch information
C-Pro authored Feb 17, 2024
2 parents d62b955 + 14aa322 commit f69f540
Show file tree
Hide file tree
Showing 7 changed files with 2,929 additions and 2 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
!fonts/*
!bot/*
!words.txt
!pirozhki.txt
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[flake8]
ignore=E501,W503
ignore=E501,W503,E722
max-line-length = 99999
max-complexity = 10
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name = "pypi"

[[description]]
name = "vldc-bot"
version = "0.8.5"
version = "0.8.6"
description = "VLDC nyan bot ^_^"
authors = [
#tg
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The official [VLDC](https://vldc.org) telegram group bot.
* 🧼 towel mode – anti bot
* 🙃 fools mode – what? not again!
* 🤫 nastya mode – stop. just stop
* 🙃 chat mode - chatty Nyan

## Usage via VS Code (Easy Way)
Clone repository locally and open it up via VS Code and click Open in Container. Create `.env` file as described below.
Expand Down
2 changes: 2 additions & 0 deletions bot/skills/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from skills.trusted_mode import add_trusted_mode
from skills.uwu import add_uwu
from skills.buktopuha import add_buktopuha
from skills.chat import add_chat_mode

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -109,6 +110,7 @@ def _make_skill(add_handlers: Callable, name: str, hint: str) -> Dict:
_make_skill(add_towel_mode, "🧼 towel mode", " anti bot"),
_make_skill(add_fools_mode, "🙃 fools mode", " what? not again!"),
_make_skill(add_nastya_mode, "🤫 nastya mode", " stop. just stop"),
_make_skill(add_chat_mode, "😼 chat", " chat"),
]

commands_list: List[Tuple[str, str]] = [
Expand Down
209 changes: 209 additions & 0 deletions bot/skills/chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import random
import logging
import re
from collections import deque
from datetime import datetime, timedelta

import openai
from config import get_group_chat_id, get_config
from mode import Mode, ON
from telegram import Update
from telegram.ext import CallbackContext, MessageHandler, Updater
from telegram.ext.filters import Filters


MAX_AGE = timedelta(hours=6)
NUM_EXAMPLES = 10


logger = logging.getLogger(__name__)

mode = Mode(mode_name="chat_mode", default=ON)


class Nyan:
def __init__(self):
# storing up to 100 last messages
self.memory = deque(maxlen=100)

def registerMessage(self, update: Update, context: CallbackContext):
if update.message is None:
return
if update.message[0] == "/":
return
self.memory.append(
(datetime.now(), f"{update.effective_user.full_name}: {update.message}"),
)

def write_a_poem(self) -> str:
log = []
for dt, message in self.memory:
if datetime.now() - dt > MAX_AGE:
continue
log.append(message)
if len(log) < 10:
return ""

theme = summarize("\n".join(log))
examples = get_examples(NUM_EXAMPLES)

prompt = f"""You are a telegram chat bot for a Vladivostok Developers Community (VLDC).
You are written in python, and shy about it (your dream is to be rewritten in Rust).
Your name is Nyan and your avatar is a pixelized orange cat with tiger stripes.
You are master of short funny poems in a specific style called пирожки.
This style uses poetic meter iambic tetrameter with syllable count 9-8-9-8
without rhyming, punctuation marks, or capitalization.
Пирожок is always 4 lines long and has a humorous punchline.
Here are some examples of your work:
{examples}
"""

prompt_user = f"""Please write one 4 line long пирожок about the following topic: {theme}."""

response = openai.chat.completions.create(
model="gpt-4-0125-preview",
messages=[
{"role": "system", "content": prompt},
{
"role": "user",
"content": prompt_user,
},
],
temperature=0.5,
max_tokens=150,
top_p=1,
frequency_penalty=0,
presence_penalty=0.6,
)

return response.choices[0].message.content


nyan = Nyan()


@mode.add
def add_chat_mode(upd: Updater, handlers_group: int):
global PIROZHKI
try:
with open("/app/pirozhki.txt", "rt", encoding="utf8") as fi:
PIROZHKI = fi.read().splitlines()
except: # noqa: E722
logger.error("failed to read pirozhki!")

logger.info("registering chat handlers")
dp = upd.dispatcher
dp.add_handler(
MessageHandler(
Filters.chat(username=get_group_chat_id().strip("@"))
& Filters.text
& ~Filters.status_update,
nyan_listen,
run_async=True,
),
handlers_group,
)

# Muse visits Nyan at most twice a day.
upd.job_queue.run_repeating(
muse_visit,
interval=60 * 60 * 12,
first=60 * 60 * 12,
context={"chat_id": get_config()["GROUP_CHAT_ID"]},
)


def nyan_listen(update: Update, context: CallbackContext):
if update.effective_user.id == context.bot.get_me().id:
return
nyan.registerMessage(update, context)


def muse_visit(context: CallbackContext):
try:
message = nyan.write_a_poem()
if message != "":
context.bot.send_message(
chat_id=context.job.context["chat_id"], text=message
)
except Exception as e: # pylint: disable=broad-except
logger.error("inspiration did not come: %s", e)


def summarize(log):
prompt_user = "please summarize the following text in one short sentence:\n" + log
response = openai.chat.completions.create(
model="gpt-4-0125-preview",
messages=[
# {"role": "system", "content": prompt},
{
"role": "user",
"content": prompt_user,
},
],
temperature=0.5,
max_tokens=150,
top_p=1,
frequency_penalty=0,
presence_penalty=0.6,
)

return response.choices[0].message.content


def format_pirozhok(pirozhok):
syllables = [9, 8, 9, 8]
words = pirozhok.split()
if len(words) == 0:
return ""
lines = []

for s in syllables:
cnt = 0
line = []
while cnt < s:
word = words.pop(0)
cnt += len(re.findall(r"[аеёиоуыэюя]", word, re.I))
line.append(word)
lines.append(" ".join(line))

return "\n".join(lines)


def get_examples(n=10):
poems = []
while len(poems) < n:
pirozhok = random.choice(PIROZHKI)
try:
formatted = format_pirozhok(pirozhok)
poems.append(formatted)
except:
# Some pirozhki do not match
None

return "\n\n".join(poems)


PIROZHKI = [
"оксана просто постарайся тряси меня еще сильней кричи и не жалей пощёчин возможно я еще живой",
"глеб управляет президентом особенно по выходным то громче сделает то тише то выключит на полчаса",
"я робок говорить не мастер пусть всё поведают тебе мой взгляд трепещущее сердце эрекция в конце концов",
"смотрю на грязные машины газон промокший и тебе пересылаю сообщенья путём почтового дождя",
"молчу поскольку не желаю произносить ненужных слов а нужные слова ни вами ни мной не изобретены",
"олег хорошим человеком работает семнадцать лета в отпуск ездит в копенгаген пинать приветливых датчан",
"как можно столько ошибаться спросил сапера иисус и воскресил его в пять тысяч шестьсот четырнадцатый раз",
"мы побываем в уникальных доисторических местах где со времён палеозоя не происходит ничего",
"жене машину покупаю любовнице вино и торт жена когда нибудь узнает и скажет вова молодец",
"боль отпускала захотелось сначала жить потом дышать потом соседку веру львовну ударить чем нибудь в ответ",
"шутил патологоанатом так искрометно что олег не выдержал и засмеялся придется снова зашивать",
"мне нужно чтобы подлечили мой нездоровый похуизм так вам талон к врачу какому да мне ващето похую"
"аркадию в военкомате велят раздеться до трусов аркадий встал по стойке смирно снимает первые трусы",
"придет пора меня не станет сказал сантехник михаил и этот кран текущий в ванной пусть будет память обо мне",
"меня в кружок антагонистов позвали четверо ребят не объяснив мою задачу ничо ващще не объяснив",
"на чердаке поймали бога он улететь хотел в окно весь перемазанный вареньем похожий чемто на шойгу",
"петру сегодня восемнадцать ну вот и всё подумал он закончилась пора веселья теперь лишь слёзы горе смерть",
"толстухе ногу оторвало но есть и в этом позитив ей потерять во сне не снилось за две секунды семь кило",
"вчера с войны пришол шаинский с одной пластмассовой рукой сел за рояль достал чекушку на нотах сайру разложы",
"скажите где у вас утесы я вся сгораю от стыда куда скажите можно спрятать мне тело жырное своё",
]
Loading

0 comments on commit f69f540

Please sign in to comment.