diff --git a/.gitignore b/.gitignore index cd4c22c..8123aee 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *__pycache__* +tmp diff --git a/blueprints/__init__.py b/blueprints/__init__.py index 87d883f..53bde0f 100644 --- a/blueprints/__init__.py +++ b/blueprints/__init__.py @@ -1,2 +1,4 @@ from .menu import menu_router -from .test import test_router \ No newline at end of file +from .test import test_router +from .teacher import teacher_router +from .student import student_router \ No newline at end of file diff --git a/blueprints/student.py b/blueprints/student.py new file mode 100644 index 0000000..bf63b61 --- /dev/null +++ b/blueprints/student.py @@ -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(), + ) \ No newline at end of file diff --git a/blueprints/teacher.py b/blueprints/teacher.py new file mode 100644 index 0000000..fe9e70c --- /dev/null +++ b/blueprints/teacher.py @@ -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(), + ) \ No newline at end of file diff --git a/blueprints/test.py b/blueprints/test.py index 1c22633..f423094 100644 --- a/blueprints/test.py +++ b/blueprints/test.py @@ -3,13 +3,14 @@ import logging import random 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 EventTypeFilter, BotEvent from vkwave.types.bot_events import BotEventType from vkwave.bots.fsm import FiniteStateMachine, StateFilter, ForWhat, State, ANY_STATE import locales +import util from config import Config from db import DB from db.db import TestResult @@ -21,9 +22,12 @@ from locales import INPUT_NAME_TEXT # 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 test_router = DefaultRouter() +fsm = FiniteStateMachine() +test_router.registrar.add_default_filter(StateFilter(fsm, ..., ..., always_false=True)) test_router.registrar.add_default_filter( 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!" @test_router.registrar.with_decorator( - PayloadContainsFilter("test"),# for state in States.questions[:-1]] + PayloadContainsFilter("test"), ) async def main_part_handle(event: BotEvent): 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}") - 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 +65,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}), + + ) 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=[util.get_image(user_id)], ) await Config().api_ctx.messages.send( user_id=user_id, attachment=big_attachment, random_id=0 diff --git a/config.py b/config.py index 268f36c..497edba 100644 --- a/config.py +++ b/config.py @@ -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 diff --git a/db/db.py b/db/db.py index f9bb992..f87fac6 100644 --- a/db/db.py +++ b/db/db.py @@ -64,7 +64,14 @@ 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): diff --git a/docker-compose.yml b/docker-compose.yml index 66d3874..6147790 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,12 @@ version: "2" services: + image_gen: + build: + context: ./nft_svc + dockerfile: Dockerfile + ports: + - 5001:5000 + pgdb: image: 'postgres:12' restart: always @@ -12,3 +19,10 @@ services: # - ${PG_MNT}:/var/lib/postgresql/data ports: - ${PG_OUTBOUND_PORT}:5432 + redis: + image: "redis:alpine" + command: redis-server --appendonly yes --appendfsync everysec + ports: + - 6379:6379 +# volumes: +# - ${FDS_REDIS_MNT}:/data diff --git a/locales.py b/locales.py index 744ba39..8064c9f 100644 --- a/locales.py +++ b/locales.py @@ -1,10 +1,57 @@ from vkwave.bots import Keyboard, ButtonColor # menu -MENU = "Привет!" +MENU = "Привет, друг! Это - бот инженерной школы. Инженерная школа - молодой проект на Механико-Математическом факультете НГУ." 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_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 INPUT_NAME_TEXT = "Пожалуйста, введите имя:" @@ -12,44 +59,57 @@ 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_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_text_button(text="Кондратюк", payload={"q": "Кондратюк"}, color=ButtonColor.PRIMARY) # 2 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_text_button(text="C/C++", payload={"q": "ccpp"}, 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="JS", payload={"q": "JS"}, 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"}, color=ButtonColor.PRIMARY) # 3 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_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": "other"}, color=ButtonColor.PRIMARY) # 4 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="online", 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="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_MESSAGE = "Спасибо, что прошел тест!" @@ -62,4 +122,7 @@ questions = [ (PROG_LANG, PROG_LANG_KB), (FAV_THEME, FAV_THEME_KB), (EGE, EGE_KB), + (TRANS_ENGINEER_COUNT, TRANS_ENGINEER_COUNT_KB), + (ZODIAC, None), + (CONTACT, None), ] diff --git a/main.py b/main.py index ca8d1c9..6f7220f 100644 --- a/main.py +++ b/main.py @@ -3,11 +3,12 @@ import logging from vkwave.bots import SimpleLongPollBot, PhotoUploader from blueprints import ( - menu_router, test_router, + menu_router, test_router, student_router, teacher_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") @@ -20,12 +21,12 @@ 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(menu_router) diff --git a/middlewares/test_state_middleware.py b/middlewares/test_state_middleware.py new file mode 100644 index 0000000..6cf5fed --- /dev/null +++ b/middlewares/test_state_middleware.py @@ -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) diff --git a/nft_svc/Dockerfile b/nft_svc/Dockerfile new file mode 100644 index 0000000..71aeaff --- /dev/null +++ b/nft_svc/Dockerfile @@ -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"] diff --git a/nft_svc/app.py b/nft_svc/app.py new file mode 100644 index 0000000..8382649 --- /dev/null +++ b/nft_svc/app.py @@ -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() diff --git a/nft_svc/gunicorn_config.py b/nft_svc/gunicorn_config.py new file mode 100644 index 0000000..6574e1b --- /dev/null +++ b/nft_svc/gunicorn_config.py @@ -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 diff --git a/nft_svc/requirements.txt b/nft_svc/requirements.txt new file mode 100644 index 0000000..91df8de --- /dev/null +++ b/nft_svc/requirements.txt @@ -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 \ No newline at end of file diff --git a/nft_things/__init__.py b/nft_things/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/util/__init__.py b/util/__init__.py index 9079c19..f317235 100644 --- a/util/__init__.py +++ b/util/__init__.py @@ -1 +1,2 @@ -from .singleton import Singleton \ No newline at end of file +from .singleton import Singleton +from .nft_util import get_image diff --git a/util/nft_util.py b/util/nft_util.py new file mode 100644 index 0000000..365d5f0 --- /dev/null +++ b/util/nft_util.py @@ -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 \ No newline at end of file diff --git a/util/redis_db.py b/util/redis_db.py new file mode 100644 index 0000000..7c8a636 --- /dev/null +++ b/util/redis_db.py @@ -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")