Spaces:
Sleeping
Sleeping
import os | |
from pathlib import Path | |
from typing import Callable, Collection | |
import gradio as gr | |
from telethon.sessions import SQLiteSession, MemorySession | |
from utils.auth import AuthState | |
from utils.parser import Parser | |
from utils.validation import Validator | |
class Components: | |
welcome_message_markdown = ''' | |
<h5 style='text-align: center'> | |
Парсер сообщений Telegram | |
</h5> | |
<h6 style='text-align: center'> | |
<a | |
href="https://github.com/sergey21000/telegram-message-parser" | |
target='_blank'>GitHub | |
</a> | |
проекта с инструкциями по получению `API_ID` и `API_HASH` приложения Telegram | |
</h6> | |
''' | |
def _create_env_var_textbox( | |
env_var: str | None = None, | |
validator_method: Callable | None = None, | |
**kwargs, | |
) -> gr.Textbox: | |
value = None | |
if env_var and validator_method: | |
validation_result = validator_method() | |
if validation_result.is_valid: | |
value = os.getenv(env_var) | |
curr_kwargs = dict(value=value) | |
curr_kwargs.update(kwargs) | |
return gr.Textbox(**curr_kwargs) | |
def api_id(cls) -> gr.Textbox: | |
return cls._create_env_var_textbox( | |
env_var='API_ID', | |
validator_method=Validator.validate_env_id, | |
label='API_ID Telegram app', | |
placeholder='API_ID приложения Telegram', | |
scale=1, | |
) | |
def api_hash(cls) -> gr.Textbox: | |
return cls._create_env_var_textbox( | |
env_var='API_HASH', | |
validator_method=Validator.validate_env_hash, | |
label='API_HASH Telegram app', | |
placeholder='API_HASH приложения Telegram', | |
scale=1, | |
) | |
def phone_number(cls) -> gr.Textbox: | |
return cls._create_env_var_textbox( | |
env_var='PHONE_NUMBER', | |
validator_method=Validator.validate_env_phone_number, | |
label='PHONE_NUMBER Telegram app', | |
placeholder='PHONE_NUMBER приложения Telegram', | |
scale=1, | |
) | |
def code(visible: str = False, render: bool = True) -> gr.Textbox: | |
component = gr.Textbox( | |
value=None, | |
label='Проверочный код', | |
visible=visible, | |
render=render, | |
placeholder=None, | |
scale=1, | |
) | |
return component | |
def password_2fa(visible: str = False, render: bool = True) -> gr.Textbox: | |
component = gr.Textbox( | |
type='password', | |
value=None, | |
label='Облачный пароль', | |
visible=visible, | |
render=render, | |
placeholder=None, | |
scale=1, | |
) | |
return component | |
def auth_status(value: str | None = None) -> gr.Textbox: | |
component = gr.Textbox( | |
value=value, | |
label='Статус авторизации', | |
placeholder=None, | |
interactive=False, | |
scale=1, | |
) | |
return component | |
def auth_btn(interactive: bool = True) -> gr.Button: | |
component = gr.Button( | |
value='Авторизация', | |
interactive=interactive, | |
scale=1, | |
) | |
return component | |
def code_btn(visible: bool = False, render: bool = True) -> gr.Button: | |
component = gr.Button( | |
value='Подтвержение кода', | |
visible=visible, | |
render=render, | |
scale=0, | |
) | |
return component | |
def password_2fa_btn(visible: bool = False, render: bool = True) -> gr.Button: | |
component = gr.Button( | |
value='Подтверждение облачного пароля', | |
visible=visible, | |
render=render, | |
scale=0, | |
) | |
return component | |
def delete_session_btn(visible: bool = False, render: bool = True) -> gr.Button: | |
component = gr.Button( | |
value='Удаление сессии', | |
visible=visible, | |
render=render, | |
scale=1, | |
) | |
return component | |
def session_type_radio(cls) -> gr.Radio: | |
session_types = {'sqlite': SQLiteSession, 'memory': MemorySession} | |
component = gr.Radio( | |
choices=session_types, | |
value='memory', | |
label='Тип сессии', | |
info=None, # cls.session_type_markdown | |
) | |
return component | |
def chats_usernames() -> gr.Textbox: | |
component = gr.Textbox( | |
label='Адреса чатов', | |
placeholder='Ссылки или ID чатов/каналов через пробел или перенос строки', | |
scale=1, | |
lines=2, | |
) | |
return component | |
def add_chat_btn() -> gr.Button: | |
component = gr.Button( | |
value='Добавить чат/чаты', | |
scale=0, | |
) | |
return component | |
def chats_list_status() -> gr.Textbox: | |
component = gr.Textbox( | |
label='Добавленные чаты', | |
placeholder='Здесь будет список чатов для парсинга', | |
scale=1, | |
lines=3, | |
) | |
return component | |
def parse_status() -> gr.Textbox: | |
component = gr.Textbox( | |
label='Статус парсинга', | |
placeholder='Здесь будет отчет о результатах парсинга', | |
scale=1, | |
lines=8, | |
) | |
return component | |
def start_parse_btn() -> gr.Button: | |
component = gr.Button( | |
value='Начать парсинг', | |
scale=0, | |
) | |
return component | |
def download_btn(value: str | None = None) -> gr.Button: | |
component = gr.DownloadButton( | |
label='Загрузить csv результаты', | |
value=value, | |
visible=value is not None, | |
scale=0, | |
) | |
return component | |
def get_parse_args() -> list[gr.component]: | |
limit = gr.Number( | |
value=None, | |
label='limit', | |
info='Сколько сообщений парсить', | |
) | |
offset_date = gr.DateTime( | |
value=None, | |
label='offset_date', | |
info='До какой даты парсить', | |
timezone='Europe/Moscow', | |
) | |
reverse = gr.Checkbox( | |
value=False, | |
label='reverse', | |
info='Парсить от сегодняшнего сообщения к самому раннему', | |
) | |
parse_args = [limit, offset_date, reverse] | |
return parse_args | |
class ComponentsFn(Components): | |
def update_status(auth_state: AuthState) -> str | None: | |
return auth_state.message | |
def get_dynamic_visible_components(cls, auth_state: AuthState, render: bool = True) -> tuple[gr.component]: | |
code = cls.code(visible=auth_state.need_verify_code, render=render) | |
code_btn = cls.code_btn(visible=auth_state.need_verify_code, render=render) | |
password_2fa = cls.password_2fa(visible=auth_state.need_verify_2fa, render=render) | |
password_2fa_btn = cls.password_2fa_btn(visible=auth_state.need_verify_2fa, render=render) | |
delete_session_btn = cls.delete_session_btn(visible=auth_state.is_auth, render=render) | |
return code, code_btn, password_2fa, password_2fa_btn, delete_session_btn | |
def update_auth_state_session_type(auth_state: AuthState, session_type: str) -> None: | |
auth_state.change_session_type(session_type) | |
async def delete_session(auth_state: AuthState) -> None: | |
await auth_state.delete_session() | |
def update_download_btn(cls, csv_paths: Collection[Path]) -> gr.Button | None: | |
if len(csv_paths) == 0: | |
return None | |
elif len(csv_paths) == 1: | |
filepath = csv_paths[0] | |
else: | |
filepath = Parser.zip_files(csv_paths) | |
component = cls.download_btn(value=filepath) | |
return component | |