File size: 6,982 Bytes
16c8bb1
 
 
 
8362100
16c8bb1
56fee53
4cff81a
866e648
56fee53
8362100
866e648
8362100
 
494dcd4
 
33d1e4c
 
8362100
 
 
 
494dcd4
 
33d1e4c
8362100
 
 
 
494dcd4
 
33d1e4c
8362100
494dcd4
 
8362100
494dcd4
8362100
494dcd4
8362100
 
 
 
494dcd4
8362100
494dcd4
8362100
 
 
33d1e4c
 
 
8362100
33d1e4c
8362100
 
33d1e4c
8362100
33d1e4c
 
 
 
866e648
494dcd4
33d1e4c
 
866e648
33d1e4c
8362100
 
 
 
 
 
 
 
33d1e4c
8362100
 
 
 
 
 
 
 
 
 
 
 
0452b8d
 
33d1e4c
494dcd4
33d1e4c
494dcd4
 
 
866e648
33d1e4c
866e648
56fee53
866e648
33d1e4c
866e648
56fee53
 
33d1e4c
0452b8d
866e648
0452b8d
 
 
 
 
866e648
0452b8d
 
866e648
0452b8d
33d1e4c
0452b8d
 
866e648
33d1e4c
866e648
0452b8d
866e648
 
56fee53
 
 
494dcd4
56fee53
33d1e4c
 
0452b8d
56fee53
8362100
33d1e4c
8362100
494dcd4
 
33d1e4c
 
 
494dcd4
866e648
8362100
 
33d1e4c
 
494dcd4
 
 
866e648
33d1e4c
8362100
16c8bb1
866e648
0452b8d
 
33d1e4c
 
0452b8d
 
 
33d1e4c
 
0452b8d
16c8bb1
866e648
16c8bb1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import os
import gradio as gr
from huggingface_hub import InferenceClient

# Token aus den Hugging Face Secrets laden
token = os.environ.get("HF_TOKEN")
text_client = InferenceClient("google/gemma-1.1-7b-it", token=token)
# Wir brauchen SDXL Turbo für extrem schnelle Bilder am Handy!
bild_client = InferenceClient("stabilityai/sdxl-turbo", token=token)

# Unser neues, ultra-atmosphärisches CSS (Gestaltungscode)
# Wir fügen die Styles für das gestapelte Logbuch hinzu.
geiles_design = """
@import url('https://fonts.googleapis.com/css2?family=Special+Elite&display=swap');

body, .gradio-container { 
    /* Düsteres Apokalypse-Hintergrundbild aus dem Netz */
    background-image: url('https://images.unsplash.com/photo-1485603099951-40344d18721c?q=80&w=2000&auto=format&fit=crop') !important;
    background-size: cover !important;
    background-position: center !important;
    background-attachment: fixed !important;
    font-family: sans-serif;
}

/* Der Hauptbereich wird schwarz und leicht durchsichtig */
.haupt-bereich {
    background: rgba(0, 0, 0, 0.7) !important; 
    border-radius: 10px;
    padding: 20px !important;
    max-width: 800px !important;
    margin: 0 auto !important;
    backdrop-filter: blur(3px); /* Macht das Hintergrundbild leicht unscharf */
    border: 1px solid rgba(255, 255, 255, 0.1);
}

h1 { color: #d4af37 !important; text-align: center; text-transform: uppercase; font-size: 2.5em !important; text-shadow: 2px 2px 4px #000; margin-bottom: 20px !important;}

/* Der Rucksack */
.rucksack-anzeige {
    background: rgba(0, 0, 0, 0.8) !important;
    border: 1px solid #8b0000 !important;
    padding: 12px !important;
    color: #d4af37 !important;
    text-align: center;
    border-radius: 5px;
    margin-bottom: 20px !important;
    font-weight: bold;
}

/* Der Notizzettel für die Story! */
.notizzettel { 
    background: #e3dec6 !important; /* Schmutzige Papier-Farbe */
    color: #1a1a1a !important; 
    font-family: 'Special Elite', monospace !important; /* Echte Schreibmaschinen-Schrift */
    font-size: 1.3em !important; 
    line-height: 1.6 !important; 
    padding: 25px !important; 
    border-radius: 2px !important;
    box-shadow: 3px 3px 15px rgba(0,0,0,0.8) !important;
    transform: rotate(-1deg); /* Leichte Drehung für den echten Zettel-Look */
    margin: 20px 5px !important;
    border-left: 4px solid #8b0000 !important; /* Roter Rand */
}

/* Rahmen für das generierte Bild */
.output-bild { border: 2px solid #555 !important; border-radius: 3px !important; box-shadow: 0 5px 15px rgba(0,0,0,0.9) !important;}

/* Eingabefeld durchsichtig machen */
input, textarea { 
    background: rgba(0, 0, 0, 0.6) !important; 
    color: #fff !important; 
    border: 1px solid #8b0000 !important; 
    font-size: 1.2em !important;
    border-radius: 5px !important;
}

/* Aggressiver Action-Button */
button { 
    background: #8b0000 !important; 
    color: #fff !important; 
    border: none !important; 
    font-weight: bold !important; 
    text-transform: uppercase !important; 
    font-size: 1.2em !important; 
    padding: 12px !important; 
    border-radius: 5px !important;
    box-shadow: 0 4px 6px rgba(0,0,0,0.6) !important;
}
button:hover { background: #aa0000 !important; }
"""

