0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-09 21:45:25 +08:00
discourse/plugins/discourse-ai/lib/agents/post_raw_translator.rb
Rafael dos Santos Silva bfeb73e3af
FIX: Seed translator agent examples as conversation turns (#41526)
Previously, the translation agents (`PostRawTranslator`,
`TopicTitleTranslator`, and `ShortTextTranslator`) embedded their
few-shot examples directly in the system prompt as `Input:`/`Output:`
text, where the example inputs were JSON but the outputs were bare text
— contradicting the `response_format` that requires a `{"output":
"..."}` object. This conflicting guidance caused some models to echo the
input wrapper into published translations, e.g. German localizations
starting with `{"content":"...` as reported in
https://meta.discourse.org/t/german-translations-contain-translation-elements/407009.

This change moves the examples to the `examples` hook — which pre-seeds
them as real user/model turns in the conversation, like our other agents
(`Proofreader`, `LocaleDetector`, `SmartDates`) — with each model turn
serialized as `{"output": "..."}` so the examples demonstrate the exact
structured output the agent must produce. It also drops the
now-unnecessary instruction claiming a bare ASCII `"` would truncate the
response (the structured output layer handles escaping), and removes a
stray trailing quote that had leaked into the Japanese example.
2026-07-08 11:47:19 -03:00

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