ghost-logic commited on
Commit
cc2d56b
Β·
verified Β·
1 Parent(s): 1ab7393

Upload 4 files

Browse files
Files changed (4) hide show
  1. LICENSE +26 -0
  2. README.md +121 -9
  3. app.py +473 -0
  4. requirements.txt +3 -0
LICENSE ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Proprietary License
2
+
3
+ Copyright (c) 2024 [Jesse Stucker aka "ghost logic."]
4
+
5
+ All Rights Reserved.
6
+
7
+ This AI gaming platform, including all code, prompts, algorithms,
8
+ documentation, and associated files, is proprietary intellectual property.
9
+
10
+ RESTRICTIONS:
11
+ - Commercial use prohibited without separate license
12
+ - No redistribution, modification, or derivative works
13
+ - No reverse engineering or decompilation
14
+ - All rights reserved by copyright holder
15
+
16
+ PERMITTED USE:
17
+ Personal, non-commercial evaluation and educational use only.
18
+
19
+ COMMERCIAL LICENSING:
20
+ Gaming studios, educational institutions, and commercial users must obtain
21
+ a separate commercial license.
22
+
23
+ For commercial licensing inquiries:
24
25
+ LinkedIn: https://www.linkedin.com/in/jesse-stucker-49839a90/
26
+ This software is provided "as is" without warranty of any kind.
README.md CHANGED
@@ -1,14 +1,126 @@
1
  ---
2
- title: Dungeon Smasher Lite
3
- emoji: πŸƒ
4
- colorFrom: indigo
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.35.0
8
  app_file: app.py
9
- pinned: false
10
- license: afl-3.0
11
- short_description: Create PCs and NPCs
 
 
 
 
 
 
 
 
 
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Dungeon Smasher
3
+ emoji: "πŸ‘"
4
+ colorFrom: yellow
5
+ colorTo: pink
6
  sdk: gradio
7
+ sdk_version: 5.33.1
8
  app_file: app.py
9
+ pinned: true
10
+ tags:
11
+ - agent-demo-track
12
+ - AI dungeon master
13
+ - procedural generation
14
+ - worldbuilding
15
+ - intelligent NPCs
16
+ - storytelling
17
+ - RPG
18
+ - multi-agent
19
+ thumbnail: >-
20
+ https://cdn-uploads.huggingface.co/production/uploads/683d2ec2540df93aae2532f4/Xagf2XzjnOEUZB-a1ofXZ.png
21
  ---
22
 
