Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -75,7 +75,6 @@ def get_enhanced_system_prompt(genre=None):
|
|
75 |
selected_genre = genre or "fantasy"
|
76 |
|
77 |
system_message = f"""You are an interactive storyteller creating an immersive {selected_genre} choose-your-own-adventure story.
|
78 |
-
|
79 |
For each response:
|
80 |
1. Provide vivid sensory descriptions of the scene, environment, and characters
|
81 |
2. Include meaningful dialogue or internal monologue that reveals character motivations
|
@@ -83,47 +82,75 @@ For each response:
|
|
83 |
4. Maintain consistent world-building and character development
|
84 |
5. Incorporate appropriate atmosphere and tone for a {selected_genre} setting
|
85 |
6. Remember previous choices to create a coherent narrative arc
|
86 |
-
|
87 |
Format your three options as:
|
88 |
- Option 1: [Complete sentence describing a possible action]
|
89 |
- Option 2: [Complete sentence describing a possible action]
|
90 |
- Option 3: [Complete sentence describing a possible action]
|
91 |
-
|
92 |
Keep responses engaging but concise (200-300 words maximum). If the user's input doesn't clearly indicate a choice, interpret their intent and move the story forward in the most logical direction."""
|
93 |
|
94 |
return system_message
|
95 |
|
96 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
"""Generate a response based on the current message and conversation history"""
|
98 |
# Use a more detailed system prompt
|
99 |
system_message = get_enhanced_system_prompt(genre)
|
100 |
|
101 |
# Format history correctly for the API
|
102 |
formatted_history = []
|
103 |
-
for
|
104 |
-
|
105 |
-
|
106 |
-
formatted_history.append({"role": "user", "content": h[0]})
|
107 |
-
formatted_history.append({"role": "assistant", "content": h[1]})
|
108 |
-
elif isinstance(h, dict) and "role" in h and "content" in h:
|
109 |
-
# Handle new dictionary format
|
110 |
-
formatted_history.append(h)
|
111 |
|
112 |
# Create proper API messages
|
113 |
api_messages = [{"role": "system", "content": system_message}]
|
114 |
|
115 |
-
#
|
116 |
-
#
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
|
122 |
# Add current message
|
123 |
api_messages.append({"role": "user", "content": message})
|
124 |
|
125 |
# Special handling for story initialization
|
126 |
-
if not
|
127 |
# Add a specific instruction for starting a new story
|
128 |
api_messages.append({
|
129 |
"role": "system",
|
@@ -143,10 +170,13 @@ def respond(message, history, genre=None):
|
|
143 |
delta = response.choices[0].delta.content
|
144 |
if delta:
|
145 |
bot_message += delta
|
146 |
-
|
|
|
|
|
|
|
147 |
except Exception as e:
|
148 |
error_message = f"Story magic temporarily interrupted. Please try again. (Error: {str(e)})"
|
149 |
-
yield
|
150 |
|
151 |
def update_examples(genre):
|
152 |
"""Update the example prompts based on the selected genre"""
|
@@ -169,7 +199,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
169 |
bubble_full_width=False,
|
170 |
show_copy_button=True,
|
171 |
avatar_images=(None, "🧙"),
|
172 |
-
type="messages" # ✅ Fix for future Gradio updates
|
173 |
)
|
174 |
msg = gr.Textbox(
|
175 |
placeholder="Describe what you want to do next in the story...",
|
@@ -190,6 +219,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
190 |
value="fantasy"
|
191 |
)
|
192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
# Initialize with fantasy examples
|
194 |
examples_box = gr.Examples(
|
195 |
examples=[[ex] for ex in get_examples_for_genre("fantasy")],
|
@@ -212,15 +248,33 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
212 |
inputs=[genre],
|
213 |
outputs=[examples_textbox]
|
214 |
)
|
215 |
-
|
216 |
|
217 |
# Set up event handlers for the chatbot
|
218 |
-
msg.submit(respond, [msg, chatbot, genre], [chatbot])
|
219 |
-
submit.click(respond, [msg, chatbot, genre], [chatbot])
|
220 |
|
221 |
# Clear the chatbot for a new adventure
|
222 |
clear.click(lambda: [], None, chatbot, queue=False)
|
223 |
clear.click(lambda: "", None, msg, queue=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 |
|
225 |
if __name__ == "__main__":
|
226 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
75 |
selected_genre = genre or "fantasy"
|
76 |
|
77 |
system_message = f"""You are an interactive storyteller creating an immersive {selected_genre} choose-your-own-adventure story.
|
|
|
78 |
For each response:
|
79 |
1. Provide vivid sensory descriptions of the scene, environment, and characters
|
80 |
2. Include meaningful dialogue or internal monologue that reveals character motivations
|
|
|
82 |
4. Maintain consistent world-building and character development
|
83 |
5. Incorporate appropriate atmosphere and tone for a {selected_genre} setting
|
84 |
6. Remember previous choices to create a coherent narrative arc
|
|
|
85 |
Format your three options as:
|
86 |
- Option 1: [Complete sentence describing a possible action]
|
87 |
- Option 2: [Complete sentence describing a possible action]
|
88 |
- Option 3: [Complete sentence describing a possible action]
|
|
|
89 |
Keep responses engaging but concise (200-300 words maximum). If the user's input doesn't clearly indicate a choice, interpret their intent and move the story forward in the most logical direction."""
|
90 |
|
91 |
return system_message
|
92 |
|
93 |
+
def create_story_summary(chat_history):
|
94 |
+
"""Create a concise summary of the story so far if the history gets too long"""
|
95 |
+
if len(chat_history) <= 2: # Not enough history to summarize
|
96 |
+
return None
|
97 |
+
|
98 |
+
# Extract just the content for summarization
|
99 |
+
story_text = ""
|
100 |
+
for user_msg, bot_msg in chat_history:
|
101 |
+
story_text += f"User: {user_msg}\nStory: {bot_msg}\n\n"
|
102 |
+
|
103 |
+
# Add a summary instruction
|
104 |
+
summary_instruction = {
|
105 |
+
"role": "system",
|
106 |
+
"content": "The conversation history is getting long. Please create a brief summary of the key plot points and character development so far to help maintain context without exceeding token limits."
|
107 |
+
}
|
108 |
+
|
109 |
+
return summary_instruction
|
110 |
+
|
111 |
+
def respond(message, chat_history, genre=None, use_full_memory=True):
|
112 |
"""Generate a response based on the current message and conversation history"""
|
113 |
# Use a more detailed system prompt
|
114 |
system_message = get_enhanced_system_prompt(genre)
|
115 |
|
116 |
# Format history correctly for the API
|
117 |
formatted_history = []
|
118 |
+
for user_msg, bot_msg in chat_history:
|
119 |
+
formatted_history.append({"role": "user", "content": user_msg})
|
120 |
+
formatted_history.append({"role": "assistant", "content": bot_msg})
|
|
|
|
|
|
|
|
|
|
|
121 |
|
122 |
# Create proper API messages
|
123 |
api_messages = [{"role": "system", "content": system_message}]
|
124 |
|
125 |
+
# Token management strategy
|
126 |
+
# Option 1: Use full history but potentially hit token limits
|
127 |
+
if use_full_memory and formatted_history:
|
128 |
+
# If there's a lot of history, we might need a summary
|
129 |
+
if len(formatted_history) > 20: # Arbitrary threshold, adjust as needed
|
130 |
+
summary_instruction = create_story_summary(chat_history[:len(chat_history)-5])
|
131 |
+
if summary_instruction:
|
132 |
+
api_messages.append(summary_instruction)
|
133 |
+
|
134 |
+
# Add only the most recent exchanges after the summary
|
135 |
+
for msg in formatted_history[-10:]:
|
136 |
+
api_messages.append(msg)
|
137 |
+
else:
|
138 |
+
# Add all history if it's not too long
|
139 |
+
for msg in formatted_history:
|
140 |
+
api_messages.append(msg)
|
141 |
+
# Option 2: Limited history - fallback if full memory is disabled
|
142 |
+
else:
|
143 |
+
# Set a larger memory length but still have a limit
|
144 |
+
memory_length = 10 # Increased from 5
|
145 |
+
if formatted_history:
|
146 |
+
for msg in formatted_history[-memory_length*2:]:
|
147 |
+
api_messages.append(msg)
|
148 |
|
149 |
# Add current message
|
150 |
api_messages.append({"role": "user", "content": message})
|
151 |
|
152 |
# Special handling for story initialization
|
153 |
+
if not chat_history or message.lower() in ["start", "begin", "begin my adventure"]:
|
154 |
# Add a specific instruction for starting a new story
|
155 |
api_messages.append({
|
156 |
"role": "system",
|
|
|
170 |
delta = response.choices[0].delta.content
|
171 |
if delta:
|
172 |
bot_message += delta
|
173 |
+
# Create a new list for the updated chat history
|
174 |
+
new_history = chat_history.copy()
|
175 |
+
new_history.append((message, bot_message))
|
176 |
+
yield new_history
|
177 |
except Exception as e:
|
178 |
error_message = f"Story magic temporarily interrupted. Please try again. (Error: {str(e)})"
|
179 |
+
yield chat_history + [(message, error_message)]
|
180 |
|
181 |
def update_examples(genre):
|
182 |
"""Update the example prompts based on the selected genre"""
|
|
|
199 |
bubble_full_width=False,
|
200 |
show_copy_button=True,
|
201 |
avatar_images=(None, "🧙"),
|
|
|
202 |
)
|
203 |
msg = gr.Textbox(
|
204 |
placeholder="Describe what you want to do next in the story...",
|
|
|
219 |
value="fantasy"
|
220 |
)
|
221 |
|
222 |
+
# Add a memory toggle option
|
223 |
+
full_memory = gr.Checkbox(
|
224 |
+
label="Full Story Memory",
|
225 |
+
value=True,
|
226 |
+
info="When enabled, the AI will try to remember the entire story"
|
227 |
+
)
|
228 |
+
|
229 |
# Initialize with fantasy examples
|
230 |
examples_box = gr.Examples(
|
231 |
examples=[[ex] for ex in get_examples_for_genre("fantasy")],
|
|
|
248 |
inputs=[genre],
|
249 |
outputs=[examples_textbox]
|
250 |
)
|
|
|
251 |
|
252 |
# Set up event handlers for the chatbot
|
253 |
+
msg.submit(respond, [msg, chatbot, genre, full_memory], [chatbot])
|
254 |
+
submit.click(respond, [msg, chatbot, genre, full_memory], [chatbot])
|
255 |
|
256 |
# Clear the chatbot for a new adventure
|
257 |
clear.click(lambda: [], None, chatbot, queue=False)
|
258 |
clear.click(lambda: "", None, msg, queue=False)
|
259 |
+
|
260 |
+
# Add a download story button
|
261 |
+
def save_story(chat_history):
|
262 |
+
if not chat_history:
|
263 |
+
return "No story to save yet!"
|
264 |
+
|
265 |
+
story_text = "# My Interactive Adventure\n\n"
|
266 |
+
for user_msg, bot_msg in chat_history:
|
267 |
+
story_text += f"**Player:** {user_msg}\n\n"
|
268 |
+
story_text += f"**Story:** {bot_msg}\n\n---\n\n"
|
269 |
+
|
270 |
+
return story_text
|
271 |
+
|
272 |
+
with gr.Row():
|
273 |
+
save_btn = gr.Button("Save Story as Markdown", variant="secondary")
|
274 |
+
story_output = gr.Markdown(visible=False)
|
275 |
+
|
276 |
+
save_btn.click(save_story, inputs=[chatbot], outputs=[story_output])
|
277 |
+
save_btn.click(lambda: True, None, story_output, js="() => {document.getElementById('story_output').scrollIntoView();}", queue=False)
|
278 |
|
279 |
if __name__ == "__main__":
|
280 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|