PeterPinetree commited on
Commit
c4ad27f
·
verified ·
1 Parent(s): 3d971c1

Update app.py

Browse files

Key Fixes for the Nonsense Output:

Corrected Message Formatting: The main problem was in how messages were being processed and returned. I've fixed the formatting between Gradio's format and the API's required format.
Improved History Handling: Added logic to properly handle both old tuple format and new dictionary format data in the chat history.
More Robust Response Generation: Improved error handling and stream processing to ensure clean responses.
Simplified Response Structure: Returned to the more reliable tuple format for the Chatbot component.

Added Genre-Specific Examples:

Comprehensive Genre Examples: Created a detailed dictionary (GENRE_EXAMPLES) with unique, themed prompts for each genre.
Dynamic Example Updates: Added a function to update the example prompts whenever the user changes the genre.
Event Handler for Genre Changes: Set up the interface to automatically refresh the examples when the genre dropdown changes.

Learning Tool Enhancements:
Since you mentioned wanting this to be a tool for creative writing learning, I've added:

Richer System Prompts: Enhanced the prompts to encourage more varied and descriptive storytelling.
Clear Stylistic Guidelines: The system prompt now explicitly requests sensory descriptions, meaningful dialogue, and character development.
Varied Scenarios: The genre-specific examples showcase different writing situations to help users understand the range of possible narrative approaches.

Files changed (1) hide show
  1. app.py +122 -48
app.py CHANGED
@@ -5,15 +5,74 @@ import random
5
  # Initialize the inference client
6
  client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
7
 
