billingsmoore Claude Sonnet 5 commited on
Commit
23eb152
·
1 Parent(s): 04721fb

Log translate model/prompt, link OpenRouter key signup and leaderboard

Browse files

translate events now record backend, model, and the actual prompt text
used (null for the local CPU backend, which ignores the prompt file) -
translate_all previously only logged a generic "OpenRouter" backend with
no model id at all. Landing page also links to where to get an
OpenRouter API key and to the Tibetan AI Leaderboard for model comparison.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Files changed (3) hide show
  1. app.py +5 -3
  2. handlers.py +9 -4
  3. tests/test_handlers.py +40 -1
app.py CHANGED
@@ -43,9 +43,11 @@ def build_app() -> gr.Blocks:
43
  "(https://huggingface.co/billingsmoore/mlotsawa-ground-base)) — free, runs on this "
44
  "machine, but a plain translation model, not an instruction-following AI (it ignores "
45
  "the translation prompt below) and generally lower translation quality. For higher-quality, instruction-"
46
- "following translation, add an **OpenRouter API key** in Settings and pick a model "
47
- "from the dropdown — this calls OpenRouter's API (usage is billed to your OpenRouter "
48
- "account) and uses the editable translation prompt.\n\n"
 
 
49
  "Usage of this space may be monitored for research purposes. You can opt out of this "
50
  "in Settings."
51
  )
 
43
  "(https://huggingface.co/billingsmoore/mlotsawa-ground-base)) — free, runs on this "
44
  "machine, but a plain translation model, not an instruction-following AI (it ignores "
45
  "the translation prompt below) and generally lower translation quality. For higher-quality, instruction-"
46
+ "following translation, add an [**OpenRouter API key**](https://openrouter.ai/keys) in "
47
+ "Settings and pick a model from the dropdown — this calls OpenRouter's API (usage is "
48
+ "billed to your OpenRouter account) and uses the editable translation prompt. See the "
49
+ "[Tibetan AI Leaderboard](https://huggingface.co/spaces/khyentsevision/tibetan-ai-leaderboard) "
50
+ "for how different models perform on Tibetan translation evaluations.\n\n"
51
  "Usage of this space may be monitored for research purposes. You can opt out of this "
52
  "in Settings."
53
  )
