Laborator commited on
Commit
acfce00
Β·
1 Parent(s): 34b5d7b

Fix card overflow + ghost translations of curated catalog answers

Browse files

1. Drop the   replacement inside <span class='ml-word'>: a non-breaking
space sequence forced lines to overflow narrow result cards and produced
the horizontal scroll seen during live generation. Plain spaces wrap
naturally under the existing `white-space: pre-wrap` rule.

2. CSS belt-and-braces on .ml-result-body β€” overflow-wrap: anywhere +
word-break: normal + max-width: 100%, plus overflow-x: hidden on
.ml-panel-body. Long latin binomena no longer push horizontal scroll.

3. do_translate / restore_original: drop the BY_FILENAME[filename] fallback.
Previously, when AI ANALYZE failed (quota / backend down) and last_answers
state was empty, translate silently fell back to the curated catalog
answer of the *picked* sample and translated THAT β€” producing a
confidently realistic translation that didn't match the live result on
screen. Now: empty state -> honest 'Run AI ANALYZE first' message and
hidden TRANSLATE button.

4. on_pick (sample switch) now also resets last_answers state to empty.
Without this, switching samples kept the previous image's live answer in
state, which could leak into translate/restore for an unrelated thumbnail.

Files changed (1) hide show
  1. app.py +37 -28
app.py CHANGED
@@ -1382,7 +1382,12 @@ footer { display: none !important; }
1382
  font-size: 19px !important; font-weight: 800 !important;
1383
  line-height: 1.45 !important; color: #ffffff !important;
1384
  letter-spacing: -0.2px !important; white-space: pre-wrap;
 
 
 
 
1385
  }
 
1386
  .ml-caret::after { content: 'β–‹'; color: #00DCE6; margin-left: 2px;
1387
  animation: ml-blink 1s steps(2) infinite; font-weight: 400; }
1388
  @keyframes ml-blink { 50% { opacity: 0; } }