8
- # Story genres and themes
9
- STORY_GENRES = [
10
- "fantasy", "sci-fi", "mystery", "horror", "historical",
11
- "cyberpunk", "western", "post-apocalyptic", "steampunk"
12
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  def get_enhanced_system_prompt(genre=None):
15
  """Generate a detailed system prompt with optional genre specification"""
16
- selected_genre = genre or random.choice(STORY_GENRES)
17
 
18
  system_message = f"""You are an interactive storyteller creating an immersive {selected_genre} choose-your-own-adventure story.
19
 
@@ -34,56 +93,71 @@ Keep responses engaging but concise (200-300 words maximum). If the user's input
34
 
35
  return system_message
36
 
37
- def respond(message, chat_history, genre=None):
38
  """Generate a response based on the current message and conversation history"""
39
- # Use system prompt
40
  system_message = get_enhanced_system_prompt(genre)
41
 
42
- # Initialize messages with system prompt
 
 
 
 
 
 
 
 
 
 
 
43
  api_messages = [{"role": "system", "content": system_message}]
44
 
45
- # Add history (limited to last 5 exchanges to prevent token overflow)
 
46
  memory_length = 5
47
- for msg in chat_history[-memory_length*2:]:
48
- api_messages.append({"role": msg["role"], "content": msg["content"]})
 
49
 
50
- # Add current user message
51
  api_messages.append({"role": "user", "content": message})
52
 
53
  # Special handling for story initialization
54
- if len(chat_history) == 0 or message.lower() in ["start", "begin", "begin my adventure"]:
 
55
  api_messages.append({
56
  "role": "system",
57
- "content": f"Begin a new {genre or random.choice(STORY_GENRES)} adventure with an intriguing opening scene."
58
  })
59
 
60
- # Generate response
61
- response = ""
62
  try:
63
- for chunk in client.chat_completion(
64
  api_messages,
65
  max_tokens=512,
66
  stream=True,
67
  temperature=0.7,
68
  top_p=0.95,
69
  ):
70
- token = chunk.choices[0].delta.content
71
- if token: # Check if token is not None
72
- response += token
73
-
74
- # Use new message format
75
- history = chat_history.copy()
76
- history.append({"role": "user", "content": message})
77
- history.append({"role": "assistant", "content": response})
78
- yield history
79
  except Exception as e:
80
- error_response = f"Story magic temporarily interrupted. Please try again. (Error: {str(e)})"
81
- history = chat_history.copy()
82
- history.append({"role": "user", "content": message})
83
- history.append({"role": "assistant", "content": error_response})
84
- yield history
85
 
86
- # Create interface with additional customization
 
 
 
 
 
 
 
 
 
87
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
88
  gr.Markdown("# 🔮 Interactive Story Adventure")
89
  gr.Markdown("Immerse yourself in an interactive story where your choices shape the narrative.")
@@ -95,10 +169,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
95
  bubble_full_width=False,
96
  show_copy_button=True,
97
  avatar_images=(None, "🧙"),
98
- label="Chatbot",
99
- type="messages" # Use the new messages format
100
  )
101
-
102
  msg = gr.Textbox(
103
  placeholder="Describe what you want to do next in the story...",
104
  container=False,
@@ -112,28 +183,31 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
112
  with gr.Column(scale=1):
113
  gr.Markdown("## Adventure Settings")
114
  genre = gr.Dropdown(
115
- choices=STORY_GENRES,
116
  label="Story Genre",
117
  info="Select a genre for your next adventure",
118
  value="fantasy"
119
  )
120
 
121
- examples = gr.Examples(
122
- examples=[
123
- ["Begin my adventure"],
124
- ["I explore the mysterious cave"],
125
- ["I approach the merchant to ask about the rumors"],
126
- ["I decide to climb the tower"],
127
- ["I hide in the shadows and observe"]
128
- ],
129
- inputs=msg
130
  )
131
 
132
- # Event handlers for the new message format
 
 
 
 
 
 
 
133
  msg.submit(respond, [msg, chatbot, genre], [chatbot])
134
  submit.click(respond, [msg, chatbot, genre], [chatbot])
135
 
136
- # Reset the chatbot with an empty list for the new format
137
  clear.click(lambda: [], None, chatbot, queue=False)
138
  clear.click(lambda: "", None, msg, queue=False)
139
 
 
5
  # Initialize the inference client
6
  client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
7
 
8
+ # Story genres with genre-specific example prompts
9
+ GENRE_EXAMPLES = {
10
+ "fantasy": [
11
+ "I enter the ancient forest seeking the wizard's tower",
12
+ "I approach the dragon cautiously with my shield raised",
13
+ "I examine the mysterious runes carved into the stone altar",
14
+ "I try to bargain with the elven council for safe passage"
15
+ ],
16
+ "sci-fi": [
17
+ "I hack into the space station's mainframe",
18
+ "I investigate the strange signal coming from the abandoned planet",
19
+ "I negotiate with the alien ambassador about the peace treaty",
20
+ "I try to repair my damaged spacecraft before oxygen runs out"
21
+ ],
22
+ "mystery": [
23
+ "I examine the crime scene for overlooked evidence",
24
+ "I question the nervous butler about the night of the murder",
25
+ "I follow the suspicious figure through the foggy streets",
26
+ "I check the victim's diary for hidden clues"
27
+ ],
28
+ "horror": [
29
+ "I slowly open the creaking door to the basement",
30
+ "I read the forbidden text while the candles flicker",
31
+ "I hide under the bed as footsteps approach",
32
+ "I investigate the strange noises coming from the attic"
33
+ ],
34
+ "western": [
35
+ "I challenge the outlaw to a duel at high noon",
36
+ "I track the bandits through the desert canyon",
37
+ "I enter the saloon looking for information",
38
+ "I defend the stagecoach from the approaching raiders"
39
+ ],
40
+ "cyberpunk": [
41
+ "I jack into the corporate mainframe to steal data",
42
+ "I negotiate with the street gang for cybernetic upgrades",
43
+ "I hide in the neon-lit alleyway from corporate security",
44
+ "I meet my mysterious client in the underground bar"
45
+ ],
46
+ "historical": [
47
+ "I attend the royal ball hoping to meet the mysterious count",
48
+ "I join the resistance against the occupying forces",
49
+ "I navigate the dangerous politics of the royal court",
50
+ "I set sail on a voyage to discover new lands"
51
+ ],
52
+ "post-apocalyptic": [
53
+ "I scavenge the abandoned shopping mall for supplies",
54
+ "I approach the fortified settlement seeking shelter",
55
+ "I navigate through the radioactive zone using my old map",
56
+ "I hide from the approaching group of raiders"
57
+ ],
58
+ "steampunk": [
59
+ "I pilot my airship through the lightning storm",
60
+ "I present my new invention to the Royal Academy",
61
+ "I investigate the mysterious clockwork automaton",
62
+ "I sneak aboard the emperor's armored train"
63
+ ]
64
+ }
65
+
66
+ def get_examples_for_genre(genre):
67
+ """Get example prompts specific to the selected genre"""
68
+ if genre in GENRE_EXAMPLES:
69
+ return GENRE_EXAMPLES[genre]
70
+ else:
71
+ return GENRE_EXAMPLES["fantasy"] # Default to fantasy
72
 
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
 
 
93
 
94
  return system_message
95
 
96
+ def respond(message, history, genre=None):
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 h in history:
104
+ if isinstance(h, list) and len(h) == 2:
105
+ # Handle old tuple format if it exists
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
+ # Add limited history to prevent token overflow (only use recent exchanges)
116
+ # Limit to last 5 exchanges
117
  memory_length = 5
118
+ if formatted_history:
119
+ for msg in formatted_history[-memory_length*2:]:
120
+ api_messages.append(msg)
121
 
122
+ # Add current message
123
  api_messages.append({"role": "user", "content": message})
124
 
125
  # Special handling for story initialization
126
+ if not history or message.lower() in ["start", "begin", "begin my adventure"]:
127
+ # Add a specific instruction for starting a new story
128
  api_messages.append({
129
  "role": "system",
130
+ "content": f"Begin a new {genre or 'fantasy'} adventure with an intriguing opening scene. Introduce the protagonist without assuming too much about them, allowing the user to shape the character."
131
  })
132
 
133
+ # Generate and stream response
134
+ bot_message = ""
135
  try:
136
+ for response in client.chat_completion(
137
  api_messages,
138
  max_tokens=512,
139
  stream=True,
140
  temperature=0.7,
141
  top_p=0.95,
142
  ):
143
+ delta = response.choices[0].delta.content
144
+ if delta:
145
+ bot_message += delta
146
+ yield history + [[message, bot_message]]
 
 
 
 
 
147
  except Exception as e:
148
+ error_message = f"Story magic temporarily interrupted. Please try again. (Error: {str(e)})"
149
+ yield history + [[message, error_message]]
 
 
 
150
 
151
+ def update_examples(genre):
152
+ """Update the example prompts based on the selected genre"""
153
+ examples = get_examples_for_genre(genre)
154
+ examples.insert(0, "Begin my adventure") # Always include this option
155
+ return gr.Examples(
156
+ examples=[[ex] for ex in examples],
157
+ inputs=msg
158
+ )
159
+
160
+ # Create interface with additional customization options
161
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
162
  gr.Markdown("# 🔮 Interactive Story Adventure")
163
  gr.Markdown("Immerse yourself in an interactive story where your choices shape the narrative.")
 
169
  bubble_full_width=False,
170
  show_copy_button=True,
171
  avatar_images=(None, "🧙"),
 
 
172
  )
 
173
  msg = gr.Textbox(
174
  placeholder="Describe what you want to do next in the story...",
175
  container=False,
 
183
  with gr.Column(scale=1):
184
  gr.Markdown("## Adventure Settings")
185
  genre = gr.Dropdown(
186
+ choices=list(GENRE_EXAMPLES.keys()),
187
  label="Story Genre",
188
  info="Select a genre for your next adventure",
189
  value="fantasy"
190
  )
191
 
192
+ # Initialize with fantasy examples
193
+ examples_box = gr.Examples(
194
+ examples=[[ex] for ex in get_examples_for_genre("fantasy")],
195
+ inputs=msg,
196
+ label="Examples"
 
 
 
 
197
  )
198
 
199
+ # Update examples when genre changes
200
+ genre.change(
201
+ fn=update_examples,
202
+ inputs=[genre],
203
+ outputs=[examples_box]
204
+ )
205
+
206
+ # Set up event handlers for the chatbot
207
  msg.submit(respond, [msg, chatbot, genre], [chatbot])
208
  submit.click(respond, [msg, chatbot, genre], [chatbot])
209
 
210
+ # Clear the chatbot for a new adventure
211
  clear.click(lambda: [], None, chatbot, queue=False)
212
  clear.click(lambda: "", None, msg, queue=False)
213