import streamlit as st from supabase import create_client, Client import random import time import io import uuid from PIL import Image, ImageDraw, ImageFont import pandas as pd from datetime import datetime import os # --- Configuração Inicial --- st.set_page_config( page_title="Number Assignment & Form System", layout="centered", initial_sidebar_state="expanded" ) # --- Estilização CSS --- st.markdown(""" """, unsafe_allow_html=True) # --- Funções --- def get_supabase_client() -> Client: """Estabelece conexão com o Supabase usando variáveis de ambiente.""" supabase_url = os.getenv("SUPABASE_URL") supabase_key = os.getenv("SUPABASE_KEY") if not supabase_url or not supabase_key: st.error("Credenciais do Supabase não configuradas no ambiente.") return None try: client = create_client(supabase_url, supabase_key) client.table("_dummy").select("*").limit(1).execute() return client except Exception as e: st.error(f"Erro ao conectar ao Supabase: {str(e)}") return None def check_table_exists(supabase, table_name): """Verifica se uma tabela específica existe no Supabase.""" try: supabase.table(table_name).select("*").limit(1).execute() return True except Exception: return False def create_meeting_table(supabase, table_name, meeting_name, max_number=999, selected_forms=None): """Cria uma nova tabela para uma reunião no Supabase e registra metadados.""" try: response_metadata = supabase.table("meetings_metadata").insert({ "table_name": table_name, "meeting_name": meeting_name, "created_at": datetime.now().isoformat(), "max_number": max_number }).execute() meeting_id = response_metadata.data[0]["id"] create_table_query = f""" CREATE TABLE public.{table_name} ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, number INTEGER NOT NULL, assigned BOOLEAN DEFAULT FALSE, assigned_at TIMESTAMPTZ, user_id TEXT ); """ supabase.rpc("execute_sql", {"query": create_table_query}).execute() time.sleep(1) if not check_table_exists(supabase, table_name): raise Exception(f"Tabela {table_name} não foi criada com sucesso no Supabase.") batch_size = 100 for i in range(0, max_number, batch_size): end = min(i + batch_size, max_number) data = [{"number": j, "assigned": False, "assigned_at": None, "user_id": None} for j in range(i+1, end+1)] supabase.table(table_name).insert(data).execute() # Associar formulários à reunião if selected_forms: for form_id in selected_forms: supabase.table("meeting_forms").insert({ "meeting_id": meeting_id, "form_id": form_id }).execute() return True except Exception as e: st.error(f"Erro ao criar tabela de reunião: {str(e)}") try: supabase.table("meetings_metadata").delete().eq("table_name", table_name).execute() supabase.rpc("execute_sql", {"query": f"DROP TABLE IF EXISTS public.{table_name}"}).execute() except Exception as rollback_e: st.error(f"Erro no rollback: {str(rollback_e)}") return False def get_available_meetings(supabase): """Recupera a lista de reuniões disponíveis da tabela de metadados.""" try: response = supabase.table("meetings_metadata").select("*").execute() return response.data if response.data else [] except Exception as e: st.error(f"Erro ao recuperar reuniões: {str(e)}") return [] def get_available_forms(supabase): """Recupera a lista de formulários disponíveis da tabela de metadados.""" try: response = supabase.table("forms_metadata").select("*").execute() return response.data if response.data else [] except Exception as e: st.error(f"Erro ao recuperar formulários: {str(e)}") return [] def get_forms_for_meeting(supabase, meeting_id): """Recupera os formulários associados a uma reunião específica.""" try: response = supabase.table("meeting_forms").select("form_id").eq("meeting_id", meeting_id).execute() form_ids = [row["form_id"] for row in response.data] if form_ids: forms = supabase.table("forms_metadata").select("*").in_("id", form_ids).execute() return forms.data if forms.data else [] return [] except Exception as e: st.error(f"Erro ao recuperar formulários da reunião: {str(e)}") return [] def get_answered_forms(supabase, participant_id): """Recupera os IDs dos formulários já respondidos por um participant_id.""" try: response = supabase.table("responses").select("form_id").eq("participant_id", participant_id).execute() return set(row["form_id"] for row in response.data) if response.data else set() except Exception as e: st.error(f"Erro ao verificar formulários respondidos: {str(e)}") return set() def generate_number_image(number): """Gera uma imagem com o número atribuído.""" width, height = 600, 300 img = Image.new("RGB", (width, height), color=(255, 255, 255)) draw = ImageDraw.Draw(img) for y in range(height): r = int(220 - y/3) g = int(240 - y/3) b = 255 for x in range(width): draw.point((x, y), fill=(r, g, b)) try: font = ImageFont.truetype("Arial.ttf", 200) except IOError: font = ImageFont.load_default() number_text = str(number) bbox = draw.textbbox((0, 0), number_text, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] text_position = ((width - text_width) // 2, (height - text_height) // 2) draw.text(text_position, number_text, font=font, fill=(0, 0, 100)) img_buffer = io.BytesIO() img.save(img_buffer, format="PNG") img_buffer.seek(0) return img_buffer def generate_participant_link(table_name, user_id=None, mode="participant"): """Gera um link para participantes acessarem a reunião ou formulário.""" base_url = "https://mynumber.streamlit.app" if user_id: return f"{base_url}/?table={table_name}&mode={mode}&user_id={user_id}" return f"{base_url}/?table={table_name}&mode={mode}" # --- Verifica Modo (Master, Participant ou Participant_Form) --- query_params = st.query_params mode = query_params.get("mode", "master") table_name_from_url = query_params.get("table", None) if "user_id" not in st.session_state: user_id_from_url = query_params.get("user_id", None) if user_id_from_url: st.session_state["user_id"] = user_id_from_url else: st.session_state["user_id"] = str(uuid.uuid4()) if mode == "participant" and table_name_from_url: # --- Modo Participante para Reuniões --- st.markdown("

