Spaces:
Sleeping
Sleeping
""" | |
Copyright (c) 2024 Jesse Stucker aka "ghost logic" | |
All rights reserved. Proprietary and confidential. | |
This AI gaming platform is proprietary software. | |
Commercial use requires separate license. | |
Contact: [email protected] | |
For commercial licensing inquiries, visit: https://www.linkedin.com/in/jesse-stucker-49839a90/ | |
""" | |
# app.py - D&D Campaign and Character Creator with AI Agents | |
import gradio as gr | |
import logging | |
from typing import Dict, List, Tuple, Optional | |
import json | |
import os | |
from dotenv import load_dotenv | |
from dataclasses import dataclass | |
from enum import Enum | |
import random | |
# Load environment variables | |
load_dotenv() | |
# Set up logging | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
# Load OpenAI API key | |
try: | |
import openai | |
api_key = os.getenv("OPENAI_API_KEY") | |
if api_key: | |
openai.api_key = api_key | |
logger.info("β OpenAI API key loaded") | |
else: | |
logger.warning("β οΈ No OpenAI API key found") | |
except ImportError: | |
logger.warning("β οΈ OpenAI package not installed") | |
# ===== DATA MODELS ===== | |
class Alignment(Enum): | |
LAWFUL_GOOD = "Lawful Good" | |
NEUTRAL_GOOD = "Neutral Good" | |
CHAOTIC_GOOD = "Chaotic Good" | |
LAWFUL_NEUTRAL = "Lawful Neutral" | |
TRUE_NEUTRAL = "True Neutral" | |
CHAOTIC_NEUTRAL = "Chaotic Neutral" | |
LAWFUL_EVIL = "Lawful Evil" | |
NEUTRAL_EVIL = "Neutral Evil" | |
CHAOTIC_EVIL = "Chaotic Evil" | |
class Character: | |
name: str | |
race: str | |
character_class: str | |
level: int | |
gender: str | |
alignment: Alignment | |
abilities: Dict[str, int] | |
hit_points: int | |
skills: List[str] | |
background: str | |
backstory: str | |
portrait_url: Optional[str] = None | |
# ===== AI AGENT CLASSES ===== | |
class DungeonMasterAgent: | |
"""AI agent that acts as a Dungeon Master""" | |
def __init__(self): | |
self.personality = "Creative, fair, and engaging storyteller" | |
def _get_proprietary_prompt(self, **kwargs): | |
""" | |
Proprietary prompt engineering system - DEMONSTRATION VERSION | |
Commercial version includes advanced optimization and techniques. | |
Contact: [email protected] | |
""" | |
theme = kwargs.get('theme', 'High Fantasy') | |
level = kwargs.get('level', 1) | |
player_count = kwargs.get('player_count', 4) | |
return f"""As an experienced D&D Dungeon Master, create a campaign concept for: | |
Theme: {theme} | |
Starting Player Level: {level} | |
Number of Players: {player_count} | |
Provide: | |
1. Campaign Name | |
2. Core Plot Hook (2-3 sentences) | |
3. Main Antagonist | |
4. 3 Key Locations | |
5. Central Conflict | |
6. Estimated Campaign Length | |
Make it engaging and ready to play!""" | |
def generate_campaign_concept(self, theme: str, level: int, player_count: int) -> Dict: | |
"""Generate a complete campaign concept""" | |
try: | |
from openai import OpenAI | |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) | |
prompt = self._get_proprietary_prompt(theme=theme, level=level, player_count=player_count) | |
response = client.chat.completions.create( | |
model="gpt-4", | |
messages=[{"role": "system", "content": "You are an expert D&D Dungeon Master with 20 years of experience."}, | |
{"role": "user", "content": prompt}], | |
max_tokens=500, | |
temperature=0.8 | |
) | |
return {"success": True, "content": response.choices[0].message.content} | |
except Exception as e: | |
logger.error(f"Campaign generation failed: {e}") | |
return {"success": False, "error": str(e), "content": f"Demo Campaign: {theme} adventure for {player_count} level {level} characters"} | |
class NPCAgent: | |
"""AI agent specialized in creating NPCs""" | |
def __init__(self): | |
self.personality = "Versatile character actor" | |
def _get_proprietary_prompt(self, **kwargs): | |
""" | |
Proprietary NPC generation system - DEMONSTRATION VERSION | |
Commercial version includes advanced personality algorithms. | |
Contact: [email protected] | |
""" | |
context = kwargs.get('context', 'fantasy tavern') | |
role = kwargs.get('role', 'neutral') | |
gender = kwargs.get('gender', '') | |
gender_text = f"Gender: {gender}" if gender else "Gender: Choose appropriate gender" | |
return f"""Create a detailed NPC for D&D: | |
Setting: {context} | |
Role: {role} | |
{gender_text} | |
Generate: | |
1. Name and demographics | |
2. Personality traits (3-4 key traits) | |
3. Background and motivation | |
4. Physical description | |
5. Speech patterns | |
6. Secret or hidden agenda | |
Make them memorable and three-dimensional!""" | |
def generate_npc(self, context: str, role: str, importance: str, gender: str = "") -> Dict: | |
"""Generate a detailed NPC""" | |
try: | |
from openai import OpenAI | |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) | |
prompt = self._get_proprietary_prompt(context=context, role=role, gender=gender) | |
response = client.chat.completions.create( | |
model="gpt-4", | |
messages=[{"role": "system", "content": "You are an expert at creating memorable NPCs for D&D campaigns."}, | |
{"role": "user", "content": prompt}], | |
max_tokens=400, | |
temperature=0.8 | |
) | |
return {"success": True, "content": response.choices[0].message.content} | |
except Exception as e: | |
logger.error(f"NPC generation failed: {e}") | |
return {"success": False, "error": str(e), "content": f"Demo NPC: {gender if gender else 'Character'} {role} for {context}"} | |
# ===== CHARACTER CREATOR ===== | |
class CharacterCreator: | |
"""Character creator with basic D&D functionality""" | |
def __init__(self): | |
self.classes = ["Fighter", "Wizard", "Rogue", "Cleric", "Barbarian", "Bard", "Druid", "Monk", "Paladin", "Ranger", "Sorcerer", "Warlock"] | |
self.races = ["Human", "Elf", "Dwarf", "Halfling", "Dragonborn", "Gnome", "Half-Elf", "Half-Orc", "Tiefling"] | |
self.backgrounds = ["Acolyte", "Criminal", "Folk Hero", "Noble", "Sage", "Soldier", "Charlatan", "Entertainer", "Guild Artisan", "Hermit", "Outlander", "Sailor"] | |
def roll_ability_scores(self) -> Dict[str, int]: | |
"""Roll 4d6, drop lowest, for each ability score""" | |
abilities = {} | |
for ability in ["Strength", "Dexterity", "Constitution", "Intelligence", "Wisdom", "Charisma"]: | |
rolls = [random.randint(1, 6) for _ in range(4)] | |
rolls.sort(reverse=True) | |
abilities[ability] = sum(rolls[:3]) | |
return abilities | |
# ===== IMAGE GENERATION ===== | |
def generate_image(prompt: str) -> str: | |
"""Generate image using OpenAI DALL-E""" | |
try: | |
from openai import OpenAI | |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) | |
response = client.images.generate( | |
model="dall-e-3", | |
prompt=prompt, | |
size="1024x1024", | |
quality="standard", | |
n=1, | |
) | |
return response.data[0].url | |
except Exception as e: | |
logger.error(f"Image generation failed: {e}") | |
return "https://via.placeholder.com/512x512/dc2626/ffffff?text=Image+Generation+Failed" | |
# ===== MAIN INTERFACE ===== | |
def create_main_interface(): | |
"""Create the main D&D Campaign Manager interface""" | |
# Initialize agents | |
dm_agent = DungeonMasterAgent() | |
npc_agent = NPCAgent() | |
character_creator = CharacterCreator() | |
with gr.Blocks(title="D&D Campaign Manager") as demo: | |
gr.Markdown(""" | |
# π° Advanced D&D Campaign Manager | |
β οΈ **PROPRIETARY SOFTWARE - Demo Version** | |
*Professional AI gaming platform available for commercial licensing* | |
π§ **Commercial License:** [email protected] | |
π **Copyright:** Β© 2024 Jesse Stucker - All Rights Reserved | |
πΌ **LinkedIn:** https://www.linkedin.com/in/jesse-stucker-49839a90/ | |
**Platform Features:** | |
- π AI Dungeon Master Assistant | |
- π₯ Intelligent NPC Creator & Roleplay | |
- πΊοΈ World Builder Agent | |
- π° Loot Master & Magic Item Designer | |
- π Enhanced Character Creator | |
- β‘ Deity & Pantheon Generator | |
*This demonstration showcases proprietary AI coordination technology* | |
**Note:** This is a demonstration version. Commercial version includes advanced optimization, enhanced algorithms, and enterprise features. | |
""") | |
with gr.Tabs(): | |
# ===== CHARACTER CREATOR TAB ===== | |
with gr.TabItem("π Character Creator"): | |
with gr.Row(): | |
with gr.Column(scale=2): | |
gr.Markdown("## π Character Details") | |
character_name = gr.Textbox(label="Character Name", placeholder="Enter name...") | |
with gr.Row(): | |
race_dropdown = gr.Dropdown(choices=character_creator.races, label="Race", value="Human") | |
class_dropdown = gr.Dropdown(choices=character_creator.classes, label="Class", value="Fighter") | |
gender_dropdown = gr.Dropdown( | |
choices=["Male", "Female", "Non-binary", "Other"], | |
label="Gender", value="Male" | |
) | |
with gr.Row(): | |
level_slider = gr.Slider(minimum=1, maximum=20, step=1, value=1, label="Level") | |
alignment_dropdown = gr.Dropdown( | |
choices=[alignment.value for alignment in Alignment], | |
label="Alignment", value=Alignment.LAWFUL_GOOD.value | |
) | |
background_dropdown = gr.Dropdown(choices=character_creator.backgrounds, label="Background", value="Folk Hero") | |
# Ability Scores | |
gr.Markdown("## π² Ability Scores") | |
roll_btn = gr.Button("π² Roll Ability Scores", variant="primary") | |
with gr.Row(): | |
str_score = gr.Number(label="Strength", value=10, precision=0) | |
dex_score = gr.Number(label="Dexterity", value=10, precision=0) | |
con_score = gr.Number(label="Constitution", value=10, precision=0) | |
with gr.Row(): | |
int_score = gr.Number(label="Intelligence", value=10, precision=0) | |
wis_score = gr.Number(label="Wisdom", value=10, precision=0) | |
cha_score = gr.Number(label="Charisma", value=10, precision=0) | |
with gr.Column(scale=1): | |
gr.Markdown("## π Character Summary") | |
character_summary = gr.Markdown("*Roll ability scores to see summary*") | |
gr.Markdown("## π¨ Character Portrait") | |
portrait_btn = gr.Button("π¨ Generate AI Portrait", variant="primary") | |
character_portrait = gr.Image(label="Portrait", height=300) | |
# ===== CAMPAIGN CREATOR TAB ===== | |
with gr.TabItem("π AI Dungeon Master"): | |
gr.Markdown("## π― Campaign Generation") | |
with gr.Row(): | |
with gr.Column(): | |
campaign_theme = gr.Dropdown( | |
choices=["High Fantasy", "Dark Fantasy", "Urban Fantasy", "Steampunk", "Horror", "Comedy", "Political Intrigue", "Exploration"], | |
label="Campaign Theme", value="High Fantasy" | |
) | |
campaign_level = gr.Slider(minimum=1, maximum=20, value=5, label="Starting Level") | |
player_count = gr.Slider(minimum=1, maximum=8, value=4, label="Number of Players") | |
generate_campaign_btn = gr.Button("π² Generate Campaign Concept", variant="primary", size="lg") | |
with gr.Column(): | |
campaign_visual_btn = gr.Button("πΌοΈ Generate Campaign Art") | |
campaign_image = gr.Image(label="Campaign Visual", height=300) | |
campaign_output = gr.Textbox(label="Campaign Concept", lines=10) | |
# ===== NPC CREATOR TAB ===== | |
with gr.TabItem("π₯ NPC Agent"): | |
gr.Markdown("## π NPC Creator") | |
with gr.Row(): | |
with gr.Column(): | |
gr.Markdown("### Create New NPC") | |
npc_context = gr.Textbox(label="Campaign/Scene Context", placeholder="Describe the setting...") | |
npc_role = gr.Dropdown( | |
choices=["Ally", "Neutral", "Antagonist", "Quest Giver", "Merchant", "Authority Figure"], | |
label="NPC Role", value="Neutral" | |
) | |
npc_importance = gr.Dropdown( | |
choices=["Minor", "Moderate", "Major", "Recurring"], | |
label="Importance Level", value="Moderate" | |
) | |
npc_gender = gr.Dropdown( | |
choices=["", "Male", "Female", "Non-binary", "Other"], | |
label="Gender (Optional)", value="" | |
) | |
create_npc_btn = gr.Button("π Generate NPC", variant="primary") | |
npc_portrait_btn = gr.Button("π¨ Generate NPC Portrait") | |
npc_portrait = gr.Image(label="NPC Portrait", height=300) | |
with gr.Column(): | |
npc_output = gr.Textbox(label="Generated NPC", lines=12) | |
# ===== EVENT HANDLERS ===== | |
def roll_abilities(): | |
abilities = character_creator.roll_ability_scores() | |
return ( | |
abilities["Strength"], abilities["Dexterity"], abilities["Constitution"], | |
abilities["Intelligence"], abilities["Wisdom"], abilities["Charisma"] | |
) | |
def update_character_summary(name, race, char_class, level, gender, alignment, | |
str_val, dex_val, con_val, int_val, wis_val, cha_val, background): | |
if not all([str_val, dex_val, con_val, int_val, wis_val, cha_val]): | |
return "*Roll ability scores to see summary*" | |
summary = f"""**{name or "Unnamed Character"}** | |
*Level {level} {gender} {race} {char_class} ({alignment})* | |
**Ability Scores:** | |
- STR: {int(str_val)} ({(int(str_val) - 10) // 2:+d}) | |
- DEX: {int(dex_val)} ({(int(dex_val) - 10) // 2:+d}) | |
- CON: {int(con_val)} ({(int(con_val) - 10) // 2:+d}) | |
- INT: {int(int_val)} ({(int(int_val) - 10) // 2:+d}) | |
- WIS: {int(wis_val)} ({(int(wis_val) - 10) // 2:+d}) | |
- CHA: {int(cha_val)} ({(int(cha_val) - 10) // 2:+d}) | |
**Background:** {background}""" | |
return summary | |
def generate_character_portrait(name, race, char_class, gender): | |
if not name: | |
return "Please enter a character name first" | |
prompt = f"Fantasy portrait of a {gender.lower()} {race.lower()} {char_class.lower()}, professional D&D character art" | |
return generate_image(prompt) | |
def generate_campaign_concept(theme, level, players): | |
result = dm_agent.generate_campaign_concept(theme, level, players) | |
return result.get("content", "Error generating campaign") | |
def generate_campaign_art(theme, level): | |
prompt = f"{theme} D&D campaign art for level {level} adventurers, epic fantasy illustration" | |
return generate_image(prompt) | |
def create_npc(context, role, importance, gender): | |
result = npc_agent.generate_npc(context, role, importance, gender) | |
return result.get("content", "Error creating NPC") | |
def generate_npc_portrait(npc_data): | |
if not npc_data: | |
prompt = "Fantasy portrait of a D&D NPC character, detailed face, professional RPG art" | |
else: | |
prompt = f"Fantasy portrait of a D&D NPC character, detailed face, professional RPG art" | |
return generate_image(prompt) | |
# Wire up events | |
roll_btn.click(roll_abilities, outputs=[str_score, dex_score, con_score, int_score, wis_score, cha_score]) | |
# Update character summary when inputs change | |
for component in [character_name, race_dropdown, class_dropdown, level_slider, gender_dropdown, | |
alignment_dropdown, str_score, dex_score, con_score, int_score, wis_score, cha_score, background_dropdown]: | |
component.change( | |
update_character_summary, | |
inputs=[character_name, race_dropdown, class_dropdown, level_slider, gender_dropdown, alignment_dropdown, | |
str_score, dex_score, con_score, int_score, wis_score, cha_score, background_dropdown], | |
outputs=[character_summary] | |
) | |
portrait_btn.click( | |
generate_character_portrait, | |
inputs=[character_name, race_dropdown, class_dropdown, gender_dropdown], | |
outputs=[character_portrait] | |
) | |
generate_campaign_btn.click( | |
generate_campaign_concept, | |
inputs=[campaign_theme, campaign_level, player_count], | |
outputs=[campaign_output] | |
) | |
campaign_visual_btn.click( | |
generate_campaign_art, | |
inputs=[campaign_theme, campaign_level], | |
outputs=[campaign_image] | |
) | |
create_npc_btn.click( | |
create_npc, | |
inputs=[npc_context, npc_role, npc_importance, npc_gender], | |
outputs=[npc_output] | |
) | |
npc_portrait_btn.click( | |
generate_npc_portrait, | |
inputs=[npc_output], | |
outputs=[npc_portrait] | |
) | |
return demo | |
# Main entry point | |
if __name__ == "__main__": | |
logger.info("π° Starting Advanced D&D Campaign Manager...") | |
# Check for OpenAI API key | |
api_key = os.getenv("OPENAI_API_KEY") | |
if api_key: | |
logger.info("β OpenAI API key found - All AI features enabled!") | |
else: | |
logger.warning("β οΈ No OpenAI API key found - AI features will be limited") | |
logger.info("π‘ Add OPENAI_API_KEY as a repository secret in HF Spaces settings") | |
demo = create_main_interface() | |
try: | |
demo.launch( | |
share=False, | |
inbrowser=False | |
) | |
logger.info("π App launched successfully!") | |
except Exception as e: | |
logger.error(f"β Launch failed: {e}") | |
demo.launch() |