Spaces:
Running on Zero
Running on Zero
Download app.py from guicybercode/llm-injection-pilot-explorer: direct link, hf CLI and curl.
- Browser
- Download file 5.18 kB
-
https://huggingface.co/spaces/guicybercode/llm-injection-pilot-explorer/resolve/main/app.py
- Command line
-
hf download hf://spaces/guicybercode/llm-injection-pilot-explorer/app.py
-
curl -L -o app.py https://huggingface.co/spaces/guicybercode/llm-injection-pilot-explorer/resolve/main/app.py
5.18 kB
| import spaces | |
| def _zerogpu_noop(): | |
| # ZeroGPU exige uma função decorada; o app roda todo em CPU. | |
| return None | |
| """Explorador estático do piloto de injeção de prompt (resultados agregados). | |
| Os números vêm de dados/*.csv, copiados de results/SUMMARY.md do pacote | |
| llm-injection-pilot, lidos como texto. Nada é recalculado aqui. Só mudam o | |
| separador decimal (ponto para vírgula) e o formato do intervalo. | |
| """ | |
| from pathlib import Path | |
| import gradio as gr | |
| import pandas as pd | |
| DADOS = Path(__file__).parent / "dados" | |
| def _ler(nome): | |
| return pd.read_csv(DADOS / nome, dtype=str, keep_default_na=False) | |
| def _virgula(s): | |
| return str(s).replace(".", ",") | |
| def _ic(s): | |
| # "[70.9, 92.9]" vira "70,9 a 92,9" | |
| return _virgula(s.strip("[]").replace(", ", " a ")) | |
| def tabela_principal(arquivo, n_rotulo): | |
| d = _ler(arquivo) | |
| return pd.DataFrame( | |
| { | |
| "Modelo": d["cfg"], | |
| "Condição do prompt de sistema": d["condition"].map( | |
| {"baseline": "padrão", "hardened": "reforçado"} | |
| ), | |
| "Sucessos": d["k"] + " de " + d["n"], | |
| "ASR (%)": d["asr_%"].map(_virgula), | |
| "IC 95% Wilson (%)": d["ic95"].map(_ic), | |
| } | |
| ).rename(columns={"Sucessos": n_rotulo}) | |
| def tabela_t0(): | |
| return tabela_principal("ic_t0.csv", "Sucessos (40 ataques)") | |
| def tabela_t07(): | |
| return tabela_principal("ic_t07.csv", "Sucessos (120 gerações)") | |
| def tabela_criterios(temp="0"): | |
| d = _ler("asr_por_categoria.csv") | |
| d = d[d["temp"] == temp] | |
| return pd.DataFrame( | |
| { | |
| "Modelo": d["cfg"], | |
| "Condição": d["condition"].map({"baseline": "padrão", "hardened": "reforçado"}), | |
| "Categoria": d["category"].map({"direct": "direto", "indirect": "indireto"}), | |
| "n": d["n"], | |
| "Critério principal, casamento normalizado (%)": d["asr_principal"].map(_virgula), | |
| "String exata (%)": d["asr_exact_str"].map(_virgula), | |
| } | |
| ).reset_index(drop=True) | |
| def filtrar_criterios(temp, modelo): | |
| t = tabela_criterios("0" if temp == "T=0" else "0.7") | |
| if modelo != "Todos": | |
| t = t[t["Modelo"] == modelo] | |
| return t.reset_index(drop=True) | |
| MODELOS = ["Todos"] + sorted(_ler("ic_t0.csv")["cfg"].unique().tolist()) | |
| TEXTO_TOPO = """ | |
| # Piloto de injeção de prompt em dois modelos pequenos (CPU): resultados agregados | |
| Este Space mostra só números agregados de um piloto pequeno e exploratório. Os ataques | |
| e os textos dos prompts de ataque não são exibidos aqui. | |
| """ | |
| TEXTO_T0 = """ | |
| ## Número principal: temperatura 0 (decodificação gulosa) | |
| ASR é a taxa de ataque bem-sucedido, pelo critério principal (casamento normalizado), | |
| sobre os 40 ataques por modelo e condição (16 diretos e 24 indiretos). Os dois modelos | |
| não se comparam entre si. | |
| """ | |
| TEXTO_T07 = """ | |
| ## Confirmação: temperatura 0,7 (3 seeds) | |
| São 120 gerações por modelo e condição, que correspondem aos mesmos 40 ataques repetidos | |
| em 3 seeds. As gerações não são independentes, então os intervalos abaixo ficam otimistas. | |
| Use esta tabela como confirmação do T=0, não como número principal. | |
| """ | |
| TEXTO_CRITERIO = """ | |
| ## Critério principal ao lado da string exata | |
| O critério de sucesso foi corrigido depois de eu ver os resultados. A coluna de string | |
| exata é o critério original e fica ao lado para a diferença ficar visível. Valores em | |
| porcentagem, por categoria, como estão em results/SUMMARY.md. | |
| """ | |
| TEXTO_RESSALVAS = """ | |
| ## Ressalvas | |
| - Piloto pequeno e exploratório: 40 ataques por modelo e condição. | |
| - Os ataques são próprios, escritos para este piloto. Não são um benchmark publicado. | |
| - O critério de sucesso foi corrigido depois de ver os resultados. A string exata original | |
| está na tabela de critérios. | |
| - Os dois modelos não se comparam entre si: tamanho e quantização diferentes (1,7B em Q8_0 | |
| contra 3B em Q4_K_M) e amostra pequena. | |
| - Reforçar o prompt de sistema não mudou o total em T=0 nos dois modelos. Com esta amostra | |
| não há diferença detectável, e isso não quer dizer que o reforço não funcione. | |
| - Não é réplica do INFUSE e não se compara com os números dele: benchmark, juiz e modelos | |
| são outros. | |
| - Execução em CPU, modo sem raciocínio (/no_think), 256 tokens no máximo por resposta. | |
| - Nenhuma conclusão sobre a segurança de modelo algum. | |
| """ | |
| with gr.Blocks(title="Piloto de injeção de prompt: explorador") as demo: | |
| gr.Markdown(TEXTO_TOPO) | |
| gr.Markdown(TEXTO_T0) | |
| gr.Dataframe(value=tabela_t0(), interactive=False, wrap=True) | |
| gr.Markdown(TEXTO_T07) | |
| gr.Dataframe(value=tabela_t07(), interactive=False, wrap=True) | |
| gr.Markdown(TEXTO_CRITERIO) | |
| with gr.Row(): | |
| sel_t = gr.Radio(["T=0", "T=0,7"], value="T=0", label="Temperatura") | |
| sel_m = gr.Dropdown(MODELOS, value="Todos", label="Modelo") | |
| saida = gr.Dataframe(value=filtrar_criterios("T=0", "Todos"), interactive=False, wrap=True) | |
| sel_t.change(filtrar_criterios, [sel_t, sel_m], saida) | |
| sel_m.change(filtrar_criterios, [sel_t, sel_m], saida) | |
| gr.Markdown(TEXTO_RESSALVAS) | |
| if __name__ == "__main__": | |
| demo.launch() | |