""" 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: official.ghost.logic@gmail.com 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" @dataclass 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: official.ghost.logic@gmail.com """ 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: official.ghost.logic@gmail.com """ 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:** official.ghost.logic@gmail.com 🔒 **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()