Obtenha Seu Número

", unsafe_allow_html=True) supabase = get_supabase_client() if not supabase: st.stop() if not check_table_exists(supabase, table_name_from_url): st.error("Reunião não encontrada ou inválida.") st.stop() try: meeting_info = supabase.table("meetings_metadata").select("*").eq("table_name", table_name_from_url).execute() meeting_name = meeting_info.data[0]["meeting_name"] if meeting_info.data else "Reunião" meeting_id = meeting_info.data[0]["id"] st.subheader(f"Reunião: {meeting_name}") except Exception: st.subheader("Obtenha um número para a reunião") st.stop() user_id = st.session_state["user_id"] participant_link = generate_participant_link(table_name_from_url, user_id, mode="participant") st.markdown(f"**Seu Link Persistente para Reunião:** [{participant_link}]({participant_link})") st.write("Guarde este link para acessar sempre o mesmo número!") try: existing = supabase.table(table_name_from_url).select("number").eq("user_id", user_id).execute() if existing.data: st.session_state["assigned_number"] = existing.data[0]["number"] else: with st.spinner("Atribuindo um número..."): response = supabase.table(table_name_from_url).select("*").eq("assigned", False).execute() if response.data: available_numbers = [row["number"] for row in response.data] if available_numbers: assigned_number = random.choice(available_numbers) supabase.table(table_name_from_url).update({ "assigned": True, "assigned_at": datetime.now().isoformat(), "user_id": user_id }).eq("number", assigned_number).execute() st.session_state["assigned_number"] = assigned_number else: st.error("Todos os números foram atribuídos!") st.stop() else: st.error("Todos os números foram atribuídos!") st.stop() st.markdown(f"""

Seu número atribuído é:

