Skip to content

Commit 07d89e6

Browse files
authored
Add error management, update scrollbar (#21)
1 parent 7216ad0 commit 07d89e6

File tree

4 files changed

+121
-73
lines changed

4 files changed

+121
-73
lines changed

examples/bedtime-story-teller/assets/app.js

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,55 +7,83 @@ const socket = io(`http://${window.location.host}`);
77
let generateStoryButtonOriginalHTML = ''; // To store the original content of the generate story button
88
let storyBuffer = '';
99

10+
// Error container elements
11+
const errorContainer = document.getElementById('error-container');
1012

13+
function showError(message) {
14+
errorContainer.textContent = message;
15+
errorContainer.style.display = 'block';
16+
}
1117

12-
function initSocketIO() {
13-
socket.on('prompt', (data) => {
14-
const promptContainer = document.getElementById('prompt-container');
15-
const promptDisplay = document.getElementById('prompt-display');
16-
promptDisplay.innerHTML = data;
17-
promptContainer.style.display = 'block';
18-
});
19-
20-
socket.on('response', (data) => {
21-
22-
document.getElementById('story-container').style.display = 'flex';
23-
24-
storyBuffer += data;
25-
26-
});
27-
28-
29-
30-
socket.on('stream_end', () => {
18+
function hideError() {
19+
errorContainer.style.display = 'none';
20+
errorContainer.textContent = '';
21+
}
3122

32-
const storyResponse = document.getElementById('story-response');
3323

34-
storyResponse.innerHTML = storyBuffer;
24+
function handlePrompt(data) {
25+
const promptContainer = document.getElementById('prompt-container');
26+
const promptDisplay = document.getElementById('prompt-display');
27+
promptDisplay.innerHTML = data;
28+
promptContainer.style.display = 'block';
29+
}
3530

36-
31+
function handleResponse(data) {
32+
document.getElementById('story-container').style.display = 'flex';
33+
storyBuffer += data;
34+
}
3735

38-
document.getElementById('loading-spinner').style.display = 'none';
36+
function handleStreamEnd() {
37+
hideError(); // Hide any errors on successful stream end
3938

40-
const clearStoryButton = document.getElementById('clear-story-button');
39+
const storyResponse = document.getElementById('story-response');
40+
storyResponse.innerHTML = storyBuffer;
4141

42-
clearStoryButton.style.display = 'block';
42+
document.getElementById('loading-spinner').style.display = 'none';
43+
const clearStoryButton = document.getElementById('clear-story-button');
44+
clearStoryButton.style.display = 'block';
45+
clearStoryButton.disabled = false;
4346

44-
clearStoryButton.disabled = false;
47+
const generateStoryButton = document.querySelector('.generate-story-button');
48+
if (generateStoryButton) {
49+
generateStoryButton.disabled = false;
50+
generateStoryButton.innerHTML = generateStoryButtonOriginalHTML; // Restore original content
51+
}
52+
}
4553

46-
54+
function handleStoryError(data) {
55+
// Hide the loading spinner
56+
document.getElementById('loading-spinner').style.display = 'none';
4757

48-
const generateStoryButton = document.querySelector('.generate-story-button');
58+
// Restore the generate story button
59+
const generateStoryButton = document.querySelector('.generate-story-button');
60+
if (generateStoryButton) {
61+
generateStoryButton.disabled = false;
62+
generateStoryButton.innerHTML = generateStoryButtonOriginalHTML;
63+
}
4964

50-
if (generateStoryButton) {
65+
// Display the error message in the dedicated error container
66+
showError(`An error occurred while generating the story: ${data.error}`);
5167

52-
generateStoryButton.disabled = false;
68+
// Also show the "New story" button to allow the user to restart
69+
const clearStoryButton = document.getElementById('clear-story-button');
70+
clearStoryButton.style.display = 'block';
71+
clearStoryButton.disabled = false;
72+
}
5373

54-
generateStoryButton.innerHTML = generateStoryButtonOriginalHTML; // Restore original content
74+
function initSocketIO() {
75+
socket.on('prompt', handlePrompt);
76+
socket.on('response', handleResponse);
77+
socket.on('stream_end', handleStreamEnd);
78+
socket.on('story_error', handleStoryError);
5579

56-
}
80+
socket.on('connect', () => {
81+
hideError(); // Clear any previous errors on successful connection
82+
});
5783

58-
});
84+
socket.on('disconnect', () => {
85+
showError("Connection to backend lost. Please refresh the page or check the backend server.");
86+
});
5987
}
6088

6189
function unlockAndOpenNext(currentContainer) {
@@ -229,6 +257,7 @@ function gatherDataAndGenerateStory() {
229257
}
230258

231259
function generateStory(data) {
260+
hideError(); // Hide any errors when starting a new generation
232261
document.querySelector('.story-output-placeholder').style.display = 'none';
233262
const responseArea = document.getElementById('story-response-area');
234263
responseArea.style.display = 'flex';
@@ -251,6 +280,7 @@ function generateStory(data) {
251280
}
252281

253282
function resetStoryView() {
283+
hideError(); // Hide any errors when resetting view
254284
document.querySelector('.story-output-placeholder').style.display = 'flex';
255285
const responseArea = document.getElementById('story-response-area');
256286
responseArea.style.display = 'none';
@@ -469,6 +499,7 @@ document.addEventListener('DOMContentLoaded', () => {
469499
});
470500

471501
document.getElementById('generate-randomly-button').addEventListener('click', () => {
502+
hideError(); // Hide any errors when starting a new generation
472503
// Age
473504
const ageChips = document.querySelectorAll('.parameter-container:nth-child(1) .chip');
474505
const randomAgeChip = getRandomElement(ageChips);
@@ -519,4 +550,4 @@ document.addEventListener('DOMContentLoaded', () => {
519550

520551
generateStory(storyData);
521552
});
522-
});
553+
});

examples/bedtime-story-teller/assets/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ <h3 class="response-title">Story</h3>
201201
</div>
202202

203203
</div>
204+
<div id="error-container" class="error-message" style="display: none;"></div>
204205
</div>
205206
</div>
206207

examples/bedtime-story-teller/assets/style.css

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,14 @@ body {
687687
100% { transform: rotate(360deg); }
688688
}
689689

690+
.error-message {
691+
background-color: #f8d7da;
692+
color: #721c24;
693+
padding: 10px;
694+
margin-top: 20px;
695+
border-radius: 5px;
696+
text-align: center;
697+
}
690698

691699

692700
/*
@@ -791,5 +799,10 @@ body {
791799
}
792800

793801
#story-response::-webkit-scrollbar-track {
794-
background-color: transparent;
802+
background-color: #ECF1F1;
795803
}
804+
805+
#story-response::-webkit-scrollbar-thumb {
806+
background-color: #C9D2D2;
807+
border-radius: 4px;
808+
}

examples/bedtime-story-teller/python/main.py

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,47 @@
1818

1919

2020
def generate_story(_, data):
21-
age = data.get('age', 'any')
22-
theme = data.get('theme', 'any')
23-
tone = data.get('tone', 'any')
24-
ending_type = data.get('endingType', 'any')
25-
narrative_structure = data.get('narrativeStructure', 'any')
26-
duration = data.get('duration', 'any')
27-
characters = data.get('characters', [])
28-
other = data.get('other', '')
29-
30-
# Create a prompt with HTML for display
31-
prompt_for_display = f"As a parent who loves to read bedtime stories to my <strong>{age}</strong> year old child, I need a delightful and age-appropriate story."
32-
33-
if characters:
34-
prompt_for_display += " Characters of the story: "
35-
char_prompts = []
36-
for i, char in enumerate(characters):
37-
ch = f"Character {i+1} (<strong>{char.get('name')}</strong>, <strong>{char.get('role')}</strong>"
38-
ch += f", <strong>{char.get('description')}</strong>)" if char.get('description') else ")"
39-
char_prompts.append(ch)
40-
prompt_for_display += ", ".join(char_prompts)
41-
prompt_for_display += "."
42-
43-
prompt_for_display += f" The story type is <strong>{theme}</strong>. The tone should be <strong>{tone}</strong>. The format should be a narrative-style story with a clear beginning, middle, and end, allowing for a smooth and engaging reading experience. The objective is to entertain and soothe the child before bedtime. Provide a brief introduction to set the scene and introduce the main character. The scope should revolve around the topic: managing emotions and conflicts. The length should be approximately <strong>{duration}</strong>. Please ensure the story has a <strong>{narrative_structure}</strong> narrative structure, leaving the child with a sense of <strong>{ending_type}</strong>. The language should be easy to understand and suitable for my child's age comprehension."
44-
if other:
45-
prompt_for_display += f"\n\nOther on optional stuff for the story: <strong>{other}</strong>"
46-
47-
# Create a plain text prompt for the LLM by stripping HTML tags
48-
prompt_for_llm = re.sub('<[^>]*>', '', prompt_for_display)
49-
50-
# Send the display prompt to the UI
51-
ui.send_message("prompt", prompt_for_display)
52-
53-
# Use the plain text prompt for the LLM and stream the response
54-
for resp in llm.chat_stream(prompt_for_llm):
55-
ui.send_message("response", resp)
56-
57-
# Signal the end of the stream
58-
ui.send_message("stream_end", {})
21+
try:
22+
age = data.get('age', 'any')
23+
theme = data.get('theme', 'any')
24+
tone = data.get('tone', 'any')
25+
ending_type = data.get('endingType', 'any')
26+
narrative_structure = data.get('narrativeStructure', 'any')
27+
duration = data.get('duration', 'any')
28+
characters = data.get('characters', [])
29+
other = data.get('other', '')
30+
31+
# Create a prompt with HTML for display
32+
prompt_for_display = f"As a parent who loves to read bedtime stories to my <strong>{age}</strong> year old child, I need a delightful and age-appropriate story."
33+
34+
if characters:
35+
prompt_for_display += " Characters of the story: "
36+
char_prompts = []
37+
for i, char in enumerate(characters):
38+
ch = f"Character {i+1} (<strong>{char.get('name')}</strong>, <strong>{char.get('role')}</strong>"
39+
ch += f", <strong>{char.get('description')}</strong>)" if char.get('description') else ")"
40+
char_prompts.append(ch)
41+
prompt_for_display += ", ".join(char_prompts)
42+
prompt_for_display += "."
43+
44+
prompt_for_display += f" The story type is <strong>{theme}</strong>. The tone should be <strong>{tone}</strong>. The format should be a narrative-style story with a clear beginning, middle, and end, allowing for a smooth and engaging reading experience. The objective is to entertain and soothe the child before bedtime. Provide a brief introduction to set the scene and introduce the main character. The scope should revolve around the topic: managing emotions and conflicts. The length should be approximately <strong>{duration}</strong>. Please ensure the story has a <strong>{narrative_structure}</strong> narrative structure, leaving the child with a sense of <strong>{ending_type}</strong>. The language should be easy to understand and suitable for my child's age comprehension."
45+
if other:
46+
prompt_for_display += f"\n\nOther on optional stuff for the story: <strong>{other}</strong>"
47+
48+
# Create a plain text prompt for the LLM by stripping HTML tags
49+
prompt_for_llm = re.sub('<[^>]*>', '', prompt_for_display)
50+
51+
# Send the display prompt to the UI
52+
ui.send_message("prompt", prompt_for_display)
53+
54+
# Use the plain text prompt for the LLM and stream the response
55+
for resp in llm.chat_stream(prompt_for_llm):
56+
ui.send_message("response", resp)
57+
58+
# Signal the end of the stream
59+
ui.send_message("stream_end", {})
60+
except Exception as e:
61+
ui.send_message("story_error", {"error": str(e)})
5962

6063
ui.on_message("generate_story", generate_story)
6164

0 commit comments

Comments
 (0)