rairo commited on
Commit
e779583
Β·
verified Β·
1 Parent(s): 6f1e948

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -21
app.py CHANGED
@@ -55,7 +55,7 @@ def parse_numbered_steps(text):
55
  if "steps" not in st.session_state:
56
  st.session_state.steps = [] # List[(int, str)]
57
  if "images" not in st.session_state:
58
- st.session_state.images = {} # Dict[int, PIL.Image]
59
  if "tools_list" not in st.session_state:
60
  st.session_state.tools_list = [] # List[str]
61
  if "current_step" not in st.session_state:
@@ -98,7 +98,7 @@ def detect_category_and_generate(uploaded_file, context_text):
98
  1) Use Gemini chat to identify the category (appliance, automotive, gardening, upcycling).
99
  2) Then use Gemini chat to get:
100
  - a "tools & materials" list
101
- - numbered step-by-step instructions
102
  3) Parse everything into session_state.
103
  """
104
  try:
@@ -113,15 +113,13 @@ def detect_category_and_generate(uploaded_file, context_text):
113
  "home appliance repair, automotive maintenance, gardening & urban farming, or upcycling & sustainable crafts. "
114
  "Reply back with exactly one category name."
115
  )
116
- # Create a chat instance that can handle both Text and Image
117
  cat_chat = client.chats.create(
118
  model=CATEGORY_MODEL,
119
  config=types.GenerateContentConfig(response_modalities=["Text", "Image"])
120
  )
121
- # Send the category prompt plus the PIL.Image directly
122
  cat_resp = cat_chat.send_message([category_prompt, image])
123
 
124
- # Extract the category name (assume it's the first text part)
125
  cat_parts = cat_resp.candidates[0].content.parts
126
  cat_text = ""
127
  for part in cat_parts:
@@ -143,6 +141,7 @@ def detect_category_and_generate(uploaded_file, context_text):
143
  "1. First step instructions (be specific and detailed)...\n"
144
  "2. Second step instructions...\n"
145
  "3. Continue with all necessary steps...\n\n"
 
146
  "Keep each numbered step clear and actionable (2-3 sentences max). "
147
  "Include safety warnings where appropriate."
148
  )
@@ -152,20 +151,28 @@ def detect_category_and_generate(uploaded_file, context_text):
152
  )
153
  full_resp = gen_chat.send_message([detailed_prompt, image])
154
 
155
- # ─── 3.3 PARSE out tools + numbered steps ─────────────────────────────────
156
- # Combine all text parts from the response
157
  gen_parts = full_resp.candidates[0].content.parts
158
- response_text = ""
 
 
159
  for part in gen_parts:
160
  if part.text is not None:
161
- response_text += part.text + "\n"
162
- response_text = response_text.strip()
 
 
 
 
 
 
 
163
 
164
- # Split into tools and steps sections
165
  tools_section = ""
166
  steps_section = ""
167
- if "TOOLS AND MATERIALS:" in response_text:
168
- parts = response_text.split("TOOLS AND MATERIALS:")
169
  if len(parts) > 1:
170
  remaining = parts[1]
171
  if "STEPS:" in remaining:
@@ -174,13 +181,13 @@ def detect_category_and_generate(uploaded_file, context_text):
174
  steps_section = steps_part.strip()
175
  else:
176
  tools_section = remaining.strip()
177
- elif "STEPS:" in response_text:
178
- parts = response_text.split("STEPS:")
179
  if len(parts) > 1:
180
  steps_section = parts[1].strip()
181
  else:
182
  # Fallback parsing
183
- lines = response_text.split("\n")
184
  tools_lines = []
185
  steps_lines = []
186
  current_section = "unknown"
@@ -207,7 +214,14 @@ def detect_category_and_generate(uploaded_file, context_text):
207
  # Parse steps
208
  parsed_steps = parse_numbered_steps(steps_section)
209
 
210
- # Store in session_state
 
 
 
 
 
 
 
211
  st.session_state.tools_list = tools
212
  st.session_state.steps = parsed_steps
213
 
@@ -230,6 +244,7 @@ def detect_category_and_generate(uploaded_file, context_text):
230
  st.error(f"Error processing request: {str(e)}")
231
  st.error("Please check your API key and try again.")
232
 
 
233
  def render_sidebar_navigation():
234
  """
235
  A sidebar listing each step by number + a button to jump to that step.
