Spaces:
Running
Running
| 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) |