27 Commits

Author SHA1 Message Date
gav
a66fde985f Merge branch 'main' into text-edition 2022-05-05 12:13:24 +07:00
f97a8286b7 Updated gitignore 2022-05-05 12:12:27 +07:00
1dfd81de31 Merge branch 'main' of https://gitea.gavt45.ru/gav/es-bot 2022-05-05 12:11:40 +07:00
20eaea722f added images and updated svc 2022-05-05 12:11:20 +07:00
ee834376db Job of fucking copywriter!!! 2022-05-04 22:05:35 +07:00
gav
ca6ac97e33 Merge pull request 'Job of fucking copiwriter!!!' (#3) from text-edition into main
Reviewed-on: gav/es-bot#3
Reviewed-by: gav <a@a.aa>
2022-05-04 21:03:34 +07:00
be430673f1 Job of fucking copiwriter!!! 2022-05-04 21:02:03 +07:00
gav
2dc6327fe1 Merge pull request 'text-edition' (#2) from text-edition into main
Reviewed-on: gav/es-bot#2
2022-05-04 20:44:44 +07:00
221ff51d3d Text edited 2022-05-04 20:43:53 +07:00
0fc4d0df82 Text edited 2022-05-04 19:59:59 +07:00
fe897a596c Merge pull request 'Text edited' (#1) from text-edition into main
Reviewed-on: gav/es-bot#1
Reviewed-by: dshestakova <d.shestakova2@g.nsu.ru>
2022-05-04 16:58:04 +07:00
2bc65d37dd Merge branch 'main' into text-edition 2022-05-04 16:56:46 +07:00
98136d93a2 Text edited 2022-05-04 16:34:01 +07:00
cc206ff358 Fixed keyboard and added man page 2022-05-03 21:06:32 +07:00
9065115927 Fixed bug in image gen 2022-05-03 11:18:05 +07:00
db629bb804 Update nft svc 2022-05-03 11:04:21 +07:00
0649bb445c Fixed circular import in nft_util 2022-05-01 12:42:22 +07:00
c5d18e56d5 Fix port of image_gen 2022-05-01 02:38:58 +07:00
08e7f4ee93 Fixed group add event 2022-05-01 02:36:51 +07:00
65ed6f9fa6 Added persistence 2022-05-01 02:00:20 +07:00
d9c9f8f131 Upd readme 2022-05-01 01:58:48 +07:00
80584dbaf9 MVP 2022-05-01 01:56:47 +07:00
gav
56adc16b04 Add '.drone.yml' 2022-05-01 01:22:43 +07:00
gav
f2e6e27179 Delete '.drone.ci' 2022-05-01 01:22:21 +07:00
gav
a54eeaf625 Update 'README.md' 2022-05-01 01:21:24 +07:00
gav
80b464baf5 Add '.drone.ci' 2022-05-01 01:20:33 +07:00
e1bd7234ed MVP 2022-05-01 00:57:58 +07:00
286 changed files with 1275 additions and 110 deletions

10
.drone.yml Normal file
View File

@ -0,0 +1,10 @@
kind: pipeline
type: docker
name: default
steps:
- name: greeting
image: alpine
commands:
- echo hello
- echo world

3
.env
View File

@ -1,3 +0,0 @@
PG_USER=pg
PG_PASS=pg
PG_OUTBOUND_PORT=5432

5
.env.sample Normal file
View File

@ -0,0 +1,5 @@
PG_USER=pg
PG_PASS=<password>
PG_OUTBOUND_PORT=5432
GROUP_ID=<group id>
TOKEN=<token>

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text

5
.gitignore vendored
View File

@ -1 +1,6 @@
*__pycache__*
tmp
.env
docker-compose-dev.yml
*.DS_Store*
.idea/

21
Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM python:3.9
ENV DB_ADDR localhost:5432
ENV GROUP_ID group_id
ENV NFT_ADDR http://localhost:5001
ENV PASS pg
ENV REDIS_ADDR localhost
ENV TMP_DIR ./tmp
ENV TOKEN token
WORKDIR /app
RUN mkdir -p /app/tmp
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY . /app
CMD ["python3", "main.py"]

View File

@ -1,3 +1,13 @@
# es-bot
todo (пока лень)
[![Build Status](https://droneci.gavt45.ru/api/badges/gav/es-bot/status.svg)](https://droneci.gavt45.ru/gav/es-bot)
## Deploy
```shell
$ cp .env.example .env
```
Change variables as you need and then:
```shell
$ docker-compose up -d
```

View File

@ -1,2 +1,5 @@
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
from .man import man_router

19
blueprints/man.py Normal file
View File

@ -0,0 +1,19 @@
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadContainsFilter, BotEvent, \
EventTypeFilter
from vkwave.types.bot_events import BotEventType
import locales
man_router = DefaultRouter()
@man_router.registrar.with_decorator(
EventTypeFilter(BotEventType.MESSAGE_NEW.value),
PayloadContainsFilter("man"),
)
async def man_menu(event: BotEvent):
sevent = SimpleBotEvent(event)
return await sevent.answer(
message=locales.MAN,
keyboard=locales.MAN_KB.get_keyboard(),
)

View File

@ -1,12 +1,29 @@
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, EventTypeFilter
from vkwave.types.bot_events import BotEventType
import locales
menu_router = DefaultRouter()
@simple_bot_message_handler(menu_router,)
@menu_router.registrar.with_decorator(
EventTypeFilter(BotEventType.MESSAGE_NEW.value),
)
async def menu(event: SimpleBotEvent):
return await event.answer(
sevent = SimpleBotEvent(event)
return await sevent.answer(
message=locales.MENU,
keyboard=locales.MENU_KB.get_keyboard(),
)
)
@menu_router.registrar.with_decorator(
EventTypeFilter(BotEventType.GROUP_JOIN.value),
)
async def menu(event: SimpleBotEvent):
return await event.api_ctx.messages.send(
keyboard=locales.MENU_KB.get_keyboard(),
peer_id=event.object.object.user_id,
message=locales.MENU,
random_id=0
)

19
blueprints/student.py Normal file
View File

@ -0,0 +1,19 @@
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadContainsFilter, BotEvent, \
EventTypeFilter
from vkwave.types.bot_events import BotEventType
import locales
student_router = DefaultRouter()
@student_router.registrar.with_decorator(
EventTypeFilter(BotEventType.MESSAGE_NEW.value),
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(),
)

19
blueprints/teacher.py Normal file
View File

@ -0,0 +1,19 @@
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadContainsFilter, BotEvent, \
EventTypeFilter
from vkwave.types.bot_events import BotEventType
import locales
teacher_router = DefaultRouter()
@teacher_router.registrar.with_decorator(
EventTypeFilter(BotEventType.MESSAGE_NEW.value),
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(),
)

View File

@ -1,46 +1,25 @@
import json
import logging
import random
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadFilter, PayloadContainsFilter, \
PhotoUploader
from vkwave.bots import Keyboard, ButtonColor
from vkwave.bots import DefaultRouter, SimpleBotEvent, PayloadContainsFilter
from vkwave.bots import Keyboard
from vkwave.bots import EventTypeFilter, BotEvent
from vkwave.types.bot_events import BotEventType
from vkwave.bots.fsm import FiniteStateMachine, StateFilter, ForWhat, State, ANY_STATE
import locales
from config import Config
from db import DB
from db.db import TestResult
from locales import INPUT_NAME_TEXT
# MENU_KB.add_row()
# MENU_KB.add_text_button(text="Профиль", payload={"command": "profile"}, color=ButtonColor.SECONDARY)
# MENU_KB.add_row()
# MENU_KB.add_text_button(text="Бонус", payload={"command": "bonus"}, color=ButtonColor.POSITIVE)
# from nft_things.NftSender import NFTSender
from util.redis_db import RedisDB
from util.nft_util import get_image
test_router = DefaultRouter()
test_router.registrar.add_default_filter(
EventTypeFilter(BotEventType.MESSAGE_NEW.value)) # we don't want to write it in all handlers.
EMPTY_KB = '{"buttons": [], "inline": false, "one_time": false}'
# # exiting from poll (works on any state)
# @test_router.registrar.with_decorator(
# lambda event: event.object.object.message.text == "exit",
# StateFilter(fsm=fsm, state=ANY_STATE, for_what=ForWhat.FOR_USER)
# )
# async def simple_handler(event: BotEvent):
# # Check if we have the user in database
# if await fsm.get_data(event, for_what=ForWhat.FOR_USER) is not None:
# await fsm.finish(event=event, for_what=ForWhat.FOR_USER)
# return "You are quited!"
@test_router.registrar.with_decorator(
PayloadContainsFilter("test"),# for state in States.questions[:-1]]
EventTypeFilter(BotEventType.MESSAGE_NEW.value),
PayloadContainsFilter("test"),
)
async def main_part_handle(event: BotEvent):
user_id = event.object.object.message.from_id
@ -50,8 +29,7 @@ async def main_part_handle(event: BotEvent):
state_idx = int(payload["test"])
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}")
# extra_state_data works as fsm.add_data(..., state_data={"name": event.object.object.message.text})
@ -61,17 +39,28 @@ async def main_part_handle(event: BotEvent):
DB().update_test_result(user_id, question=state_idx, answer=q_res)
if state_idx + 1 < len(locales.questions):
return await botevent.answer(
message=locales.questions[state_idx + 1][0],
keyboard=locales.questions[state_idx + 1][1].get_keyboard(),
)
RedisDB().set_state(user_id, state_idx + 1)
kb = locales.questions[state_idx + 1][1]
if kb:
return await botevent.answer(
message=locales.questions[state_idx + 1][0],
keyboard=kb.get_keyboard(),
)
else:
return await botevent.answer(
message=locales.questions[state_idx + 1][0],
payload=json.dumps({"test": state_idx + 1}),
keyboard=EMPTY_KB, # try to remove keyboard
)
else:
# todo add task to send user an image here
# Config().nft_sender.add_task()
RedisDB().del_state(user_id)
logging.warn("Sending attach!")
big_attachment = await Config().uploader.get_attachments_from_paths(
peer_id=user_id,
file_paths=["img.jpg"],
file_paths=[get_image(user_id)],
)
await Config().api_ctx.messages.send(
user_id=user_id, attachment=big_attachment, random_id=0
@ -80,21 +69,3 @@ async def main_part_handle(event: BotEvent):
message=locales.LAST_MESSAGE,
keyboard=locales.LAST_MESSAGE_KB.get_keyboard(),
)
# @test_router.registrar.with_decorator(
# StateFilter(fsm=fsm, state=MyState.age, for_what=ForWhat.FOR_USER),
# )
# async def simple_handler(event: BotEvent):
# if not event.object.object.message.text.isdigit():
# return f"Please, send only positive numbers!"
# await fsm.add_data(
# event=event,
# for_what=ForWhat.FOR_USER,
# state_data={"age": event.object.object.message.text},
# )
# user_data = await fsm.get_data(event=event, for_what=ForWhat.FOR_USER)
#
# # finish poll and delete the user
# # `fsm.finish` will do it
# await fsm.finish(event=event, for_what=ForWhat.FOR_USER)
# return f"Your data - {user_data}"

View File

@ -1,4 +1,7 @@
import os
from vkwave.bots import PhotoUploader
from util import Singleton
@ -9,8 +12,13 @@ class Config(metaclass=Singleton):
PG_USER = os.environ["USER"]
PG_PASS = os.environ["PASS"]
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):
self.api_ctx = None
self.uploader = None
self.uploader: PhotoUploader = None

View File

@ -64,10 +64,19 @@ class DB(metaclass=Singleton):
def update_test_result(self, user_id: int, question: int, answer: str):
user = self._session.query(Candidate).filter(Candidate.id == user_id).first()
user.test_result[0].answers.append(QuestionAnswer(question=question, answer=answer))
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))
self._session.commit()
def add_candidate(self, candidate: Candidate):
if self._session.query(Candidate).filter(Candidate.id == candidate.id).first() is not None:
return
tres = TestResult(answers=[])
candidate.test_result = [tres]
self._session.add(candidate)

View File

@ -1,5 +1,30 @@
version: "2"
services:
image_gen:
build:
context: ./nft_svc
dockerfile: Dockerfile
ports:
- 5001:5000
bot:
build:
context: .
dockerfile: Dockerfile
environment:
- DB_ADDR=pgdb:5432
- GROUP_ID=${GROUP_ID}
- NFT_ADDR=http://image_gen:5000
- PASS=${PG_PASS}
- REDIS_ADDR=redis
- TMP_DIR=./tmp
- TOKEN=${TOKEN}
- USER=${PG_USER}
depends_on:
- pgdb
- redis
- image_gen
pgdb:
image: 'postgres:12'
restart: always
@ -8,7 +33,18 @@ services:
- POSTGRES_PASSWORD=${PG_PASS}
- POSTGRES_DB=db
- PGDATA=/var/lib/postgresql/data/pgdata
# volumes:
# - ${PG_MNT}:/var/lib/postgresql/data
ports:
- ${PG_OUTBOUND_PORT}:5432
volumes:
- bot_pg_data:/var/lib/postgresql/data
# ports:
# - ${PG_OUTBOUND_PORT}:5432
redis:
image: "redis:alpine"
command: redis-server --appendonly yes --appendfsync everysec
# ports:
# - 6379:6379
volumes:
- bot_redis_data:/data
volumes:
bot_pg_data:
bot_redis_data:

BIN
img.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 131 B

View File

@ -1,10 +1,72 @@
from vkwave.bots import Keyboard, ButtonColor
# menu
MENU = "Привет!"
MENU = """С помощью бота вы можете:
&#9881; пройти тест и получить индивидуальный NFT-талисман, сгенерированный специально для вас нейросетью;
&#9881; вступить в чат абитуриентов, студентов и преподавателей;
&#9881; пообщаться со студентом (можно выбрать с кем);
&#9881; пообщаться с руководителем ИШ или преподавателем (можно выбрать с кем)."""
MENU_KB = Keyboard()
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_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_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)
# MENU_KB.add_row()
# MENU_KB.add_text_button(text="АЧе делать?", payload={"man": "1"}, color=ButtonColor.PRIMARY)
# Student menu
ST_MENU = """Если вы ходите узнать про жизнь студента Инженерной школы, то можете написать этим ребятам:
*fossa_mar (Даша Пискеева), 2 курс;
*shestakova__d (Даша Шестакова), 2 курс;
*cleverbitch (Лиза Булгакова), 2 курс;
*brainkiller78 (Данил Тищенко), 1 курс;
*skazaniyk (Дмитрий Хамутский), 1 курс;
*kirik229 (Анжела Шадрина), 2 курс;
*dinazavrrrik (Назар Коновалов), 1 курс;
*tenikeev (Тимур Еникеев), 1 курс.
"""
ST_KB = Keyboard()
ST_KB.add_link_button(text="Даша Пискеева", link="https://vk.com/fossa_mar")
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/cleverbitch")
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 = """Вы можете написать преподавателям и руководителям Инженерной школы:
*anastasia.v.karpenko (Анастасия Валерьевна Карпенко) — руководитель ИШ, преподаватель «Математической логики» и «Основ проектной деятельности»;
*krkaushan (Кристина Андреевна Насыбуллова) — заместитель декана по 2 курсу;
*id11073597 (Тимур Ринатович Насыбуллов) — преподаватель «Алгебры и геометрии» и «Теории функций комплексного переменного»;
*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)
# Manual
MAN = """Если вы хотите пройти тест - нажми на соответствующую кнопку.
Если вы абитуриент, и хотите узнать больше про инженерную школу, то вы можете пообщаться со студентами или преподавателями!
Для этого нажмите на кнопку “Диалог со студентом” или “Диалог с преподавателем”.
Также вы можете узнать про нас из соцсетей - для этого нажмите на кнопку “Таплинк”.
Если вы хотите пообщаться с другими абитуриентами - нажми на кнопку “Неформальный чат”.
Приятного пользования!"""
MAN_KB = Keyboard()
MAN_KB.add_text_button(text="ХОЧУ ДОМОЙ!!!!!!!!!!!!!!!", payload={}, color=ButtonColor.NEGATIVE)
# TEST Questions
INPUT_NAME_TEXT = "Пожалуйста, введите имя:"
@ -12,54 +74,75 @@ INPUT_NAME_TEXT = "Пожалуйста, введите имя:"
# 1
WHAT_ENGINEER_ARE_YOU = "Кто ты из инженеров?"
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": "Рогозин", "test": "0"}, 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": "Дмитрий Рогозин"}, color=ButtonColor.PRIMARY)
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": "Калашников", "test": "0"}, 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": "Иван Кулибин"}, color=ButtonColor.PRIMARY)
WHAT_ENGINEER_ARE_YOU_KB.add_row()
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": "Юрий Кондратюк"}, color=ButtonColor.PRIMARY)
# 2
PROG_LANG = "Какой ЯП нравится?"
PROG_LANG = "Какой язык программирования вы чаще всего используете?"
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="Pascal", payload={"q": "Pascal", "test": "1"}, 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="Python", payload={"q": "Python"}, color=ButtonColor.PRIMARY)
PROG_LANG_KB.add_text_button(text="Pascal", payload={"q": "Pascal"}, color=ButtonColor.PRIMARY)
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="HTML+CSS", payload={"q": "HTMLCSS", "test": "1"}, 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="C/C++", payload={"q": "ccpp"}, color=ButtonColor.PRIMARY)
PROG_LANG_KB.add_text_button(text="JS", payload={"q": "JS"}, color=ButtonColor.PRIMARY)
PROG_LANG_KB.add_row()
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"}, color=ButtonColor.PRIMARY)
PROG_LANG_KB.add_row()
PROG_LANG_KB.add_text_button(text="Java", payload={"q": "Java"}, color=ButtonColor.PRIMARY)
PROG_LANG_KB.add_text_button(text="Я не программирую", payload={"q": "Я не программирую"}, color=ButtonColor.PRIMARY)
# 3
FAV_THEME = "Какой предмет нравится?"
FAV_THEME = "Какая школьная дисциплина нравится вам больше?"
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": "русскийлитра", "test": "2"}, 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": "русскийлитра"}, color=ButtonColor.PRIMARY)
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": "other", "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": "Физика"}, color=ButtonColor.PRIMARY)
FAV_THEME_KB.add_row()
FAV_THEME_KB.add_text_button(text="История/обществознание", payload={"q": "Инфа"}, color=ButtonColor.PRIMARY)
FAV_THEME_KB.add_text_button(text="Другой", payload={"q": "other"}, color=ButtonColor.PRIMARY)
# 4
EGE = "Как готовился к ЕГЭ?"
EGE = "Как вы готовитесь к ЕГЭ?"
EGE_KB = Keyboard()
EGE_KB.add_text_button(text="В школе", payload={"q": "школа", "test": "3"}, color=ButtonColor.PRIMARY)
EGE_KB.add_text_button(text="online", payload={"q": "online", "test": "3"}, 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_text_button(text="В онлайн-школе", payload={"q": "online"}, color=ButtonColor.PRIMARY)
EGE_KB.add_text_button(text="С репетитором", payload={"q": "репетитор"}, color=ButtonColor.PRIMARY)
EGE_KB.add_row()
EGE_KB.add_text_button(text="Сам", payload={"q": "Сам", "test": "3"}, color=ButtonColor.PRIMARY)
EGE_KB.add_text_button(text="wtf?", payload={"q": "wtf", "test": "3"}, color=ButtonColor.PRIMARY)
EGE_KB.add_text_button(text="Самостоятельно", payload={"q": "Сам"}, color=ButtonColor.PRIMARY)
EGE_KB.add_text_button(text="А? Какие экзамены?", payload={"q": "А? Какие экзамены?"}, 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 = "Кто вы по знаку зодиака?"
# ZODIAC_KB = Keyboard()
# # 7
# CONTACT = "Введите почту или ник в телеграмме, по которому мы сможем прислать вам результаты"
# last
LAST_MESSAGE = "Спасибо, что прошел тест!"
LAST_MESSAGE = "Теперь у вас есть ваш персональный NFT-талисман! Он поможет вам при сдаче экзаменов и поступлении в желаемый университет &#127775;"
LAST_MESSAGE_KB = Keyboard()
LAST_MESSAGE_KB.add_text_button(text="Вернуться на главную", payload={}, color=ButtonColor.POSITIVE)
questions = [
(WHAT_ENGINEER_ARE_YOU, WHAT_ENGINEER_ARE_YOU_KB),
(PROG_LANG, PROG_LANG_KB),
(FAV_THEME, FAV_THEME_KB),
(EGE, EGE_KB),
(TRANS_ENGINEER_COUNT, TRANS_ENGINEER_COUNT_KB),
(ZODIAC, None),
# (CONTACT, None),
]

13
main.py
View File

@ -3,29 +3,28 @@ import logging
from vkwave.bots import SimpleLongPollBot, PhotoUploader
from blueprints import (
menu_router, test_router,
menu_router, test_router, student_router, teacher_router, man_router,
)
from config import Config
from middlewares import UserMiddleware
# from nft_things.NftSender import NFTSender
from middlewares.test_state_middleware import TestStateMiddleware
logging.basicConfig(level="DEBUG")
bot = SimpleLongPollBot(Config.TOKEN, group_id=Config.GROUP_ID)
# nft_sender = NFTSender(bot.api_context)
# nft_sender.start()
uploader = PhotoUploader(bot.api_context)
Config().api_ctx = bot.api_context
Config().uploader = uploader
bot.middleware_manager.add_middleware(UserMiddleware())
bot.middleware_manager.add_middleware(TestStateMiddleware())
bot.dispatcher.add_router(test_router)
# bot.dispatcher.add_router(games_router)
# bot.dispatcher.add_router(coin_flip_router)
# bot.dispatcher.add_router(bonus_router)
bot.dispatcher.add_router(student_router)
bot.dispatcher.add_router(teacher_router)
bot.dispatcher.add_router(man_router)
# регаем последним чтобы сначала проверялись все остальные команды
bot.dispatcher.add_router(menu_router)

View File

@ -0,0 +1,31 @@
import json
import logging
from vkwave.bots import BaseMiddleware, BotEvent, MiddlewareResult, SimpleBotEvent, Storage
from vkwave.bots.storage.types import Key
from vkwave.types.bot_events import MessageNewObject
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:
if isinstance(event.object.object, MessageNewObject):
user_id = event.object.object.message.from_id
else:
return MiddlewareResult(True)
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)

View File

@ -1,19 +1,33 @@
import logging
from vkwave.bots import BaseMiddleware, BotEvent, MiddlewareResult, SimpleBotEvent
from vkwave.types.bot_events import GroupJoinObject, MessageNewObject
from vkwave.types.objects import UsersUser
from db import DB, Candidate
async def get_user(api_ctx, user_id):
raw_user = (
await api_ctx.api_request("users.get", {"user_ids": user_id})
)["response"][0]
return UsersUser(**raw_user)
class UserMiddleware(BaseMiddleware):
async def pre_process_event(self, event: BotEvent) -> MiddlewareResult:
db = DB()
botevent = SimpleBotEvent(event)
user_id = event.object.object.message.from_id
if isinstance(event.object.object, GroupJoinObject):
user_id = event.object.object.user_id
elif isinstance(event.object.object, MessageNewObject):
user_id = event.object.object.message.from_id
else:
return MiddlewareResult(True)
user = db.get_user(user_id)
if not user:
user_info = await botevent.get_user()
user_info = await get_user(event.api_ctx, user_id)
logging.debug(f"Got user info: {user_info}")
user = Candidate(id=user_id, sex=user_info.sex, name=user_info.first_name, last_name=user_info.last_name)
db.add_candidate(user)

14
nft_svc/Dockerfile Normal file
View 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"]

45
nft_svc/app.py Normal file
View File

@ -0,0 +1,45 @@
import io
import random
import os
from PIL import Image
from flask import Flask, request, jsonify
import matplotlib.image as mpimg
import base64
app = Flask(__name__)
IMAGE_PATH = 'pics'
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 str(encoded_img)
@app.route('/getImage', methods=['GET'])
def get_image():
# print(random.choice(os.listdir(IMAGE_PATH)))
image = mpimg.imread(os.path.join(IMAGE_PATH, random.choice(os.listdir(IMAGE_PATH))))
# buffered = io.BytesIO()
# image.save(buffered, format="JPEG")
# img_str = base64.b64encode(buffered.getvalue())
return jsonify({
"code": 0,
"image": get_encoded_img(image),
"first_time": 1
})
def start_app():
app.run()
if __name__ == '__main__':
start_app()

View 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

BIN
nft_svc/pics/pic_0.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_1.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_10.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_100.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_101.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_102.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_103.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_104.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_105.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_106.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_107.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_108.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_109.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_11.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_110.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_111.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_112.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_113.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_114.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_115.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_116.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_117.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_118.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_119.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_12.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_120.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_121.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_122.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_123.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_124.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_125.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_126.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_127.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_128.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_129.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_13.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_130.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_131.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_132.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_133.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_134.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_135.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_136.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_137.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_138.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_139.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_14.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_140.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_141.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_142.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_143.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_144.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_145.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_146.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_147.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_148.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_149.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_15.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_150.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_151.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_152.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_153.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_154.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_155.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_156.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_157.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_158.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_159.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_16.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_160.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_161.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_162.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_163.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_164.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_165.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
nft_svc/pics/pic_166.jpg (Stored with Git LFS) Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More