@@ -242,13 +257,14 @@ def render_sidebar_navigation():
242
  st.sidebar.progress(completed / total_steps)
243
  st.sidebar.write(f"Progress: {completed}/{total_steps} steps")
244
 
245
- for (idx, text) in st.session_state.steps:
246
  is_done = st.session_state.done_flags.get(idx, False)
247
  label = f"{'βœ“' if is_done else 'Β·'} Step {idx}"
248
  if st.sidebar.button(label, key=f"nav_{idx}"):
249
  st.session_state.current_step = idx
250
  st.rerun()
251
 
 
252
  def render_tools_list():
253
  """Show the Tools/Materials list in an expander."""
254
  if st.session_state.tools_list:
@@ -256,11 +272,13 @@ def render_tools_list():
256
  for item in st.session_state.tools_list:
257
  st.write(f"- {item}")
258
 
 
259
  def render_step(idx, text):
260
  """
261
  Render a single step:
262
  - Show step number
263
  - Show instruction text
 
264
  - Timer if needed
265
  - Checkbox for "Done"
266
  - Text area for notes
@@ -271,6 +289,14 @@ def render_step(idx, text):
271
  st.markdown(f"### Step {idx} of {total}")
272
  st.write(text)
273
 
 
 
 
 
 
 
 
 
274
  # Timer functionality
275
  seconds_left = st.session_state.timers.get(idx, 0)
276
  if seconds_left > 0:
@@ -353,9 +379,10 @@ with st.expander("ℹ️ How it works", expanded=False):
353
  """
354
  1. **Upload a photo** of the item you want to fix or build (appliance, car part, plant, craft project).
355
  2. **Add context** (optional) - describe what’s wrong or what you want to achieve.
356
- 3. **Get AI guidance** - The AI will detect the category and provide step-by-step instructions.
357
  4. **Follow the steps** - Each step includes:
358
  - Clear instructions
 
359
  - Progress tracking with checkboxes
360
  - Timer functionality for waiting periods
361
  - Note-taking area
@@ -416,8 +443,7 @@ if st.session_state.prompt_sent:
416
  elif st.session_state.current_step < 1:
417
  st.session_state.current_step = 1
418
 
419
- step_tuple = st.session_state.steps[st.session_state.current_step - 1]
420
- step_num, step_text = step_tuple
421
  render_step(step_num, step_text)
422
 
423
  # Overall progress at bottom
 
55
  if "steps" not in st.session_state:
56
  st.session_state.steps = [] # List[(int, str)]
57
  if "images" not in st.session_state:
58
+ st.session_state.images = {} # Dict[int, PIL.Image] (illustrations per step)
59
  if "tools_list" not in st.session_state:
60
  st.session_state.tools_list = [] # List[str]
61
  if "current_step" not in st.session_state:
 
98
  1) Use Gemini chat to identify the category (appliance, automotive, gardening, upcycling).
99
  2) Then use Gemini chat to get:
100
  - a "tools & materials" list
101
+ - numbered step-by-step instructions (and optional illustrations)
102
  3) Parse everything into session_state.
