Spaces:
Runtime error
Runtime error
| # app.py — Verificador de Hashes (SHA256, SHA512, MD5) com tema padronizado | |
| import gradio as gr | |
| import re | |
| from pathlib import Path | |
| from typing import List, Union | |
| from hash_tools import gerar_planilha_hash_multi # usa sua lógica existente | |
| # -------------------- Tema + CSS do portfólio -------------------- | |
| CUSTOM_CSS = """ | |
| :root{ | |
| --bg:#000; /* fundo geral */ | |
| --panel:#0b0b0b; /* blocos/painéis */ | |
| --panel-2:#0e0e0e; /* inputs/dropdowns */ | |
| --border:#2a2a2a; /* borda padrão */ | |
| --text:#e5e5e5; /* texto branco suave */ | |
| --muted:#a3a3a3; /* texto secundário */ | |
| --accent:#6ee7b7; /* cor do foco/seleção (verde menta) */ | |
| } | |
| /* fonte geral (system UI) */ | |
| html, body, .gradio-container { | |
| background: var(--bg)!important; | |
| color: var(--text)!important; | |
| font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif !important; | |
| } | |
| /* blocos/painéis */ | |
| .gradio-container .block, | |
| .gradio-container .gr-box, | |
| .gradio-container .gr-panel { | |
| background: var(--panel) !important; | |
| border: 1px solid var(--border) !important; | |
| border-radius: 12px !important; | |
| } | |
| /* remover o bloco atrás do TÍTULO */ | |
| .gradio-container .block:has(h1){ | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| } | |
| /* botões estilo "pílula" */ | |
| button, .gr-button{ | |
| border-radius: 9999px !important; | |
| border: 1px solid var(--border) !important; | |
| background: var(--panel-2) !important; | |
| } | |
| button:hover{ border-color:#4a4a4a !important; } | |
| /* inputs/textarea/file/dropdown */ | |
| input, textarea, select, | |
| .gradio-container .gr-textbox, | |
| .gradio-container .gr-input, | |
| .gradio-container .gradio-dropdown, | |
| .gradio-container .gr-file, | |
| .gradio-container .gr-file-download { | |
| background: var(--panel-2) !important; | |
| border: 1px solid var(--border) !important; | |
| color: var(--text) !important; | |
| border-radius: 12px !important; | |
| } | |
| .gradio-container textarea { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; } | |
| select > option { background: var(--panel-2); color: var(--text); } | |
| /* foco/seleção visível */ | |
| input:focus, textarea:focus, select:focus, | |
| .gradio-container .gr-textbox:focus-within, | |
| .gradio-container .gr-input:focus-within, | |
| .gradio-container .gradio-dropdown:focus-within, | |
| .gradio-container .gr-file:focus-within, | |
| .gradio-container .gr-select-container:focus-within { | |
| outline: none !important; | |
| border-color: var(--accent) !important; | |
| box-shadow: 0 0 0 2px rgba(110,231,183,0.18) !important; | |
| } | |
| /* esconder rodapé do Gradio */ | |
| .gradio-container .fixed.bottom-0, | |
| .gradio-container div[class*="fixed"][class*="bottom-0"], | |
| .gradio-container footer, | |
| body > div.fixed.bottom-0, | |
| div.fixed.bottom-0 { | |
| display: none !important; | |
| visibility: hidden !important; | |
| height: 0 !important; | |
| overflow: hidden !important; | |
| pointer-events: none !important; | |
| } | |
| """ | |
| THEME = gr.themes.Soft(primary_hue="zinc", neutral_hue="zinc") | |
| # -------------------- Utils -------------------- | |
| def _normalize_paths(arquivos: Union[str, Path, List[Union[str, Path, dict]]]) -> List[Path]: | |
| """Converte o que o gr.Files entrega (str | Path | dict | lista) em List[Path].""" | |
| items = arquivos if isinstance(arquivos, list) else [arquivos] | |
| paths: List[Path] = [] | |
| for a in items: | |
| if isinstance(a, (str, Path)): | |
| paths.append(Path(a)) | |
| else: | |
| name = getattr(a, "name", None) | |
| if name is None: | |
| try: | |
| name = a["name"] # alguns navegadores/versões retornam dict-like | |
| except Exception: | |
| name = str(a) | |
| paths.append(Path(name)) | |
| return paths | |
| # -------------------- Função do app -------------------- | |
| def processar(arquivos): | |
| if not arquivos: | |
| gr.Warning("Envie ao menos um arquivo (pode ser .zip).") | |
| return "Nenhum arquivo enviado.", None | |
| try: | |
| paths = _normalize_paths(arquivos) | |
| xlsx_path = gerar_planilha_hash_multi(paths) | |
| return "Planilha gerada com sucesso.", xlsx_path | |
| except Exception as e: | |
| gr.Error(f"{type(e).__name__}: {e}") | |
| return "Erro ao processar. Verifique os logs.", None | |
| # -------------------- Interface -------------------- | |
| demo = gr.Interface( | |
| fn=processar, | |
| inputs=[ | |
| gr.Files( | |
| label="Envie arquivo(s)", | |
| file_count="multiple", | |
| ) | |
| ], | |
| outputs=[ | |
| gr.Textbox(label="Status", lines=2, show_copy_button=True), | |
| gr.File(label="Baixar planilha (.xlsx)"), | |
| ], | |
| title="Gerador de Hashes (SHA256, SHA512, MD5) — Upload único/múltiplo/ZIP", | |
| allow_flagging="never", | |
| theme=THEME, | |
| css=CUSTOM_CSS, | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |