Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
79e1153248 |
59
.drone.yml
59
.drone.yml
@ -1,59 +0,0 @@
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: deploy-to-docker-vm
|
||||
# clone:
|
||||
# disable: true
|
||||
|
||||
# steps:
|
||||
# - name: greeting
|
||||
# image: appleboy/drone-ssh
|
||||
# settings:
|
||||
# host:
|
||||
# from_secret: docker_host
|
||||
# username:
|
||||
# from_secret: docker_user
|
||||
# key:
|
||||
# from_secret: docker_privkey
|
||||
# port: 2200
|
||||
# script:
|
||||
# - whoami
|
||||
# - uname -a
|
||||
# - mkdir -p deploy; cd deploy
|
||||
# - git clone https://gitea.gavt45.ru/gav/es-bot.git
|
||||
# - cd es-bot
|
||||
# - git checkout main
|
||||
# - docker-compose build
|
||||
# when:
|
||||
# branch:
|
||||
# - main
|
||||
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: test-secrets-pipeline
|
||||
|
||||
# steps:
|
||||
# - name: test-secrets
|
||||
# image: alpine
|
||||
# environment:
|
||||
# HOST:
|
||||
# from_secret: docker_host
|
||||
# commands:
|
||||
# - env
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: docker
|
||||
image: plugins/docker
|
||||
settings:
|
||||
auto_tag: true
|
||||
auto_tag_suffix: kek
|
||||
registry: registry.gavt45.ru
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
repo: registry.gavt45.ru/es-bot
|
@ -1,5 +0,0 @@
|
||||
PG_USER=pg
|
||||
PG_PASS=<password>
|
||||
PG_OUTBOUND_PORT=5432
|
||||
GROUP_ID=<group id>
|
||||
TOKEN=<token>
|
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,2 +0,0 @@
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,6 +1 @@
|
||||
*__pycache__*
|
||||
tmp
|
||||
.env
|
||||
docker-compose-dev.yml
|
||||
*.DS_Store*
|
||||
.idea/
|
||||
|
21
Dockerfile
21
Dockerfile
@ -1,21 +0,0 @@
|
||||
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"]
|
12
README.md
12
README.md
@ -1,13 +1,3 @@
|
||||
# es-bot
|
||||
|
||||
[](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
|
||||
```
|
||||
todo (пока лень)
|
||||
|
@ -1,5 +1,2 @@
|
||||
from .menu import menu_router
|
||||
from .test import test_router
|
||||
from .teacher import teacher_router
|
||||
from .student import student_router
|
||||
from .man import man_router
|
||||
from .test import test_router
|
@ -1,19 +0,0 @@
|
||||
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(),
|
||||
)
|
@ -1,29 +1,12 @@
|
||||
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, EventTypeFilter
|
||||
from vkwave.types.bot_events import BotEventType
|
||||
|
||||
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler
|
||||
import locales
|
||||
|
||||
menu_router = DefaultRouter()
|
||||
|
||||
|
||||
@menu_router.registrar.with_decorator(
|
||||
EventTypeFilter(BotEventType.MESSAGE_NEW.value),
|
||||
)
|
||||
@simple_bot_message_handler(menu_router,)
|
||||
async def menu(event: SimpleBotEvent):
|
||||
sevent = SimpleBotEvent(event)
|
||||
return await sevent.answer(
|
||||
return await event.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
|
||||
)
|
||||
)
|
@ -1,19 +0,0 @@
|
||||
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(),
|
||||
)
|
@ -1,19 +0,0 @@
|
||||
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(),
|
||||
)
|
@ -1,25 +1,46 @@
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
|
||||
from vkwave.bots import DefaultRouter, SimpleBotEvent, PayloadContainsFilter
|
||||
from vkwave.bots import Keyboard
|
||||
from vkwave.bots import DefaultRouter, SimpleBotEvent, simple_bot_message_handler, PayloadFilter, PayloadContainsFilter, \
|
||||
PhotoUploader
|
||||
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
|
||||
from config import Config
|
||||
from db import DB
|
||||
from db.db import TestResult
|
||||
from locales import INPUT_NAME_TEXT
|
||||
|
||||
from util.redis_db import RedisDB
|
||||
from util.nft_util import get_image
|
||||
|
||||
# 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
|
||||
|
||||
test_router = DefaultRouter()
|
||||
|
||||
EMPTY_KB = '{"buttons": [], "inline": false, "one_time": false}'
|
||||
test_router.registrar.add_default_filter(
|
||||
EventTypeFilter(BotEventType.MESSAGE_NEW.value)) # we don't want to write it in all handlers.
|
||||
|
||||
|
||||
# # 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(
|
||||
EventTypeFilter(BotEventType.MESSAGE_NEW.value),
|
||||
PayloadContainsFilter("test"),
|
||||
PayloadContainsFilter("test"),# for state in States.questions[:-1]]
|
||||
)
|
||||
async def main_part_handle(event: BotEvent):
|
||||
user_id = event.object.object.message.from_id
|
||||
@ -29,7 +50,8 @@ 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 event.object.object.message.text
|
||||
|
||||
q_res = payload['q'] if 'q' in payload else None
|
||||
logging.debug(f"Qres: {q_res}")
|
||||
|
||||
# extra_state_data works as fsm.add_data(..., state_data={"name": event.object.object.message.text})
|
||||
@ -39,28 +61,17 @@ 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):
|
||||
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
|
||||
)
|
||||
return await botevent.answer(
|
||||
message=locales.questions[state_idx + 1][0],
|
||||
keyboard=locales.questions[state_idx + 1][1].get_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=[get_image(user_id)],
|
||||
file_paths=["img.jpg"],
|
||||
)
|
||||
await Config().api_ctx.messages.send(
|
||||
user_id=user_id, attachment=big_attachment, random_id=0
|
||||
@ -69,3 +80,21 @@ 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}"
|
||||
|
10
config.py
10
config.py
@ -1,7 +1,4 @@
|
||||
import os
|
||||
|
||||
from vkwave.bots import PhotoUploader
|
||||
|
||||
from util import Singleton
|
||||
|
||||
|
||||
@ -12,13 +9,8 @@ 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: PhotoUploader = None
|
||||
self.uploader = None
|
||||
|
||||
|
11
db/db.py
11
db/db.py
@ -64,19 +64,10 @@ 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()
|
||||
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()
|
||||
|
||||
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)
|
||||
|
@ -1,30 +1,5 @@
|
||||
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
|
||||
@ -33,18 +8,7 @@ services:
|
||||
- POSTGRES_PASSWORD=${PG_PASS}
|
||||
- POSTGRES_DB=db
|
||||
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||
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:
|
||||
# volumes:
|
||||
# - ${PG_MNT}:/var/lib/postgresql/data
|
||||
ports:
|
||||
- ${PG_OUTBOUND_PORT}:5432
|
||||
|
BIN
img.jpg
BIN
img.jpg
Binary file not shown.
Before Width: | Height: | Size: 131 B After Width: | Height: | Size: 184 KiB |
146
locales.py
146
locales.py
@ -1,72 +1,11 @@
|
||||
from vkwave.bots import Keyboard, ButtonColor
|
||||
|
||||
# menu
|
||||
MENU = """С помощью бота вы можете:
|
||||
⚙ пройти тест и получить индивидуальный NFT-талисман, сгенерированный специально для вас нейросетью;
|
||||
⚙ вступить в чат абитуриентов, студентов и преподавателей;
|
||||
⚙ пообщаться со студентом (можно выбрать с кем);
|
||||
⚙ пообщаться с руководителем ИШ или преподавателем (можно выбрать с кем)."""
|
||||
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)
|
||||
# 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)
|
||||
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")
|
||||
|
||||
# TEST Questions
|
||||
INPUT_NAME_TEXT = "Пожалуйста, введите имя:"
|
||||
@ -74,75 +13,54 @@ 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": "Илон Маск"}, 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": "Рогозин", "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_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)
|
||||
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)
|
||||
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)
|
||||
|
||||
# 2
|
||||
PROG_LANG = "Какой язык программирования вы чаще всего используете?"
|
||||
PROG_LANG = "Твой любимый язык программирования?"
|
||||
PROG_LANG_KB = Keyboard()
|
||||
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="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_row()
|
||||
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)
|
||||
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)
|
||||
|
||||
# 3
|
||||
FAV_THEME = "Какая школьная дисциплина нравится вам больше?"
|
||||
FAV_THEME = "Какой предмет нравится?"
|
||||
FAV_THEME_KB = Keyboard()
|
||||
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": "Матеша", "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_row()
|
||||
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)
|
||||
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)
|
||||
|
||||
# 4
|
||||
EGE = "Как вы готовитесь к ЕГЭ?"
|
||||
EGE = "Как готовился к ЕГЭ?"
|
||||
EGE_KB = Keyboard()
|
||||
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_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_row()
|
||||
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 = "Введите почту или ник в телеграмме, по которому мы сможем прислать вам результаты"
|
||||
EGE_KB.add_text_button(text="Сам", payload={"q": "Сам", "test": "3"}, color=ButtonColor.PRIMARY)
|
||||
EGE_KB.add_text_button(text="Никак :)", payload={"q": "wtf", "test": "3"}, color=ButtonColor.PRIMARY)
|
||||
|
||||
# last
|
||||
LAST_MESSAGE = "Теперь у вас есть ваш персональный NFT-талисман! Он поможет вам при сдаче экзаменов и поступлении в желаемый университет 🌟"
|
||||
LAST_MESSAGE = "Спасибо, что прошел тест!"
|
||||
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
13
main.py
@ -3,28 +3,29 @@ import logging
|
||||
from vkwave.bots import SimpleLongPollBot, PhotoUploader
|
||||
|
||||
from blueprints import (
|
||||
menu_router, test_router, student_router, teacher_router, man_router,
|
||||
menu_router, test_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(student_router)
|
||||
bot.dispatcher.add_router(teacher_router)
|
||||
bot.dispatcher.add_router(man_router)
|
||||
# bot.dispatcher.add_router(games_router)
|
||||
# bot.dispatcher.add_router(coin_flip_router)
|
||||
# bot.dispatcher.add_router(bonus_router)
|
||||
|
||||
# регаем последним чтобы сначала проверялись все остальные команды
|
||||
bot.dispatcher.add_router(menu_router)
|
||||
|
@ -1,31 +0,0 @@
|
||||
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)
|
@ -1,33 +1,19 @@
|
||||
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()
|
||||
|
||||
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)
|
||||
botevent = SimpleBotEvent(event)
|
||||
user_id = event.object.object.message.from_id
|
||||
|
||||
user = db.get_user(user_id)
|
||||
if not user:
|
||||
user_info = await get_user(event.api_ctx, user_id)
|
||||
user_info = await botevent.get_user()
|
||||
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)
|
||||
|
@ -1,14 +0,0 @@
|
||||
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"]
|
@ -1,46 +0,0 @@
|
||||
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)
|
||||
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)))
|
||||
file = 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())
|
||||
image = base64.encodebytes(open(file, 'rb').read()).decode('ascii')
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"image": image,
|
||||
"first_time": 1
|
||||
})
|
||||
|
||||
|
||||
def start_app():
|
||||
app.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
start_app()
|
@ -1,10 +0,0 @@
|
||||
# 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/CVT_Qma1K5CgzcthqmeKj6SrYUwKd9Tho2dRimE3tKKDtJ5Jg1.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma1K5CgzcthqmeKj6SrYUwKd9Tho2dRimE3tKKDtJ5Jg1.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qma2BZS2XDo9qMLfNQJ5c5wA7nAhKBXF87ewi3BJB6KG6z.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma2BZS2XDo9qMLfNQJ5c5wA7nAhKBXF87ewi3BJB6KG6z.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qma34ddY5rpprLa18iiCbNMpXSm75za6ASXebXjmFuxJda.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma34ddY5rpprLa18iiCbNMpXSm75za6ASXebXjmFuxJda.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qma3NdGrDkHtk18UYrH397ucQEHcoDtKkzzHDbEobts9Ye.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma3NdGrDkHtk18UYrH397ucQEHcoDtKkzzHDbEobts9Ye.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qma4aVQkgWrN9mJ15u9ERXfP7Tgw6KS3VuAAFkB7bT7ofc.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma4aVQkgWrN9mJ15u9ERXfP7Tgw6KS3VuAAFkB7bT7ofc.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qma6Gmadq87bN871FwVZFakEj27m6NHvWdQCJ8nqsfHN6y.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma6Gmadq87bN871FwVZFakEj27m6NHvWdQCJ8nqsfHN6y.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qma9B6buzf1bpbVehmPaRYhs9JnpEtqH3x1c1ChGpD4oSF.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma9B6buzf1bpbVehmPaRYhs9JnpEtqH3x1c1ChGpD4oSF.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qma9LH68TqyVLkSc3ML48m2Do2McTNbLdzCbDMcxtxTZYi.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qma9LH68TqyVLkSc3ML48m2Do2McTNbLdzCbDMcxtxTZYi.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaDRbLMfvknqBFBPfMV4T2L1nHvazcvyMeNrzHTmkBh2Q.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaDRbLMfvknqBFBPfMV4T2L1nHvazcvyMeNrzHTmkBh2Q.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaDxVYiftgzFpdPyvwPSmpmCaJQY6heXvhcqkd6A9c2Th.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaDxVYiftgzFpdPyvwPSmpmCaJQY6heXvhcqkd6A9c2Th.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaEi29fEJ6oCsmzVkzvbgkHaUgBLGbejz3wfPwn2gAKGB.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaEi29fEJ6oCsmzVkzvbgkHaUgBLGbejz3wfPwn2gAKGB.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaEmyNJkaGwPzt81Ckh6gfCjWkS8SU6rcGinitrgwoTC1.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaEmyNJkaGwPzt81Ckh6gfCjWkS8SU6rcGinitrgwoTC1.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaGZ5ZLWpcBDfVc1nk1Z9NKhRbosdpmRf5ou6LomjFyFt.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaGZ5ZLWpcBDfVc1nk1Z9NKhRbosdpmRf5ou6LomjFyFt.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaGbUgTouqsEms6YV549GTEgnGDU9tcKd7phjxdop9miq.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaGbUgTouqsEms6YV549GTEgnGDU9tcKd7phjxdop9miq.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaJCu36QXpZU8Yxb9ed4FaF1zdCH5jpyUVataa42N8ymE.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaJCu36QXpZU8Yxb9ed4FaF1zdCH5jpyUVataa42N8ymE.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaKgSXg6CuLcgTTEYmzi3Wf39iJCRvC8L7qzCFyurKjca.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaKgSXg6CuLcgTTEYmzi3Wf39iJCRvC8L7qzCFyurKjca.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaKrSzBM6Z2gDZoj3LzVYteeJTEH5nKuf1xH477P3pWZD.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaKrSzBM6Z2gDZoj3LzVYteeJTEH5nKuf1xH477P3pWZD.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaL58fifkbmp5ua5UdqHoDSFUXCbAZtdhYNDbEXepBbyY.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaL58fifkbmp5ua5UdqHoDSFUXCbAZtdhYNDbEXepBbyY.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaMAijN3sidd278axRth5VSM7QtYGmXmG5HToGRohzX3o.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaMAijN3sidd278axRth5VSM7QtYGmXmG5HToGRohzX3o.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaMEgoT2JUp4TbhrZyWN6AyEFpaVTPnZzUXxjBUGgKhqz.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaMEgoT2JUp4TbhrZyWN6AyEFpaVTPnZzUXxjBUGgKhqz.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaSyaW1BAjCiJ8yY73PN4FPm4xP93gjdZFGqdPu86ZSwH.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaSyaW1BAjCiJ8yY73PN4FPm4xP93gjdZFGqdPu86ZSwH.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaVotBMs8gz3SwSadgx9kyWXNmiCHWecEYEjui4AjiHYN.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaVotBMs8gz3SwSadgx9kyWXNmiCHWecEYEjui4AjiHYN.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaWvdqVZQeQXqSfR1HwPgWUUp1rfvDCQKvcc3gouhfbRm.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaWvdqVZQeQXqSfR1HwPgWUUp1rfvDCQKvcc3gouhfbRm.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmaZUBZqVyogW15Bs9dLepFDZAcCCAfXcGrpR91B9jTNRs.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmaZUBZqVyogW15Bs9dLepFDZAcCCAfXcGrpR91B9jTNRs.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmabbuMzAAmC6FoCB5CirX7wLqzRMaSGzNXo4ZydP4qQXS.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmabbuMzAAmC6FoCB5CirX7wLqzRMaSGzNXo4ZydP4qQXS.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmabmeKDLNuP3U1APbqTZBVteRcGtyz7HMhzWgdYRCZJrM.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmabmeKDLNuP3U1APbqTZBVteRcGtyz7HMhzWgdYRCZJrM.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmadeX35BEv7BSPD4iwZFVv75Bjko9zwUM4EScNyF2odwE.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmadeX35BEv7BSPD4iwZFVv75Bjko9zwUM4EScNyF2odwE.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmafTeagXdPKnAS8idcBCopmHXQYfqXgHxYbbbpnQ4NL6p.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmafTeagXdPKnAS8idcBCopmHXQYfqXgHxYbbbpnQ4NL6p.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmafjR3GJ9HDGxbgr5rnUHcYTo63aV4wKu1Fy88orezvRr.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmafjR3GJ9HDGxbgr5rnUHcYTo63aV4wKu1Fy88orezvRr.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmag6ZLzmBS8Yq5a7zTYEz29guMnVahzgC1ubNdTTp9Dwt.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmag6ZLzmBS8Yq5a7zTYEz29guMnVahzgC1ubNdTTp9Dwt.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmaj61UgqQ1GKaYKYXQa1kztVSRKojEF8CEyyudKbpWqJE.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmaj61UgqQ1GKaYKYXQa1kztVSRKojEF8CEyyudKbpWqJE.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmajN2HLraSryKk85yL8ziJkgfW8fdrLBTgbDHnuzSkeLD.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmajN2HLraSryKk85yL8ziJkgfW8fdrLBTgbDHnuzSkeLD.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmajjKGWrDdqsVwfFWvtEALX5zeg1Ju8B8CJ7xAEsx6aKy.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmajjKGWrDdqsVwfFWvtEALX5zeg1Ju8B8CJ7xAEsx6aKy.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmam7Fv62fax4JCzcWzpGwcfVD79CvVfEnvfx1fF4wHSgv.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmam7Fv62fax4JCzcWzpGwcfVD79CvVfEnvfx1fF4wHSgv.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmanJPfagsPv5rop4wFqXwCXYm2c4EwzCVozspz6FSPUAA.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmanJPfagsPv5rop4wFqXwCXYm2c4EwzCVozspz6FSPUAA.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmapDRkc9ftLKvfBEFutDq2r39ATczU7GMStMXmXfz6p4t.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmapDRkc9ftLKvfBEFutDq2r39ATczU7GMStMXmXfz6p4t.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmatP5oEnCHCdcH9ZvKnutVNDJdf9nj2ih3Empvnxuy4J2.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmatP5oEnCHCdcH9ZvKnutVNDJdf9nj2ih3Empvnxuy4J2.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmattVVN45mTHCvCmMNxi6GiZZHedP3ew3ENZbpCpHFC5f.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmattVVN45mTHCvCmMNxi6GiZZHedP3ew3ENZbpCpHFC5f.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmaw8pNjYTY1TsHiBmVQ9QdfMnt7xFphWzPY5iggXCwnrP.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmaw8pNjYTY1TsHiBmVQ9QdfMnt7xFphWzPY5iggXCwnrP.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmawx1RjED8arBaFoG8vWc9YDBPiQY4QVgCSAUqHrnWTzP.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmawx1RjED8arBaFoG8vWc9YDBPiQY4QVgCSAUqHrnWTzP.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmayRDxaK7xWnSE8oRJEAL3xsCNT6tQNNaWk1FhCCKLHHf.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmayRDxaK7xWnSE8oRJEAL3xsCNT6tQNNaWk1FhCCKLHHf.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmazun61wXRfPjHDwwE7pDtRSuekeHjHeu1LcvowW9VjJK.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmazun61wXRfPjHDwwE7pDtRSuekeHjHeu1LcvowW9VjJK.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmb1k7w7Cef71qoz7nf2wVBQjNgfDSzoCvqQyNuZHA48xd.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmb1k7w7Cef71qoz7nf2wVBQjNgfDSzoCvqQyNuZHA48xd.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmb3b4TE8E6KozFw8PQdM4Z6V92coFQ8EA6CoWnVf2wJPA.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmb3b4TE8E6KozFw8PQdM4Z6V92coFQ8EA6CoWnVf2wJPA.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmb3hii9pPbiJmkrhRWJu2ehuf5WPhcvteubxYxMDJGBx1.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmb3hii9pPbiJmkrhRWJu2ehuf5WPhcvteubxYxMDJGBx1.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmb4w4VqJWkWVGveh49cPixAfXNEASYTswVjso2HB7v4eU.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmb4w4VqJWkWVGveh49cPixAfXNEASYTswVjso2HB7v4eU.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmb6aDehMdQvLQ8mz8kQyKBb7JyMCXh2sHyfvjPdNaNeTN.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmb6aDehMdQvLQ8mz8kQyKBb7JyMCXh2sHyfvjPdNaNeTN.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmb8z12AJm8kXDp6yc6qATgLpBT3tqqavoWmrRTVRAqAuW.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmb8z12AJm8kXDp6yc6qATgLpBT3tqqavoWmrRTVRAqAuW.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbD3xEVxvSkWXjj3c1xEGUwKuEuVau3mwGL4ghVorJbGX.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbD3xEVxvSkWXjj3c1xEGUwKuEuVau3mwGL4ghVorJbGX.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbNh3L2XUMnh3xMirGKQeLBfmwEvVkNEYVkqMVoPFqkJd.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbNh3L2XUMnh3xMirGKQeLBfmwEvVkNEYVkqMVoPFqkJd.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbT3GLeJrdyqfHYjsPpRfBTgNdqyEi3JnnCMkHktD3ush.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbT3GLeJrdyqfHYjsPpRfBTgNdqyEi3JnnCMkHktD3ush.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbTadqUAqYaUKCDEiXkRxAExZ4u4wF61BKzqDbKyeo79B.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbTadqUAqYaUKCDEiXkRxAExZ4u4wF61BKzqDbKyeo79B.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbUykVTfuyDjPKMB9ec58ZeCzobgk1Wj2j1YahLpdUNtq.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbUykVTfuyDjPKMB9ec58ZeCzobgk1Wj2j1YahLpdUNtq.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbYdArMsaDTkCykbrmmy2ZMu6cib4Xi8fxZUWmLEC5EKe.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbYdArMsaDTkCykbrmmy2ZMu6cib4Xi8fxZUWmLEC5EKe.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbfY4coP6E8WuZBAQTksBaED2CG8Er1CBgiPwg22kgftC.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbfY4coP6E8WuZBAQTksBaED2CG8Er1CBgiPwg22kgftC.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmbfk9P6YmqVdZjnLSWJKpH35TY2v7FACwSf7NBmiiNxaU.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmbfk9P6YmqVdZjnLSWJKpH35TY2v7FACwSf7NBmiiNxaU.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmbh85akVePYM5HpoDsXXnFAZArYfiUbj2oiL5XC7KNV6R.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmbh85akVePYM5HpoDsXXnFAZArYfiUbj2oiL5XC7KNV6R.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbhficXqS3857gzmLEqozznAcSsN3UBc4asmsDpsUMDac.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbhficXqS3857gzmLEqozznAcSsN3UBc4asmsDpsUMDac.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbpiEk2vGRhPUXeCcuHkchj7VKYcAk3FcsP84GC34psep.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbpiEk2vGRhPUXeCcuHkchj7VKYcAk3FcsP84GC34psep.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbqCf38McontHnRg4sA345N2P8njmt4uNsRhZW15fmBc1.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbqCf38McontHnRg4sA345N2P8njmt4uNsRhZW15fmBc1.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbsBtJPp94znjxs2NGtYa5D32Rhx6k2w9vNhGeh44ps9v.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbsBtJPp94znjxs2NGtYa5D32Rhx6k2w9vNhGeh44ps9v.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbtEg8b7yHNnZjzs5jjCvBVFG3Nad3R6z7TYqbw2rWEaA.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbtEg8b7yHNnZjzs5jjCvBVFG3Nad3R6z7TYqbw2rWEaA.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbuGEbHofRxXipQRKNQbLCDr6h4z2orZLx9zwBB1i5kAv.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbuGEbHofRxXipQRKNQbLCDr6h4z2orZLx9zwBB1i5kAv.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbvYXRjmdxA64MtX9GBJZbJKuhK27rpTavasxqa28ZCCx.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbvYXRjmdxA64MtX9GBJZbJKuhK27rpTavasxqa28ZCCx.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmbxxsHUGX9w3JFrvsnDFbQLCSre1mTjgfy9hUjBYstzm6.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmbxxsHUGX9w3JFrvsnDFbQLCSre1mTjgfy9hUjBYstzm6.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmc2tNpvg9evTm3EYN6qeYCwTgvx38AWNsCwRmbByc27HU.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmc2tNpvg9evTm3EYN6qeYCwTgvx38AWNsCwRmbByc27HU.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmc2vAko2xbADEPNBri4tCLBiyQukViXPEQQ9FrSVmcGLp.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmc2vAko2xbADEPNBri4tCLBiyQukViXPEQQ9FrSVmcGLp.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmc4B7rijMBru7g88XntiiendhUwBAy7ASEXct2d1ExZxS.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmc4B7rijMBru7g88XntiiendhUwBAy7ASEXct2d1ExZxS.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_Qmc4sVnPar1Ew2Q54YPLxy7Yj6m7yJGo6ptzp6PUXmEMoN.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_Qmc4sVnPar1Ew2Q54YPLxy7Yj6m7yJGo6ptzp6PUXmEMoN.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmcALPkMEZPunyk57CSBQWKArvx1K5SECNAGrPhnELo4xh.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmcALPkMEZPunyk57CSBQWKArvx1K5SECNAGrPhnELo4xh.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmcBPQg4L8rgzuPEnPiVWXES2Zu21zqLcFMxzm6Bo2AEBK.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmcBPQg4L8rgzuPEnPiVWXES2Zu21zqLcFMxzm6Bo2AEBK.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmcBpKKFCx8Vq9sjiEtR3opUfdXZqbMHyFwXuQqkrgHnW9.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmcBpKKFCx8Vq9sjiEtR3opUfdXZqbMHyFwXuQqkrgHnW9.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmcCApW7BTAtDrhJXRz58ZneBWLHueqPyWCKAfRE84F1Ng.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmcCApW7BTAtDrhJXRz58ZneBWLHueqPyWCKAfRE84F1Ng.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmcCyoX3fX7HSACrh89z1FHKCCfypxxSCrfBxkMUWXXwW7.jpg.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmcCyoX3fX7HSACrh89z1FHKCCfypxxSCrfBxkMUWXXwW7.jpg.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmcDtbawGDgCLBs8fBahVwTiuqLDc4uJqyZkL7P6J2s3gF.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmcDtbawGDgCLBs8fBahVwTiuqLDc4uJqyZkL7P6J2s3gF.png
(Stored with Git LFS)
Binary file not shown.
BIN
nft_svc/pics/CVT_QmcFardKJdWsTZ8DVv2Nj16MHFzgnZmdcsWtbwuhCyLJ6P.png
(Stored with Git LFS)
BIN
nft_svc/pics/CVT_QmcFardKJdWsTZ8DVv2Nj16MHFzgnZmdcsWtbwuhCyLJ6P.png
(Stored with Git LFS)
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user