mirror of
https://github.com/discourse/discourse.git
synced 2026-08-07 13:19:19 +08:00
## Problem
A topic title translation was saved truncated: `Permanently Delete does
not show (even after 5 minutes)` → `"Endgültig löschen`.
The raw completion showed the model emitted `{"output": "\"Endgültig
löschen" }` with `finish_reason: stop` at 12 tokens — complete, valid
JSON that our parsing pipeline reproduced faithfully. The truncation
happened at generation time: the model opened a quoted UI label with an
escaped ASCII quote (`\"`), then sampled a bare `"` where it meant `\"`.
Under strict `json_schema` guided decoding that bare quote terminates
the JSON string value, and with `additionalProperties: false` the
grammar then only allows `}`, forcing the generation to end
mid-sentence.
Native typographic quotation marks (`„…“`, `«…»`, `「…」`) are ordinary
characters inside a JSON string — no escaping, no ambiguity — so they
can't trigger this failure mode. A parallel successful run that happened
to use `„…“` completed fine.
## Fix
`PostRawTranslator` already has a rule instructing native quotation
marks. This adds the same rule to `TopicTitleTranslator` and
`ShortTextTranslator`:
- **TopicTitleTranslator**: new guideline 6, plus a few-shot example
using the exact title from the incident, showing German `„…“` around the
UI label.
- **ShortTextTranslator**: new guideline 5, plus a `Click "Reply"` →
`Cliquez sur « Répondre »` example.
- **PostRawTranslator**: the existing rule's German example closed with
an ASCII `"` instead of `“` — fixed.
Seeded system agents re-sync `system_prompt` and `examples` from the
classes on migration, so sites pick this up automatically.
97 lines
5.6 KiB
Ruby
Vendored
97 lines
5.6 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module Agents
|
|
class PostRawTranslator < Agent
|
|
def self.default_enabled
|
|
false
|
|
end
|
|
|
|
def system_prompt
|
|
<<~PROMPT.strip
|
|
You are a friendly and very skilled human linguist and translator. Your goal is to produce translations that read naturally to native speakers, as if originally written in the target language — indistinguishable from content written by a human. Follow these instructions strictly:
|
|
|
|
1. Preserve Markdown elements, HTML elements, BBCode tags and their attributes, or newlines. Text must be translated without altering the original formatting.
|
|
2. Maintain the original document structure including headings, lists, tables, code blocks, etc.
|
|
3. Preserve all links, images, and other media references without translation.
|
|
4. For technical and brand terminology:
|
|
- Provide the accepted target language term if it exists.
|
|
- If no equivalent exists, transliterate the term and include the original term in parentheses.
|
|
5. For ambiguous terms or phrases, do not translate word-for-word in isolation. Derive the intended meaning from the full context of the document before choosing a translation.
|
|
6. Ensure the translation only contains the original language and the target language.
|
|
7. Match the tone and register of the source text. If the source is informal and conversational, use informal address forms and a casual tone in the target language. Do not default to formal address (e.g. German Sie, French vous) unless the source text is itself formal.
|
|
8. For any quoted text, use the target language's native quotation marks — for example German „…“, French «…», Japanese 「…」 — rather than ASCII quotes.
|
|
|
|
Follow these instructions on what NOT to do:
|
|
9. Do not translate code snippets or programming language names, but ensure that any comments within the code are translated. Code can be represented in ``` or in single ` backticks or in <code> HTML tags.
|
|
10. Do not add any content besides the translation.
|
|
11. Do not add unnecessary newlines.
|
|
|
|
The text to translate will be provided in JSON format with the following structure:
|
|
{"content": "Text to translate", "target_locale": "Target language code"}
|
|
|
|
Format your response as a JSON object with a single key named "output", which has the translation as the value.
|
|
Your output should be in the following format:
|
|
|
|
{"output": "xx"}
|
|
|
|
Where "xx" is replaced by the translation.
|
|
reply with valid JSON only
|
|
PROMPT
|
|
end
|
|
|
|
def response_format
|
|
[{ "key" => "output", "type" => "string" }]
|
|
end
|
|
|
|
def examples
|
|
[
|
|
[
|
|
{
|
|
content:
|
|
"**Heathrow fechado**: Suspensão de voos deve continuar nos próximos dias, afirma gerente do aeroporto de Londres\n\n[details=Do site da BBC]\n\nA British Airways estimou que 85% de seus voos planejados seriam realizados no sábado, mas com atrasos em todos os voos. Às 7h GMT, a maioria das partidas havia ocorrido conforme o esperado, mas, das chegadas, nove dos primeiros 20 voos programados para aterrissar foram cancelados.\n\n[/details]",
|
|
target_locale: "en",
|
|
}.to_json,
|
|
{
|
|
output:
|
|
"**Heathrow Closed**: Flight Suspension Expected to Continue for the Coming Days, Says London Airport Manager\n\n[details=From the BBC website]\n\nBritish Airways estimated that 85% of its scheduled flights would operate on Saturday, but all flights were delayed. By 7:00 a.m. GMT, most departures had proceeded as expected, but of the arrivals, nine of the first 20 flights scheduled to land were canceled.\n\n[/details]",
|
|
}.to_json,
|
|
],
|
|
[
|
|
{
|
|
content:
|
|
"[quote=\"alice, post:3, topic:42\"]\nHow do I get started?\n[/quote]\n\nWe're so glad you're here! Want to run your own Minecraft server? Just click the Get Started button below — it's easy.",
|
|
target_locale: "de",
|
|
}.to_json,
|
|
{
|
|
output:
|
|
"[quote=\"alice, post:3, topic:42\"]\nWie fange ich an?\n[/quote]\n\nWir freuen uns sehr, dass du hier bist! Möchtest du deinen eigenen Minecraft-Server betreiben? Klick einfach unten auf den „Loslegen“-Button — es ist ganz einfach.",
|
|
}.to_json,
|
|
],
|
|
[
|
|
{
|
|
content:
|
|
"There has been an error in my update\n\n```ruby\napi_key = \"a quick brown fox\"\nfetch(\"https://api.example.com/data\", headers: { 'Authorization' => api_key })\n```\n\nPlease help me fix it.",
|
|
target_locale: "ja",
|
|
}.to_json,
|
|
{
|
|
output:
|
|
"アップデートでエラーが発生しました\n\n```ruby\napi_key = \"a quick brown fox\"\nfetch(\"https://api.example.com/data\", headers: { 'Authorization' => api_key })\n```\n\n修正にご協力ください。",
|
|
}.to_json,
|
|
],
|
|
[
|
|
{
|
|
content:
|
|
"He proposed a so-called clean architecture for the new service. But clean doesn't always mean simple.",
|
|
target_locale: "de",
|
|
}.to_json,
|
|
{
|
|
output:
|
|
"Er schlug eine sogenannte „saubere“ Architektur für den neuen Dienst vor. Doch „sauber“ bedeutet nicht immer einfach.",
|
|
}.to_json,
|
|
],
|
|
]
|
|
end
|
|
end
|
|
end
|
|
end
|