MVP
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
*__pycache__*
|
*__pycache__*
|
||||||
|
tmp
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
from .menu import menu_router
|
from .menu import menu_router
|
||||||
from .test import test_router
|
from .test import test_router
|
||||||
|
from .teacher import teacher_router
|
||||||
|
from .student import student_router
|
13
blueprints/student.py
Normal file
13
blueprints/student.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadContainsFilter, BotEvent
|
||||||
|
import locales
|
||||||
|
|
||||||
|
student_router = DefaultRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@student_router.registrar.with_decorator(PayloadContainsFilter("student"),)
|
||||||
|
async def student_menu(event: BotEvent):
|
||||||
|
sevent = SimpleBotEvent(event)
|
||||||
|
return await sevent.answer(
|
||||||
|
message=locales.ST_MENU,
|
||||||
|
keyboard=locales.ST_KB.get_keyboard(),
|
||||||
|
)
|
13
blueprints/teacher.py
Normal file
13
blueprints/teacher.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadContainsFilter, BotEvent
|
||||||
|
import locales
|
||||||
|
|
||||||
|
teacher_router = DefaultRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@teacher_router.registrar.with_decorator(PayloadContainsFilter("teacher"),)
|
||||||
|
async def teacher_menu(event: BotEvent):
|
||||||
|
sevent = SimpleBotEvent(event)
|
||||||
|
return await sevent.answer(
|
||||||
|
message=locales.TC_MENU,
|
||||||
|
keyboard=locales.TC_KB.get_keyboard(),
|
||||||
|
)
|
@ -3,13 +3,14 @@ import logging
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadFilter, PayloadContainsFilter, \
|
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadFilter, PayloadContainsFilter, \
|
||||||
PhotoUploader
|
PhotoUploader, Storage
|
||||||
from vkwave.bots import Keyboard, ButtonColor
|
from vkwave.bots import Keyboard, ButtonColor
|
||||||
from vkwave.bots import EventTypeFilter, BotEvent
|
from vkwave.bots import EventTypeFilter, BotEvent
|
||||||
from vkwave.types.bot_events import BotEventType
|
from vkwave.types.bot_events import BotEventType
|
||||||
from vkwave.bots.fsm import FiniteStateMachine, StateFilter, ForWhat, State, ANY_STATE
|
from vkwave.bots.fsm import FiniteStateMachine, StateFilter, ForWhat, State, ANY_STATE
|
||||||
|
|
||||||
import locales
|
import locales
|
||||||
|
import util
|
||||||
from config import Config
|
from config import Config
|
||||||
from db import DB
|
from db import DB
|
||||||
from db.db import TestResult
|
from db.db import TestResult
|
||||||
@ -21,9 +22,12 @@ from locales import INPUT_NAME_TEXT
|
|||||||
# MENU_KB.add_row()
|
# MENU_KB.add_row()
|
||||||
# MENU_KB.add_text_button(text="Бонус", payload={"command": "bonus"}, color=ButtonColor.POSITIVE)
|
# MENU_KB.add_text_button(text="Бонус", payload={"command": "bonus"}, color=ButtonColor.POSITIVE)
|
||||||
# from nft_things.NftSender import NFTSender
|
# from nft_things.NftSender import NFTSender
|
||||||
|
from util.redis_db import RedisDB
|
||||||
|
|
||||||
test_router = DefaultRouter()
|
test_router = DefaultRouter()
|
||||||
|
|
||||||
|
fsm = FiniteStateMachine()
|
||||||
|
test_router.registrar.add_default_filter(StateFilter(fsm, ..., ..., always_false=True))
|
||||||
test_router.registrar.add_default_filter(
|
test_router.registrar.add_default_filter(
|
||||||
EventTypeFilter(BotEventType.MESSAGE_NEW.value)) # we don't want to write it in all handlers.
|
EventTypeFilter(BotEventType.MESSAGE_NEW.value)) # we don't want to write it in all handlers.
|
||||||
|
|
||||||
@ -40,7 +44,7 @@ test_router.registrar.add_default_filter(
|
|||||||
# return "You are quited!"
|
# return "You are quited!"
|
||||||
|
|
||||||
@test_router.registrar.with_decorator(
|
@test_router.registrar.with_decorator(
|
||||||
PayloadContainsFilter("test"),# for state in States.questions[:-1]]
|
PayloadContainsFilter("test"),
|
||||||
)
|
)
|
||||||
async def main_part_handle(event: BotEvent):
|
async def main_part_handle(event: BotEvent):
|
||||||
user_id = event.object.object.message.from_id
|
user_id = event.object.object.message.from_id
|
||||||
@ -51,7 +55,7 @@ async def main_part_handle(event: BotEvent):
|
|||||||
logging.debug(f"State index: {state_idx}")
|
logging.debug(f"State index: {state_idx}")
|
||||||
|
|
||||||
|
|
||||||
q_res = payload['q'] if 'q' in payload else None
|
q_res = payload['q'] if 'q' in payload else event.object.object.message.text
|
||||||
logging.debug(f"Qres: {q_res}")
|
logging.debug(f"Qres: {q_res}")
|
||||||
|
|
||||||
# extra_state_data works as fsm.add_data(..., state_data={"name": event.object.object.message.text})
|
# extra_state_data works as fsm.add_data(..., state_data={"name": event.object.object.message.text})
|
||||||
@ -61,17 +65,28 @@ async def main_part_handle(event: BotEvent):
|
|||||||
DB().update_test_result(user_id, question=state_idx, answer=q_res)
|
DB().update_test_result(user_id, question=state_idx, answer=q_res)
|
||||||
|
|
||||||
if state_idx + 1 < len(locales.questions):
|
if state_idx + 1 < len(locales.questions):
|
||||||
|
RedisDB().set_state(user_id, state_idx + 1)
|
||||||
|
kb = locales.questions[state_idx + 1][1]
|
||||||
|
if kb:
|
||||||
return await botevent.answer(
|
return await botevent.answer(
|
||||||
message=locales.questions[state_idx + 1][0],
|
message=locales.questions[state_idx + 1][0],
|
||||||
keyboard=locales.questions[state_idx + 1][1].get_keyboard(),
|
keyboard=kb.get_keyboard(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return await botevent.answer(
|
||||||
|
message=locales.questions[state_idx + 1][0],
|
||||||
|
payload=json.dumps({"test": state_idx + 1}),
|
||||||
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# todo add task to send user an image here
|
# todo add task to send user an image here
|
||||||
# Config().nft_sender.add_task()
|
# Config().nft_sender.add_task()
|
||||||
|
RedisDB().del_state(user_id)
|
||||||
logging.warn("Sending attach!")
|
logging.warn("Sending attach!")
|
||||||
|
|
||||||
big_attachment = await Config().uploader.get_attachments_from_paths(
|
big_attachment = await Config().uploader.get_attachments_from_paths(
|
||||||
peer_id=user_id,
|
peer_id=user_id,
|
||||||
file_paths=["img.jpg"],
|
file_paths=[util.get_image(user_id)],
|
||||||
)
|
)
|
||||||
await Config().api_ctx.messages.send(
|
await Config().api_ctx.messages.send(
|
||||||
user_id=user_id, attachment=big_attachment, random_id=0
|
user_id=user_id, attachment=big_attachment, random_id=0
|
||||||
|
10
config.py
10
config.py
@ -1,4 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
from vkwave.bots import PhotoUploader
|
||||||
|
|
||||||
from util import Singleton
|
from util import Singleton
|
||||||
|
|
||||||
|
|
||||||
@ -9,8 +12,13 @@ class Config(metaclass=Singleton):
|
|||||||
PG_USER = os.environ["USER"]
|
PG_USER = os.environ["USER"]
|
||||||
PG_PASS = os.environ["PASS"]
|
PG_PASS = os.environ["PASS"]
|
||||||
PG_ADDR = os.environ["DB_ADDR"]
|
PG_ADDR = os.environ["DB_ADDR"]
|
||||||
|
REDIS_ADDR = os.environ["REDIS_ADDR"]
|
||||||
|
|
||||||
|
NFT_SVC_ADDR = os.environ["NFT_ADDR"]
|
||||||
|
|
||||||
|
TMP_DIR = os.environ["TMP_DIR"]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.api_ctx = None
|
self.api_ctx = None
|
||||||
self.uploader = None
|
self.uploader: PhotoUploader = None
|
||||||
|
|
||||||
|
7
db/db.py
7
db/db.py
@ -64,6 +64,13 @@ class DB(metaclass=Singleton):
|
|||||||
|
|
||||||
def update_test_result(self, user_id: int, question: int, answer: str):
|
def update_test_result(self, user_id: int, question: int, answer: str):
|
||||||
user = self._session.query(Candidate).filter(Candidate.id == user_id).first()
|
user = self._session.query(Candidate).filter(Candidate.id == user_id).first()
|
||||||
|
for i, ans in enumerate(user.test_result[0].answers):
|
||||||
|
if ans.question == question:
|
||||||
|
logging.debug(f"Update test result: {question} {answer}")
|
||||||
|
user.test_result[0].answers[i].answer = answer
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logging.warn(f"New test result: {question} {answer}")
|
||||||
user.test_result[0].answers.append(QuestionAnswer(question=question, answer=answer))
|
user.test_result[0].answers.append(QuestionAnswer(question=question, answer=answer))
|
||||||
self._session.commit()
|
self._session.commit()
|
||||||
|
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
version: "2"
|
version: "2"
|
||||||
services:
|
services:
|
||||||
|
image_gen:
|
||||||
|
build:
|
||||||
|
context: ./nft_svc
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- 5001:5000
|
||||||
|
|
||||||
pgdb:
|
pgdb:
|
||||||
image: 'postgres:12'
|
image: 'postgres:12'
|
||||||
restart: always
|
restart: always
|
||||||
@ -12,3 +19,10 @@ services:
|
|||||||
# - ${PG_MNT}:/var/lib/postgresql/data
|
# - ${PG_MNT}:/var/lib/postgresql/data
|
||||||
ports:
|
ports:
|
||||||
- ${PG_OUTBOUND_PORT}:5432
|
- ${PG_OUTBOUND_PORT}:5432
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
command: redis-server --appendonly yes --appendfsync everysec
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
# volumes:
|
||||||
|
# - ${FDS_REDIS_MNT}:/data
|
||||||
|
109
locales.py
109
locales.py
@ -1,10 +1,57 @@
|
|||||||
from vkwave.bots import Keyboard, ButtonColor
|
from vkwave.bots import Keyboard, ButtonColor
|
||||||
|
|
||||||
# menu
|
# menu
|
||||||
MENU = "Привет!"
|
MENU = "Привет, друг! Это - бот инженерной школы. Инженерная школа - молодой проект на Механико-Математическом факультете НГУ."
|
||||||
MENU_KB = Keyboard()
|
MENU_KB = Keyboard()
|
||||||
MENU_KB.add_text_button(text="Пройти тест!", payload={"test": "-1"}, color=ButtonColor.POSITIVE)
|
MENU_KB.add_text_button(text="Пройти тест!", payload={"test": "-1"}, color=ButtonColor.POSITIVE)
|
||||||
MENU_KB.add_link_button(text="Общий чатик", link="https://vk.me/join/AJQ1dw97/SBEQYIyQdZfG69y")
|
MENU_KB.add_link_button(text="Общий чатик", link="https://vk.me/join/AJQ1dw97/SBEQYIyQdZfG69y")
|
||||||
|
MENU_KB.add_row()
|
||||||
|
MENU_KB.add_text_button(text="Пообщаться со студентом", payload={"student": "1"}, color=ButtonColor.PRIMARY)
|
||||||
|
MENU_KB.add_row()
|
||||||
|
MENU_KB.add_text_button(text="Пообщаться с преподавателем", payload={"teacher": "1"}, color=ButtonColor.PRIMARY)
|
||||||
|
|
||||||
|
|
||||||
|
# Student menu
|
||||||
|
ST_MENU = """Вот список студентов, которые могут рассказать тебе про Инженерную Школу
|
||||||
|
https://vk.com/cleverbitch - Булгакова Лиза, 2 курс
|
||||||
|
https://vk.com/shestakova__d - Шестакова Даша, 2 курс
|
||||||
|
https://vk.com/fossa_mar - Пискеева Даша, 2 курс
|
||||||
|
https://vk.com/brainkiller78 - Тищенко Данил, 1 курс
|
||||||
|
https://vk.com/skazaniyk - Хамутский Дима, 1 курс
|
||||||
|
https://vk.com/kirik229 - Шадрина Анжела, 2 курс
|
||||||
|
https://vk.com/dinazavrrrik - Коновалов Назар, 1 курс
|
||||||
|
https://vk.com/tenikeev - Еникеев Тимур, 1 курс
|
||||||
|
"""
|
||||||
|
ST_KB = Keyboard()
|
||||||
|
ST_KB.add_link_button(text="Булгакова Лиза", link="https://vk.com/cleverbitch")
|
||||||
|
ST_KB.add_link_button(text="Шестакова Даша", link="https://vk.com/shestakova__d")
|
||||||
|
ST_KB.add_row()
|
||||||
|
ST_KB.add_link_button(text="Пискеева Даша", link="https://vk.com/fossa_mar")
|
||||||
|
ST_KB.add_link_button(text="Тищенко Данил", link="https://vk.com/brainkiller78")
|
||||||
|
ST_KB.add_row()
|
||||||
|
ST_KB.add_link_button(text="Хамутский Дима", link="https://vk.com/skazaniyk")
|
||||||
|
ST_KB.add_link_button(text="Шадрина Анжела", link="https://vk.com/kirik229")
|
||||||
|
ST_KB.add_row()
|
||||||
|
ST_KB.add_link_button(text="Коновалов Назар", link="https://vk.com/dinazavrrrik")
|
||||||
|
ST_KB.add_link_button(text="Еникеев Тимур", link="https://vk.com/tenikeev")
|
||||||
|
ST_KB.add_row()
|
||||||
|
ST_KB.add_text_button(text="ХОЧУ ДОМОЙ!!!!!!!!!!!!!!!", payload={}, color=ButtonColor.NEGATIVE)
|
||||||
|
|
||||||
|
# Teacher menu
|
||||||
|
TC_MENU = """Вот список преподавателей, которые могут рассказать тебе про Инженерную Школу
|
||||||
|
https://vk.com/anastasia.v.karpenko - Карпенко Анастасия Валерьевна, преподаватель по логике и ОПД
|
||||||
|
https://vk.com/krkaushan - Насыбуллова Кристина Андреевна,
|
||||||
|
https://vk.com/id11073597 - Насыбуллов Тимур Ринатович, преподаватель по Алгебре и геометрии и ТФКП
|
||||||
|
https://vk.com/yury_efremenko - Ефременко Юрий Данилович, преподаватель по Алгебре и геометрии."""
|
||||||
|
TC_KB = Keyboard()
|
||||||
|
TC_KB.add_link_button(text="Анастасия Валерьевна", link="https://vk.com/anastasia.v.karpenko")
|
||||||
|
TC_KB.add_link_button(text="Кристина Андреевна", link="https://vk.com/krkaushan")
|
||||||
|
TC_KB.add_row()
|
||||||
|
TC_KB.add_link_button(text="Тимур Ринатович", link="https://vk.com/id11073597")
|
||||||
|
TC_KB.add_link_button(text="Юрий Данилович", link="https://vk.com/yury_efremenko")
|
||||||
|
TC_KB.add_row()
|
||||||
|
TC_KB.add_text_button(text="ХОЧУ ДОМОЙ!!!!!!!!!!!!!!!", payload={}, color=ButtonColor.NEGATIVE)
|
||||||
|
|
||||||
|
|
||||||
# TEST Questions
|
# TEST Questions
|
||||||
INPUT_NAME_TEXT = "Пожалуйста, введите имя:"
|
INPUT_NAME_TEXT = "Пожалуйста, введите имя:"
|
||||||
@ -12,44 +59,57 @@ INPUT_NAME_TEXT = "Пожалуйста, введите имя:"
|
|||||||
# 1
|
# 1
|
||||||
WHAT_ENGINEER_ARE_YOU = "Кто ты из инженеров?"
|
WHAT_ENGINEER_ARE_YOU = "Кто ты из инженеров?"
|
||||||
WHAT_ENGINEER_ARE_YOU_KB = Keyboard()
|
WHAT_ENGINEER_ARE_YOU_KB = Keyboard()
|
||||||
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Маск", payload={"q": "Маск", "test": "0"}, color=ButtonColor.PRIMARY)
|
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Маск", payload={"q": "Маск"}, color=ButtonColor.PRIMARY)
|
||||||
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Рогозин", payload={"q": "Рогозин", "test": "0"}, color=ButtonColor.PRIMARY)
|
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Рогозин", payload={"q": "Рогозин"}, color=ButtonColor.PRIMARY)
|
||||||
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Тесла", payload={"q": "Тесла", "test": "0"}, color=ButtonColor.PRIMARY)
|
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Тесла", payload={"q": "Тесла"}, color=ButtonColor.PRIMARY)
|
||||||
WHAT_ENGINEER_ARE_YOU_KB.add_row()
|
WHAT_ENGINEER_ARE_YOU_KB.add_row()
|
||||||
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Кулибин", payload={"q": "Кулибин", "test": "0"}, color=ButtonColor.PRIMARY)
|
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Кулибин", payload={"q": "Кулибин"}, color=ButtonColor.PRIMARY)
|
||||||
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Калашников", payload={"q": "Калашников", "test": "0"}, color=ButtonColor.PRIMARY)
|
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Калашников", payload={"q": "Калашников"}, color=ButtonColor.PRIMARY)
|
||||||
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Кондратюк", payload={"q": "Кондратюк", "test": "0"}, color=ButtonColor.PRIMARY)
|
WHAT_ENGINEER_ARE_YOU_KB.add_text_button(text="Кондратюк", payload={"q": "Кондратюк"}, color=ButtonColor.PRIMARY)
|
||||||
|
|
||||||
# 2
|
# 2
|
||||||
PROG_LANG = "Какой ЯП нравится?"
|
PROG_LANG = "Какой ЯП нравится?"
|
||||||
PROG_LANG_KB = Keyboard()
|
PROG_LANG_KB = Keyboard()
|
||||||
PROG_LANG_KB.add_text_button(text="Python", payload={"q": "Python", "test": "1"}, color=ButtonColor.PRIMARY)
|
PROG_LANG_KB.add_text_button(text="Python", payload={"q": "Python"}, color=ButtonColor.PRIMARY)
|
||||||
PROG_LANG_KB.add_text_button(text="Pascal", payload={"q": "Pascal", "test": "1"}, color=ButtonColor.PRIMARY)
|
PROG_LANG_KB.add_text_button(text="Pascal", payload={"q": "Pascal"}, color=ButtonColor.PRIMARY)
|
||||||
PROG_LANG_KB.add_text_button(text="C/C++", payload={"q": "ccpp", "test": "1"}, color=ButtonColor.PRIMARY)
|
PROG_LANG_KB.add_text_button(text="C/C++", payload={"q": "ccpp"}, color=ButtonColor.PRIMARY)
|
||||||
PROG_LANG_KB.add_row()
|
PROG_LANG_KB.add_row()
|
||||||
PROG_LANG_KB.add_text_button(text="JS", payload={"q": "JS", "test": "1"}, color=ButtonColor.PRIMARY)
|
PROG_LANG_KB.add_text_button(text="JS", payload={"q": "JS"}, color=ButtonColor.PRIMARY)
|
||||||
PROG_LANG_KB.add_text_button(text="HTML+CSS", payload={"q": "HTMLCSS", "test": "1"}, color=ButtonColor.PRIMARY)
|
PROG_LANG_KB.add_text_button(text="HTML+CSS", payload={"q": "HTMLCSS"}, color=ButtonColor.PRIMARY)
|
||||||
PROG_LANG_KB.add_text_button(text="Haskel", payload={"q": "Haskel", "test": "1"}, color=ButtonColor.PRIMARY)
|
PROG_LANG_KB.add_text_button(text="Haskel", payload={"q": "Haskel"}, color=ButtonColor.PRIMARY)
|
||||||
|
|
||||||
# 3
|
# 3
|
||||||
FAV_THEME = "Какой предмет нравится?"
|
FAV_THEME = "Какой предмет нравится?"
|
||||||
FAV_THEME_KB = Keyboard()
|
FAV_THEME_KB = Keyboard()
|
||||||
FAV_THEME_KB.add_text_button(text="Матеша", payload={"q": "Матеша", "test": "2"}, color=ButtonColor.PRIMARY)
|
FAV_THEME_KB.add_text_button(text="Матеша", payload={"q": "Матеша"}, color=ButtonColor.PRIMARY)
|
||||||
FAV_THEME_KB.add_text_button(text="Русский/Литра", payload={"q": "русскийлитра", "test": "2"}, color=ButtonColor.PRIMARY)
|
FAV_THEME_KB.add_text_button(text="Русский/Литра", payload={"q": "русскийлитра"}, color=ButtonColor.PRIMARY)
|
||||||
FAV_THEME_KB.add_text_button(text="Инфа", payload={"q": "Инфа", "test": "2"}, color=ButtonColor.PRIMARY)
|
FAV_THEME_KB.add_text_button(text="Инфа", payload={"q": "Инфа"}, color=ButtonColor.PRIMARY)
|
||||||
FAV_THEME_KB.add_row()
|
FAV_THEME_KB.add_row()
|
||||||
FAV_THEME_KB.add_text_button(text="Физика", payload={"q": "Физика", "test": "2"}, color=ButtonColor.PRIMARY)
|
FAV_THEME_KB.add_text_button(text="Физика", payload={"q": "Физика"}, color=ButtonColor.PRIMARY)
|
||||||
FAV_THEME_KB.add_text_button(text="другое", payload={"q": "other", "test": "2"}, color=ButtonColor.PRIMARY)
|
FAV_THEME_KB.add_text_button(text="другое", payload={"q": "other"}, color=ButtonColor.PRIMARY)
|
||||||
|
|
||||||
# 4
|
# 4
|
||||||
EGE = "Как готовился к ЕГЭ?"
|
EGE = "Как готовился к ЕГЭ?"
|
||||||
EGE_KB = Keyboard()
|
EGE_KB = Keyboard()
|
||||||
EGE_KB.add_text_button(text="В школе", payload={"q": "школа", "test": "3"}, color=ButtonColor.PRIMARY)
|
EGE_KB.add_text_button(text="В школе", payload={"q": "школа"}, color=ButtonColor.PRIMARY)
|
||||||
EGE_KB.add_text_button(text="online", payload={"q": "online", "test": "3"}, color=ButtonColor.PRIMARY)
|
EGE_KB.add_text_button(text="online", payload={"q": "online"}, color=ButtonColor.PRIMARY)
|
||||||
EGE_KB.add_text_button(text="репетитор", payload={"q": "репетитор", "test": "3"}, color=ButtonColor.PRIMARY)
|
EGE_KB.add_text_button(text="репетитор", payload={"q": "репетитор"}, color=ButtonColor.PRIMARY)
|
||||||
EGE_KB.add_row()
|
EGE_KB.add_row()
|
||||||
EGE_KB.add_text_button(text="Сам", payload={"q": "Сам", "test": "3"}, color=ButtonColor.PRIMARY)
|
EGE_KB.add_text_button(text="Сам", payload={"q": "Сам"}, color=ButtonColor.PRIMARY)
|
||||||
EGE_KB.add_text_button(text="wtf?", payload={"q": "wtf", "test": "3"}, color=ButtonColor.PRIMARY)
|
EGE_KB.add_text_button(text="wtf?", payload={"q": "wtf"}, color=ButtonColor.PRIMARY)
|
||||||
|
|
||||||
|
# 5
|
||||||
|
TRANS_ENGINEER_COUNT = "Сколько студентов ИШ надо, чтобы включить трансу?"
|
||||||
|
TRANS_ENGINEER_COUNT_KB = Keyboard()
|
||||||
|
TRANS_ENGINEER_COUNT_KB.add_text_button(text="1", payload={"q": "1"}, color=ButtonColor.PRIMARY)
|
||||||
|
TRANS_ENGINEER_COUNT_KB.add_text_button(text="2", payload={"q": "2"}, color=ButtonColor.PRIMARY)
|
||||||
|
TRANS_ENGINEER_COUNT_KB.add_text_button(text="5", payload={"q": "5"}, color=ButtonColor.PRIMARY)
|
||||||
|
|
||||||
|
# 6
|
||||||
|
ZODIAC = "Кто вы по знаку зодиака?"
|
||||||
|
|
||||||
|
# 7
|
||||||
|
CONTACT = "Введите почту или ник в телеграмме, по которому мы сможем прислать вам результаты"
|
||||||
|
|
||||||
# last
|
# last
|
||||||
LAST_MESSAGE = "Спасибо, что прошел тест!"
|
LAST_MESSAGE = "Спасибо, что прошел тест!"
|
||||||
@ -62,4 +122,7 @@ questions = [
|
|||||||
(PROG_LANG, PROG_LANG_KB),
|
(PROG_LANG, PROG_LANG_KB),
|
||||||
(FAV_THEME, FAV_THEME_KB),
|
(FAV_THEME, FAV_THEME_KB),
|
||||||
(EGE, EGE_KB),
|
(EGE, EGE_KB),
|
||||||
|
(TRANS_ENGINEER_COUNT, TRANS_ENGINEER_COUNT_KB),
|
||||||
|
(ZODIAC, None),
|
||||||
|
(CONTACT, None),
|
||||||
]
|
]
|
||||||
|
9
main.py
9
main.py
@ -3,11 +3,12 @@ import logging
|
|||||||
from vkwave.bots import SimpleLongPollBot, PhotoUploader
|
from vkwave.bots import SimpleLongPollBot, PhotoUploader
|
||||||
|
|
||||||
from blueprints import (
|
from blueprints import (
|
||||||
menu_router, test_router,
|
menu_router, test_router, student_router, teacher_router,
|
||||||
)
|
)
|
||||||
from config import Config
|
from config import Config
|
||||||
from middlewares import UserMiddleware
|
from middlewares import UserMiddleware
|
||||||
# from nft_things.NftSender import NFTSender
|
# from nft_things.NftSender import NFTSender
|
||||||
|
from middlewares.test_state_middleware import TestStateMiddleware
|
||||||
|
|
||||||
logging.basicConfig(level="DEBUG")
|
logging.basicConfig(level="DEBUG")
|
||||||
|
|
||||||
@ -20,12 +21,12 @@ Config().api_ctx = bot.api_context
|
|||||||
Config().uploader = uploader
|
Config().uploader = uploader
|
||||||
|
|
||||||
bot.middleware_manager.add_middleware(UserMiddleware())
|
bot.middleware_manager.add_middleware(UserMiddleware())
|
||||||
|
bot.middleware_manager.add_middleware(TestStateMiddleware())
|
||||||
|
|
||||||
|
|
||||||
bot.dispatcher.add_router(test_router)
|
bot.dispatcher.add_router(test_router)
|
||||||
# bot.dispatcher.add_router(games_router)
|
bot.dispatcher.add_router(student_router)
|
||||||
# bot.dispatcher.add_router(coin_flip_router)
|
bot.dispatcher.add_router(teacher_router)
|
||||||
# bot.dispatcher.add_router(bonus_router)
|
|
||||||
|
|
||||||
# регаем последним чтобы сначала проверялись все остальные команды
|
# регаем последним чтобы сначала проверялись все остальные команды
|
||||||
bot.dispatcher.add_router(menu_router)
|
bot.dispatcher.add_router(menu_router)
|
||||||
|
26
middlewares/test_state_middleware.py
Normal file
26
middlewares/test_state_middleware.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from vkwave.bots import BaseMiddleware, BotEvent, MiddlewareResult, SimpleBotEvent, Storage
|
||||||
|
from vkwave.bots.storage.types import Key
|
||||||
|
|
||||||
|
from db import DB, Candidate
|
||||||
|
from util.redis_db import RedisDB
|
||||||
|
|
||||||
|
storage = Storage()
|
||||||
|
|
||||||
|
|
||||||
|
class TestStateMiddleware(BaseMiddleware):
|
||||||
|
async def pre_process_event(self, event: BotEvent) -> MiddlewareResult:
|
||||||
|
user_id = event.object.object.message.from_id
|
||||||
|
redis_test_state = RedisDB().get_state(user_id)
|
||||||
|
logging.debug(event.object.object.message.payload)
|
||||||
|
payload_json = json.loads(event.object.object.message.payload) if event.object.object.message.payload else {}
|
||||||
|
|
||||||
|
if 'test' not in payload_json.keys() and (
|
||||||
|
redis_test_state != None):
|
||||||
|
logging.debug(f"User {user_id} is in state: {redis_test_state}")
|
||||||
|
payload_json["test"] = int(redis_test_state)
|
||||||
|
|
||||||
|
event.object.object.message.payload = json.dumps(payload_json)
|
||||||
|
return MiddlewareResult(True)
|
14
nft_svc/Dockerfile
Normal file
14
nft_svc/Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3.9
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY ./requirements.txt /app/requirements.txt
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||||
|
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
ENTRYPOINT [ "flask" ]
|
||||||
|
CMD ["run", "--host=0.0.0.0", "--port=5000"]
|
61
nft_svc/app.py
Normal file
61
nft_svc/app.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import base64
|
||||||
|
import io
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
from flask import Flask, request, jsonify
|
||||||
|
import matplotlib.image as mpimg
|
||||||
|
import numpy as np
|
||||||
|
import numba
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@numba.njit
|
||||||
|
def optimized_mandelbrot(n_rows, n_columns, iterations, cx, cy):
|
||||||
|
x_cor = np.linspace(-2, 2, n_rows)
|
||||||
|
y_cor = np.linspace(-2, 2, n_columns)
|
||||||
|
output = np.zeros((n_rows,n_columns))
|
||||||
|
c = cx + 1j * cy
|
||||||
|
for i in range(n_rows):
|
||||||
|
for j in range(n_columns):
|
||||||
|
z = x_cor[i] + y_cor[j] * 1j
|
||||||
|
count = 0
|
||||||
|
for k in range(iterations):
|
||||||
|
z = (z*z) + c
|
||||||
|
count += 1
|
||||||
|
if np.abs(z) > 4:
|
||||||
|
break
|
||||||
|
output[i, j] = count
|
||||||
|
return output.T
|
||||||
|
|
||||||
|
|
||||||
|
def open_image_as_array(path):
|
||||||
|
return mpimg.imread(path)
|
||||||
|
|
||||||
|
|
||||||
|
def get_encoded_img(arr):
|
||||||
|
img = Image.fromarray(arr).convert("L")
|
||||||
|
img_byte_arr = io.BytesIO()
|
||||||
|
img.save(img_byte_arr, format='PNG')
|
||||||
|
encoded_img = base64.encodebytes(img_byte_arr.getvalue()).decode('ascii')
|
||||||
|
return encoded_img
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/getImage', methods=['GET'])
|
||||||
|
def get_image():
|
||||||
|
name = request.args.get('name')
|
||||||
|
fractal = optimized_mandelbrot(1000, 1000, np.random.randint(2, 251), np.random.uniform(-1, 1), np.random.uniform(-1, 1))
|
||||||
|
img = get_encoded_img(fractal)
|
||||||
|
return jsonify({
|
||||||
|
"code": 0,
|
||||||
|
"image": img,
|
||||||
|
"first_time": 1
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def start_app():
|
||||||
|
app.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
start_app()
|
10
nft_svc/gunicorn_config.py
Normal file
10
nft_svc/gunicorn_config.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Gunicorn config variables
|
||||||
|
loglevel = "info"
|
||||||
|
errorlog = "-" # stderr
|
||||||
|
accesslog = "-" # stdout
|
||||||
|
worker_tmp_dir = "/dev/shm"
|
||||||
|
graceful_timeout = 120
|
||||||
|
timeout = 120
|
||||||
|
keepalive = 5
|
||||||
|
threads = 4
|
||||||
|
workers = 4
|
6
nft_svc/requirements.txt
Normal file
6
nft_svc/requirements.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
matplotlib~=3.5.1
|
||||||
|
numpy~=1.21.6
|
||||||
|
numba~=0.55.1
|
||||||
|
Pillow~=9.1.0
|
||||||
|
Flask~=2.1.1
|
||||||
|
gunicorn
|
@ -1 +1,2 @@
|
|||||||
from .singleton import Singleton
|
from .singleton import Singleton
|
||||||
|
from .nft_util import get_image
|
||||||
|
17
util/nft_util.py
Normal file
17
util/nft_util.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import base64
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from sphinx.util import requests
|
||||||
|
|
||||||
|
from config import Config
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(user_id: int) -> str:
|
||||||
|
path = os.path.join(Config().TMP_DIR, f"{user_id}.png")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
logging.warn(f"Getting new image for {user_id}!")
|
||||||
|
req = requests.get(f"{Config().NFT_SVC_ADDR}/getImage").json()
|
||||||
|
with open(path, "wb") as f:
|
||||||
|
f.write(base64.b64decode(req["image"]))
|
||||||
|
return path
|
18
util/redis_db.py
Normal file
18
util/redis_db.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from config import Config
|
||||||
|
from util import Singleton
|
||||||
|
import redis
|
||||||
|
|
||||||
|
|
||||||
|
class RedisDB(metaclass=Singleton):
|
||||||
|
def __init__(self):
|
||||||
|
self.r = redis.Redis(Config().REDIS_ADDR)
|
||||||
|
|
||||||
|
def get_state(self, user_id: int) -> int:
|
||||||
|
db_ret = self.r.get(f"{user_id}_test_state")
|
||||||
|
return int(db_ret.decode()) if db_ret else None
|
||||||
|
|
||||||
|
def set_state(self, user_id: int, state: int):
|
||||||
|
self.r.set(f"{user_id}_test_state", str(state))
|
||||||
|
|
||||||
|
def del_state(self, user_id):
|
||||||
|
self.r.delete(f"{user_id}_test_state")
|
Reference in New Issue
Block a user