优化Gemini翻译

This commit is contained in:
John Smith 2024-02-25 18:22:13 +08:00
parent 21a06e68b1
commit 8c3d62d08d
3 changed files with 106 additions and 97 deletions

View File

@ -161,12 +161,11 @@ class AppConfig:
translator_config['app_id'] = section['app_id']
translator_config['secret'] = section['secret']
elif type_ == 'GeminiTranslate':
translator_config['app_id'] = section['app_id']
translator_config['prompt'] = section['prompt']
translator_config['temperature'] = section['temperature']
translator_config['model_name'] = section['model_name']
translator_config['is_use_proxy'] = section.getboolean('is_use_proxy')
translator_config['proxy'] = section['proxy']
translator_config['api_key'] = section['api_key']
translator_config['model_code'] = section['model_code']
translator_config['prompt'] = section['prompt']
translator_config['temperature'] = section.getfloat('temperature')
else:
raise ValueError(f'Invalid translator type: {type_}')
except Exception: # noqa

View File

@ -146,27 +146,45 @@ target_language = jp
app_id =
secret =
[gemini_translate]
# 文档https://blog.google/technology/ai/gemini-api-developers-cloud/
# https://ai.google.dev/tutorials/rest_quickstart
# https://ai.google.dev/models/gemini?hl=zh-cn#model-versions
[gemini_translate]
# 文档https://ai.google.dev/docs
# 定价https://ai.google.dev/pricing
# * 目前只有免费版最高QPS为1
# * 收费版 输入 $0.000125 / 1000 个字符;输出 $0.000375 / 1000 个字符
# 模型规格https://ai.google.dev/models/gemini
# * Gemini Pro 最高QPS为1
# 类型Gemini翻译
type = GeminiTranslate
# 请求间隔时间(秒),等于 1 / QPS
# 如果直播间里其实并不是很多弹幕,可以适当减少请求间隔值
query_interval = 1
query_interval = 1.1
# 代理地址
is_use_proxy = false
proxy = http://127.0.0.1:1087
# 代理地址如果为空不使用代理。注意必须要在指定地区才能使用https://ai.google.dev/available_regions
proxy = http://127.0.0.1:7890
# Model versions
# https://ai.google.dev/models/gemini?hl=zh-cn#model-versions
model_name = gemini-1.0-pro-latest
app_id = xxxxxx
# API密钥
api_key =
# 模型代码
model_code = models/gemini-1.0-pro
# 提示词
prompt = As an advanced translation software, your role is to provide accurate translations
that respect the original content's meaning and tone. If the input text includes brackets,
ensure that these are retained in the translation. Aim to deliver the translated text in a
polite and gentle tone, as per the preferences of the audience.\n\nBelow are some examples
to guide you:\n\nExamples:\nInput1:\n来拉(莱拉) 设置一下吧\nOutput1:\nライラちゃん、設定してみましょうか。
\n\nInput2:\n我来拉一下各位进队伍\nOutput2:\n皆さんをチームに入れさせていただきます。\n\nInput3:\n死了w\n
Output3:\n死んじゃったわw\n\nInput4:\n每天来宝这里打个卡\nOutput4:\n毎日、ここに来て宝さんにチェックインしま
\n\n\nPlease keep in mind that accurate translation is not just about linguistic conversion;
it is about conveying the same sentiment and meaning as the original input. Pay special
attention to internet vernaculars and colloquial expressions to maintain the nuances of the
source language.\n\nNow, proceed with the translation of the following Chinese comment text
into Japanese, ensuring accuracy and preservation of the original message:\nInput:\n
{{original_text}}\nOutput ONLY:\n
# 温度,用于控制令牌选择的随机性,较低的温度适合需要更具确定性或不够开放的回答的提示,而较高的温度可以产生更加多样化或更具创意的结果
temperature = 0.4
prompt = "As an advanced translation software, your role is to provide accurate translations that respect the original content's meaning and tone. If the input text includes brackets, ensure that these are retained in the translation. Aim to deliver the translated text in a polite and gentle tone, as per the preferences of the audience.\n\nBelow are some examples to guide you:\n\nExamples:\nInput1:\n来拉(莱拉) 设置一下吧\nOutput1:\nライラちゃん、設定してみましょうか。\n\nInput2:\n我来拉一下各位进队伍\nOutput2:\n皆さんをチームに入れさせていただきます。\n\nInput3:\n死了w\nOutput3:\n死んじゃったわw\n\nInput4:\n每天来宝这里打个卡\nOutput4:\n毎日、ここに来て宝さんにチェックインしま\n\n\nPlease keep in mind that accurate translation is not just about linguistic conversion; it is about conveying the same sentiment and meaning as the original input. Pay special attention to internet vernaculars and colloquial expressions to maintain the nuances of the source language.\n\nNow, proceed with the translation of the following Chinese comment text into Japanese, ensuring accuracy and preservation of the original message:\nInput:\n{{original_text}}\nOutput ONLY:\n"
# 傻逼B站获取表情都要登录开放平台也不发文本表情的URL我服了

View File

