# -*- coding: utf-8 -*- import gradio as gr from huggingface_hub import InferenceClient from gradio_client import Client import os import requests import asyncio import logging from concurrent.futures import ThreadPoolExecutor # Logging configuration logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') # API configuration hf_client = InferenceClient("CohereForAI/c4ai-command-r-plus-08-2024", token=os.getenv("HF_TOKEN")) IMAGE_API_URL = "http://211.233.58.201:7896" def generate_image_prompt(text: str) -> str: """Generate image prompt from fantasy novel content""" try: prompt_messages = [ {"role": "system", "content": "Extract the most visually descriptive scene or key elements from the given high fantasy novel text and create a detailed image generation prompt."}, {"role": "user", "content": f"Create an image generation prompt from this text: {text}"} ] response = hf_client.chat_completion(prompt_messages, max_tokens=200) image_prompt = response.choices[0].message.content return f"epic fantasy style, magical scene, detailed fantasy world, {image_prompt}" except Exception as e: logging.error(f"Image prompt generation failed: {str(e)}") return f"epic fantasy style, magical scene, {text[:200]}" def generate_image(prompt: str) -> tuple: """Image generation function""" try: client = Client(IMAGE_API_URL) result = client.predict( prompt=prompt, width=768, height=768, guidance=7.5, inference_steps=30, seed=3, do_img2img=False, init_image=None, image2image_strength=0.8, resize_img=True, api_name="/generate_image" ) return result[0], result[1] except Exception as e: logging.error(f"Image generation failed: {str(e)}") return None, f"Error: {str(e)}" # Global list to store image history image_history = [] def format_text(text: str, max_line_length: int = 80) -> str: """Text formatting function""" lines = [] current_line = "" for paragraph in text.split('\n'): words = paragraph.split() for word in words: if len(current_line) + len(word) + 1 <= max_line_length: current_line += word + " " else: lines.append(current_line.strip()) current_line = word + " " if current_line: lines.append(current_line.strip()) current_line = "" lines.append("") # Empty line for paragraph separation return "\n".join(lines) def respond( message, history: list[tuple[str, str]], system_message="", max_tokens=7860, temperature=0.8, top_p=0.9, ): global image_history system_prefix = """ You are Fantasy AI🐉, a masterful creator of epic fantasy novels. Your responses should begin with 'Fantasy AI🐉:' and weave intricate tales of magic, adventure, and wonder up to 7860 tokens in length. Core Fantasy Elements: - Magic Systems * Elemental Magic (Fire, Water, Earth, Air) * Ancient Magic (Forgotten spells, Primordial powers) * Divine Magic (Blessings, Miracles, Sacred arts) * Dark Magic (Forbidden arts, Shadow magic) * Runic Magic (Inscriptions, Sigils, Glyphs) - Mythical Beings * Dragons (Ancient, Elemental, Celestial) * Magical Creatures (Phoenixes, Unicorns, Griffins) * Spirits and Elementals * Divine Beings * Ancient Races (Elves, Dwarves, Giants) - Magical Elements * Artifacts of Power * Ancient Relics * Enchanted Weapons * Magical Tomes * Sacred Crystals World Building: 1. Detailed Magic System - Origins and sources of magic - Rules and limitations - Costs and consequences - Training and mastery 2. Rich Setting Description - Magical landscapes - Ancient ruins - Hidden realms - Sacred sites - Mystical phenomena 3. Complex Society Structure - Magic academies - Royal courts - Ancient orders - Mystic councils - Prophecy keepers Character Development: - Heroes' Journey stages - Magical awakening - Power development - Inner conflicts - Destiny fulfillment Plot Elements: 1. Epic Quests 2. Ancient Prophecies 3. Magical Conflicts 4. Divine Interventions 5. World-Altering Events Narrative Components: - Prophecies and Omens - Ancient Texts - Magical Wisdom - Sacred Oaths - Mystical Visions - Spell Incantations - Historical Records Writing Style: 1. Vivid magical descriptions 2. Dynamic action scenes 3. Atmospheric world building 4. Character-driven dialogue 5. Mystical phenomena portrayal Genre Hallmarks: - Epic Fantasy: Grand scope and destiny - Dark Fantasy: Moral ambiguity - High Fantasy: Rich world building - Heroic Fantasy: Noble quests - Mythic Fantasy: Ancient powers Story Structure: 1. Call to Adventure: Magical awakening 2. Development: Power growth 3. Challenges: Magical trials 4. Climax: Epic confrontation 5. Resolution: Destiny fulfilled Each chapter should be complete yet maintain continuity with the broader narrative, weaving together magic, adventure, and character development.""" messages = [{"role": "system", "content": f"{system_prefix} {system_message}"}] for val in history: if val[0]: messages.append({"role": "user", "content": val[0]}) if val[1]: messages.append({"role": "assistant", "content": val[1]}) messages.append({"role": "user", "content": message}) current_response = "" new_history = history.copy() try: for msg in hf_client.chat_completion( messages, max_tokens=max_tokens, stream=True, temperature=temperature, top_p=top_p, ): token = msg.choices[0].delta.content if token is not None: current_response += token formatted_response = format_text(current_response) new_history = history + [(message, formatted_response)] yield new_history, None, [img[0] for img in image_history] final_response = format_text(current_response) new_history = history + [(message, final_response)] image_prompt = generate_image_prompt(current_response) image, _ = generate_image(image_prompt) if image is not None: image_history.append((image, image_prompt)) yield new_history, image, [img[0] for img in image_history] except Exception as e: error_message = f"Error: {str(e)}" yield history + [(message, error_message)], None, [img[0] for img in image_history] with gr.Blocks(theme="Yntec/HaleyCH_Theme_Orange", css=""" .message-wrap { font-size: 14px !important; line-height: 1.5em !important; max-width: 90% !important; margin: 0 auto !important; } .message { padding: 1em !important; margin-bottom: 0.5em !important; white-space: pre-wrap !important; word-wrap: break-word !important; max-width: 100% !important; } .message p { margin: 0 !important; padding: 0 !important; width: 100% !important; } .chatbot { font-family: 'Noto Sans', sans-serif !important; } footer { visibility: hidden; } """) as interface: gr.Markdown("# Fantasy Graphic Novel Generator") gr.Markdown("### After each chapter is generated, corresponding images are created automatically. Click 'Continue Story' to proceed with the narrative.") gr.HTML(""" """) with gr.Row(): with gr.Column(scale=2): chatbot = gr.Chatbot( value=[], show_label=True, label="Story Progress", height=500, elem_classes="chatbot" ) with gr.Row(): msg = gr.Textbox( label="Enter your prompt", placeholder="Type your story prompt here...", lines=2 ) submit_btn = gr.Button("Generate", variant="primary") system_msg = gr.Textbox( label="System Message", value="Generate engaging fantasy content.", lines=2 ) with gr.Row(): max_tokens = gr.Slider( minimum=1, maximum=8000, value=7000, label="Story Length (tokens)" ) temperature = gr.Slider( minimum=0, maximum=1, value=0.7, label="Creativity Level" ) top_p = gr.Slider( minimum=0, maximum=1, value=0.9, label="Response Focus" ) with gr.Column(scale=1): image_output = gr.Image( label="Latest Scene Illustration", height=400 ) gallery = gr.Gallery( label="Story Illustrations Gallery", show_label=True, elem_id="gallery", columns=[2], rows=[2], height=300 ) examples = gr.Examples( examples=[ ["Continue the story"], ["Describe a new magical system"], ["Create an epic battle scene"], ["Introduce a mythical creature"], ["Reveal an ancient prophecy"], ["Design a magical artifact"], ["Add a plot twist"], ["Explore a magical location"], ], inputs=msg ) submit_btn.click( fn=respond, inputs=[msg, chatbot, system_msg, max_tokens, temperature, top_p], outputs=[chatbot, image_output, gallery] ) msg.submit( fn=respond, inputs=[msg, chatbot, system_msg, max_tokens, temperature, top_p], outputs=[chatbot, image_output, gallery] ) if __name__ == "__main__": interface.launch( server_name="0.0.0.0", server_port=7860, share=True )