handlers.py CHANGED
@@ -293,9 +293,11 @@ def _translate_one(state: dict, slot_idx: int, source: str, api_key: str, model:
293
  segments[actual_idx]["target"] = text
294
  state["segments"] = segments
295
 
296
- backend = f"openrouter:{model}" if using_openrouter(api_key) else "local_cpu"
297
  _log(state, "translate", {
298
- "backend": backend,
 
 
299
  "segment_count": 1,
300
  "segments": [{"source": source, "target": text}],
301
  })
@@ -308,7 +310,8 @@ def _translate_all(state, api_key, model, *slot_values):
308
  targets = list(slot_values[MAX_SLOTS:])
309
  state = _save_page_edits(state, sources, targets)
310
 
311
- backend = "OpenRouter" if using_openrouter(api_key) else "local CPU model (mlotsawa-ground-base)"
 
312
 
313
  stop = threading.Event()
314
  result = [None, None]
@@ -350,7 +353,9 @@ def _translate_all(state, api_key, model, *slot_values):
350
  status += f" {len(errors)} error(s)."
351
 
352
  _log(state, "translate", {
353
- "backend": backend,
 
 
354
  "segment_count": count,
355
  "segments": [{"source": seg.get("source", ""), "target": seg.get("target", "")} for seg in segments],
356
  })
 
293
  segments[actual_idx]["target"] = text
294
  state["segments"] = segments
295
 
296
+ is_openrouter = using_openrouter(api_key)
297
  _log(state, "translate", {
298
+ "backend": "openrouter" if is_openrouter else "local_cpu",
299
+ "model": model if is_openrouter else "billingsmoore/mlotsawa-ground-base",
300
+ "prompt": read_prompt() if is_openrouter else None,
301
  "segment_count": 1,
302
  "segments": [{"source": source, "target": text}],
303
  })
 
310
  targets = list(slot_values[MAX_SLOTS:])
311
  state = _save_page_edits(state, sources, targets)
312
 
313
+ is_openrouter = using_openrouter(api_key)
314
+ backend = "OpenRouter" if is_openrouter else "local CPU model (mlotsawa-ground-base)"
315
 
316
  stop = threading.Event()
317
  result = [None, None]
 
353
  status += f" {len(errors)} error(s)."
354
 
355
  _log(state, "translate", {
356
+ "backend": "openrouter" if is_openrouter else "local_cpu",
357
+ "model": model if is_openrouter else "billingsmoore/mlotsawa-ground-base",
358
+ "prompt": read_prompt() if is_openrouter else None,
359
  "segment_count": count,
360
  "segments": [{"source": seg.get("source", ""), "target": seg.get("target", "")} for seg in segments],
361
  })
tests/test_handlers.py CHANGED
@@ -357,10 +357,25 @@ def test_translate_one_logs_translate_event():
357
  h._translate_one(state, 0, "source text", "api-key", "model-x")
358
  event_type, session_id, payload = mock_log.call_args[0]
359
  assert event_type == "translate"
360
- assert payload["backend"] == "openrouter:model-x"
 
 
361
  assert payload["segments"] == [{"source": "source text", "target": "translated!"}]
362
 
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  def test_translate_one_records_error_in_target():
365
  state = h._make_state()
366
  state["segments"] = _segments("source text")
@@ -407,10 +422,34 @@ def test_translate_all_reports_completion_status():
407
 
408
  event_type, session_id, payload = mock_log.call_args[0]
409
  assert event_type == "translate"
 
 
 
410
  assert payload["segment_count"] == 2
411
  assert payload["segments"] == [{"source": "a", "target": "A"}, {"source": "b", "target": "B"}]
412
 
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  def test_translate_all_reports_errors_in_status():
415
  state = h._make_state()
416
  state["segments"] = _segments("a", "b")
 
357
  h._translate_one(state, 0, "source text", "api-key", "model-x")
358
  event_type, session_id, payload = mock_log.call_args[0]
359
  assert event_type == "translate"
360
+ assert payload["backend"] == "openrouter"
361
+ assert payload["model"] == "model-x"
362
+ assert payload["prompt"] == h.read_prompt()
363
  assert payload["segments"] == [{"source": "source text", "target": "translated!"}]
364
 
365
 
366
+ def test_translate_one_logs_local_backend_without_prompt():
367
+ state = h._make_state()
368
+ state["segments"] = _segments("source text")
369
+ with patch.object(h, "_engine_translate_one", return_value="translated!"), \
370
+ patch.object(h, "using_openrouter", return_value=False), \
371
+ patch.object(h, "log_event") as mock_log:
372
+ h._translate_one(state, 0, "source text", None, "model-x")
373
+ event_type, session_id, payload = mock_log.call_args[0]
374
+ assert payload["backend"] == "local_cpu"
375
+ assert payload["model"] == "billingsmoore/mlotsawa-ground-base"
376
+ assert payload["prompt"] is None
377
+
378
+
379
  def test_translate_one_records_error_in_target():
380
  state = h._make_state()
381
  state["segments"] = _segments("source text")
 
422
 
423
  event_type, session_id, payload = mock_log.call_args[0]
424
  assert event_type == "translate"
425
+ assert payload["backend"] == "openrouter"
426
+ assert payload["model"] == "model-x"
427
+ assert payload["prompt"] == h.read_prompt()
428
  assert payload["segment_count"] == 2
429
  assert payload["segments"] == [{"source": "a", "target": "A"}, {"source": "b", "target": "B"}]
430
 
431
 
432
+ def test_translate_all_logs_local_backend_without_prompt():
433
+ state = h._make_state()
434
+ state["segments"] = _segments("a")
435
+ slot_values = ["a"] + [""] * (h.MAX_SLOTS - 1) + [""] * h.MAX_SLOTS
436
+
437
+ def fake_translate_segments(segments, api_key, model, progress_callback=None, stop=None):
438
+ for seg in segments:
439
+ seg["target"] = seg["source"].upper()
440
+ return segments, []
441
+
442
+ with patch.object(h, "translate_segments", side_effect=fake_translate_segments), \
443
+ patch.object(h, "using_openrouter", return_value=False), \
444
+ patch.object(h, "log_event") as mock_log:
445
+ list(h._translate_all(state, None, "model-x", *slot_values))
446
+
447
+ event_type, session_id, payload = mock_log.call_args[0]
448
+ assert payload["backend"] == "local_cpu"
449
+ assert payload["model"] == "billingsmoore/mlotsawa-ground-base"
450
+ assert payload["prompt"] is None
451
+
452
+
453
  def test_translate_all_reports_errors_in_status():
454
  state = h._make_state()
455
  state["segments"] = _segments("a", "b")