GPT4ALLと日本語で会話したい
とおもったら、すでにやってくれている方がいた。
DeepL APIなどもっていないので、FuguMTをつかうことにした。これで、LLMが完全ローカル、それも日本語でうごくぞ…。
import signal
import subprocess
from time import sleep
import re
from transformers import pipeline
from prompt_toolkit import prompt
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.keys import Keys
kb = KeyBindings()
@kb.add(Keys.Tab)
def _(event):
event.app.exit(result=event.app.current_buffer.text)
# テキストの翻訳を行う関数
def translate(text: str, input_lang='en') -> str:
text = remove_ansi_escape_sequence(text)
if text == '' or text is None:
return ''
if input_lang=='en':
translation = ej_translator(text.lstrip(">"))
else:
translation = je_translator(text.lstrip(">"))
if translation == '' or translation is None:
return text
return translation
# ANSIエスケープシーケンスを削除する関数
def remove_ansi_escape_sequence(text: str) -> str:
return re \
.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') \
.sub('', text)
#複数行受け取り
def prompt_continuation(width, line_number, wrap_count):
"""
The continuation: display line numbers and '->' before soft wraps.
Notice that we can return any kind of formatted text from here.
The prompt continuation doesn't have to be the same width as the prompt
which is displayed before the first line, but in this example we choose to
align them. The `width` input that we receive here represents the width of
the prompt.
"""
if wrap_count > 0:
return " " * (width - 3) + "-> "
else:
text = ("- %i - " % (line_number + 1)).rjust(width)
return HTML("<strong>%s</strong>") % text
ej_translator = pipeline("translation", model="staka/fugumt-en-ja")
je_translator = pipeline("translation", model="staka/fugumt-ja-en")
if __name__ == '__main__':
# 対話するプログラムを起動する
process = subprocess.Popen(
[r'C:\xxxx\gpt4all\chat\gpt4all-lora-quantized-win64.exe'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
cwd=r'C:\xxxx\gpt4all\chat'
)
# プロセスをクリーンアップする関数
# Python終了時にこの関数からプロセスをキルすることで、メモリやCPUをがっつり食べるプロセスが残るのを防ぐ
def cleanup():
process.terminate()
sleep(5)
signal.signal(signal.SIGTERM, cleanup)
init_load = True
try:
output = ''
while True:
# プログラムからの出力を読めるだけ読む
output += process.stdout.readline().decode('utf-8')
if output == '' and process.poll() is not None:
break
# 起動時のメッセージはフィルタリングしない
if init_load:
print(output)
init_load = False
else:
# 出力をフィルタリングする
filtered_output = translate(output, input_lang='en')
filtered_output = str(filtered_output).replace("[{'translation_text': '", "").replace("'}]", "")
# フィルタリングされた出力を表示
print(filtered_output)
output = ''
# ユーザー入力を読み取る
user_input = prompt(
'> ', multiline=True, prompt_continuation=prompt_continuation, key_bindings=kb
)
user_input = translate(user_input, input_lang='ja')
user_input = re.sub(r"\[{'translation_text': ['\"]", "", str(user_input))
user_input = re.sub(r"['\"]}]", "", user_input)
#str(user_input).re.sub("[{'translation_text': ['\"]", "").re.sub("['\"]}]", "")
print(user_input)
# 入力をプログラムに渡す
process.stdin.write((user_input + '\n').encode('utf-8'))
process.stdin.flush()
finally:
# プログラムの終了
signal.signal(signal.SIGTERM, signal.SIG_IGN)
signal.signal(signal.SIGINT, signal.SIG_IGN)
cleanup()
signal.signal(signal.SIGTERM, signal.SIG_DFL)
signal.signal(signal.SIGINT, signal.SIG_DFL)
複数行入力も対応した。タブキーで決定する。プログラムはchatGPTに雑に編集させたので、なんかおかしいとこあるかも。