@ -92,8 +92,8 @@ def create_translate_provider(cfg):
)
elif type_ == 'GeminiTranslate':
return GeminiTranslate(
cfg['query_interval'], cfg['app_id'], cfg['prompt'], cfg['temperature'],
cfg['model_name'], cfg['is_use_proxy'], cfg['proxy']
cfg['query_interval'], cfg['proxy'], cfg['api_key'], cfg['model_code'],
cfg['prompt'], cfg['temperature']
)
return None
@ -681,27 +681,20 @@ class BaiduTranslate(TranslateProvider):
self._cool_down_timer_handle = None
self._on_availability_change()
class GeminiTranslate(TranslateProvider):
def __init__(self, query_interval, app_id, prompt, temperature=0.9, model_name="gemini-1.0-pro", is_use_proxy=False, proxy=None):
super().__init__(query_interval)
self._app_id = app_id
self._prompt = prompt
self._temperature = temperature
self._model_name = model_name
self._is_use_proxy = is_use_proxy
self._proxy = proxy
async def _do_translate(self, text) -> Optional[str]:
api_endpoint = f'https://generativelanguage.googleapis.com/v1beta/models/{self._model_name}:generateContent'
api_key = self._app_id
final_prompt = self._prompt.replace('{{original_text}}', text)
payload = {
class GeminiTranslate(TranslateProvider):
def __init__(self, query_interval, proxy, api_key, model_code, prompt, temperature):
super().__init__(query_interval)
self._proxy = proxy or None
self._api_key = api_key
self._url = f'https://generativelanguage.googleapis.com/v1beta/{model_code}:generateContent'
self._prompt = prompt.replace('\n', ' ').replace('\\n', '\n')
self._body = {
'contents': [
{
'role': 'user',
'parts': [{'text': final_prompt}]
},
# 'role': 'user',
'parts': [{'text': ''}]
}
],
'safetySettings': [
{
@ -722,64 +715,63 @@ class GeminiTranslate(TranslateProvider):
}
],
'generationConfig': {
'temperature': str(self._temperature),
'topP': '1',
'topK': '32',
'candidateCount': '1',
'maxOutputTokens': '8192'
'temperature': temperature,
'topP': 1,
'topK': 32,
'candidateCount': 1,
'maxOutputTokens': 8192
}
}
headers = {
'Content-Type': 'application/json',
}
if self._is_use_proxy:
proxy = self._proxy
else:
proxy = None
max_retries = 3
retry_delay = 1
attempts = 0 # 初始化尝试计数
while attempts < max_retries:
try:
# 设置超时时间为10秒
timeout = aiohttp.ClientTimeout(total=10)
async with utils.request.http_session.post(
f'{api_endpoint}?key={api_key}',
headers=headers,
json=payload,
proxy=proxy,
timeout=timeout
) as r:
if r.status == 200:
data = await r.json()
try:
translated_text = data['candidates'][0]['content']['parts'][0]['text']
return translated_text # 成功获取翻译文本,返回结果
except (KeyError, IndexError):
logger.warning('Failed to process the response correctly: %s', data)
# 如果响应结构有误,则退出循环
return None
else:
logger.warning('Request failed with status %d: %s', r.status, r.reason)
except asyncio.TimeoutError as toe:
logger.warning('Request timeout occurred: %s', str(toe))
except Exception as e:
log_str = f'{str(e)}\ndata:\n{data}'
logger.error('An error occurred during the request: %s', log_str)
try:
logger.error('FinishReason: ' + {data['candidates'][0]['finishReason']})
except:
pass
# 未成功获取翻译文本,增加尝试次数并等待重新尝试
attempts += 1
if attempts < max_retries:
logger.info('Retrying request (%d/%d)...', attempts, max_retries)
await asyncio.sleep(retry_delay)
# 如果所有重试尝试后还未成功,则记录日志并返回 None
logger.error('All retry attempts failed.')
return None
self._cool_down_timer_handle = None
@property
def is_available(self):
return self._cool_down_timer_handle is None and super().is_available
async def _do_translate(self, text) -> Optional[str]:
input_text = self._prompt.replace('{{original_text}}', text)
self._body['contents'][0]['parts'][0]['text'] = input_text
try:
async with utils.request.http_session.post(
self._url,
params={'key': self._api_key},
json=self._body,
proxy=self._proxy,
) as r:
if r.status != 200:
logger.warning('GeminiTranslate request failed: status=%d %s', r.status, r.reason)
self._on_fail(r.status)
return None
data = await r.json()
except (aiohttp.ClientConnectionError, asyncio.TimeoutError) as e:
logger.warning('GeminiTranslate request failed, %s: %s', type(e).__name__, e)
return None
try:
candidates = data['candidates']
if not candidates:
block_reason = data['promptFeedback'].get('blockReason', '')
logger.warning('GeminiTranslate no candidate, block_reason=%s, text=%s', block_reason, text)
return None
first_content_parts = candidates[0]['content']['parts']
return ''.join(part.get('text', '') for part in first_content_parts)
except (KeyError, IndexError):
logger.warning('GeminiTranslate failed to parse response: %s', data)
return None
def _on_fail(self, code):
if self._cool_down_timer_handle is not None:
return
if code in (401, 403):
# API密钥无效没有权限或者不在有效地区。需要手动处理等5分钟
self._cool_down_timer_handle = asyncio.get_running_loop().call_later(
5 * 60, self._on_cool_down_timeout
)
self._on_availability_change()
def _on_cool_down_timeout(self):
self._cool_down_timer_handle = None
self._on_availability_change()