@@ -1960,21 +1965,27 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base(primary_hue="red", neutral_hue="zin
1960
  except ValueError: grid = 0
1961
  try: cross = int(cross_str or "0")
1962
  except ValueError: cross = 0
 
 
 
 
1963
  if not filename:
1964
  return (folder_html(cat_label, None),
1965
  viewport_html(None, shape, grid, cross), "", *empty_panels(),
1966
  gr.Button(visible=False),
1967
- gr.Dropdown(value=DEFAULT_LANG_DISPLAY))
 
1968
  uri = full_uri(filename)
1969
  return (folder_html(cat_label, filename),
1970
  viewport_html(uri, shape, grid, cross), uri, *empty_panels(),
1971
  gr.Button(visible=False),
1972
- gr.Dropdown(value=DEFAULT_LANG_DISPLAY))
 
1973
 
1974
  picked_filename.change(on_pick,
1975
  [picked_filename, cat_state, shape_state, grid_state, cross_state],
1976
  [folder_grid, viewport, viewport_uri, vanilla_panel, v2_panel, v3_panel,
1977
- original_btn, lang_dropdown], api_name=False)
1978
 
1979
  def on_file_upload(file_obj, shape, grid_str, cross_str):
1980
  try: grid = int(grid_str or "0")
@@ -2092,7 +2103,11 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base(primary_hue="red", neutral_hue="zin
2092
  spans = []
2093
  for i, tok in enumerate(tokens):
2094
  delay = i * ms_per_word
2095
- safe = _html.escape(tok).replace(" ", "&nbsp;")
 
 
 
 
2096
  spans.append(
2097
  f'<span class="ml-word" style="animation-delay:{delay}ms;">{safe}</span>'
2098
  )
@@ -2171,20 +2186,19 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base(primary_hue="red", neutral_hue="zin
2171
  js=ANALYZE_PRE_JS, api_name=False)
2172
 
2173
  def do_translate(filename, lang_label, answers):
2174
- # Prefer live state (works for upload/webcam too); fall back to catalog
2175
- # for samples mode if state empty.
 
 
 
 
2176
  sources = answers if (answers and any(answers.values())) else None
2177
  if not sources:
2178
- s = BY_FILENAME.get(filename)
2179
- if not s:
2180
- msg = "Run AI ANALYZE first to get an answer to translate."
2181
- return (panel_html("vanilla", msg, state="ready"),
2182
- panel_html("v2", msg, state="ready"),
2183
- panel_html("v3", msg, state="ready"),
2184
- gr.Button(visible=False))
2185
- sources = {"vanilla": s.get("vanilla_answer", ""),
2186
- "v2": s.get("v2_answer", ""),
2187
- "v3": s.get("v3_answer", "")}
2188
 
2189
  lang_code = LANG_BY_DISPLAY.get(lang_label, "en")
2190
  lang_name = next((name for _, name, code in LANGUAGES if code == lang_code), "English")
@@ -2240,20 +2254,15 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base(primary_hue="red", neutral_hue="zin
2240
  [vanilla_panel, v2_panel, v3_panel, original_btn], api_name=False)
2241
 
2242
  def restore_original(filename, answers):
2243
- # Prefer state (works for live upload/webcam); fall back to catalog
 
 
 
2244
  sources = answers if (answers and any(answers.values())) else None
2245
  if not sources:
2246
- s = BY_FILENAME.get(filename)
2247
- if not s:
2248
- msg = "No answer to restore."
2249
- return (panel_html("vanilla", msg, state="ready"),
2250
- panel_html("v2", msg, state="ready"),
2251
- panel_html("v3", msg, state="ready"),
2252
- gr.Button(visible=False),
2253
- gr.Dropdown(value=DEFAULT_LANG_DISPLAY))
2254
- sources = {"vanilla": s.get("vanilla_answer", ""),
2255
- "v2": s.get("v2_answer", ""),
2256
- "v3": s.get("v3_answer", "")}
2257
  return (panel_html("vanilla", sources.get("vanilla", "")),
2258
  panel_html("v2", sources.get("v2", "")),
2259
  panel_html("v3", sources.get("v3", "")),
 
1382
  font-size: 19px !important; font-weight: 800 !important;
1383
  line-height: 1.45 !important; color: #ffffff !important;
1384
  letter-spacing: -0.2px !important; white-space: pre-wrap;
1385
+ /* Force long latin binomena (e.g. *Cocconeis-placentula*) and code-like
1386
+ tokens to break inside the card instead of pushing a horizontal scroll. */
1387
+ overflow-wrap: anywhere; word-break: normal;
1388
+ max-width: 100%;
1389
  }
1390
+ .ml-panel-body { overflow-x: hidden; }
1391
  .ml-caret::after { content: 'β–‹'; color: #00DCE6; margin-left: 2px;
1392
  animation: ml-blink 1s steps(2) infinite; font-weight: 400; }
1393
  @keyframes ml-blink { 50% { opacity: 0; } }
 
1965
  except ValueError: grid = 0
1966
  try: cross = int(cross_str or "0")
1967
  except ValueError: cross = 0
1968
+ # Reset live-answer state on every sample switch β€” without this the
1969
+ # previous image's live answer could leak into translate/restore for
1970
+ # the next sample and look like a real result.
1971
+ cleared_state = {"vanilla": "", "v2": "", "v3": ""}
1972
  if not filename:
1973
  return (folder_html(cat_label, None),
1974
  viewport_html(None, shape, grid, cross), "", *empty_panels(),
1975
  gr.Button(visible=False),
1976
+ gr.Dropdown(value=DEFAULT_LANG_DISPLAY),
1977
+ cleared_state)
1978
  uri = full_uri(filename)
1979
  return (folder_html(cat_label, filename),
1980
  viewport_html(uri, shape, grid, cross), uri, *empty_panels(),
1981
  gr.Button(visible=False),
1982
+ gr.Dropdown(value=DEFAULT_LANG_DISPLAY),
1983
+ cleared_state)
1984
 
1985
  picked_filename.change(on_pick,
1986
  [picked_filename, cat_state, shape_state, grid_state, cross_state],
1987
  [folder_grid, viewport, viewport_uri, vanilla_panel, v2_panel, v3_panel,
1988
+ original_btn, lang_dropdown, last_answers], api_name=False)
1989
 
1990
  def on_file_upload(file_obj, shape, grid_str, cross_str):
1991
  try: grid = int(grid_str or "0")
 
2103
  spans = []
2104
  for i, tok in enumerate(tokens):
2105
  delay = i * ms_per_word
2106
+ # Plain HTML-escaped token; trailing whitespace is kept as a real
2107
+ # space so the parent's `white-space: pre-wrap` lets the browser
2108
+ # break lines naturally. Using &nbsp; here forces a non-breaking
2109
+ # run that overflows narrow cards and creates ugly h-scroll.
2110
+ safe = _html.escape(tok)
2111
  spans.append(
2112
  f'<span class="ml-word" style="animation-delay:{delay}ms;">{safe}</span>'
2113
  )
 
2186
  js=ANALYZE_PRE_JS, api_name=False)
2187
 
2188
  def do_translate(filename, lang_label, answers):
2189
+ # Translate ONLY what the live model produced this session. The previous
2190
+ # version fell back to BY_FILENAME[filename] (curated catalog answers)
2191
+ # when state was empty β€” which silently translated the wrong image's
2192
+ # pre-baked text whenever AI ANALYZE failed (quota / backend down).
2193
+ # That looked like a successful translation of fictional content. Now:
2194
+ # no live answer β†’ honest "Run AI ANALYZE first" message.
2195
  sources = answers if (answers and any(answers.values())) else None
2196
  if not sources:
2197
+ msg = "Run AI ANALYZE first to get an answer to translate."
2198
+ return (panel_html("vanilla", msg, state="ready"),
2199
+ panel_html("v2", msg, state="ready"),
2200
+ panel_html("v3", msg, state="ready"),
2201
+ gr.Button(visible=False))
 
 
 
 
 
2202
 
2203
  lang_code = LANG_BY_DISPLAY.get(lang_label, "en")
2204
  lang_name = next((name for _, name, code in LANGUAGES if code == lang_code), "English")
 
2254
  [vanilla_panel, v2_panel, v3_panel, original_btn], api_name=False)
2255
 
2256
  def restore_original(filename, answers):
2257
+ # Restore ONLY the live answer that produced this translation. Same
2258
+ # rationale as do_translate: never fall back to BY_FILENAME catalog β€”
2259
+ # otherwise pressing ORIGINAL after a failed analyze silently restores
2260
+ # a pre-baked answer for a different image.
2261
  sources = answers if (answers and any(answers.values())) else None
2262
  if not sources:
2263
+ return (*empty_panels(),
2264
+ gr.Button(visible=False),
2265
+ gr.Dropdown(value=DEFAULT_LANG_DISPLAY))
 
 
 
 
 
 
 
 
2266
  return (panel_html("vanilla", sources.get("vanilla", "")),
2267
  panel_html("v2", sources.get("v2", "")),
2268
  panel_html("v3", sources.get("v3", "")),