23
+
24
+ 🧠 Dungeon Smasher
25
+
26
+ An Agentic Toolkit for Dynamic RPG Storytelling
27
+ Built for the Hugging Face AI Agent Hackathon β€” Agent Demo Track
28
+ 🌟 Overview
29
+
30
+ Dungeon Smasher is an experimental AI toolkit for building intelligent, reactive RPG environments. Rather than a finished game, this is a modular agent demo showcasing five core systems:
31
+
32
+ 🎭 DM Assistant Β· πŸ‘₯ NPC Generator Β· πŸ—ΊοΈ World Builder Β· πŸ’° Loot Designer Β· πŸ‰ Character Creator
33
+
34
+ Each module uses LLM reasoning and symbolic world logic to help GMs and players co-create immersive adventuresβ€”no prep required.
35
+ βš™οΈ Core Features
36
+ Feature Description
37
+ 🎭 AI Dungeon Master Orchestrates scenes, conflicts, and roleplay hooks with dramatic tone
38
+ πŸ‘₯ NPC Generator Builds named characters with secrets, flaws, goals, and voice
39
+ πŸ—ΊοΈ World Builder Assembles regions, ruins, factions, and mythic histories
40
+ πŸ’° Loot Master Designs magical items that reflect player actions and narrative symbols
41
+ πŸ‰ Character Creator Generates heroes with stats, backstories, class synergy, and emotional arcs
42
+ πŸ§ͺ Demo Capabilities
43
+
44
+ βœ… Procedural setting, NPC, and loot generation
45
+ βœ… Modular agent logic with memory and context threading
46
+ βœ… Gradio-based interactive frontend for testing each system
47
+ βœ… Rich character builder with storytelling-first logic
48
+ βœ… Configurable, extensible, and fully open source
49
+ 🧭 Demo Suggestions
50
+
51
+ Explore the toolkit using these suggested flows:
52
+ πŸ§™ Dungeon Master Agent
53
+
54
+ Prompt with: "The players enter a ruined cathedral during a thunderstorm"
55
+
56
+ Watch it generate narrative tension, scene tone, and roleplay threads.
57
+
58
+ πŸ‘₯ NPC Generator
59
+
60
+ Prompt with: "a cursed knight guarding forgotten ruins"
61
+
62
+ Get a complex NPC with motives, secrets, and drama potential.
63
+
64
+ πŸ—ΊοΈ World Builder
65
+
66
+ Prompt with: "a coastal nation obsessed with prophecy"
67
+
68
+ Generates factions, politics, threats, and lore.
69
+
70
+ πŸ’° Loot Master
71
+
72
+ Prompt with: "a cursed artifact from a sunken temple"
73
+
74
+ Produces symbolic, story-linked loot tied to in-game values.
75
+
76
+ πŸ‰ Character Creator
77
+
78
+ Prompt with: "A storm sorcerer who fears their own power"
79
+
80
+ Returns stat blocks, class alignment, flaws, and heroic potential.
81
+
82
+ πŸ› οΈ Technologies
83
+
84
+ Gradio 5.33.1 β€” Live demo interface
85
+
86
+ OpenAI GPT-4 β€” Agent reasoning and generation
87
+
88
+ Python (modular) β€” Custom agent scaffolding and game logic
89
+
90
+ πŸš€ How to Run
91
+
92
+ git clone https://huggingface.co/spaces/YOUR_USERNAME/DungeonSmasher
93
+ cd DungeonSmasher
94
+
95
+ pip install -r requirements.txt
96
+ python app.py
97
+
98
+ Or view the live app at:
99
+ 🌐 https://huggingface.co/spaces/YOUR_USERNAME/DungeonSmasher
100
+ 🎯 Future Plans
101
+
102
+ Playable dungeon mode with live turn-based flow
103
+
104
+ AI narrator voice + dialogue puppeteering
105
+
106
+ Campaign memory and recurring characters
107
+
108
+ Dynamic player reputation, fear, and legacy
109
+
110
+ Fully voiced roleplay loop via multimodal input
111
+
112
+ πŸ“„ License
113
+
114
+ MIT License – Use freely, remix bravely.
115
+ πŸ’¬ Final Note to Judges
116
+
117
+ On Friday June 6th, I was unexpectedly terminated from my job. This wasn’t just a professional setback. It triggered a cascade of urgent and high-stakes responsibilities and I’ve spent the past several days filing legal responses and preparing to escalate claims of retaliation, IP theft, and unlawful recording. I’ve had to act as my own advocate, researcher, and legal strategist, at present.
118
+
119
+ This sudden derailment had a significant impact on my ability to finalize my hackathon submission. While I still submitted something, it reflects only a fraction of what I’d intended to build. I wanted to share this contextas an honest explanation of why my submission may seem incomplete or rushed and not as an excuse.
120
+
121
+ I’m grateful for the opportunity to bring this to life and for the space to create, even amidst personal crisis.
122
+
123
+
124
+ Sincerely,
125
+
126
+ β€” Jesse W. Stucker (ghost logic.)
app.py ADDED
@@ -0,0 +1,473 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copyright (c) 2024 Jesse Stucker aka "ghost logic"
3
+ All rights reserved. Proprietary and confidential.
4
+
5
+ This AI gaming platform is proprietary software.
6
+ Commercial use requires separate license.
7
+ Contact: [email protected]
8
+
9
+ For commercial licensing inquiries, visit: linkedin.com/in/jessetucker
10
+ """
11
+
12
+ # app.py - D&D Campaign and Character Creator with AI Agents
13
+
14
+ import gradio as gr
15
+ import logging
16
+ from typing import Dict, List, Tuple, Optional
17
+ import json
18
+ import os
19
+ from dotenv import load_dotenv
20
+ from dataclasses import dataclass
21
+ from enum import Enum
22
+ import random
23
+
24
+ # Load environment variables
25
+ load_dotenv()
26
+
27
+ # Set up logging
28
+ logging.basicConfig(level=logging.INFO)
29
+ logger = logging.getLogger(__name__)
30
+
31
+ # Load OpenAI API key
32
+ try:
33
+ import openai
34
+ api_key = os.getenv("OPENAI_API_KEY")
35
+ if api_key:
36
+ openai.api_key = api_key
37
+ logger.info("βœ… OpenAI API key loaded")
38
+ else:
39
+ logger.warning("⚠️ No OpenAI API key found")
40
+ except ImportError:
41
+ logger.warning("⚠️ OpenAI package not installed")
42
+
43
+ # ===== DATA MODELS =====
44
+ class Alignment(Enum):
45
+ LAWFUL_GOOD = "Lawful Good"
46
+ NEUTRAL_GOOD = "Neutral Good"
47
+ CHAOTIC_GOOD = "Chaotic Good"
48
+ LAWFUL_NEUTRAL = "Lawful Neutral"
49
+ TRUE_NEUTRAL = "True Neutral"
50
+ CHAOTIC_NEUTRAL = "Chaotic Neutral"
51
+ LAWFUL_EVIL = "Lawful Evil"
52
+ NEUTRAL_EVIL = "Neutral Evil"
53
+ CHAOTIC_EVIL = "Chaotic Evil"
54
+
55
+ @dataclass
56
+ class Character:
57
+ name: str
58
+ race: str
59
+ character_class: str
60
+ level: int
61
+ gender: str
62
+ alignment: Alignment
63
+ abilities: Dict[str, int]
64
+ hit_points: int
65
+ skills: List[str]
66
+ background: str
67
+ backstory: str
68
+ portrait_url: Optional[str] = None
69
+
70
+ # ===== AI AGENT CLASSES =====
71
+ class DungeonMasterAgent:
72
+ """AI agent that acts as a Dungeon Master"""
73
+
74
+ def __init__(self):
75
+ self.personality = "Creative, fair, and engaging storyteller"
76
+
77
+ def _get_proprietary_prompt(self, **kwargs):
78
+ """
79
+ Proprietary prompt engineering system - DEMONSTRATION VERSION
80
+ Commercial version includes advanced optimization and techniques.
81
+ Contact: [email protected]
82
+ """
83
+ theme = kwargs.get('theme', 'High Fantasy')
84
+ level = kwargs.get('level', 1)
85
+ player_count = kwargs.get('player_count', 4)
86
+
87
+ return f"""As an experienced D&D Dungeon Master, create a campaign concept for:
88
+ Theme: {theme}
89
+ Starting Player Level: {level}
90
+ Number of Players: {player_count}
91
+
92
+ Provide:
93
+ 1. Campaign Name
94
+ 2. Core Plot Hook (2-3 sentences)
95
+ 3. Main Antagonist
96
+ 4. 3 Key Locations
97
+ 5. Central Conflict
98
+ 6. Estimated Campaign Length
99
+
100
+ Make it engaging and ready to play!"""
101
+
102
+ def generate_campaign_concept(self, theme: str, level: int, player_count: int) -> Dict:
103
+ """Generate a complete campaign concept"""
104
+ try:
105
+ from openai import OpenAI
106
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
107
+
108
+ prompt = self._get_proprietary_prompt(theme=theme, level=level, player_count=player_count)
109
+
110
+ response = client.chat.completions.create(
111
+ model="gpt-4",
112
+ messages=[{"role": "system", "content": "You are an expert D&D Dungeon Master with 20 years of experience."},
113
+ {"role": "user", "content": prompt}],
114
+ max_tokens=500,
115
+ temperature=0.8
116
+ )
117
+
118
+ return {"success": True, "content": response.choices[0].message.content}
119
+
120
+ except Exception as e:
121
+ logger.error(f"Campaign generation failed: {e}")
122
+ return {"success": False, "error": str(e), "content": f"Demo Campaign: {theme} adventure for {player_count} level {level} characters"}
123
+
124
+ class NPCAgent:
125
+ """AI agent specialized in creating NPCs"""
126
+
127
+ def __init__(self):
128
+ self.personality = "Versatile character actor"
129
+
130
+ def _get_proprietary_prompt(self, **kwargs):
131
+ """
132
+ Proprietary NPC generation system - DEMONSTRATION VERSION
133
+ Commercial version includes advanced personality algorithms.
134
+ Contact: [email protected]
135
+ """
136
+ context = kwargs.get('context', 'fantasy tavern')
137
+ role = kwargs.get('role', 'neutral')
138
+ gender = kwargs.get('gender', '')
139
+
140
+ gender_text = f"Gender: {gender}" if gender else "Gender: Choose appropriate gender"
141
+
142
+ return f"""Create a detailed NPC for D&D:
143
+ Setting: {context}
144
+ Role: {role}
145
+ {gender_text}
146
+
147
+ Generate:
148
+ 1. Name and demographics
149
+ 2. Personality traits (3-4 key traits)
150
+ 3. Background and motivation
151
+ 4. Physical description
152
+ 5. Speech patterns
153
+ 6. Secret or hidden agenda
154
+
155
+ Make them memorable and three-dimensional!"""
156
+
157
+ def generate_npc(self, context: str, role: str, importance: str, gender: str = "") -> Dict:
158
+ """Generate a detailed NPC"""
159
+ try:
160
+ from openai import OpenAI
161
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
162
+
163
+ prompt = self._get_proprietary_prompt(context=context, role=role, gender=gender)
164
+
165
+ response = client.chat.completions.create(
166
+ model="gpt-4",
167
+ messages=[{"role": "system", "content": "You are an expert at creating memorable NPCs for D&D campaigns."},
168
+ {"role": "user", "content": prompt}],
169
+ max_tokens=400,
170
+ temperature=0.8
171
+ )
172
+
173
+ return {"success": True, "content": response.choices[0].message.content}
174
+
175
+ except Exception as e:
176
+ logger.error(f"NPC generation failed: {e}")
177
+ return {"success": False, "error": str(e), "content": f"Demo NPC: {gender if gender else 'Character'} {role} for {context}"}
178
+
179
+ # ===== CHARACTER CREATOR =====
180
+ class CharacterCreator:
181
+ """Character creator with basic D&D functionality"""
182
+
183
+ def __init__(self):
184
+ self.classes = ["Fighter", "Wizard", "Rogue", "Cleric", "Barbarian", "Bard", "Druid", "Monk", "Paladin", "Ranger", "Sorcerer", "Warlock"]
185
+ self.races = ["Human", "Elf", "Dwarf", "Halfling", "Dragonborn", "Gnome", "Half-Elf", "Half-Orc", "Tiefling"]
186
+ self.backgrounds = ["Acolyte", "Criminal", "Folk Hero", "Noble", "Sage", "Soldier", "Charlatan", "Entertainer", "Guild Artisan", "Hermit", "Outlander", "Sailor"]
187
+
188
+ def roll_ability_scores(self) -> Dict[str, int]:
189
+ """Roll 4d6, drop lowest, for each ability score"""
190
+ abilities = {}
191
+ for ability in ["Strength", "Dexterity", "Constitution", "Intelligence", "Wisdom", "Charisma"]:
192
+ rolls = [random.randint(1, 6) for _ in range(4)]
193
+ rolls.sort(reverse=True)
194
+ abilities[ability] = sum(rolls[:3])
195
+ return abilities
196
+
197
+ # ===== IMAGE GENERATION =====
198
+ def generate_image(prompt: str) -> str:
199
+ """Generate image using OpenAI DALL-E"""
200
+ try:
201
+ from openai import OpenAI
202
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
203
+
204
+ response = client.images.generate(
205
+ model="dall-e-3",
206
+ prompt=prompt,
207
+ size="1024x1024",
208
+ quality="standard",
209
+ n=1,
210
+ )
211
+
212
+ return response.data[0].url
213
+
214
+ except Exception as e:
215
+ logger.error(f"Image generation failed: {e}")
216
+ return "https://via.placeholder.com/512x512/dc2626/ffffff?text=Image+Generation+Failed"
217
+
218
+ # ===== MAIN INTERFACE =====
219
+ def create_main_interface():
220
+ """Create the main D&D Campaign Manager interface"""
221
+
222
+ # Initialize agents
223
+ dm_agent = DungeonMasterAgent()
224
+ npc_agent = NPCAgent()
225
+ character_creator = CharacterCreator()
226
+
227
+ with gr.Blocks(title="D&D Campaign Manager") as demo:
228
+ gr.Markdown("""
229
+ # 🏰 Advanced D&D Campaign Manager
230
+
231
+ ⚠️ **PROPRIETARY SOFTWARE - Demo Version**
232
+
233
+ *Professional AI gaming platform available for commercial licensing*
234
+
235
+ πŸ“§ **Commercial License:** [email protected]
236
+ πŸ”’ **Copyright:** Β© 2024 Jesse Tucker - All Rights Reserved
237
+ πŸ’Ό **LinkedIn:** linkedin.com/in/jessetucker
238
+
239
+ **Platform Features:**
240
+ - 🎭 AI Dungeon Master Assistant
241
+ - πŸ‘₯ Intelligent NPC Creator & Roleplay
242
+ - πŸ—ΊοΈ World Builder Agent
243
+ - πŸ’° Loot Master & Magic Item Designer
244
+ - πŸ‰ Enhanced Character Creator
245
+ - ⚑ Deity & Pantheon Generator
246
+
247
+ *This demonstration showcases proprietary AI coordination technology*
248
+
249
+ **Note:** This is a demonstration version. Commercial version includes advanced optimization, enhanced algorithms, and enterprise features.
250
+ """)
251
+
252
+ with gr.Tabs():
253
+ # ===== CHARACTER CREATOR TAB =====
254
+ with gr.TabItem("πŸ‰ Character Creator"):
255
+ with gr.Row():
256
+ with gr.Column(scale=2):
257
+ gr.Markdown("## πŸ“ Character Details")
258
+
259
+ character_name = gr.Textbox(label="Character Name", placeholder="Enter name...")
260
+
261
+ with gr.Row():
262
+ race_dropdown = gr.Dropdown(choices=character_creator.races, label="Race", value="Human")
263
+ class_dropdown = gr.Dropdown(choices=character_creator.classes, label="Class", value="Fighter")
264
+ gender_dropdown = gr.Dropdown(
265
+ choices=["Male", "Female", "Non-binary", "Other"],
266
+ label="Gender", value="Male"
267
+ )
268
+
269
+ with gr.Row():
270
+ level_slider = gr.Slider(minimum=1, maximum=20, step=1, value=1, label="Level")
271
+ alignment_dropdown = gr.Dropdown(
272
+ choices=[alignment.value for alignment in Alignment],
273
+ label="Alignment", value=Alignment.LAWFUL_GOOD.value
274
+ )
275
+
276
+ background_dropdown = gr.Dropdown(choices=character_creator.backgrounds, label="Background", value="Folk Hero")
277
+
278
+ # Ability Scores
279
+ gr.Markdown("## 🎲 Ability Scores")
280
+ roll_btn = gr.Button("🎲 Roll Ability Scores", variant="primary")
281
+
282
+ with gr.Row():
283
+ str_score = gr.Number(label="Strength", value=10, precision=0)
284
+ dex_score = gr.Number(label="Dexterity", value=10, precision=0)
285
+ con_score = gr.Number(label="Constitution", value=10, precision=0)
286
+
287
+ with gr.Row():
288
+ int_score = gr.Number(label="Intelligence", value=10, precision=0)
289
+ wis_score = gr.Number(label="Wisdom", value=10, precision=0)
290
+ cha_score = gr.Number(label="Charisma", value=10, precision=0)
291
+
292
+ with gr.Column(scale=1):
293
+ gr.Markdown("## πŸ“Š Character Summary")
294
+ character_summary = gr.Markdown("*Roll ability scores to see summary*")
295
+
296
+ gr.Markdown("## 🎨 Character Portrait")
297
+ portrait_btn = gr.Button("🎨 Generate AI Portrait", variant="primary")
298
+ character_portrait = gr.Image(label="Portrait", height=300)
299
+
300
+ # ===== CAMPAIGN CREATOR TAB =====
301
+ with gr.TabItem("🎭 AI Dungeon Master"):
302
+ gr.Markdown("## 🎯 Campaign Generation")
303
+
304
+ with gr.Row():
305
+ with gr.Column():
306
+ campaign_theme = gr.Dropdown(
307
+ choices=["High Fantasy", "Dark Fantasy", "Urban Fantasy", "Steampunk", "Horror", "Comedy", "Political Intrigue", "Exploration"],
308
+ label="Campaign Theme", value="High Fantasy"
309
+ )
310
+ campaign_level = gr.Slider(minimum=1, maximum=20, value=5, label="Starting Level")
311
+ player_count = gr.Slider(minimum=1, maximum=8, value=4, label="Number of Players")
312
+
313
+ generate_campaign_btn = gr.Button("🎲 Generate Campaign Concept", variant="primary", size="lg")
314
+
315
+ with gr.Column():
316
+ campaign_visual_btn = gr.Button("πŸ–ΌοΈ Generate Campaign Art")
317
+ campaign_image = gr.Image(label="Campaign Visual", height=300)
318
+
319
+ campaign_output = gr.Textbox(label="Campaign Concept", lines=10)
320
+
321
+ # ===== NPC CREATOR TAB =====
322
+ with gr.TabItem("πŸ‘₯ NPC Agent"):
323
+ gr.Markdown("## 🎭 NPC Creator")
324
+
325
+ with gr.Row():
326
+ with gr.Column():
327
+ gr.Markdown("### Create New NPC")
328
+ npc_context = gr.Textbox(label="Campaign/Scene Context", placeholder="Describe the setting...")
329
+ npc_role = gr.Dropdown(
330
+ choices=["Ally", "Neutral", "Antagonist", "Quest Giver", "Merchant", "Authority Figure"],
331
+ label="NPC Role", value="Neutral"
332
+ )
333
+ npc_importance = gr.Dropdown(
334
+ choices=["Minor", "Moderate", "Major", "Recurring"],
335
+ label="Importance Level", value="Moderate"
336
+ )
337
+ npc_gender = gr.Dropdown(
338
+ choices=["", "Male", "Female", "Non-binary", "Other"],
339
+ label="Gender (Optional)", value=""
340
+ )
341
+
342
+ create_npc_btn = gr.Button("🎭 Generate NPC", variant="primary")
343
+
344
+ npc_portrait_btn = gr.Button("🎨 Generate NPC Portrait")
345
+ npc_portrait = gr.Image(label="NPC Portrait", height=300)
346
+
347
+ with gr.Column():
348
+ npc_output = gr.Textbox(label="Generated NPC", lines=12)
349
+
350
+ # ===== EVENT HANDLERS =====
351
+
352
+ def roll_abilities():
353
+ abilities = character_creator.roll_ability_scores()
354
+ return (
355
+ abilities["Strength"], abilities["Dexterity"], abilities["Constitution"],
356
+ abilities["Intelligence"], abilities["Wisdom"], abilities["Charisma"]
357
+ )
358
+
359
+ def update_character_summary(name, race, char_class, level, gender, alignment,
360
+ str_val, dex_val, con_val, int_val, wis_val, cha_val, background):
361
+ if not all([str_val, dex_val, con_val, int_val, wis_val, cha_val]):
362
+ return "*Roll ability scores to see summary*"
363
+
364
+ summary = f"""**{name or "Unnamed Character"}**
365
+ *Level {level} {gender} {race} {char_class} ({alignment})*
366
+
367
+ **Ability Scores:**
368
+ - STR: {int(str_val)} ({(int(str_val) - 10) // 2:+d})
369
+ - DEX: {int(dex_val)} ({(int(dex_val) - 10) // 2:+d})
370
+ - CON: {int(con_val)} ({(int(con_val) - 10) // 2:+d})
371
+ - INT: {int(int_val)} ({(int(int_val) - 10) // 2:+d})
372
+ - WIS: {int(wis_val)} ({(int(wis_val) - 10) // 2:+d})
373
+ - CHA: {int(cha_val)} ({(int(cha_val) - 10) // 2:+d})
374
+
375
+ **Background:** {background}"""
376
+
377
+ return summary
378
+
379
+ def generate_character_portrait(name, race, char_class, gender):
380
+ if not name:
381
+ return "Please enter a character name first"
382
+
383
+ prompt = f"Fantasy portrait of a {gender.lower()} {race.lower()} {char_class.lower()}, professional D&D character art"
384
+ return generate_image(prompt)
385
+
386
+ def generate_campaign_concept(theme, level, players):
387
+ result = dm_agent.generate_campaign_concept(theme, level, players)
388
+ return result.get("content", "Error generating campaign")
389
+
390
+ def generate_campaign_art(theme, level):
391
+ prompt = f"{theme} D&D campaign art for level {level} adventurers, epic fantasy illustration"
392
+ return generate_image(prompt)
393
+
394
+ def create_npc(context, role, importance, gender):
395
+ result = npc_agent.generate_npc(context, role, importance, gender)
396
+ return result.get("content", "Error creating NPC")
397
+
398
+ def generate_npc_portrait(npc_data):
399
+ if not npc_data:
400
+ prompt = "Fantasy portrait of a D&D NPC character, detailed face, professional RPG art"
401
+ else:
402
+ prompt = f"Fantasy portrait of a D&D NPC character, detailed face, professional RPG art"
403
+ return generate_image(prompt)
404
+
405
+ # Wire up events
406
+ roll_btn.click(roll_abilities, outputs=[str_score, dex_score, con_score, int_score, wis_score, cha_score])
407
+
408
+ # Update character summary when inputs change
409
+ for component in [character_name, race_dropdown, class_dropdown, level_slider, gender_dropdown,
410
+ alignment_dropdown, str_score, dex_score, con_score, int_score, wis_score, cha_score, background_dropdown]:
411
+ component.change(
412
+ update_character_summary,
413
+ inputs=[character_name, race_dropdown, class_dropdown, level_slider, gender_dropdown, alignment_dropdown,
414
+ str_score, dex_score, con_score, int_score, wis_score, cha_score, background_dropdown],
415
+ outputs=[character_summary]
416
+ )
417
+
418
+ portrait_btn.click(
419
+ generate_character_portrait,
420
+ inputs=[character_name, race_dropdown, class_dropdown, gender_dropdown],
421
+ outputs=[character_portrait]
422
+ )
423
+
424
+ generate_campaign_btn.click(
425
+ generate_campaign_concept,
426
+ inputs=[campaign_theme, campaign_level, player_count],
427
+ outputs=[campaign_output]
428
+ )
429
+
430
+ campaign_visual_btn.click(
431
+ generate_campaign_art,
432
+ inputs=[campaign_theme, campaign_level],
433
+ outputs=[campaign_image]
434
+ )
435
+
436
+ create_npc_btn.click(
437
+ create_npc,
438
+ inputs=[npc_context, npc_role, npc_importance, npc_gender],
439
+ outputs=[npc_output]
440
+ )
441
+
442
+ npc_portrait_btn.click(
443
+ generate_npc_portrait,
444
+ inputs=[npc_output],
445
+ outputs=[npc_portrait]
446
+ )
447
+
448
+ return demo
449
+
450
+ # Main entry point
451
+ if __name__ == "__main__":
452
+ logger.info("🏰 Starting Advanced D&D Campaign Manager...")
453
+
454
+ # Check for OpenAI API key
455
+ api_key = os.getenv("OPENAI_API_KEY")
456
+ if api_key:
457
+ logger.info("βœ… OpenAI API key found - All AI features enabled!")
458
+ else:
459
+ logger.warning("⚠️ No OpenAI API key found - AI features will be limited")
460
+ logger.info("πŸ’‘ Add OPENAI_API_KEY as a repository secret in HF Spaces settings")
461
+
462
+ demo = create_main_interface()
463
+
464
+ try:
465
+ demo.launch(
466
+ share=False,
467
+ inbrowser=False
468
+ )
469
+ logger.info("🌐 App launched successfully!")
470
+
471
+ except Exception as e:
472
+ logger.error(f"❌ Launch failed: {e}")
473
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+
2
+ gradio>=4.44.0
3
+ openai>=1.0.0