[refactor] translation engines: common interface

This commit is contained in:
Bnyro 2024-10-15 15:39:14 +02:00
parent 3e87354f0e
commit 7edd75ff93
8 changed files with 125 additions and 78 deletions

View file

@ -1,8 +1,6 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
"""Deepl translation engine""" """Deepl translation engine"""
from json import loads
about = { about = {
"website": 'https://deepl.com', "website": 'https://deepl.com',
"wikidata_id": 'Q43968444', "wikidata_id": 'Q43968444',
@ -41,16 +39,14 @@ def request(_query, params):
def response(resp): def response(resp):
results = [] results = []
result = loads(resp.text)
translations = result['translations']
infobox = "<dl>" result = resp.json()
for translation in translations: if not result.get('translations'):
infobox += f"<dd>{translation['text']}</dd>" return results
infobox += "</dl>" translations = [{'text': translation['text']} for translation in result['translations']]
results.append({'answer': infobox}) results.append({'answer': translations[0]['text'], 'answer_type': 'translations', 'translations': translations})
return results return results

View file

@ -3,7 +3,6 @@
Dictzone Dictzone
""" """
from urllib.parse import urljoin
from lxml import html from lxml import html
from searx.utils import eval_xpath from searx.utils import eval_xpath
@ -33,11 +32,10 @@ def request(query, params): # pylint: disable=unused-argument
def response(resp): def response(resp):
results = []
dom = html.fromstring(resp.text) dom = html.fromstring(resp.text)
for k, result in enumerate(eval_xpath(dom, results_xpath)[1:]): translations = []
for result in eval_xpath(dom, results_xpath)[1:]:
try: try:
from_result, to_results_raw = eval_xpath(result, './td') from_result, to_results_raw = eval_xpath(result, './td')
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
@ -49,12 +47,17 @@ def response(resp):
if t.strip(): if t.strip():
to_results.append(to_result.text_content()) to_results.append(to_result.text_content())
results.append( translations.append(
{ {
'url': urljoin(str(resp.url), '?%d' % k), 'text': f"{from_result.text_content()} - {'; '.join(to_results)}",
'title': from_result.text_content(),
'content': '; '.join(to_results),
} }
) )
return results if translations:
result = {
'answer': translations[0]['text'],
'translations': translations,
'answer_type': 'translations',
}
return [result]

View file

@ -24,7 +24,7 @@ def request(_query, params):
request_url = random.choice(base_url) if isinstance(base_url, list) else base_url request_url = random.choice(base_url) if isinstance(base_url, list) else base_url
params['url'] = f"{request_url}/translate" params['url'] = f"{request_url}/translate"
args = {'source': params['from_lang'][1], 'target': params['to_lang'][1], 'q': params['query']} args = {'source': params['from_lang'][1], 'target': params['to_lang'][1], 'q': params['query'], 'alternatives': 3}
if api_key: if api_key:
args['api_key'] = api_key args['api_key'] = api_key
params['data'] = dumps(args) params['data'] = dumps(args)
@ -42,12 +42,11 @@ def response(resp):
json_resp = resp.json() json_resp = resp.json()
text = json_resp.get('translatedText') text = json_resp.get('translatedText')
from_lang = resp.search_params["from_lang"][1] if not text:
to_lang = resp.search_params["to_lang"][1] return results
query = resp.search_params["query"]
req_url = resp.search_params["req_url"]
if text: translations = [{'text': text}] + [{'text': alternative} for alternative in json_resp.get('alternatives', [])]
results.append({"answer": text, "url": f"{req_url}/?source={from_lang}&target={to_lang}&q={query}"})
results.append({'answer': text, 'answer_type': 'translations', 'translations': translations})
return results return results

View file

@ -1,8 +1,6 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
"""Lingva (alternative Google Translate frontend)""" """Lingva (alternative Google Translate frontend)"""
from json import loads
about = { about = {
"website": 'https://lingva.ml', "website": 'https://lingva.ml',
"wikidata_id": None, "wikidata_id": None,
@ -29,7 +27,7 @@ def request(_query, params):
def response(resp): def response(resp):
results = [] results = []
result = loads(resp.text) result = resp.json()
info = result["info"] info = result["info"]
from_to_prefix = "%s-%s " % (resp.search_params['from_lang'][1], resp.search_params['to_lang'][1]) from_to_prefix = "%s-%s " % (resp.search_params['from_lang'][1], resp.search_params['to_lang'][1])
@ -38,27 +36,40 @@ def response(resp):
if 'definitions' in info: # pylint: disable=too-many-nested-blocks if 'definitions' in info: # pylint: disable=too-many-nested-blocks
for definition in info['definitions']: for definition in info['definitions']:
if 'list' in definition: for item in definition.get('list', []):
for item in definition['list']: for synonym in item.get('synonyms', []):
if 'synonyms' in item: results.append({"suggestion": from_to_prefix + synonym})
for synonym in item['synonyms']:
results.append({"suggestion": from_to_prefix + synonym})
infobox = "" data = []
for definition in info['definitions']:
for translation in definition['list']:
data.append(
{
'text': result['translation'],
'definitions': [translation['definition']] if translation['definition'] else [],
'examples': [translation['example']] if translation['example'] else [],
'synonyms': translation['synonyms'],
}
)
for translation in info["extraTranslations"]: for translation in info["extraTranslations"]:
for word in translation["list"]: for word in translation["list"]:
infobox += f"<dl><dt>{word['word']}</dt>" data.append(
{
'text': word['word'],
'definitions': word['meanings'],
}
)
for meaning in word["meanings"]: if not data and result['translation']:
infobox += f"<dd>{meaning}</dd>" data.append({'text': result['translation']})
infobox += "</dl>"
results.append( results.append(
{ {
'infobox': result["translation"], 'answer': data[0]['text'],
'content': infobox, 'answer_type': 'translations',
'translations': data,
} }
) )

View file

@ -4,7 +4,6 @@
import random import random
import re import re
from urllib.parse import urlencode from urllib.parse import urlencode
from flask_babel import gettext
about = { about = {
"website": 'https://codeberg.org/aryak/mozhi', "website": 'https://codeberg.org/aryak/mozhi',
@ -35,30 +34,27 @@ def request(_query, params):
def response(resp): def response(resp):
translation = resp.json() translation = resp.json()
infobox = "" data = {'text': translation['translated-text'], 'definitions': [], 'examples': []}
if translation['target_transliteration'] and not re.match( if translation['target_transliteration'] and not re.match(
re_transliteration_unsupported, translation['target_transliteration'] re_transliteration_unsupported, translation['target_transliteration']
): ):
infobox = f"<b>{translation['target_transliteration']}</b>" data['transliteration'] = translation['target_transliteration']
if translation['word_choices']: if translation['word_choices']:
for word in translation['word_choices']: for word in translation['word_choices']:
infobox += f"<dl><dt>{word['word']}: {word['definition']}</dt>" if word.get('definition'):
data['definitions'].append(word['definition'])
if word['examples_target']: for example in word.get('examples_target', []):
for example in word['examples_target']: data['examples'].append(re.sub(r"<|>", "", example).lstrip('- '))
infobox += f"<dd>{re.sub(r'<|>', '', example)}</dd>"
infobox += f"<dd>{re.sub(r'<|>', '', example)}</dd>"
infobox += "</dl>" data['synonyms'] = translation.get('source_synonyms', [])
if translation['source_synonyms']:
infobox += f"<dl><dt>{gettext('Synonyms')}: {', '.join(translation['source_synonyms'])}</dt></dl>"
result = { result = {
'infobox': translation['translated-text'], 'answer': translation['translated-text'],
'content': infobox, 'answer_type': 'translations',
'translations': [data],
} }
return [result] return [result]

View file

@ -35,18 +35,16 @@ def request(query, params): # pylint: disable=unused-argument
def response(resp): def response(resp):
results = [] json_resp = resp.json()
results.append( text = json_resp['responseData']['translatedText']
{
'url': web_url.format( alternatives = [match['translation'] for match in json_resp['matches'] if match['translation'] != text]
from_lang=resp.search_params['from_lang'][2], translations = [{'text': translation} for translation in [text] + alternatives]
to_lang=resp.search_params['to_lang'][2],
query=resp.search_params['query'], result = {
), 'answer': translations[0]['text'],
'title': '[{0}-{1}] {2}'.format( 'answer_type': 'translations',
resp.search_params['from_lang'][1], resp.search_params['to_lang'][1], resp.search_params['query'] 'translations': translations,
), }
'content': resp.json()['responseData']['translatedText'],
} return [result]
)
return results

View file

@ -0,0 +1,38 @@
<div class="answer-translations">
{% for translation in translations %}
{% if loop.index > 1 %}
<hr />
{% endif %}
<h3>{{ translation.text }}</h3>
{% if translation.transliteration %}
<b>translation.transliteration</b>
{% endif %} {% if translation.definitions %}
<dl>
<dt>{{ _('Definitions') }}</dt>
<ul>
{% for definition in translation.definitions %}
<li>{{ definition }}</li>
{% endfor %}
<ul>
</dl>
{% endif %} {% if translation.examples %}
<dl>
<dt>{{ _('Examples') }}</dt>
<ul>
{% for example in translation.examples %}
<li>{{ example }}</li>
{% endfor %}
</ul>
</dl>
{% endif %} {% if translation.synonyms %}
<dl>
<dt>{{ _('Synonyms') }}</dt>
<ul>
{% for synonym in translation.synonyms %}
<li>{{ synonym }}</li>
{% endfor %}
</ul>
</dl>
{% endif %}
{% endfor %}
</div>

View file

@ -23,14 +23,20 @@
<div id="answers" role="complementary" aria-labelledby="answers-title"><h4 class="title" id="answers-title">{{ _('Answers') }} : </h4> <div id="answers" role="complementary" aria-labelledby="answers-title"><h4 class="title" id="answers-title">{{ _('Answers') }} : </h4>
{%- for answer in answers.values() -%} {%- for answer in answers.values() -%}
<div class="answer"> <div class="answer">
<span>{{ answer.answer }}</span> {%- if answer.answer_type == 'translations' -%}
{%- if answer.url -%} {% with translations=answer.translations %}
<a href="{{ answer.url }}" class="answer-url" {% include 'simple/answerers/translate.html' %}
{%- if results_on_new_tab %} target="_blank" rel="noopener noreferrer" {% endwith %}
{%- else -%} rel="noreferrer" {%- else -%}
{%- endif -%} <span>{{ answer.answer }}</span>
>{{ urlparse(answer.url).hostname }}</a> {%- if answer.url -%}
{% endif -%} <a href="{{ answer.url }}" class="answer-url"
{%- if results_on_new_tab %} target="_blank" rel="noopener noreferrer"
{%- else -%} rel="noreferrer"
{%- endif -%}
>{{ urlparse(answer.url).hostname }}</a>
{% endif -%}
{%- endif -%}
</div> </div>
{%- endfor -%} {%- endfor -%}
</div> </div>