{st.session_state['assigned_number']}
""", unsafe_allow_html=True) # Mostrar links de formulários disponíveis para esta reunião com status st.subheader("Formulários Disponíveis para Você") forms = get_forms_for_meeting(supabase, meeting_id) participant_id = str(st.session_state["assigned_number"]) answered_forms = get_answered_forms(supabase, participant_id) if forms: for form in forms: form_id = form["id"] form_link = generate_participant_link(form["table_name"], user_id, mode="participant_form") status = "✅ Respondido" if form_id in answered_forms else "⏳ Pendente" st.markdown(f"- **{form['form_name']}** ({status}): [{form_link}]({form_link})") else: st.info("Nenhum formulário disponível para esta reunião.") except Exception as e: st.error(f"Erro ao atribuir número: {str(e)}") st.stop() if st.button("Salvar como Imagem"): with st.spinner("Gerando imagem..."): img_buffer = generate_number_image(st.session_state["assigned_number"]) st.image(img_buffer) st.download_button( "Baixar Imagem", img_buffer, file_name=f"meu_numero_{st.session_state['assigned_number']}.png", mime="image/png" ) elif mode == "participant_form" and table_name_from_url: # --- Modo Participante para Formulários --- st.markdown("

Responder Formulário

", unsafe_allow_html=True) supabase = get_supabase_client() if not supabase: st.stop() form_info = supabase.table("forms_metadata").select("*").eq("table_name", table_name_from_url).execute() if not form_info.data: st.error("Formulário não encontrado.") st.stop() form_id = form_info.data[0]['id'] st.subheader(f"Formulário: {form_info.data[0]['form_name']}") questions = supabase.table("questions").select("*").eq("form_id", form_id).execute() if not questions.data: st.error("Nenhuma pergunta encontrada para este formulário.") st.stop() user_id = st.session_state["user_id"] participant_id_default = "" meeting_table_name = "" for meeting in get_available_meetings(supabase): assigned = supabase.table(meeting["table_name"]).select("number").eq("user_id", user_id).execute() if assigned.data: participant_id_default = str(assigned.data[0]["number"]) meeting_table_name = meeting["table_name"] break if not participant_id_default: st.error("Você precisa ter um número atribuído para responder formulários.") st.stop() # Verificar se o formulário já foi respondido participant_id = participant_id_default answered_forms = get_answered_forms(supabase, participant_id) if form_id in answered_forms: st.warning("Você já respondeu este formulário. Cada participante só pode responder uma vez.") st.stop() with st.form("form_submission"): responses = {} for q in questions.data: st.write(f"{q['question_text']}") if q['question_type'] == 'text': responses[q['id']] = st.text_input("Sua resposta", key=f"resp_{q['id']}") elif q['question_type'] == 'multiple_choice': options = supabase.table("options").select("*").eq("question_id", q['id']).execute() option_texts = [opt['option_text'] for opt in options.data] option_ids = [opt['id'] for opt in options.data] selected_option = st.selectbox("Escolha uma opção", option_texts, key=f"resp_{q['id']}") responses[q['id']] = option_ids[option_texts.index(selected_option)] st.text_input("Seu Nome ou ID", value=participant_id, key="participant_id", disabled=True) if st.form_submit_button("Enviar"): if all(responses.values()): for q_id, answer in responses.items(): response_data = { "form_id": form_id, "participant_id": participant_id, "question_id": q_id, "answer": str(answer) } supabase.table("responses").insert(response_data).execute() st.success("Respostas enviadas com sucesso!") st.markdown(f"Voltando para sua página de participante em 3 segundos...") time.sleep(3) st.query_params.update({ "table": meeting_table_name, "mode": "participant", "user_id": user_id }) st.rerun() else: st.warning("Preencha todas as respostas.") else: # --- Modo Master --- valid_pages = ["Gerenciar Reuniões", "Compartilhar Link da Reunião", "Ver Estatísticas", "Gerenciar Formulários", "Compartilhar Link do Formulário"] if "page" not in st.session_state or st.session_state["page"] not in valid_pages: st.session_state["page"] = "Gerenciar Reuniões" st.sidebar.title("Menu (Master)") page = st.sidebar.radio("Escolha uma opção", valid_pages, index=valid_pages.index(st.session_state["page"])) # --- Página 1: Gerenciar Reuniões --- if page == "Gerenciar Reuniões": st.session_state["page"] = "Gerenciar Reuniões" st.markdown("

Gerenciar Reuniões

", unsafe_allow_html=True) supabase = get_supabase_client() if not supabase: st.stop() with st.form("create_meeting_form"): st.subheader("Criar Nova Reunião") meeting_name = st.text_input("Nome da Reunião") max_number = st.number_input("Número Máximo", min_value=10, max_value=10000, value=999) # Seleção de formulários disponíveis para a reunião forms = get_available_forms(supabase) form_options = {f"{f['form_name']} ({f['table_name']})": f["id"] for f in forms} selected_forms = st.multiselect("Formulários Disponíveis nesta Reunião", list(form_options.keys())) selected_form_ids = [form_options[form] for form in selected_forms] if selected_forms else None submit_button = st.form_submit_button("Criar Reunião") if submit_button: if meeting_name: table_name = f"meeting_{int(time.time())}_{meeting_name.lower().replace(' ', '_')}" if check_table_exists(supabase, table_name): st.error("Uma reunião com esse nome já existe. Tente outro nome.") else: with st.spinner("Criando reunião..."): success = create_meeting_table(supabase, table_name, meeting_name, max_number, selected_form_ids) if success: participant_link = generate_participant_link(table_name, mode="participant") st.success(f"Reunião '{meeting_name}' criada com sucesso!") st.markdown(f"**Link para Participantes:** [{participant_link}]({participant_link})") st.session_state["selected_table"] = table_name st.session_state["page"] = "Compartilhar Link da Reunião" st.rerun() else: st.error("Falha ao criar a reunião.") else: st.warning("Por favor, insira um nome para a reunião.") st.subheader("Reuniões Existentes") meetings = get_available_meetings(supabase) if meetings: meeting_data = [] for meeting in meetings: if "table_name" in meeting and "meeting_name" in meeting: table_name = meeting["table_name"] if check_table_exists(supabase, table_name): try: count_response = supabase.table(table_name).select("*", count="exact").eq("assigned", True).execute() assigned_count = count_response.count if hasattr(count_response, 'count') else 0 participant_link = generate_participant_link(table_name, mode="participant") meeting_data.append({ "Nome": meeting.get("meeting_name", "Sem nome"), "Tabela": table_name, "Link": participant_link, "Criada em": meeting.get("created_at", "")[:16].replace("T", " "), "Números Atribuídos": assigned_count, "Total de Números": meeting.get("max_number", 0) }) except Exception as e: st.warning(f"Erro ao processar reunião {table_name}: {str(e)}") if meeting_data: df = pd.DataFrame(meeting_data) st.dataframe(df) else: st.info("Nenhuma reunião válida encontrada.") else: st.info("Nenhuma reunião disponível ou erro ao acessar o Supabase.") # --- Página 2: Compartilhar Link da Reunião --- elif page == "Compartilhar Link da Reunião": st.session_state["page"] = "Compartilhar Link da Reunião" st.markdown("

Compartilhar Link da Reunião

", unsafe_allow_html=True) supabase = get_supabase_client() if not supabase: st.stop() meetings = get_available_meetings(supabase) if not meetings: st.info("Nenhuma reunião disponível. Crie uma reunião primeiro.") st.stop() options = {f"{m['meeting_name']} ({m['table_name']})": m["table_name"] for m in meetings if "table_name" in m and "meeting_name" in m} selected = st.selectbox("Selecione uma reunião para compartilhar:", list(options.keys())) if selected: selected_table = options[selected] participant_link = generate_participant_link(selected_table, mode="participant") st.markdown(f"**Link para Participantes:** [{participant_link}]({participant_link})") if st.button("Copiar Link"): st.write("Link copiado para a área de transferência!") st.code(participant_link) # --- Página 3: Ver Estatísticas --- elif page == "Ver Estatísticas": st.session_state["page"] = "Ver Estatísticas" st.markdown("

Estatísticas da Reunião

", unsafe_allow_html=True) supabase = get_supabase_client() if not supabase: st.stop() meetings = get_available_meetings(supabase) if not meetings: st.info("Nenhuma reunião disponível para análise.") st.stop() options = {f"{m['meeting_name']} ({m['table_name']})": m["table_name"] for m in meetings if "table_name" in m and "meeting_name" in m} selected = st.selectbox("Selecione uma reunião:", list(options.keys())) if selected: selected_table = options[selected] meeting_info = supabase.table("meetings_metadata").select("id").eq("table_name", selected_table).execute() meeting_id = meeting_info.data[0]["id"] # Estatísticas de números try: total_response = supabase.table(selected_table).select("*", count="exact").execute() total_numbers = total_response.count if hasattr(total_response, 'count') else 0 assigned_response = supabase.table(selected_table).select("*", count="exact").eq("assigned", True).execute() assigned_numbers = assigned_response.count if hasattr(assigned_response, 'count') else 0 percentage = (assigned_numbers / total_numbers) * 100 if total_numbers > 0 else 0 col1, col2, col3 = st.columns(3) with col1: st.metric("Total de Números", total_numbers) with col2: st.metric("Números Atribuídos", assigned_numbers) with col3: st.metric("Porcentagem Atribuída", f"{percentage:.1f}%") try: time_data_response = supabase.table(selected_table).select("*").eq("assigned", True).order("assigned_at").execute() if time_data_response.data: time_data = [] for item in time_data_response.data: if item.get("assigned_at"): time_data.append({ "time": item.get("assigned_at")[:16].replace("T", " "), "count": 1 }) if time_data: df = pd.DataFrame(time_data) df["time"] = pd.to_datetime(df["time"]) df["hour"] = df["time"].dt.floor("H") hourly_counts = df.groupby("hour").count().reset_index() hourly_counts["hour_str"] = hourly_counts["hour"].dt.strftime("%m/%d %H:00") st.subheader("Atribuições de Números por Hora") st.bar_chart(data=hourly_counts, x="hour_str", y="count") except Exception: st.info("Dados temporais não disponíveis para esta reunião.") if st.button("Exportar Dados de Números"): try: all_data_response = supabase.table(selected_table).select("*").execute() if all_data_response.data: df = pd.DataFrame(all_data_response.data) csv = df.to_csv(index=False) st.download_button( "Baixar CSV", csv, file_name=f"{selected_table}_numeros_export.csv", mime="text/csv" ) except Exception as e: st.error(f"Erro ao exportar dados: {str(e)}") except Exception as e: st.error(f"Erro ao recuperar estatísticas de números: {str(e)}") # Estatísticas de respostas dos formulários st.subheader("Respostas dos Formulários") forms = get_forms_for_meeting(supabase, meeting_id) if forms: form_ids = [f["id"] for f in forms] responses = supabase.table("responses").select("participant_id, form_id, question_id, answer").in_("form_id", form_ids).execute() if responses.data: response_data = [] for resp in responses.data: form = next((f for f in forms if f["id"] == resp["form_id"]), None) question = supabase.table("questions").select("question_text").eq("id", resp["question_id"]).execute().data[0] response_data.append({ "Participante": resp["participant_id"], "Formulário": form["form_name"] if form else "Desconhecido", "Pergunta": question["question_text"], "Resposta": resp["answer"] }) df = pd.DataFrame(response_data) st.dataframe(df) if st.button("Exportar Respostas dos Formulários"): csv = df.to_csv(index=False) st.download_button( "Baixar CSV", csv, file_name=f"{selected_table}_respostas_export.csv", mime="text/csv" ) else: st.info("Nenhuma resposta registrada para os formulários desta reunião.") else: st.info("Nenhum formulário associado a esta reunião.") # --- Página 4: Gerenciar Formulários --- elif page == "Gerenciar Formulários": st.session_state["page"] = "Gerenciar Formulários" st.markdown("

Gerenciar Formulários

", unsafe_allow_html=True) supabase = get_supabase_client() if not supabase: st.stop() with st.form("create_form_form"): st.subheader("Criar Novo Formulário") form_name = st.text_input("Nome do Formulário", key="form_name") if 'questions' not in st.session_state: st.session_state['questions'] = [] st.markdown("

Adicionar Pergunta

", unsafe_allow_html=True) question_type = st.selectbox("Tipo da Pergunta", ["Texto", "Múltipla Escolha"], key="q_type") question_text = st.text_input("Texto da Pergunta", key="q_text") correct_answer = None options = [] if question_type == "Múltipla Escolha": num_options = st.number_input("Número de Opções", min_value=2, max_value=10, value=2, key="num_opts") for i in range(num_options): option_text = st.text_input(f"Opção {i+1}", key=f"opt_{i}") if option_text: options.append(option_text) correct_option = st.selectbox("Opção Correta (opcional)", ["Nenhuma"] + options, key="correct_opt") if correct_option != "Nenhuma": correct_answer = correct_option else: correct_answer = st.text_input("Resposta Correta (opcional)", key="correct_text") if st.form_submit_button("Adicionar Pergunta"): if question_text: if question_type == "Múltipla Escolha" and len(options) >= 2: st.session_state['questions'].append({ 'type': 'multiple_choice', 'text': question_text, 'options': options, 'correct': correct_answer }) st.success("Pergunta de múltipla escolha adicionada!") elif question_type == "Texto": st.session_state['questions'].append({ 'type': 'text', 'text': question_text, 'correct': correct_answer if correct_answer else None }) st.success("Pergunta de texto adicionada!") else: st.warning("Adicione pelo menos 2 opções para perguntas de múltipla escolha.") else: st.warning("O texto da pergunta é obrigatório.") if st.session_state['questions']: st.markdown("

Perguntas Adicionadas

", unsafe_allow_html=True) for i, q in enumerate(st.session_state['questions']): st.write(f"{i+1}. {q['text']} ({q['type']})") if q['type'] == 'multiple_choice': st.write("Opções:", ", ".join(q['options'])) st.write(f"Correta: {q['correct'] if q['correct'] else 'Nenhuma'}") else: st.write(f"Correta: {q['correct'] if q['correct'] else 'Nenhuma'}") if st.form_submit_button("Criar Formulário"): if form_name and st.session_state['questions']: table_name = f"form_{int(time.time())}_{form_name.lower().replace(' ', '_')}" form_data = {"form_name": form_name, "table_name": table_name, "created_at": datetime.now().isoformat()} form_response = supabase.table("forms_metadata").insert(form_data).execute() form_id = form_response.data[0]['id'] for q in st.session_state['questions']: question_data = { "form_id": form_id, "question_text": q['text'], "question_type": q['type'], "correct_answer": q['correct'] } q_response = supabase.table("questions").insert(question_data).execute() question_id = q_response.data[0]['id'] if q['type'] == 'multiple_choice': for opt in q['options']: opt_data = {"question_id": question_id, "option_text": opt} opt_response = supabase.table("options").insert(opt_data).execute() if opt == q['correct']: supabase.table("questions").update({"correct_answer": str(opt_response.data[0]['id'])}).eq("id", question_id).execute() participant_link = generate_participant_link(table_name, mode="participant_form") st.success(f"Formulário '{form_name}' criado com sucesso!") st.markdown(f"**Link Geral para Participantes:** [{participant_link}]({participant_link})") st.session_state['questions'] = [] st.session_state["selected_form_table"] = table_name st.session_state["page"] = "Compartilhar Link do Formulário" st.rerun() else: st.warning("Insira um nome para o formulário e pelo menos uma pergunta.") st.subheader("Formulários Disponíveis") forms = get_available_forms(supabase) if forms: form_data = [] for form in forms: participant_link = generate_participant_link(form["table_name"], mode="participant_form") form_data.append({ "Nome": form["form_name"], "Link Geral": participant_link, "Criado em": form["created_at"][:16].replace("T", " ") }) df = pd.DataFrame(form_data) st.dataframe(df, column_config={"Link Geral": st.column_config.LinkColumn("Link Geral")}) else: st.info("Nenhum formulário disponível.") # --- Página 5: Compartilhar Link do Formulário --- elif page == "Compartilhar Link do Formulário": st.session_state["page"] = "Compartilhar Link do Formulário" st.markdown("

Compartilhar Link do Formulário

", unsafe_allow_html=True) supabase = get_supabase_client() if not supabase: st.stop() forms = get_available_forms(supabase) if not forms: st.info("Nenhum formulário disponível. Crie um formulário primeiro.") st.stop() options = {f"{f['form_name']} ({f['table_name']})": f["table_name"] for f in forms if "table_name" in f and "form_name" in f} selected = st.selectbox("Selecione um formulário para compartilhar:", list(options.keys())) if selected: selected_table = options[selected] participant_link = generate_participant_link(selected_table, mode="participant_form") st.markdown(f"**Link Geral para Participantes:** [{participant_link}]({participant_link})") if st.button("Copiar Link Geral"): st.write("Link copiado para a área de transferência!") st.code(participant_link) st.subheader("Links Únicos por Usuário") meetings = get_available_meetings(supabase) user_links = [] for meeting in meetings: assigned_users = supabase.table(meeting["table_name"]).select("user_id, number").eq("assigned", True).execute() for user in assigned_users.data: user_link = generate_participant_link(selected_table, user["user_id"], mode="participant_form") user_links.append({"Número": user["number"], "Link": user_link}) if user_links: df = pd.DataFrame(user_links) st.dataframe(df, column_config={"Link": st.column_config.LinkColumn("Link")}) else: st.info("Nenhum usuário com número atribuído encontrado.") if __name__ == "__main__": pass