103
  """
104
  try:
 
113
  "home appliance repair, automotive maintenance, gardening & urban farming, or upcycling & sustainable crafts. "
114
  "Reply back with exactly one category name."
115
  )
 
116
  cat_chat = client.chats.create(
117
  model=CATEGORY_MODEL,
118
  config=types.GenerateContentConfig(response_modalities=["Text", "Image"])
119
  )
 
120
  cat_resp = cat_chat.send_message([category_prompt, image])
121
 
122
+ # Extract the category name (combine all text parts)
123
  cat_parts = cat_resp.candidates[0].content.parts
124
  cat_text = ""
125
  for part in cat_parts:
 
141
  "1. First step instructions (be specific and detailed)...\n"
142
  "2. Second step instructions...\n"
143
  "3. Continue with all necessary steps...\n\n"
144
+ "Additionally, for each step you may include a brief illustrative image. "
145
  "Keep each numbered step clear and actionable (2-3 sentences max). "
146
  "Include safety warnings where appropriate."
147
  )
 
151
  )
152
  full_resp = gen_chat.send_message([detailed_prompt, image])
153
 
154
+ # ─── 3.3 PARSE out tools, numbered steps, and images ────────────────────────
 
155
  gen_parts = full_resp.candidates[0].content.parts
156
+
157
+ # First, gather all text into one string to parse tools/steps
158
+ combined_text = ""
159
  for part in gen_parts:
160
  if part.text is not None:
161
+ combined_text += part.text + "\n"
162
+ combined_text = combined_text.strip()
163
+
164
+ # Now identify and extract any inline images. We'll assign them sequentially to steps.
165
+ inline_images = []
166
+ for part in gen_parts:
167
+ if part.inline_data is not None:
168
+ img = Image.open(BytesIO(part.inline_data.data))
169
+ inline_images.append(img)
170
 
171
+ # Split combined_text into tools and steps sections
172
  tools_section = ""
173
  steps_section = ""
174
+ if "TOOLS AND MATERIALS:" in combined_text:
175
+ parts = combined_text.split("TOOLS AND MATERIALS:")
176
  if len(parts) > 1:
177
  remaining = parts[1]
178
  if "STEPS:" in remaining:
 
181
  steps_section = steps_part.strip()
182
  else:
183
  tools_section = remaining.strip()
184
+ elif "STEPS:" in combined_text:
185
+ parts = combined_text.split("STEPS:")
186
  if len(parts) > 1:
187
  steps_section = parts[1].strip()
188
  else:
189
  # Fallback parsing
190
+ lines = combined_text.split("\n")
191
  tools_lines = []
192
  steps_lines = []
193
  current_section = "unknown"
 
214
  # Parse steps
215
  parsed_steps = parse_numbered_steps(steps_section)
216
 
217
+ # Assign inline_images to steps (one-to-one, up to number of steps)
218
+ st.session_state.images = {}
219
+ for idx, step in parsed_steps:
220
+ img_index = idx - 1 # zero-based
221
+ if img_index < len(inline_images):
222
+ st.session_state.images[idx] = inline_images[img_index]
223
+
224
+ # Store tools and steps in session_state
225
  st.session_state.tools_list = tools
226
  st.session_state.steps = parsed_steps
227
 
 
244
  st.error(f"Error processing request: {str(e)}")
245
  st.error("Please check your API key and try again.")
246
 
247
+
248
  def render_sidebar_navigation():
249
  """
250
  A sidebar listing each step by number + a button to jump to that step.
 
257
  st.sidebar.progress(completed / total_steps)
258
  st.sidebar.write(f"Progress: {completed}/{total_steps} steps")
259
 
260
+ for (idx, _) in st.session_state.steps:
261
  is_done = st.session_state.done_flags.get(idx, False)
262
  label = f"{'βœ“' if is_done else 'Β·'} Step {idx}"
263
  if st.sidebar.button(label, key=f"nav_{idx}"):
264
  st.session_state.current_step = idx
265
  st.rerun()
266
 
267
+
268
  def render_tools_list():
269
  """Show the Tools/Materials list in an expander."""
270
  if st.session_state.tools_list:
 
272
  for item in st.session_state.tools_list:
273
  st.write(f"- {item}")
274
 
275
+
276
  def render_step(idx, text):
277
  """
278
  Render a single step:
279
  - Show step number
280
  - Show instruction text
281
+ - Possibly show an illustration if available
282
  - Timer if needed
283
  - Checkbox for "Done"
284
  - Text area for notes
 
289
  st.markdown(f"### Step {idx} of {total}")
290
  st.write(text)
291
 
292
+ # If an illustration exists for this step, display it
293
+ if idx in st.session_state.images:
294
+ st.image(
295
+ st.session_state.images[idx],
296
+ caption=f"Illustration for step {idx}",
297
+ use_container_width=True
298
+ )
299
+
300
  # Timer functionality
301
  seconds_left = st.session_state.timers.get(idx, 0)
302
  if seconds_left > 0:
 
379
  """
380
  1. **Upload a photo** of the item you want to fix or build (appliance, car part, plant, craft project).
381
  2. **Add context** (optional) - describe what’s wrong or what you want to achieve.
382
+ 3. **Get AI guidance** - The AI will detect the category and provide step-by-step instructions (with possible illustrations).
383
  4. **Follow the steps** - Each step includes:
384
  - Clear instructions
385
+ - An illustrative image (if provided)
386
  - Progress tracking with checkboxes
387
  - Timer functionality for waiting periods
388
  - Note-taking area
 
443
  elif st.session_state.current_step < 1:
444
  st.session_state.current_step = 1
445
 
446
+ step_num, step_text = st.session_state.steps[st.session_state.current_step - 1]
 
447
  render_step(step_num, step_text)
448
 
449
  # Overall progress at bottom