| | |
| | import gradio as gr |
| | import re |
| | from pathlib import Path |
| | from typing import List |
| | from processador import processar_misto |
| |
|
| | |
| | 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, |
| | .gradio-container .gr-select-container, |
| | .gradio-container .wrap .items-center select { |
| | background: var(--panel-2) !important; |
| | border: 1px solid var(--border) !important; |
| | color: var(--text) !important; |
| | border-radius: 12px !important; |
| | } |
| | 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; |
| | } |
| | |
| | /* uploader QUADRADO */ |
| | .gradio-container [data-testid="file"] .rounded-full, |
| | .gradio-container [data-testid="files"] .rounded-full { border-radius:12px !important; } |
| | .gradio-container [data-testid="file"] [class*="aspect-"], |
| | .gradio-container [data-testid="files"] [class*="aspect-"] { aspect-ratio:auto !important; } |
| | .gradio-container [data-testid="file"] .h-full.w-full, |
| | .gradio-container [data-testid="files"] .h-full.w-full { border-radius:12px !important; } |
| | |
| | /* gallery e saídas */ |
| | .gradio-container .gr-gallery, |
| | .gradio-container .gr-file-download{ |
| | background: var(--panel-2) !important; |
| | border: 1px solid var(--border) !important; |
| | border-radius: 12px !important; |
| | } |
| | |
| | /* badges/labels */ |
| | .badge, .token { background:#0f0f0f !important; border-radius:9999px !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") |
| |
|
| | |
| | def _normalize_paths(arquivos) -> List[Path]: |
| | """gr.Files pode entregar str, Path, objeto com .name ou até dict-like.""" |
| | 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"] |
| | except Exception: |
| | name = str(a) |
| | paths.append(Path(name)) |
| | return paths |
| |
|
| | |
| | def processar(arquivos, modo, paginas_input, formato_opcao): |
| | if not arquivos: |
| | return "Por favor, envie ao menos um PDF (ou .zip com PDFs).", None |
| |
|
| | paths = _normalize_paths(arquivos) |
| |
|
| | |
| | formato = formato_opcao.split(" [")[0].strip().lower() |
| |
|
| | paginas = None |
| | if "específica" in modo.lower(): |
| | nums = re.findall(r"\d+", paginas_input or "") |
| | if not nums: |
| | return "Nenhuma página válida foi informada.", None |
| | paginas = [int(n) for n in nums] |
| |
|
| | try: |
| | galeria, zip_path = processar_misto(paths, modo, paginas, formato) |
| | return galeria, zip_path |
| | except Exception as e: |
| | return f"Erro ao processar: {e}", None |
| |
|
| | |
| | FORMATOS = [ |
| | "jpeg [Recomendado - compacto e boa qualidade]", |
| | "png [Alta qualidade, suporta transparência]", |
| | "bmp [Sem compressão - ideal para edição bruta]", |
| | "ico [Favicon para sites, atalhos e apps]", |
| | ] |
| |
|
| | demo = gr.Interface( |
| | fn=processar, |
| | inputs=[ |
| | gr.Files( |
| | label="Envie PDF(s) ou .zip com PDFs", |
| | file_count="multiple", |
| | file_types=[".pdf", ".zip"], |
| | ), |
| | gr.Radio( |
| | ["Extrair todas as páginas", "Extrair páginas específicas"], |
| | label="Modo", |
| | value="Extrair todas as páginas", |
| | ), |
| | gr.Textbox( |
| | label="Páginas (se usar 'Específicas')", |
| | placeholder="Ex.: 3 - 5 - 10", |
| | ), |
| | gr.Dropdown(choices=FORMATOS, value=FORMATOS[0], label="Formato das imagens"), |
| | ], |
| | outputs=[ |
| | gr.Gallery(label="Imagens"), |
| | gr.File(label="ZIP com as imagens"), |
| | ], |
| | title="Extrator de Imagens de PDF", |
| | allow_flagging="never", |
| | theme=THEME, |
| | css=CUSTOM_CSS, |
| | ) |
| |
|
| | if __name__ == "__main__": |
| | demo.launch() |
| |
|