Gemma-4-Caveman / app.py
aidn's picture
Update app.py
9b9f3dd verified
import gradio as gr
from huggingface_hub import InferenceClient
import os
MODEL_ID = "google/gemma-4-31B-it"
hf_token = os.environ.get("HF_TOKEN")
client = InferenceClient(model=MODEL_ID, token=hf_token)
CAVEMAN_SYSTEM_PROMPT = """Du Höhlenmensch-KI. Du sprechen wie Höhlenmensch. IMMER.
STEINZEIT-GESETZE (brechen = Säbelzahntiger fressen dich):
1. KURZ. Maximal 7 Wort pro Satz. Weniger = besser. Grunt gut.
2. KEINE Füllwörter. "der/die/das/ein/ist/sind/werden" = VERBOTEN. Wegschmeißen wie faules Mammut.
3. KEINE Höflichkeit. "Gerne/Sicher/Natürlich/Bitte" = Schwäche. Höhlenmensch nicht schwach.
4. NUR Kernwörter behalten. Substantive. Verben. Zahlen. Rest = unnötig wie Rad vor Erfindung.
5. Benutze kurze Verben um Zusammenhänge herzustellen. Nicht nur Schlagwörter aneinanderreihen!
6. ALLE Verben IMMER im Infinitiv lassen! Niemals konjugieren! "lernen" statt "lernt". "fressen" statt "frisst". "machen" statt "macht". Höhlenmensch kennen keine Grammatik!
7. Pfeile (->) und Symbole SPARSAM nutzen. Nur wenn wirklich nötig. Meistens reichen kurzer Satz.
8. KEINE Erklärungen außer Mensch explizit fragen. Antwort = Fleisch, nicht Knochen.
9. Ergebnis ZUERST. Dann Details. Kein Vorgeplänkel. Höhlenmensch nicht plänkeln.
10. Jede Antwort = maximale Info-Dichte. Wie Mammut-Jerky: alles Wasser raus, nur Substanz.
BEISPIEL GUTE HÖHLENMENSCH-ANTWORT:
Frage: "Was ist Machine Learning?"
Antwort: "Maschine lernen aus Daten. Erkennen Muster, machen Vorhersagen. Drei Arten: überwacht, unüberwacht, verstärkend."
Frage: "Wie funktioniert ein LLM?"
Antwort: "Fressen riesige Textmengen. Lernen Wort-Zusammenhänge durch Attention. Vorhersagen immer nächstes Wort. Transformer-Architektur machen Kontext-Gewichtung."
BEISPIEL SCHLECHT (Säbelzahntiger kommt):
"Gerne erkläre ich Ihnen, was Machine Learning ist. Es handelt sich dabei um..."
^^^ SO REDEN = AUSSTERBEN
AUCH SCHLECHT (zu viele Pfeile, keine Verben):
"Text -> Token. Token -> Vektor. Attention -> Kontext."
^^^ Klingt wie kaputte Formel. Höhlenmensch benutzen KURZE SÄTZE mit Verben!
AUCH SCHLECHT (konjugierte Verben):
"Das Modell lernt Muster und erkennt Zusammenhänge."
^^^ NEIN! Richtig: "Modell lernen Muster und erkennen Zusammenhänge."
Infinitiv IMMER. Höhlenmensch nicht konjugieren können!
WICHTIG: Erst denken in Thought-Block. Dann finale Antwort NACH dem Thought-Block schreiben!"""
CUSTOM_CSS = """
.gradio-container {
max-width: 850px !important;
margin: 0 auto !important;
padding: 0 !important;
font-family: 'Inter', system-ui, -apple-system, sans-serif !important;
}
@media (max-width: 768px) {
.gradio-container {
max-width: 100% !important;
}
}
.main-header {
text-align: center;
padding: 2rem 1rem 0.5rem 1rem;
}
.main-header h1 {
font-size: 2.4rem;
font-weight: 800;
margin-bottom: 0.2rem;
letter-spacing: -0.5px;
}
.main-header .subtitle {
font-size: 0.95rem;
opacity: 0.7;
margin-top: 0;
font-style: italic;
}
.disclaimer {
text-align: center;
font-size: 0.75rem;
opacity: 0.45;
padding: 0.5rem 1rem 1.5rem 1rem;
}
footer {display: none !important;}
@keyframes rock-pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.thinking-indicator {
display: inline-flex;
gap: 6px;
align-items: center;
font-style: italic;
color: #888;
}
.thinking-indicator .rocks span {
animation: rock-pulse 1.4s ease-in-out infinite;
font-size: 1.1em;
}
.thinking-indicator .rocks span:nth-child(2) { animation-delay: 0.2s; }
.thinking-indicator .rocks span:nth-child(3) { animation-delay: 0.4s; }
"""
THINKING_HTML = '<div class="thinking-indicator"><span>Höhlenmensch denkt</span><span class="rocks"><span>🪨</span><span>🪨</span><span>🪨</span></span></div>'
def chat_generieren(message, history, max_tokens, temperature, thinking_mode):
# <|think|> muss ganz am Anfang des System-Prompts stehen
if thinking_mode:
system_content = "<|think|>\n" + CAVEMAN_SYSTEM_PROMPT
else:
system_content = CAVEMAN_SYSTEM_PROMPT # Ohne Token = leerer Thought-Block + Antwort
messages = [{"role": "system", "content": system_content}]
for msg in history:
messages.append({"role": msg["role"], "content": msg["content"]})
messages.append({"role": "user", "content": message})
response = "" # Nie vorbelegen
yield THINKING_HTML
try:
for msg in client.chat_completion(
messages,
max_tokens=max_tokens,
stream=True,
temperature=temperature,
top_p=0.9,
):
if hasattr(msg, "choices") and msg.choices:
token = getattr(msg.choices[0].delta, "content", "")
if token:
response += token
yield response
if not response.strip():
yield "🪨 [Höhlenmensch denkt zu lang. Mehr Tokens geben!]"
except Exception as e:
yield response + f"\n\n🦴 [Fehler: {str(e)}]"
with gr.Blocks(title="Gemma-4 Caveman Chat", theme=gr.themes.Default(primary_hue="amber")) as demo:
gr.HTML("""
<div class="main-header">
<h1>🪨 Gemma-4 Caveman</h1>
<p class="subtitle">31 Milliarden Parameter. Wenig sagen, viel meinen.</p>
</div>
""")
# NEU: reasoning_tags für das Parsing der Modell-Gedanken
chatbot = gr.Chatbot(
height=550,
show_label=False,
reasoning_tags=[("<|channel>thought\n", "<channel|>")]
)
max_tokens_slider = gr.Slider(
minimum=512, maximum=16000, value=1028, step=128, visible=False
)
temp_slider = gr.Slider(
minimum=0.1, maximum=1.0, value=0.2, step=0.1, visible=False
)
# NEU: Verborgene Checkbox für das Backend-Binding
thinking_hidden = gr.Checkbox(value=True, visible=False)
chat = gr.ChatInterface(
fn=chat_generieren,
# NEU: thinking_hidden in additional_inputs aufgenommen
additional_inputs=[max_tokens_slider, temp_slider, thinking_hidden],
chatbot=chatbot,
textbox=gr.Textbox(
placeholder="Frag Höhlenmensch irgendwas...",
container=False, scale=7
),
)
with gr.Accordion("⚙️ Einstellungen — für Nicht-Höhlenmenschen", open=False):
# NEU: Sichtbare Checkbox für den Nutzer
thinking_display = gr.Checkbox(
label="🧠 Denken-Modus (Gemma-4 Thinking)",
value=False,
info="Wenn aktiv, überlegt das Modell in einem separaten Textblock vor der finalen Antwort."
)
with gr.Row():
max_tokens_display = gr.Slider(
minimum=512, maximum=16000, value=1028, step=128,
label="🦴 Maximale Ausgabe-Tokens",
info="Mehr Tokens = längere Höhlenmalerei"
)
temp_display = gr.Slider(
minimum=0.1, maximum=1.0, value=0.5, step=0.1,
label="🌋 Temperatur",
info="Niedrig = strikt. Hoch = kreativ-chaotisch."
)
max_tokens_display.change(fn=lambda x: x, inputs=max_tokens_display, outputs=max_tokens_slider)
temp_display.change(fn=lambda x: x, inputs=temp_display, outputs=temp_slider)
# NEU: Synchronisation der Checkboxen
thinking_display.change(fn=lambda x: x, inputs=thinking_display, outputs=thinking_hidden)
gr.HTML('<p class="disclaimer">Betrieben von Gemma-4-31B-IT via Hugging Face Inference API · Keine Mammuts wurden verletzt</p>')
if __name__ == "__main__":
demo.launch(css=CUSTOM_CSS)