def spiel_zug(nachricht, aktueller_rucksack):
    if not nachricht:
        return None, "Du musst schon was tun!", aktueller_rucksack, f"🎒 INVENTAR: {aktueller_rucksack}", ""

    system_prompt = f"""Du bist 'Zombie Go'.
    Inventar des Spielers: {aktueller_rucksack}.
    Regel: Der Spieler darf NUR Dinge nutzen, die im Inventar sind. Erfinde keine Waffen für ihn.
    Füge neu gefundene Gegenstände oder gesammeltes 'Go' logisch zum Rucksack hinzu.
    Aktion des Spielers: '{nachricht}'.
    
    Antworte EXAKT in dieser Form (ohne Ausnahmen):
    STORY: [Beschreibe in max 3 spannenden Sätzen, was passiert]
    RUCKSACK: [Liste der Items] | GO: [Anzahl]"""
    
    try:
        antwort = text_client.text_generation(system_prompt, max_new_tokens=200)
        
        # Split (Text zerteilen): Wir trennen Story und Rucksack am Wort "RUCKSACK:"
        if "RUCKSACK:" in antwort:
            teile = antwort.split("RUCKSACK:")
            story_text = teile[0].replace("STORY:", "").strip()
            neuer_rucksack = teile[1].strip()
        else:
            # Falls die KI den Befehl vermasselt, behalten wir den alten Rucksack
            story_text = antwort.replace("STORY:", "").strip()
            neuer_rucksack = aktueller_rucksack
            
    except Exception as e:
        story_text = "Die Verbindung stottert... die KI schnappt nach Luft."
        neuer_rucksack = aktueller_rucksack
        
    # Bild-KI (SDXL Turbo - EXTREM SCHNELL!)
    # Wir fügen düstere englische Begriffe hinzu, damit die KI das Zombie-Go-Thema versteht
    bild_prompt = f"dark zombie apocalypse survival scene, first person view, {nachricht}, eerie green lighting from glowing crystals, highly detailed, realistic texture, derelict ruined city, atmospheric"
    try:
        # SDXL Turbo braucht extrem wenige Schritte und ist fast sofort fertig!
        bild = bild_client.text_to_image(bild_prompt, num_inference_steps=1)
    except:
        bild = None

    rucksack_ui_text = f"🎒 INVENTAR: {neuer_rucksack}"
    
    # Gibt alles zurück: Chat, Bild, leeres Textfeld, schicke Anzeige, unsichtbarer Speicher
    return bild, story_text, neuer_rucksack, rucksack_ui_text, ""


with gr.Blocks(css=geiles_design, theme=gr.themes.Base()) as spiel_oberflaeche:
    # Wir geben dem Haupt-Bereich die CSS-Klasse 'haupt-bereich'
    with gr.Column(elem_classes="haupt-bereich"):
        gr.Markdown("# 🧟 ZOMBIE GO")
        
        # State (unsichtbarer Speicher) für deinen Start-Rucksack
        rucksack_speicher = gr.State("Taschenlampe, leere Wasserflasche | GO: 0")
        rucksack_ui = gr.Markdown("🎒 INVENTAR: Taschenlampe, leere Wasserflasche | GO: 0", elem_classes="rucksack-anzeige")
        
        # Das generierte Bild
        szene_bild = gr.Image(label="Visuelles Echo", type="pil", elem_classes="output-bild")
        
        # Der Notizzettel für die Story!
        story_ausgabe = gr.Markdown("*Warte auf Eingabe... (Tipp: 'Umschauen')*", elem_classes="notizzettel")
        
        gr.Markdown("---")
        
        # Eingabe-Bereich
        eingabe = gr.Textbox(label="", placeholder="Was tust du? (z.B. Zombies looten)", lines=1)
        senden_btn = gr.Button("▶ AKTION EINTRAGEN")

    # Verknüpfungen der Knöpfe (wichtige Reihenfolge der Outputs!)
    senden_btn.click(
        spiel_zug, 
        inputs=[eingabe, rucksack_speicher], 
        outputs=[szene_bild, story_ausgabe, rucksack_speicher, rucksack_ui, eingabe]
    )
    eingabe.submit(
        spiel_zug, 
        inputs=[eingabe, rucksack_speicher], 
        outputs=[szene_bild, story_ausgabe, rucksack_speicher, rucksack_ui, eingabe]
    )

# Startet das Game
spiel_oberflaeche.launch()