mirror of
https://github.com/xfgryujk/blivechat.git
synced 2024-12-26 04:41:40 +08:00
优化Gemini翻译
This commit is contained in:
parent
21a06e68b1
commit
8c3d62d08d
@ -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
|
||||
|
@ -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,我服了
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user