Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -73,7 +73,6 @@ def get_examples_for_genre(genre):
|
|
73 |
def get_enhanced_system_prompt(genre=None):
|
74 |
"""Generate a detailed system prompt with optional genre specification"""
|
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
|
@@ -87,90 +86,70 @@ Format your three options as:
|
|
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:
|
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 |
-
|
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 |
-
|
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",
|
157 |
-
"content": f"Begin a new {genre or 'fantasy'} adventure with an intriguing opening scene. Introduce the protagonist without assuming too much about them
|
158 |
})
|
159 |
|
160 |
-
# Generate and stream response
|
161 |
bot_message = ""
|
162 |
try:
|
163 |
-
for
|
164 |
api_messages,
|
165 |
max_tokens=512,
|
166 |
stream=True,
|
167 |
temperature=0.7,
|
168 |
top_p=0.95,
|
169 |
):
|
170 |
-
delta =
|
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
|
@@ -197,11 +176,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
197 |
|
198 |
with gr.Row():
|
199 |
with gr.Column(scale=3):
|
|
|
200 |
chatbot = gr.Chatbot(
|
201 |
height=500,
|
202 |
bubble_full_width=False,
|
203 |
show_copy_button=True,
|
204 |
avatar_images=(None, "🧙"),
|
|
|
205 |
)
|
206 |
msg = gr.Textbox(
|
207 |
placeholder="Describe what you want to do next in the story...",
|
@@ -222,62 +203,64 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
222 |
value="fantasy"
|
223 |
)
|
224 |
|
225 |
-
# Add a memory toggle option
|
226 |
full_memory = gr.Checkbox(
|
227 |
label="Full Story Memory",
|
228 |
value=True,
|
229 |
-
info="When enabled, the AI
|
230 |
)
|
231 |
|
232 |
-
# Create story starter buttons that automatically submit
|
233 |
gr.Markdown("## Story Starters")
|
234 |
-
story_starters = []
|
235 |
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
|
|
|
|
240 |
|
241 |
-
#
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
|
253 |
-
#
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
fn=
|
|
|
259 |
outputs=[msg],
|
260 |
queue=False
|
261 |
).then(
|
262 |
fn=respond,
|
263 |
inputs=[msg, chatbot, genre, full_memory],
|
264 |
-
outputs=[chatbot]
|
|
|
265 |
)
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
# Connect genre dropdown to update example buttons
|
274 |
-
genre.change(
|
275 |
-
fn=update_example_buttons,
|
276 |
-
inputs=[genre],
|
277 |
-
outputs=example_buttons
|
278 |
-
)
|
279 |
|
280 |
-
#
|
281 |
msg.submit(respond, [msg, chatbot, genre, full_memory], [chatbot])
|
282 |
submit.click(respond, [msg, chatbot, genre, full_memory], [chatbot])
|
283 |
|
@@ -285,13 +268,20 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
285 |
clear.click(lambda: [], None, chatbot, queue=False)
|
286 |
clear.click(lambda: "", None, msg, queue=False)
|
287 |
|
288 |
-
#
|
289 |
with gr.Row():
|
290 |
-
save_btn = gr.Button("
|
291 |
story_output = gr.Markdown(visible=False)
|
292 |
|
|
|
293 |
save_btn.click(save_story, inputs=[chatbot], outputs=[story_output])
|
294 |
-
save_btn.click(
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
|
296 |
if __name__ == "__main__":
|
297 |
-
demo.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
73 |
def get_enhanced_system_prompt(genre=None):
|
74 |
"""Generate a detailed system prompt with optional genre specification"""
|
75 |
selected_genre = genre or "fantasy"
|
|
|
76 |
system_message = f"""You are an interactive storyteller creating an immersive {selected_genre} choose-your-own-adventure story.
|
77 |
For each response:
|
78 |
1. Provide vivid sensory descriptions of the scene, environment, and characters
|
|
|
86 |
- Option 2: [Complete sentence describing a possible action]
|
87 |
- Option 3: [Complete sentence describing a possible action]
|
88 |
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."""
|
|
|
89 |
return system_message
|
90 |
|
91 |
def create_story_summary(chat_history):
|
92 |
"""Create a concise summary of the story so far if the history gets too long"""
|
93 |
+
if len(chat_history) <= 2:
|
94 |
return None
|
95 |
|
|
|
96 |
story_text = ""
|
97 |
for user_msg, bot_msg in chat_history:
|
98 |
story_text += f"User: {user_msg}\nStory: {bot_msg}\n\n"
|
99 |
|
|
|
100 |
summary_instruction = {
|
101 |
"role": "system",
|
102 |
"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."
|
103 |
}
|
|
|
104 |
return summary_instruction
|
105 |
|
106 |
def respond(message, chat_history, genre=None, use_full_memory=True):
|
107 |
"""Generate a response based on the current message and conversation history"""
|
|
|
108 |
system_message = get_enhanced_system_prompt(genre)
|
109 |
+
|
|
|
110 |
formatted_history = []
|
111 |
for user_msg, bot_msg in chat_history:
|
112 |
formatted_history.append({"role": "user", "content": user_msg})
|
113 |
formatted_history.append({"role": "assistant", "content": bot_msg})
|
114 |
|
|
|
115 |
api_messages = [{"role": "system", "content": system_message}]
|
116 |
|
|
|
|
|
117 |
if use_full_memory and formatted_history:
|
118 |
+
if len(formatted_history) > 20: # Arbitrary threshold
|
|
|
119 |
summary_instruction = create_story_summary(chat_history[:len(chat_history)-5])
|
120 |
if summary_instruction:
|
121 |
api_messages.append(summary_instruction)
|
|
|
|
|
122 |
for msg in formatted_history[-10:]:
|
123 |
api_messages.append(msg)
|
124 |
else:
|
|
|
125 |
for msg in formatted_history:
|
126 |
api_messages.append(msg)
|
|
|
127 |
else:
|
128 |
+
memory_length = 10
|
|
|
129 |
if formatted_history:
|
130 |
for msg in formatted_history[-memory_length*2:]:
|
131 |
api_messages.append(msg)
|
132 |
|
|
|
133 |
api_messages.append({"role": "user", "content": message})
|
134 |
|
|
|
135 |
if not chat_history or message.lower() in ["start", "begin", "begin my adventure"]:
|
|
|
136 |
api_messages.append({
|
137 |
"role": "system",
|
138 |
+
"content": f"Begin a new {genre or 'fantasy'} adventure with an intriguing opening scene. Introduce the protagonist without assuming too much about them."
|
139 |
})
|
140 |
|
|
|
141 |
bot_message = ""
|
142 |
try:
|
143 |
+
for response_chunk in client.chat_completion(
|
144 |
api_messages,
|
145 |
max_tokens=512,
|
146 |
stream=True,
|
147 |
temperature=0.7,
|
148 |
top_p=0.95,
|
149 |
):
|
150 |
+
delta = response_chunk.choices[0].delta.content
|
151 |
if delta:
|
152 |
bot_message += delta
|
|
|
153 |
new_history = chat_history.copy()
|
154 |
new_history.append((message, bot_message))
|
155 |
yield new_history
|
|
|
176 |
|
177 |
with gr.Row():
|
178 |
with gr.Column(scale=3):
|
179 |
+
# Chat window + user input
|
180 |
chatbot = gr.Chatbot(
|
181 |
height=500,
|
182 |
bubble_full_width=False,
|
183 |
show_copy_button=True,
|
184 |
avatar_images=(None, "🧙"),
|
185 |
+
type="messages" # Use OpenAI-style messages
|
186 |
)
|
187 |
msg = gr.Textbox(
|
188 |
placeholder="Describe what you want to do next in the story...",
|
|
|
203 |
value="fantasy"
|
204 |
)
|
205 |
|
|
|
206 |
full_memory = gr.Checkbox(
|
207 |
label="Full Story Memory",
|
208 |
value=True,
|
209 |
+
info="When enabled, the AI tries to remember the entire story. If disabled, only the last few exchanges are used."
|
210 |
)
|
211 |
|
|
|
212 |
gr.Markdown("## Story Starters")
|
|
|
213 |
|
214 |
+
# -- Create four placeholder buttons for story starters --
|
215 |
+
starter_btn1 = gr.Button("Starter 1")
|
216 |
+
starter_btn2 = gr.Button("Starter 2")
|
217 |
+
starter_btn3 = gr.Button("Starter 3")
|
218 |
+
starter_btn4 = gr.Button("Starter 4")
|
219 |
+
starter_buttons = [starter_btn1, starter_btn2, starter_btn3, starter_btn4]
|
220 |
|
221 |
+
# Function to update the labels of the 4 starter buttons
|
222 |
+
def update_starter_buttons(selected_genre):
|
223 |
+
# Grab up to 4 examples from the chosen genre
|
224 |
+
examples = get_examples_for_genre(selected_genre)
|
225 |
+
# If there are fewer than 4, fill the rest with placeholders or hide them
|
226 |
+
button_updates = []
|
227 |
+
for i in range(4):
|
228 |
+
if i < len(examples):
|
229 |
+
button_updates.append(gr.Button.update(value=examples[i], visible=True))
|
230 |
+
else:
|
231 |
+
button_updates.append(gr.Button.update(value="(no starter)", visible=False))
|
232 |
+
return button_updates
|
233 |
+
|
234 |
+
# Function that populates the msg with the chosen starter text, then calls respond
|
235 |
+
def pick_starter(starter_text, chat_history, selected_genre, memory_flag):
|
236 |
+
# The function returns the text to put in msg
|
237 |
+
# but we also chain the respond function via .then
|
238 |
+
return starter_text
|
239 |
|
240 |
+
# Hook each starter button:
|
241 |
+
# 1) Put the chosen text into 'msg'
|
242 |
+
# 2) Then call 'respond' to update the chatbot
|
243 |
+
for starter_button in starter_buttons:
|
244 |
+
starter_button.click(
|
245 |
+
fn=pick_starter,
|
246 |
+
inputs=[starter_button, chatbot, genre, full_memory],
|
247 |
outputs=[msg],
|
248 |
queue=False
|
249 |
).then(
|
250 |
fn=respond,
|
251 |
inputs=[msg, chatbot, genre, full_memory],
|
252 |
+
outputs=[chatbot],
|
253 |
+
queue=False
|
254 |
)
|
255 |
+
|
256 |
+
# Connect the genre dropdown to update these 4 starter buttons
|
257 |
+
genre.change(
|
258 |
+
fn=update_starter_buttons,
|
259 |
+
inputs=[genre],
|
260 |
+
outputs=starter_buttons
|
261 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
262 |
|
263 |
+
# -- Chat submission + button events --
|
264 |
msg.submit(respond, [msg, chatbot, genre, full_memory], [chatbot])
|
265 |
submit.click(respond, [msg, chatbot, genre, full_memory], [chatbot])
|
266 |
|
|
|
268 |
clear.click(lambda: [], None, chatbot, queue=False)
|
269 |
clear.click(lambda: "", None, msg, queue=False)
|
270 |
|
271 |
+
# -- "Download My Story" row --
|
272 |
with gr.Row():
|
273 |
+
save_btn = gr.Button("Download My Story", variant="secondary")
|
274 |
story_output = gr.Markdown(visible=False)
|
275 |
|
276 |
+
# "Download My Story" logic
|
277 |
save_btn.click(save_story, inputs=[chatbot], outputs=[story_output])
|
278 |
+
save_btn.click(
|
279 |
+
fn=lambda: True,
|
280 |
+
inputs=None,
|
281 |
+
outputs=story_output,
|
282 |
+
js="() => {document.getElementById('story_output').scrollIntoView();}",
|
283 |
+
queue=False
|
284 |
+
)
|
285 |
|
286 |
if __name__ == "__main__":
|
287 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|