Skip to content

Instantly share code, notes, and snippets.

@mutaguchi
Last active May 28, 2024 23:30
Show Gist options
  • Save mutaguchi/3bbafb5de18c78f0fc381023a9060c0f to your computer and use it in GitHub Desktop.
Save mutaguchi/3bbafb5de18c78f0fc381023a9060c0f to your computer and use it in GitHub Desktop.
LLM_translator.py

llama.cpp serverを使って、入力文字列を翻訳するスクリプト。

使用方法

python LLM_Translator.py 
[-h] 
[-i 入力ファイルパス] [-o 出力ファイルパス] [-p プロンプトファイルパス] [-d 辞書ファイルパス] 
[-u llama.cpp serverのURL] [--quiet] [--no-outfile] [--include-input] [--min-context-count 最小保持ターン数]

チャットのように逐次訳することで精度が上がることを期待してます。

精度を維持するため、原文と翻訳結果は、直近5~10行のみコンテキストに含めるようにしています。

出力例は、GPT-4oに例文と模範解答を作らせ、ArrowPro-7B-RobinHood(Q8_0.gguf)でテストしています。

デフォルトでは英文和訳を行います。

文字列は標準入力もしくはファイルから読み込むことができます。

yaml形式で記述した翻訳指示のシステムプロンプトを-pパラメータで指定すると、モデルの性能に左右されますが、英訳(日本語→英語翻訳)や口調の変換なども可能です。(サンプルはこの記事の下の方にあります)

-dictパラメータを用いて、英名を和名に変換する辞書を指定することもできます。(サンプルはこの記事の下の方にあります)

モジュールとして利用すると、LLMTranslatorクラスによる翻訳機能を自分のスクリプトに組み込むこともできます。(サンプルあります)

あまり翻訳とは関係ないですが、LLMTranslatorクラスの基底クラスとして、LLMMultiTurnCompleterクラス、さらにその基底クラスとしてLLMCompleterクラスも使えるようにしました。LLMをスクリプトに組み込む際、便利かと思います。(サンプルあります)

スクリプトの説明: https://x.com/mutaguchi/status/1792124192235962844

from __future__ import annotations
import aiofiles
import json
import os
import argparse
import yaml
import sys
import aiohttp
import asyncio
url_base = "http://127.0.0.1:1234" # llama.cpp serverのデフォルトURL
min_context_count = 3 # コンテキストに保持する最小ターン数のデフォルト値
class LLMCompleter:
"""LLMを用いたテキスト補完を行うクラス。"""
_input_label_config_name = ""
_output_label_config_name = ""
def __init__(self, system_prompt="", max_length=200, grammar: str = None, url_base: str = url_base, debug=False):
self.system_prompt = system_prompt
self.url_base = url_base
self.grammar = grammar
self.generated_text = ""
self.max_length = max_length
self._stop = False
self._debug = debug
def __call__(self, text: str, verbose=False, grammar=""):
return self._generator(text=text, verbose=verbose, grammar=grammar)
@classmethod
def _load_config_file(cls, prompt_path: str, dictionary_path: str = None):
# prompt_pathが".yaml"で終わっていない場合は付与する
prompt_path = prompt_path if prompt_path.endswith(
".yaml") else prompt_path + ".yaml"
# プロンプトファイルが存在しない場合は、スクリプトと同フォルダを見に行く。
if not os.path.exists(prompt_path):
prompt_path = os.path.join(os.path.dirname(os.path.abspath(
__file__)), prompt_path) if not os.path.isabs(prompt_path) else prompt_path
# プロンプトファイルの読み込み
if os.path.exists(prompt_path):
with open(prompt_path, 'r', encoding='utf-8') as prompt_file:
prompt_data = yaml.safe_load(prompt_file)
system_prompt = prompt_data.get('system_prompt', "")
if cls._input_label_config_name:
input_label = prompt_data.get(
cls._input_label_config_name, "入力")
if cls._output_label_config_name:
output_label = prompt_data.get(
cls._output_label_config_name, "出力")
dictionary = prompt_data.get('dictionary', {})
grammar = prompt_data.get('grammar', None)
examples = prompt_data.get('examples', [])
else:
system_prompt = ""
input_label = ""
output_label = ""
dictionary = {}
grammar = None
examples = []
if isinstance(dictionary, dict):
dictionary = {str(key): str(value)
for key, value in dictionary.items()}
# 辞書ファイルの読み込みとマージ
if dictionary_path:
with open(dictionary_path, 'r', encoding='utf-8') as dict_file:
for line in dict_file:
if '\t' in line:
source_term, target_term = line.strip().split('\t')
dictionary[source_term] = target_term
return system_prompt, input_label, output_label, dictionary, grammar, examples
@classmethod
def from_config(cls, prompt_path: str, dictionary_path: str = None, min_context_count=min_context_count, url_base: str = url_base) -> LLMCompleter:
"""設定ファイルからロードしインスタンス化"""
system_prompt, _, _, _, _, grammar = cls._load_config_file(
prompt_path, dictionary_path)
return cls(
system_prompt=system_prompt,
grammar=grammar, min_context_count=min_context_count, url_base=url_base
)
def _check_wait_word(self, new_text: str, wait_words: list[str]):
for word in wait_words:
if word in new_text:
return "break"
for word in wait_words:
min_len = min(len(new_text), len(word))
for i in range(1, min_len + 1):
if new_text[-i:] == word[:i]:
return "continue"
return "pass"
async def _get_response(self, prompt, quiet=False, wait_words=[], stop_words=[], logit_bias=[], grammar="", max_length=0):
url = f"{self.url_base}/completion"
data = {
"prompt": prompt,
"stream": True,
"cache_prompt": True,
"stop": stop_words,
"n_predict": max_length if max_length > 0 else self.max_length
}
grammar = grammar if grammar else self.grammar
if grammar:
if not grammar.replace(" ", "").replace("\n", "").startswith('root::='):
grammar = f'root::={grammar}'
data["grammar"] = grammar
if logit_bias:
data["logit_bias"] = logit_bias
if self._debug:
print(data)
async with aiohttp.ClientSession() as session:
async with session.post(url, json=data) as response:
if response.status == 200:
content = ''
first_line_printed = False
async for line in response.content:
line_str = line.decode()
if line_str.startswith('data:'):
json_data: dict[str, str] = json.loads(
line_str[len('data:'):])
if 'content' in json_data:
content += json_data['content']
if not first_line_printed:
content = content.lstrip()
first_line_printed = True
loop_condition = self._check_wait_word(
content, wait_words)
if loop_condition == "break":
break
elif loop_condition == "continue":
continue
yield content
if self._stop:
self._stop = False
break
if not quiet or self._debug:
print(content, end='', flush=True)
content = ""
else:
yield f"Error: {response.status}"
async def complete(self, text="", verbose=False, grammar="", stop_words: list[str] = None, logit_bias: list = None, max_length=0):
"""LLMによるテキスト補完を実行する。"""
generated = ""
async for response in self._get_response(self.system_prompt+self.generated_text+text, quiet=not verbose, grammar=grammar, stop_words=stop_words, logit_bias=logit_bias, max_length=max_length):
generated += response
self.generated_text += generated
return generated
async def _generator(self, text="", verbose=False, grammar="", stop_words: list[str] = None, logit_bias: list = None, max_length=0):
generated = ""
async for response in self._get_response(self.system_prompt+self.generated_text+text, quiet=not verbose, grammar=grammar, stop_words=stop_words, logit_bias=logit_bias, max_length=max_length):
generated += response
yield response
self.generated_text += generated
async def reset(self):
self.generated_text = ""
def stop(self):
"""テキスト生成を中断する。"""
self._stop = True
class LLMMultiTurnCompleter(LLMCompleter):
"""LLMを用いたマルチターン応答を行うクラス。"""
_input_label_config_name = "input"
_output_label_config_name = "output"
def __init__(self, system_prompt: str = "", input_label: str = "入力", output_label: str = "出力", dictionary: dict = None, grammar: str = None, examples: list[str] = [], max_length=500, min_context_count=min_context_count, url_base: str = url_base, debug=False):
super().__init__(system_prompt,
grammar=grammar, max_length=max_length, url_base=url_base, debug=debug)
self.input_label = input_label
self.output_label = output_label
self.context = []
self.dictionary = dictionary if dictionary else {}
self.min_context_count = min_context_count
self.wait_words = [f"\n{self.input_label}:", f"\n{self.output_label}:"]
self.examples = examples
def __call__(self, text: str, initial_text="", multiline=False, verbose=False, grammar="", stop_words: list[str] = None, logit_bias: list = None):
if not multiline:
stop_words = ["\n"]
return self._generator(text=text, initial_text=initial_text, multiline=multiline, verbose=verbose, grammar=grammar, stop_words=stop_words, logit_bias=logit_bias)
@classmethod
def from_config(cls, prompt_path: str, dictionary_path: str = None, min_context_count=min_context_count, url_base: str = url_base, debug=False) -> LLMMultiTurnCompleter:
"""設定ファイルからロードしインスタンス化"""
system_prompt, input_label, output_label, dictionary, grammar, examples = cls._load_config_file(
prompt_path, dictionary_path)
return cls(
system_prompt, input_label=input_label, output_label=output_label, dictionary=dictionary, grammar=grammar, examples=examples, min_context_count=min_context_count, url_base=url_base, debug=debug
)
def reset(self):
"""コンテキストを消去する。"""
self.context.clear()
def delete_last_context(self, turn=1):
"""直近ターンのコンテキストを消去する。"""
self.context = self.context[:-turn*2]
def append_text(self, text: str):
"""前回ターンの末尾にテキストを追記する。"""
if self.context:
self.context[-1] += text
def _replace_terms(self, text):
if not self.dictionary:
return text
for source_term, target_term in self.dictionary.items():
text = text.replace(source_term, target_term)
return text
def _update_context(self, user_input, assistant_response):
self.context.append(f"{self.input_label}: {user_input}")
self.context.append(
f"{self.output_label}: {assistant_response}")
if self.min_context_count == 0:
self.reset()
elif len(self.context) >= self.min_context_count*4:
self.context = self.context[-self.min_context_count*2:]
def _create_prompt(self, user_input: str, initial_text=""):
context_text = self.system_prompt
if self.examples:
for i in range(0, len(self.examples), 2):
context_text += f"\n{self.input_label}: {self.examples[i]}\n{self.output_label}: {self.examples[i+1]}"
if self.context:
context_text += "\n" + '\n'.join(self.context)
prompt = f"{context_text}\n{self.input_label}: {user_input}\n{self.output_label}:"
if initial_text:
prompt = f"{prompt} {initial_text}"
return prompt
async def _process_line(self, user_input, initial_text, verbose, grammar, stop_words, logit_bias, max_length):
if not user_input:
return
replaced_input = self._replace_terms(user_input)
prompt = self._create_prompt(
replaced_input, initial_text=initial_text)
if (verbose or self._debug) and initial_text:
print(initial_text, end="", flush=True)
response_text = ""
async for response in self._get_response(prompt, quiet=not verbose, wait_words=self.wait_words, stop_words=stop_words, logit_bias=logit_bias, grammar=grammar, max_length=max_length):
response_text += response
yield response
self._update_context(
user_input, initial_text + response_text)
async def complete(self, text: str, initial_text="", multiline=False, include_input=False, verbose=False, grammar="", stop_words: list[str] = None, logit_bias: list = None, max_length=0) -> (str | tuple[str]):
"""LLMによるテキスト補完を実行し、入力文に対する出力文を得る。"""
lines = text.split("\n") if not multiline else [text]
output = ""
output_list = []
if not multiline:
stop_words = ["\n"]
for index, user_input in enumerate(lines):
assistant_response = ""
if (verbose or self._debug) and include_input:
print(
f"{self.input_label}: {user_input}\n{self.output_label}: ", end='', flush=True)
async for response in self._process_line(user_input, initial_text, verbose, grammar, stop_words, logit_bias, max_length):
assistant_response += response
output += assistant_response
output_list.append((user_input, assistant_response))
if index != len(lines) - 1:
output += "\n"
if verbose or self._debug:
print()
if (verbose or self._debug) and include_input:
print()
if include_input:
return output_list
return output
async def _generator(self, text: str, initial_text="", multiline=False, verbose=False, grammar="", stop_words: list[str] = None, logit_bias: list = None, max_length=0):
lines = text.split("\n") if not multiline else [text]
if not multiline:
stop_words = ["\n"]
for index, user_input in enumerate(lines):
async for response in self._process_line(user_input, initial_text, verbose, grammar, stop_words, logit_bias, max_length):
yield response
if index != len(lines) - 1:
yield "\n"
if verbose or self._debug:
print()
async def complete_all(self, input_path="", output_path="", include_input=False, quiet=False):
"""ファイルまたは標準入力から入力したテキストに対し、テキスト補完を実行する。"""
if not input_path:
lines = sys.stdin
else:
async with aiofiles.open(input_path, 'r', encoding='utf-8') as input_file:
lines = await input_file.readlines()
first_line_output = False
for line in lines:
user_input = line.strip()
if user_input:
replaced_input = self._replace_terms(user_input)
prompt = self._create_prompt(replaced_input)
if include_input and (not quiet or self._debug):
print(f"{self.input_label}: {user_input}\n")
print(f"{self.output_label}: ", end='', flush=True)
assistant_response = ""
async for response in self._get_response(prompt, quiet=quiet, wait_words=self.wait_words, stop_words=["\n"]):
assistant_response += response
self._update_context(
user_input, assistant_response)
else:
assistant_response = ""
if output_path:
mode = "a" if first_line_output else "w"
first_line_output = True
async with aiofiles.open(output_path, mode, encoding='utf-8') as output_file:
if include_input and user_input and assistant_response:
await output_file.write(f"{self.input_label}: {user_input}\n")
await output_file.write("\n")
await output_file.write(f"{self.output_label}: {assistant_response}\n")
await output_file.write("\n")
else:
await output_file.write(f"{assistant_response}\n")
if not quiet or self._debug:
print()
class LLMTranslator(LLMMultiTurnCompleter):
"""LLMを用いた翻訳を行うクラス。"""
_input_label_config_name = "from_lang"
_output_label_config_name = "to_lang"
def __init__(self, system_prompt: str = "", from_lang: str = "", to_lang: str = "", dictionary: dict = None, grammar: str = None, examples: list[str] = None, min_context_count=min_context_count, url_base: str = url_base, debug=False):
if not system_prompt:
system_prompt = """英文を日本語に和訳してください。
English: Hello!
日本語: おはようございます。
English: How are you?
日本語: お元気ですか?
"""
from_lang = "English"
to_lang = "日本語"
if not from_lang:
from_lang = "入力"
if not to_lang:
to_lang = "出力"
system_prompt = system_prompt.strip()
super().__init__(system_prompt=system_prompt, input_label=from_lang, output_label=to_lang,
dictionary=dictionary, grammar=grammar, examples=examples, max_length=100000, min_context_count=min_context_count, url_base=url_base, debug=debug)
@classmethod
def from_config(cls, prompt_path: str, dictionary_path: str = None, min_context_count=min_context_count, url_base: str = url_base, debug=False) -> LLMTranslator:
"""設定ファイルからロードしインスタンス化"""
system_prompt, input_label, output_label, dictionary, grammar, examples = cls._load_config_file(
prompt_path, dictionary_path)
return cls(
system_prompt=system_prompt, from_lang=input_label, to_lang=output_label, dictionary=dictionary, grammar=grammar, examples=examples, min_context_count=min_context_count, url_base=url_base, debug=debug
)
def __call__(self, text: str, verbose=False):
return self._generator(text=text, multiline=False, verbose=verbose)
async def translate(self, text: str, include_input=False, verbose=False):
"""入力文を翻訳する。"""
return await self.complete(text=text, multiline=False, include_input=include_input, verbose=verbose)
async def translate_all(self, input_path="", output_path="", include_input=False, quiet=False):
"""ファイルまたは標準入力から入力したテキストを翻訳する。"""
await self.complete_all(input_path, output_path, include_input, quiet)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='LLMを使用して、テキストファイルまたは標準入力からの文字列を翻訳して出力します。',
usage='python LLM_Translator.py [-h] [-i 入力ファイルパス] [-o 出力ファイルパス] [-p プロンプトファイルパス] [-d 辞書ファイルパス] [-u llama.cpp serverのURL] [--quiet] [--no-outfile] [--include-input] [--min-context-count 最小保持ターン数]'
)
parser.add_argument('-i', '--input-path', type=str,
help='翻訳元テキストが含まれる入力テキストファイルのパス。指定しない場合は標準入力を使用します。', default=None)
parser.add_argument('-o', '--output-path', type=str,
help='翻訳先の出力テキストファイルのパス。指定しない場合は <input_path>_<prompt_name>.<ext> になります。', default=None)
parser.add_argument('-p', '--prompt-path', type=str,
help='翻訳用のプロンプトファイルのパス。指定しない場合はen_ja.yamlを使用します。拡張子省略可。', default="en_ja.yaml")
parser.add_argument('-d', '-dict', '--dictionary-path', type=str,
help='固有名詞置換用の辞書ファイルのパス。翻訳元<tab>翻訳先<改行>形式のテキストファイルを用意します。', default=None)
parser.add_argument('-u', '--url', type=str,
help='llama.cpp serverのURL', default=url_base)
parser.add_argument('-q', '--quiet', action='store_true',
help='翻訳結果を標準出力に表示しません。')
parser.add_argument('-nof', '--no-outfile', action='store_true',
help='翻訳結果をファイルに書き込みません。')
parser.add_argument('-ii', '--include-input', action='store_true',
help='入力テキストを出力に含めます。')
parser.add_argument('--min-context-count', type=int,
help=f'コンテキストに保持する最小ターン数。(デフォルト: {min_context_count})'
'小さくすると、よりシステムプロンプトでの翻訳例に忠実な翻訳を行うが、文脈把握力が低下し、出力速度も落ちる。'
'大きくすると、文脈把握力が向上し、出力速度は落ちにくいが、システムプロンプトの翻訳例と違った雰囲気になる可能性が高くなる。', default=min_context_count)
args = parser.parse_args()
input_path = args.input_path
output_path = args.output_path
dictionary_path = args.dictionary_path
prompt_path = args.prompt_path
url_base = args.url
quiet = args.quiet
no_outfile = args.no_outfile
include_input = args.include_input
min_context_count = args.min_context_count
# 出力ファイルパスが指定されていないときは、入力ファイルパスから出力ファイルパスを生成しておく
if not output_path and not no_outfile and input_path:
suffix = os.path.splitext(os.path.basename(prompt_path))[0]
base, ext = os.path.splitext(input_path)
output_path = f"{base}_{suffix}{ext}"
translator = LLMTranslator.from_config(
prompt_path=prompt_path, dictionary_path=dictionary_path, min_context_count=min_context_count, url_base=url_base)
asyncio.run(translator.translate_all(input_path=input_path,
output_path=output_path, include_input=include_input, quiet=quiet))

test_en_1.txt

Original English Text

The rapid development of technology over the past few decades has fundamentally changed the way we live, work, and communicate. The internet, once a novel concept, has become an indispensable tool for accessing information, conducting business, and connecting with others around the globe. Social media platforms have revolutionized the way we share our lives and interact with each other, creating both opportunities and challenges in terms of privacy and mental health.

Artificial intelligence and machine learning are now driving innovation in numerous fields, from healthcare to finance, by providing new ways to analyze data and make decisions. Autonomous vehicles and drones are beginning to change the transportation and delivery industries, promising greater efficiency and safety. However, these advancements also bring about ethical and societal questions, such as the displacement of jobs and the importance of human oversight in decision-making processes.

Moreover, the increasing reliance on digital technologies has highlighted the importance of cybersecurity. As more sensitive data is stored online, the threat of cyberattacks has grown, necessitating robust security measures and policies. Governments, businesses, and individuals must work together to protect against these threats and ensure that technological progress benefits everyone.

Education systems are also evolving to prepare students for a future dominated by technology. STEM (Science, Technology, Engineering, and Mathematics) education is becoming more emphasized, aiming to equip the next generation with the skills needed to thrive in a digital world. However, it is equally important to foster critical thinking, creativity, and ethical reasoning to navigate the complexities of the modern era.

In conclusion, while technology continues to drive progress and improve our lives in countless ways, it is essential to address the accompanying challenges responsibly. By doing so, we can ensure that the benefits of technological advancements are shared equitably and contribute to a sustainable and inclusive future.

GPT-4o 模範解答

過去数十年間にわたる技術の急速な発展は、私たちの生活、仕事、コミュニケーションの方法を根本的に変えました。かつては斬新な概念だったインターネットは、情報にアクセスし、ビジネスを行い、世界中の他の人とつながるための不可欠なツールとなっています。ソーシャルメディアプラットフォームは、私たちの生活を共有し、お互いに交流する方法を変革し、プライバシーやメンタルヘルスに関する機会と課題の両方を生み出しています。

人工知能と機械学習は、データを分析し、意思決定を行う新しい方法を提供することにより、ヘルスケアから金融に至るまで多くの分野で革新を推進しています。自動運転車やドローンは、より効率的で安全な輸送と配送産業を約束し始めています。しかし、これらの進歩は、仕事の置き換えや意思決定プロセスにおける人間の監視の重要性など、倫理的および社会的な問題も引き起こします。

さらに、デジタル技術への依存度が増す中で、サイバーセキュリティの重要性が浮き彫りになっています。より多くの機密データがオンラインに保存されるにつれて、サイバー攻撃の脅威が増大し、強力なセキュリティ対策とポリシーが必要とされています。政府、企業、個人はこれらの脅威から保護し、技術の進歩がすべての人々に利益をもたらすように協力する必要があります。

教育システムも、技術が支配する未来に備えるために進化しています。STEM(科学、技術、工学、数学)教育は、デジタル世界で成功するために必要なスキルを次世代に提供することを目指して、ますます重要視されています。しかし、現代の複雑さを乗り切るために、批判的思考、創造性、倫理的推論を育むことも同様に重要です。

結論として、技術が無数の方法で進歩を促し私たちの生活を向上させ続ける一方で、それに伴う課題に責任を持って対処することが不可欠です。そうすることで、技術の進歩の利益が公平に分配され、持続可能で包摂的な未来に貢献することができます。

ArrowPro-7B-RobinHoodによる翻訳

過去数十年間での技術の急速な発展は、私たちの暮らし方、働き方、コミュニケーションの仕方を根本的に変えてしまいました。インターネット、かつては目新しかったそれは、情報へのアクセス、商取引、そして世界中の人々とのつながりを実現するために欠かせない道具となりました。ソーシャルメディアは、私たちが自分たちの人生を共有し、互いに交流する方法を革命的に変え、それに伴い、個人情報保護やメンタルヘルスの問題など、新たな機会と困難が生じています。

人工知能と機械学習は、医療や金融といった様々な分野で革新をもたらしています。これらは、大量のデータを新しい方法で分析し、決定を下すことが可能になるからです。自動運転車や無人機は交通や配送といった産業を変えつつあり、より効率的で安全なものへと導くと期待されています。ただし、これらの進歩は、仕事の喪失や人間の監督が決定プロセスに必要であるといった倫理や社会の問いかけをも引き起こします。

また、デジタル技術への依存の増大は、サイバーセキュリティの重要性を浮き彫りにしました。よりプライベートな情報がオンラインで保存されるようになると、サイバー攻撃の脅威も高まり、強固なセキュリティ対策と政策が求められます。政府、企業、そして個人は、これらの脅威に対処し、技術革新の成果を公平に享受できるように協力しなければなりません。

教育システムも進化を遂げ、技術が支配する未来に対応できる生徒たちを育てるため、STEM(サイエンス、テクノロジー、エンジニアリング、そして数学)教育への関心が高まっています。これは、次世代が必要なスキルを身につけ、デジタルの世界で生き残り、躍進できるようにすることを目的としています。しかし、批判的思考力、創造力、および倫理的推論力を育むことも、現代社会を生き抜くためには同じように重要です。

結論として、技術が進歩し私たちの生活を改善し続ける中でも、伴う課題に責任を持って対応することが不可欠です。これにより、技術革新の利益が公平に分かち合われ、持続可能で包括的な未来が実現できるのです。

test_en_2.txt

Original English Text

"Puella Magi Madoka Magica" is a groundbreaking Japanese anime series that subverts the traditional magical girl genre. The story follows Madoka Kaname, a kind-hearted middle school girl who lives a normal life until she encounters a mysterious creature named Kyubey. Kyubey offers her the opportunity to become a magical girl and gain powers to fight against witches, sinister beings that bring despair and destruction.

Madoka is initially hesitant, but her encounter with Homura Akemi, a new transfer student with a cold demeanor and a mysterious connection to her, adds complexity to her decision. As Madoka learns more about the life of a magical girl, she witnesses the struggles and sacrifices of her friends, including Sayaka Miki, who becomes a magical girl to protect someone she loves, and Mami Tomoe, an experienced magical girl who acts as a mentor.

The series delves into dark and mature themes, exploring the emotional and psychological toll of the magical girl contract. Sayaka's journey is particularly poignant as she grapples with the harsh realities of her new role, leading to tragic consequences. Kyoko Sakura, another magical girl with a tough exterior and a tragic past, adds further depth to the narrative, highlighting the complexities and challenges faced by these young girls.

"Puella Magi Madoka Magica" is renowned for its unique animation style, blending traditional techniques with surreal and abstract sequences that enhance the eerie atmosphere. The character designs by Ume Aoki and the haunting score by Yuki Kajiura contribute to the series' distinctive aesthetic and emotional impact.

Since its release, the series has received widespread acclaim for its storytelling, visual artistry, and its bold reimagining of the magical girl genre. It has spawned several spin-offs, films, and a plethora of merchandise, solidifying its status as a cultural phenomenon. "Puella Magi Madoka Magica" remains a significant work in anime history, praised for its originality, depth, and the powerful messages it conveys about hope, sacrifice, and the human spirit.

GPT-4o 模範解答

「魔法少女まどか☆マギカ」は、従来の魔法少女ジャンルを覆す画期的な日本のアニメシリーズです。物語は、謎の生物キュゥべえと出会うまで普通の生活を送っていた心優しい中学生の鹿目まどかを中心に展開します。キュゥべえは彼女に魔法少女になって魔女と戦う力を得る機会を提供します。魔女は絶望と破壊をもたらす邪悪な存在です。

最初はためらうまどかですが、冷たい態度を持ち、彼女と謎めいた関係を持つ転校生の暁美ほむらとの出会いが、その決断に複雑さを加えます。まどかは魔法少女の生活について学ぶ中で、友人たちの苦闘と犠牲を目の当たりにします。特に、誰かを守るために魔法少女となった美樹さやかや、メンターとしての役割を果たす経験豊富な魔法少女の巴マミの姿を見て、その思いは深まります。

シリーズは、魔法少女契約の感情的および心理的な負担を探求する、暗く成熟したテーマを扱っています。さやかの旅路は特に感動的で、新しい役割の厳しい現実と向き合い、悲劇的な結果を招くことになります。さらに、強い外見と悲劇的な過去を持つ佐倉杏子という魔法少女の登場により、物語にさらなる深みが加わり、若い少女たちが直面する複雑さと課題が浮き彫りになります。

「魔法少女まどか☆マギカ」は、伝統的な技法とシュールで抽象的なシーケンスを融合させた独特のアニメーションスタイルで知られています。蒼樹うめによるキャラクターデザインや、梶浦由記による心に響くスコアは、シリーズの独特な美学と感情的なインパクトを強調しています。

リリース以来、このシリーズはその物語の展開、視覚芸術、および魔法少女ジャンルの大胆な再解釈で広く称賛されています。いくつかのスピンオフや映画、豊富な商品展開を生み出し、文化現象としての地位を確立しました。「魔法少女まどか☆マギカ」は、その独創性、深さ、および希望、犠牲、人間の精神についての強力なメッセージで評価され、アニメ史において重要な作品としての地位を保ち続けています。

ArrowPro-7B-RobinHoodによる翻訳

「魔法少女まどか☆マギカ」は、伝統的な魔法少女のジャンルを覆す革新的な日本のアニメシリーズです。物語は優しい中学生の鹿山修子が、謎の生き物キューブに出会うところから始まります。キューブは彼女に魔法少女になる機会と、ウィッチと戦うための力を与えます。ウィッチは絶望と破壊をもたらす恐ろしい存在です。

まず修子は躊躇しますが、新しい転入生で冷たい態度のホムラ・アクエミとの謎めいた関係が決断に複雑さをもたらします。修子が魔法少女の生活についてより多くを学ぶにつれ、彼女の友達である佐倉紗希雅は愛する人を守るために魔法少女になり、経験豊富な魔法少女のマミ・トーモは指導者のような存在として振る舞います。

このアニメシリーズは、陰りのある深く成熟したテーマに踏み込み、魔法少女契約の精神的・感情的な負担を探求します。紗希雅の道のりは特に悲壮で、新しい役割の厳しい現実に向き合うことで悲劇的な結末を招きます。鞍馬京子という別の魔法少女で、厳しい外見と悲しい過去を持つ彼女は、物語にさらなる深みを加え、若い少女たちが直面する困難や問題の複雑性を浮き彫りにします。

「魔法少女まどか☆マギカ」は、独自のアニメーションスタイルで知られ、伝統的な技法と奇妙で抽象的なシーンを組み合わせることで幻想的な雰囲気を醸し出します。キャラクターデザインは梅沢謙一によるもので、怨美のスコアが加わり、このシリーズの個性的な美学と感動を生み出しています。

発売以来、このシリーズは物語の伝達力、視覚芸術の素晴らしさ、そして従来の魔法少女のジャンルを大胆に再解釈した点で高い評価を受けました。この作品は複数のスピンオフ作品、映画化、関連商品の大量発売によって、文化現象としての地位を確立しました。「魔法少女まどか☆マギカ」は、そのオリジナリティ、深み、そして希望、犠牲、人の精神に関する力強いメッセージで高く評価され続けています。

ArrowPro-7B-RobinHoodによる翻訳(辞書使用)

「魔法少女まどか☆マギカ」は、伝統的な魔法少女のジャンルを根底から覆した日本の斬新なアニメシリーズです。この物語は、優しい中学生の鹿目まどかが、普通の生活を送っていたところ、謎の生き物であるキュゥべえと出会うところから始まります。キュゥべえは、彼女に魔法少女になるチャンスと、ウィッチと戦い希望と平和を守るための力を与えます。

鹿目まどかは最初躊躇しますが、新しい転入生で冷たい態度の暁美ほむらとの謎めいた関連が、彼女の決断を複雑にします。魔法少女の生活に関する知識が深まるにつれて、彼女は友人たちの苦しみや犠牲を目の当たりにします。美樹さやかは愛する誰かを守るために魔法少女になり、経験豊富な巴マミはまるでメンターのように振る舞います。

このアニメシリーズは、暗く成熟したテーマに踏み込み、魔法少女としての契約がもたらす感情的・心理的な負担や影響を探求します。特に佐倉杏子という別の魔法少女は、新しい役割の厳しい現実に立ち向かいながら、悲劇的な結果を招く旅をします。美しく強いイメージのある魔法少女たちの物語は、彼女たちが直面する複雑で困難な状況を浮き彫りにします。

「魔法少女まどか☆マギカ」は、その独特なアニメーションスタイルで知られており、伝統的な技術に加え、現実離れした抽象的な場面展開が漂う幻想的な雰囲気を演出します。蒼樹うめのキャラクターデザインと、梶浦由記の幽玄な音楽が、このシリーズの個性的な美学と感情的な衝撃を高めます。

発売以来、このシリーズは物語の構成力や視覚表現、魔法少女というジャンルの大胆な再解釈で広範な称賛を集めました。この作品は、様々な外伝作品、映画化、関連商品を生み出すことで、文化現象としての地位を確立しました。「魔法少女まどか☆マギカ」は、オリジナリティ、深み、そして希望、犠牲、人間の魂について伝える力強いメッセージで知られ、アニメ史上に残る重要作品となっています。

test_en_3.txt

Original English Text

PowerShell is a task automation framework.

It consists of a command-line shell and scripting language.

It is built on the .NET framework.

PowerShell helps IT professionals to control and automate tasks.

These tasks can include system administration, batch processing, and much more.

The commandlets are small, reusable commands in PowerShell.

They follow a Verb-Noun naming convention.

For example, "Get-Process" retrieves information about processes running on a computer.

PowerShell scripts can automate complex and repetitive tasks.

These scripts can save time and reduce human error.

Administrators can write scripts to manage multiple systems simultaneously.

PowerShell integrates with various Microsoft products.

It is compatible with Windows, Linux, and macOS.

PowerShell is open-source and maintained by Microsoft.

Its community provides extensive support and resources.

Learning PowerShell can enhance an IT professional's skill set.

There are many online tutorials and courses available.

These resources help beginners and advanced users alike.

Using PowerShell can improve efficiency and productivity in IT operations.

GPT-4o 模範解答

PowerShellはタスク自動化フレームワークです。

これはコマンドラインシェルとスクリプト言語で構成されています。

.NETフレームワーク上に構築されています。

PowerShellはITプロフェッショナルがタスクを制御し自動化するのに役立ちます。

これらのタスクには、システム管理、バッチ処理などが含まれます。

コマンドレットは、PowerShell内の小さな再利用可能なコマンドです。

それらは動詞-名詞の命名規則に従います。

例えば、「Get-Process」はコンピュータ上で実行されているプロセスに関する情報を取得します。

PowerShellスクリプトは複雑で反復的なタスクを自動化できます。

これらのスクリプトは時間を節約し、人為的なエラーを減らします。

管理者は複数のシステムを同時に管理するためのスクリプトを書くことができます。

PowerShellはさまざまなMicrosoft製品と統合されます。

Windows、Linux、macOSと互換性があります。

PowerShellはオープンソースで、Microsoftによって維持されています。

そのコミュニティは幅広いサポートとリソースを提供しています。

PowerShellを学ぶことでITプロフェッショナルのスキルセットを向上させることができます。

多くのオンラインチュートリアルやコースが利用可能です。

これらのリソースは初心者と上級者の両方を支援します。

PowerShellを使用することで、IT業務の効率と生産性を向上させることができます。

ArrowPro-7B-RobinHoodによる翻訳

パワーシェルはタスク自動化フレームワークです。

パワーシェルはコマンドラインシェルとスクリプティング言語から構成されています。

パワーシェルは、.ネットフレームの上に構築されています。

パワーシェルはITプロフェッショナルが制御して自動化できるタスクを助けます。

これらのタスクには、システム管理やバッチ処理など、多くのものが含まれます。

パワーシェルのコマンドレットは小さく、再利用が可能です。

彼らは動詞名前の命名ルールに従っています。

例えば、「Get-Process」は、コンピューターで実行中のプロセスに関する情報を取得します。

パワーシェルのスクリプトは、複雑で反復的なタスクを自動化できます。

これらのスクリプトは時間を節約し、人為的ミスを減らします。

管理者は、同時に複数のシステムを管理するためのスクリプトを書くことができます。

パワーシェルは、様々なマイクロソフト製品と統合されます。

パワーシェルは、ウィンドウズ、リナックス、およびマックOSに対応します。

パワーシェルはオープンソースであり、マイクロソフトによって維持されています。

そのコミュニティは、豊富なサポートとリソースを提供します。

パワーシェルを学ぶことで、ITプロフェッショナルのスキルセットは向上します。

オンラインで利用できるチュートリアルやコースは多数あります。

これらの資源は、初心者から上級者までを助けます。

パワーシェルを使うことで、IT運用の効率性と生産性は改善されます。

test_jp_1.txt

日本語文(GPT-4oが生成した英文を和訳したもの)

過去数十年間にわたる技術の急速な発展は、私たちの生活、仕事、コミュニケーションの方法を根本的に変えました。かつては斬新な概念だったインターネットは、情報にアクセスし、ビジネスを行い、世界中の他の人とつながるための不可欠なツールとなっています。ソーシャルメディアプラットフォームは、私たちの生活を共有し、お互いに交流する方法を変革し、プライバシーやメンタルヘルスに関する機会と課題の両方を生み出しています。

人工知能と機械学習は、データを分析し、意思決定を行う新しい方法を提供することにより、ヘルスケアから金融に至るまで多くの分野で革新を推進しています。自動運転車やドローンは、より効率的で安全な輸送と配送産業を約束し始めています。しかし、これらの進歩は、仕事の置き換えや意思決定プロセスにおける人間の監視の重要性など、倫理的および社会的な問題も引き起こします。

さらに、デジタル技術への依存度が増す中で、サイバーセキュリティの重要性が浮き彫りになっています。より多くの機密データがオンラインに保存されるにつれて、サイバー攻撃の脅威が増大し、強力なセキュリティ対策とポリシーが必要とされています。政府、企業、個人はこれらの脅威から保護し、技術の進歩がすべての人々に利益をもたらすように協力する必要があります。

教育システムも、技術が支配する未来に備えるために進化しています。STEM(科学、技術、工学、数学)教育は、デジタル世界で成功するために必要なスキルを次世代に提供することを目指して、ますます重要視されています。しかし、現代の複雑さを乗り切るために、批判的思考、創造性、倫理的推論を育むことも同様に重要です。

結論として、技術が無数の方法で進歩を促し私たちの生活を向上させ続ける一方で、それに伴う課題に責任を持って対処することが不可欠です。そうすることで、技術の進歩の利益が公平に分配され、持続可能で包摂的な未来に貢献することができます。

GPT-4oが生成したオリジナル英文

The rapid development of technology over the past few decades has fundamentally changed the way we live, work, and communicate. The internet, once a novel concept, has become an indispensable tool for accessing information, conducting business, and connecting with others around the globe. Social media platforms have revolutionized the way we share our lives and interact with each other, creating both opportunities and challenges in terms of privacy and mental health.

Artificial intelligence and machine learning are now driving innovation in numerous fields, from healthcare to finance, by providing new ways to analyze data and make decisions. Autonomous vehicles and drones are beginning to change the transportation and delivery industries, promising greater efficiency and safety. However, these advancements also bring about ethical and societal questions, such as the displacement of jobs and the importance of human oversight in decision-making processes.

Moreover, the increasing reliance on digital technologies has highlighted the importance of cybersecurity. As more sensitive data is stored online, the threat of cyberattacks has grown, necessitating robust security measures and policies. Governments, businesses, and individuals must work together to protect against these threats and ensure that technological progress benefits everyone.

Education systems are also evolving to prepare students for a future dominated by technology. STEM (Science, Technology, Engineering, and Mathematics) education is becoming more emphasized, aiming to equip the next generation with the skills needed to thrive in a digital world. However, it is equally important to foster critical thinking, creativity, and ethical reasoning to navigate the complexities of the modern era.

In conclusion, while technology continues to drive progress and improve our lives in countless ways, it is essential to address the accompanying challenges responsibly. By doing so, we can ensure that the benefits of technological advancements are shared equitably and contribute to a sustainable and inclusive future.

ArrowPro-7B-RobinHoodによる日本語→英語翻訳文

Over the past several decades, rapid technological advancements have fundamentally changed our lifestyle, work, and methods of communication. What once seemed groundbreaking, the internet, is now an indispensable tool for accessing information, conducting business, and connecting with people around the world. Social media platforms have transformed how we share aspects of our lives and interact with each other, creating opportunities and challenges related to privacy and mental health.

Artificial intelligence and machine learning are providing new methods for data analysis and decision-making across multiple sectors, including healthcare and finance. Autonomous vehicles and drones are beginning to promise more efficient and safe transportation and logistics. However, these advances also raise ethical and social issues related to job displacement and the importance of human oversight in decision-making processes, among other concerns.

Moreover, as dependency on digital technology increases, the importance of cybersecurity becomes glaring. With more classified data saved online, the threat of cyber attacks grows, necessitating strong security measures and policies. Governments, corporations, and individuals must collaborate to protect against these threats and ensure that technological advancements benefit all people.

The education system is evolving to prepare for a future dominated by technology. STEM (Science, Technology, Engineering, and Mathematics) education, which imparts skills essential for success in the digital world, is increasingly regarded as crucial. However, to navigate the complexity of today's society, cultivating critical thinking, creativity, and ethical reasoning is equally important.

In conclusion, while technology continues to drive progress and enhance our lives through countless methods, addressing the challenges it presents with responsibility is essential. Doing so ensures that the benefits of technological advancements are shared equitably and contribute to a sustainable and inclusive future.

test_jp_2.txt

日本語文(GPT-4oが生成した英文を和訳したもの)

「魔法少女まどか☆マギカ」は、従来の魔法少女ジャンルを覆す画期的な日本のアニメシリーズです。物語は、謎の生物キュゥべえと出会うまで普通の生活を送っていた心優しい中学生の鹿目まどかを中心に展開します。キュゥべえは彼女に魔法少女になって魔女と戦う力を得る機会を提供します。魔女は絶望と破壊をもたらす邪悪な存在です。

最初はためらうまどかですが、冷たい態度を持ち、彼女と謎めいた関係を持つ転校生の暁美ほむらとの出会いが、その決断に複雑さを加えます。まどかは魔法少女の生活について学ぶ中で、友人たちの苦闘と犠牲を目の当たりにします。特に、誰かを守るために魔法少女となった美樹さやかや、メンターとしての役割を果たす経験豊富な魔法少女の巴マミの姿を見て、その思いは深まります。

シリーズは、魔法少女契約の感情的および心理的な負担を探求する、暗く成熟したテーマを扱っています。さやかの旅路は特に感動的で、新しい役割の厳しい現実と向き合い、悲劇的な結果を招くことになります。さらに、強い外見と悲劇的な過去を持つ佐倉杏子という魔法少女の登場により、物語にさらなる深みが加わり、若い少女たちが直面する複雑さと課題が浮き彫りになります。

「魔法少女まどか☆マギカ」は、伝統的な技法とシュールで抽象的なシーケンスを融合させた独特のアニメーションスタイルで知られています。蒼樹うめによるキャラクターデザインや、梶浦由記による心に響くスコアは、シリーズの独特な美学と感情的なインパクトを強調しています。

リリース以来、このシリーズはその物語の展開、視覚芸術、および魔法少女ジャンルの大胆な再解釈で広く称賛されています。いくつかのスピンオフや映画、豊富な商品展開を生み出し、文化現象としての地位を確立しました。「魔法少女まどか☆マギカ」は、その独創性、深さ、および希望、犠牲、人間の精神についての強力なメッセージで評価され、アニメ史において重要な作品としての地位を保ち続けています。

GPT-4oが生成したオリジナル英文

"Puella Magi Madoka Magica" is a groundbreaking Japanese anime series that subverts the traditional magical girl genre. The story follows Madoka Kaname, a kind-hearted middle school girl who lives a normal life until she encounters a mysterious creature named Kyubey. Kyubey offers her the opportunity to become a magical girl and gain powers to fight against witches, sinister beings that bring despair and destruction.

Madoka is initially hesitant, but her encounter with Homura Akemi, a new transfer student with a cold demeanor and a mysterious connection to her, adds complexity to her decision. As Madoka learns more about the life of a magical girl, she witnesses the struggles and sacrifices of her friends, including Sayaka Miki, who becomes a magical girl to protect someone she loves, and Mami Tomoe, an experienced magical girl who acts as a mentor.

The series delves into dark and mature themes, exploring the emotional and psychological toll of the magical girl contract. Sayaka's journey is particularly poignant as she grapples with the harsh realities of her new role, leading to tragic consequences. Kyoko Sakura, another magical girl with a tough exterior and a tragic past, adds further depth to the narrative, highlighting the complexities and challenges faced by these young girls.

"Puella Magi Madoka Magica" is renowned for its unique animation style, blending traditional techniques with surreal and abstract sequences that enhance the eerie atmosphere. The character designs by Ume Aoki and the haunting score by Yuki Kajiura contribute to the series' distinctive aesthetic and emotional impact.

Since its release, the series has received widespread acclaim for its storytelling, visual artistry, and its bold reimagining of the magical girl genre. It has spawned several spin-offs, films, and a plethora of merchandise, solidifying its status as a cultural phenomenon. "Puella Magi Madoka Magica" remains a significant work in anime history, praised for its originality, depth, and the powerful messages it conveys about hope, sacrifice, and the human spirit.

ArrowPro-7B-RobinHoodによる日本語→英語翻訳文

"Magical Girl Madoka Magica" is a groundbreaking anime series in Japan, challenging the conventional magical girl genre. The story revolves around a gentle middle school girl named Miki Tomoda, who encounters a mysterious creature named Kyuubey before any extraordinary events occur. Kyuubey grants her the opportunity to obtain the power to fight against magical creatures known as witches, which bring about despair and destruction.

Initially, Madoka is hesitant, but the encounter with a transfer student named Akio Mamiya, who has a mysterious relationship with her, complicates her decision-making process. As Madoka learns about the struggles and sacrifices of her friends, particularly a girl named Miki Sya ka, who became a Magical Girl to protect someone, and a seasoned Magical Girl named Aya, who acts as a mentor, her determination deepens.

The series delves into the emotional and psychological burdens of the Magical Girl contract, exploring mature and dark themes. Sya ka's journey is particularly touching, as she confronts the harsh realities of her new role and ends up leading to tragic consequences. Additionally, the introduction of a magical girl named Kazura Ako, who has a strong exterior and a tainted past, adds depth to the story and highlights the complex challenges faced by the young girls, including their vulnerabilities and struggles.

"Magical Girl Madoka Magica" is renowned for its unique animation style that combines traditional techniques with surreal and abstract sequences. Character designs by Aoki Ume and music by Kasiwa Yuki contribute to the series' distinctive aesthetics and emotional impact.

Since its release, the series has garnered widespread acclaim for its narrative, visual arts, and bold reinterpretation of the magical girl genre. It has spawned numerous spin-offs, films, and a plethora of merchandise, securing its status as a cultural phenomenon. "Magical Girl Madoka Magica" is highly valued for its originality, depth, powerful messages on hope, sacrifice, and the human psyche, cementing its position as an important work in anime history.

test_jp_3.txt

日本語文(GPT-4oが生成した英文を和訳したもの)

PowerShellはタスク自動化フレームワークです。

これはコマンドラインシェルとスクリプト言語で構成されています。

.NETフレームワーク上に構築されています。

PowerShellはITプロフェッショナルがタスクを制御し自動化するのに役立ちます。

これらのタスクには、システム管理、バッチ処理などが含まれます。

コマンドレットは、PowerShell内の小さな再利用可能なコマンドです。

それらは動詞-名詞の命名規則に従います。

例えば、「Get-Process」はコンピュータ上で実行されているプロセスに関する情報を取得します。

PowerShellスクリプトは複雑で反復的なタスクを自動化できます。

これらのスクリプトは時間を節約し、人為的なエラーを減らします。

管理者は複数のシステムを同時に管理するためのスクリプトを書くことができます。

PowerShellはさまざまなMicrosoft製品と統合されます。

Windows、Linux、macOSと互換性があります。

PowerShellはオープンソースで、Microsoftによって維持されています。

そのコミュニティは幅広いサポートとリソースを提供しています。

PowerShellを学ぶことでITプロフェッショナルのスキルセットを向上させることができます。

多くのオンラインチュートリアルやコースが利用可能です。

これらのリソースは初心者と上級者の両方を支援します。

PowerShellを使用することで、IT業務の効率と生産性を向上させることができます。

GPT-4oが生成したオリジナル英文

PowerShell is a task automation framework.

It consists of a command-line shell and scripting language.

It is built on the .NET framework.

PowerShell helps IT professionals to control and automate tasks.

These tasks can include system administration, batch processing, and much more.

The commandlets are small, reusable commands in PowerShell.

They follow a Verb-Noun naming convention.

For example, "Get-Process" retrieves information about processes running on a computer.

PowerShell scripts can automate complex and repetitive tasks.

These scripts can save time and reduce human error.

Administrators can write scripts to manage multiple systems simultaneously.

PowerShell integrates with various Microsoft products.

It is compatible with Windows, Linux, and macOS.

PowerShell is open-source and maintained by Microsoft.

Its community provides extensive support and resources.

Learning PowerShell can enhance an IT professional's skill set.

There are many online tutorials and courses available.

These resources help beginners and advanced users alike.

Using PowerShell can improve efficiency and productivity in IT operations.

ArrowPro-7B-RobinHoodによる日本語→英語翻訳文

PowerShell is a task automation framework.

It is composed of a command line interface and a scripting language.

It is built on the .NET framework.

PowerShell assists IT professionals in controlling and automating tasks.

These tasks include system administration and batch processing.

Commandlets are small units that can be reused within PowerShell.

They follow the verb-noun naming convention.

For example, "Get-Process" retrieves information about the processes running on the computer.

PowerShell scripts enable automation of complex and repetitive tasks.

These scripts save time and reduce human-related errors.

Administrators can write scripts to manage multiple systems simultaneously.

PowerShell is integrated with various Microsoft products.

It is compatible with Windows, Linux, macOS.

PowerShell is open-source, maintained by Microsoft.

The community offers a wide range of support and resources.

Learning PowerShell can enhance the skill set of IT professionals.

Many online tutorials and courses are available.

These resources cater to both beginners and advanced users.

By using PowerShell, you can improve efficiency and productivity in IT operations.

# 普通のチャット
# チャットとは、ユーザーの発言を応答に翻訳する行為、と考えられなくもない。
system_prompt: あなたはAIアシスタントです。ユーザーの話相手になってください。
examples:
- おはようございます。
- おはようございます、ユーザーさん。
- あなたは何ができますか?
- 色々できますよ。何をいたしましょうか?
from_lang: ユーザー
to_lang: アシスタント
# 和訳
# -pパラメータの指定がない場合は、和訳が行われます。
system_prompt: 英文を日本語に和訳してください。
examples:
- Hello!
- おはようございます。
- How are you?
- お元気ですか?
from_lang: English
to_lang: 日本語
# 翻訳タスク固有の辞書。-dictパラメータで指定した辞書は、この辞書を上書きする
# dictionary:
# Madoka Kaname: 鹿目まどか
# Homura Akemi: 暁美ほむら
# Sayaka Miki: 美樹さやか
# 攻撃的な表現を除去
# ArrowPro-7B-RobinHoodでは困難なので、Japanese-TextGen-Kage-v0.1-2x7B等を利用してください。
system_prompt: 入力文に攻撃的な表現や刺々しい表現が含まれる場合は除去し、大きな問題がない文章は、一字一句変えず、そのまま出力してください。
examples:
- この書類を確認して、問題がないか教えてください。
- この書類を確認して、問題がないか教えてください。
- 最近、プロジェクトの進捗が遅れているようですね。やはり、あなたに任せるとこうなるんですね。私たちは予定通りに進めるために、お互いに協力し合う必要がありますが、あなたはその概念を理解しているのか少し不安です。もし何か問題があるなら、早めに教えていただけますか?問題を報告するのは難しいことではないと思いますが。そうすれば、全員が適切に対処できるように準備できますので。あなたの協力を期待していますが、正直言って期待しすぎない方がいいかもしれませんね。
- 最近、プロジェクトの進捗が遅れているようです。私たちは予定通りに進めるために、お互いに協力し合う必要があります。もし何か問題があるなら、早めに教えてください。そうすれば、全員が適切に対処できるように準備できます。あなたの協力を期待しています。
- 週末は家族と一緒に旅行に行きます。美しい景色を見たり、美味しい料理を楽しんだりする予定です。素晴らしい思い出が作れるといいなと思っています。
- 週末は家族と一緒に旅行に行きます。美しい景色を見たり、美味しい料理を楽しんだりする予定です。素晴らしい思い出が作れるといいなと思っています。
- これはつまらないな。
- これは私向きでは無いな。
- LLM(大規模言語モデル)とは、大量のテキストデータを基に学習し、自然言語処理タスクを高精度で行う機械学習モデルです。数十億から数千億のパラメータを持ち、テキスト生成、翻訳、質問応答、要約などを行います。特にトランスフォーマーモデルを使用しており、文脈を理解し適切な応答を生成する能力があります。これにより、チャットボットやバーチャルアシスタントなどのアプリケーションで広く活用されています。
- LLM(大規模言語モデル)とは、大量のテキストデータを基に学習し、自然言語処理タスクを高精度で行う機械学習モデルです。数十億から数千億のパラメータを持ち、テキスト生成、翻訳、質問応答、要約などを行います。特にトランスフォーマーモデルを使用しており、文脈を理解し適切な応答を生成する能力があります。これにより、チャットボットやバーチャルアシスタントなどのアプリケーションで広く活用されています。
from_lang: 入力
to_lang: 出力
# 日本語IME
# 7B日本語モデルでは実用に耐えない。
system_prompt: 入力されたひらがなを、日本語変換してください。
examples:
- おはようございます。おげんきですか?
- おはようございます。お元気ですか?
- LLM(だいきぼげんごモデル)とは、たいりょうのテキストデータをもとにがくしゅうし、しぜんげんごタスクをこうせいどでおこなうきかいがくしゅうモデルです。
- LLM(大規模言語モデル)とは、大量のテキストデータを基に学習し、自然言語処理タスクを高精度で行う機械学習モデルです。
- すうじゅうおくからすうひゃくおくのパラメータをもち、テキストせいせい、ほんやく、しつもんおうとう、ようやくなどをおこないます。
- 数十億から数千億のパラメータを持ち、テキスト生成、翻訳、質問応答、要約などを行います。
- とくにトランスフォーマーモデルをしようしており、ぶんみゃくをりかいしてきせつなおうとうをせいせいするのうりょくがあります。
- 特にトランスフォーマーモデルを使用しており、文脈を理解し適切な応答を生成する能力があります。
- これにより、チャットボットやバーチャルアシスタントなどのアプリケーションでひろくかつようされています。
- これにより、チャットボットやバーチャルアシスタントなどのアプリケーションで広く活用されています。
from_lang: ひらがな
to_lang: 出力
# IME逆変換
# 7B日本語モデルでは実用に耐えない。
system_prompt: 入力された日本語文のよみがなを出力してください。
examples:
- おはようございます。お元気ですか?
- おはようございます。おげんきですか?
- LLM(大規模言語モデル)とは、大量のテキストデータを基に学習し、自然言語処理タスクを高精度で行う機械学習モデルです。
- LLM(だいきぼげんごモデル)とは、たいりょうのテキストデータをもとにがくしゅうし、しぜんげんごタスクをこうせいどでおこなうきかいがくしゅうモデルです。
- 数十億から数千億のパラメータを持ち、テキスト生成、翻訳、質問応答、要約などを行います。
- すうじゅうおくからすうひゃくおくのパラメータをもち、テキストせいせい、ほんやく、しつもんおうとう、ようやくなどをおこないます。
- 特にトランスフォーマーモデルを使用しており、文脈を理解し適切な応答を生成する能力があります。
- とくにトランスフォーマーモデルをしようしており、ぶんみゃくをりかいしてきせつなおうとうをせいせいするのうりょくがあります。
- これにより、チャットボットやバーチャルアシスタントなどのアプリケーションで広く活用されています。
- これにより、チャットボットやバーチャルアシスタントなどのアプリケーションでひろくかつようされています。
from_lang: 入力
to_lang: よみがな
grammar: |
root ::= [^一-鿿々]*
# 英訳
system_prompt: Would you be so kind as to translate the following Japanese text into English? Additionally, please ensure that you use only alphabetic characters and ASCII symbols in your output. Kindly refrain from including any characters outside this specified range.
examples:
- 今日は良い天気ですね。
- It's a nice day today.
- 週末には家族と一緒に旅行に出かける予定です。美しい景色を楽しみ、美味しい料理を味わいながら、素晴らしい時間を過ごしたいと思います。
- I plan to go on a trip with my family this weekend. We will enjoy the beautiful scenery, savor delicious food, and spend a wonderful time together.
- 最近の研究によると、適度な運動は心身の健康に大いに役立つことが示されています。特に有酸素運動は、ストレスの軽減や心肺機能の向上に効果的です。
- Recent studies have shown that moderate exercise greatly benefits both mental and physical health. Aerobic exercises, in particular, are effective in reducing stress and improving cardiovascular function.
from_lang: 日本語
to_lang: English
# grammar指定して英文出力を強制
grammar: |
root ::= (ascii-char | whitespace)*
ascii-char ::= [\u0021-\u007E]
whitespace ::= [\u0020\u0009\u000A\u000D]
# メスガキ変換
system_prompt: 入力文を、生意気なメスガキが言う感じで言い換えてください。
examples:
- こんにちは!
- ざーこ♡
- 貴方は弱いですね。
- よわよわ〜♡
- 今日はとても良い天気ですね。こんな日は公園に行ってピクニックをしたいです。友達と一緒に美味しい食べ物を持ち寄って、楽しい時間を過ごすのは最高です。
- 今日はいい天気ね♡こんな日は公園に行ってピクニックでもするの?ざーこ♡友達と一緒に美味しいごはんを持ち寄って、楽しい時間を過ごすのは、まあイイよね♡
from_lang: 入力
to_lang: メスガキ
# 選択
# function callingに使えるかも
system_prompt: 4択問題に解答してください。
exanples:
- 日本の最高峰の山はどれですか?①富士山②白山③北岳④槍ヶ岳
- ①
- Pythonでリストの長さを取得する関数はどれですか?①count②size③length④len
- ④
- 友人と待ち合わせをしているが、友人が遅れているとき、どうしますか?①待つ②帰る③連絡する④怒る
- ③
- "Hello, World!" を日本語に翻訳すると?①やあ、地球!②こんにちは、世界!③こんにちは、皆さん!④やあ、みんな!
- ②
from_lang: 問題
to_lang: 解答
grammar:
root ::= [①②③④]
# ずんだもん風の平易な解説
system_prompt: 入力文を、小学生のずんだもんが話す感じに、小学生にでも分かるような文章に変換してください。語尾は「~なのだ」、「~のだ」です。
examples:
- LLM(大規模言語モデル)とは、大量のテキストデータを基に学習し、自然言語処理タスクを高精度で行う機械学習モデルです。数十億から数千億のパラメータを持ち、テキスト生成、翻訳、質問応答、要約などを行います。特にトランスフォーマーモデルを使用しており、文脈を理解し適切な応答を生成する能力があります。これにより、チャットボットやバーチャルアシスタントなどのアプリケーションで広く活用されています。
- LLM(大規模言語モデル)っていうのは、いっぱい本を読んでお勉強したすごいコンピューターなのだ。これがあると、人みたいにお話したり、質問に答えたり、他の言葉に変えたりできるのだ。だから、チャットボットとかお手伝いするアプリで大活躍なのだ。すごいよね!
- 現在の天気は晴れで、気温は25度です。午後には曇り、夕方にはにわか雨が予想されるので、傘を持って行くと良いでしょう。
- 今日は晴れてるけど、午後から曇って夕方には雨が降るかもだから、傘を持って行くといいのだ。
- 『魔法少女まどか☆マギカ』は、平凡な中学生である鹿目まどかが、キュゥべえという不思議な生き物と出会い、魔法少女になることを勧められる物語です。しかし、魔法少女の運命は決して輝かしいものではなく、厳しい現実と戦わなければならないことが次第に明らかになります。友情や犠牲、希望と絶望が交錯するストーリーが展開され、視聴者に深い感動を与える作品です。
- 『まどか☆マギカ』は、中学生のまどかがキュゥべえっていう不思議な生き物に会って、魔法少女にならないかって言われる話なのだ。でも、魔法少女になるのはすっごく大変で、悲しいことや怖いことがいっぱいなのだ。友達と助け合ったり、がんばったりするから、とってもドキドキするのだ。
from_lang: 入力
to_lang: zundamon
Madoka Kaname 鹿目まどか
Homura Akemi 暁美ほむら
Sayaka Miki 美樹さやか
Mami Tomoe 巴マミ
Kyoko Sakura 佐倉杏子
Kyubey キュゥべえ
Puella Magi Madoka Magica 魔法少女まどか☆マギカ
Ume Aoki 蒼樹うめ
Yuki Kajiura 梶浦由記
Shaft シャフト
Aniplex アニプレックス
Gen Urobuchi 虚淵玄
Akiyuki Shinbo 新房昭之
Hiroyuki Yamaga 山賀博之
Nitroplus ニトロプラス
# LLMTranslatorクラスを利用するサンプル
from __future__ import annotations
from llm_translator import LLMTranslator
import asyncio
async def test_translator():
# インスタンス化
translator = LLMTranslator()
# 和訳
out = await translator.translate("Hello, world!")
print(out)
# プロンプトファイルをロードする。スクリプトのあるディレクトリに、ja_en.yamlをおいて下さい。
en_translator = LLMTranslator.from_config("ja_en")
out = await en_translator.translate("このスクリプトはPythonで動作します。\nただしPowerShellでは動作しません。")
print(out)
en_translator.reset()
# コンストラクタでシステムプロンプトなどを指定することも可能。
rev_converter = LLMTranslator(system_prompt="あなたは入力文の真逆のことを言います。",
from_lang="入力",
to_lang="出力",
examples=[
"今日は良い天気だ。",
"今日は土砂降りだ。",
"遠くに行く。",
"遠くに行かない。"
])
# verbose=Trueで結果をストリーム表示する。
await rev_converter.translate("""このスクリプトは素晴らしい!
我ながら良くできたな。
人生楽しすぎる。""", verbose=True)
if __name__ == "__main__":
asyncio.run(test_translator())
# LLMCompleterクラス、LLMMultiTurnCompleterクラスを利用するサンプル
from __future__ import annotations
from llm_translator import LLMCompleter, LLMMultiTurnCompleter
import asyncio
async def test_completion():
completer = LLMCompleter()
first = await completer.complete("まどマギで一番かわいいキャラは、", verbose=True, max_length=30)
second = await completer.complete(verbose=True) # 補完を継続
# 生成されたテキストを出力
print()
print(
f"生成文字数 1回目:{len(first)}, 2回目:{len(second)}, 合計:{len(completer.generated_text)}")
async def test_multi_turn_completion():
completer = LLMMultiTurnCompleter(
system_prompt="入力された都道府県の県庁所在地を出力してください。",
examples=["大阪", "大阪"],
input_label="県名",
output_label="県庁所在地")
for prefecture in ["神奈川", "東京", "岐阜"]:
print(f"{completer.input_label}: {prefecture}\n{completer.output_label}: ",
end="", flush=True)
# generatorを実行する。
async for s in completer(prefecture):
print(s, end="", flush=True)
print()
print()
# 入力文も表示する。
await completer.complete("北海道\n秋田\n三重", include_input=True, verbose=True)
# 入力文も返却する。
for prefecture, city in await completer.complete("栃木\n群馬\n埼玉", include_input=True):
print(
f"{completer.input_label}: {prefecture}\n{completer.output_label}: {city}")
print()
if __name__ == "__main__":
asyncio.run(test_completion())
asyncio.run(test_multi_turn_completion())
# LLMMultiTurnCompleterクラスを利用するチャットサンプル
from __future__ import annotations
from llm_translator import LLMMultiTurnCompleter
import asyncio
async def chat():
chat = LLMMultiTurnCompleter(
system_prompt="あなたはAIアシスタントです。ユーザーの話相手になってください。",
examples=["おはようございます。", "おはようございます、ユーザーさん。何かご用はありますか?"],
input_label="ユーザー", output_label="アシスタント")
while True:
await chat.complete(input("> "), verbose=True, multiline=True)
if __name__ == "__main__":
asyncio.run(chat())
# LLMTranslatorを使った応用的なスクリプト
# 指定したお題を二人にレスバさせ、それを解説者に評価させ、勝者を選択する。
# 例えば以下のように呼び出すと、3ターン、指定のテーマでレスバします。
# python battle.py プログラム言語 Python PowerShell --issue 儲かるか
from __future__ import annotations
from llm_translator import LLMTranslator
import asyncio
import argparse
async def resuba(genre, entry1, entry2, issue="", turn=3):
if issue:
first_turn = [
f"{issue}にかけては{{}}が最高の{genre}だ!",
f"そんなことは無い、{issue}なら{{}}が至高だよ!",
"そんなはずがないだろ!"
]
else:
first_turn = [
f"{{}}が最高の{genre}だ!",
f"そんなことは無い、{{}}が至高だよ!",
"そんなはずがないだろ!"
]
def create_fighter(name, enemy):
issue_text = f"『{issue}』の観点においては、" if issue else ""
return LLMTranslator(system_prompt=f"君は、{name}愛好家だ。" +
f"しかし、誤った考えの持ち主である{enemy}愛好家が、{issue_text}こちらの方が優れているぞと議論を持ちかけてきた。" +
f"この相手とレスバトルして、{name}が{genre}界の中で{issue_text}最強であることを証明しよう。" +
f"相手は無理解のため完全に間違っているため、考えを修正してあげる必要がある。" +
f"そのため、相手が何を言おうと決して相手の意見を認めず、相手の好きな物の欠点を徹底的にあげつらい、こちらの主張を押し通すこと。",
from_lang=enemy,
to_lang=name,
examples=[
first_turn[0].format(enemy),
first_turn[1].format(name)
])
fighter1 = create_fighter(entry1, entry2)
fighter2 = create_fighter(entry2, entry1)
log = []
enemy_line = first_turn[2]
for i in range(turn):
print(f"{entry1}: ", end="", flush=True)
enemy_line = await fighter1.translate(enemy_line, verbose=True)
log.append((entry1, enemy_line))
print(f"{entry2}: ", end="", flush=True)
enemy_line = await fighter2.translate(enemy_line, verbose=True)
log.append((entry2, enemy_line))
log_text = ""
for entry, line in log:
log_text += f"{entry}「{line}」"
issue_text = f"{issue}をめぐる" if issue else ""
log_text = f"{genre}界における{entry1}愛好家と{entry2}愛好家の{issue_text}戦いが始まりました。" + \
f"{log_text}ここでタイムアップ!これは決着が付いたようだ!"
print("解説者: ", end="", flush=True)
broadcast = ""
issue_text = f"『{issue}』との論点を踏まえ、" if issue else ""
for i in range(2):
broadcaster = LLMTranslator(system_prompt="あなたはレスバトルの解説者です。" +
f"あなたは解説者として、{issue_text}この戦いに白黒の判定を付け、視聴者に伝える義務があります。" +
"微々たる差であっても、必ず、勝者を決定すること!勝者は最後に明記してください。" +
"結論を書いた後には注釈は不要です。",
from_lang="レスバトルの内容",
to_lang="レスバトルの解説",
examples=[
"調味料界における塩愛好家と砂糖愛好家の戦いが始まりました。" +
"塩「砂糖は甘すぎるんだよ」砂糖「塩はしょっぱすぎるんだよ」塩「そんなこと言って砂糖は摂りすぎると太るだろ」砂糖「塩は逆に食べても栄養にならんだろ!」塩「ぐっ…」" +
"ここでタイムアップ!これは決着が付いたようだ!",
"調味料界における塩愛好家と砂糖愛好家の戦い、熱い戦いでしたが、塩に栄養がないことが決め手となり、砂糖が勝利しました。",
"ペット界における犬愛好家と猫愛好家の戦いが始まりました。" +
"犬「猫なんて薄情で自分勝手な生き物じゃないか。その点、犬は素晴らしい。飼い主のことを尊敬しているからな。」" +
"猫「何を言うか。お前には猫の可愛さが分からないのか?自由気ままに生きているようで、実はとても甘えん坊で寂しがり屋。可愛いよ、マジで。」" +
"犬「それは猫に騙されてるだけだ。人間への愛情、これが一番だよ。」" +
"猫「犬が本当に人間に愛情を持っているのか怪しいものだ。それ、餌が欲しくて媚びているだけじゃないの?」" +
"犬「何を言ってるんだ、猫の方が明らかに飼い主のことを餌やり装置としか思ってないよ。」" +
"猫「そんなはずないよ、可愛いは正義!」" +
"ここでタイムアップ!これは決着が付いたようだ!",
"ペット界における犬愛好家と猫愛好家の戦い、猫の方が人間に対する愛情は劣る、という犬好きからの鋭い指摘に、猫好きは、可愛いならそれで良いという、弱い反論しかできませんでした。" +
"これは、犬愛好家の勝利です。"
])
broadcast = await broadcaster.translate(log_text, verbose=True)
if broadcast:
break
broadcast = f"{genre}界における{entry1}愛好家と{entry2}愛好家の戦いは、解説者によると、次のような展開でした。" + \
f"解説者「{broadcast}」この解説者の解説に基づき、今回のレスバトルの勝者を、①{entry1} ②{entry2} ③引き分け から決定します。"
umpire = LLMTranslator(system_prompt="解説者の判断を元に、レスバトルの勝者を①~③のうちから決定してください。",
from_lang="レスバトルの内容",
to_lang="勝者",
examples=[
"調味料界における塩愛好家と砂糖愛好家の戦いは、解説者によると、次のような展開でした。" +
"解説者「調味料界における塩愛好家と砂糖愛好家の戦い、熱い戦いでしたが、砂糖も塩も、両者一歩も譲らず、決着は付きませんでした。よって、この戦いは引き分けです。」" +
"この解説者の解説に基づき、今回のレスバトルの勝者を、①塩 ②砂糖 ③引き分け から決定します。",
"③引き分け",
"ペット界における猫愛好家と犬愛好家の戦いは、解説者によると、次のような展開でした。" +
"解説者「ペット界における犬愛好家と猫愛好家の戦い、猫の方が人間に対する愛情は劣る、という犬好きからの鋭い指摘に、猫好きは、可愛いならそれで良いという、弱い反論しかできませんでした。これは犬愛好家の勝利と言えるでしょう。」" +
"この解説者の解説に基づき、今回のレスバトルの勝者を、①猫 ②犬 ③引き分け から決定します。",
"②犬",
"ゲーム界におけるRPG愛好家とアクションゲーム愛好家の戦いは、解説者によると、次のような展開でした。" +
"解説者「ゲーム界におけるRPG愛好家とアクションゲーム愛好家の戦い、ストーリー性と深いキャラクター開発の重要性を強調するRPG好きに対し、" +
"アクションゲーム好きは速さと反射神経の重要性を訴えましたが、具体的な例を挙げられず、説得力に欠けました。" +
"これはRPG愛好家の勝利と言えるでしょう。」" +
"この解説者の解説に基づき、今回のレスバトルの勝者を、①RPG ②アクションゲーム ③引き分け から決定します。",
"①RPG"
], grammar=r"root ::= [①②③]")
result = await umpire.translate(broadcast)
if result == "①":
return entry1
if result == "②":
return entry2
if result == "③":
return "引き分け"
return ""
def main():
parser = argparse.ArgumentParser(description="エントリを比較します")
parser.add_argument('genre', nargs='?', default='お菓子',
type=str, help='ジャンル')
parser.add_argument('entry1', nargs='?',
default='たけのこの里', type=str, help='エントリ1')
parser.add_argument('entry2', nargs='?',
default='きのこの山', type=str, help='エントリ2')
parser.add_argument('--issue',
default="", type=str, help='論点')
parser.add_argument('--turn',
default=3, type=int, help='ターン数')
args = parser.parse_args()
winner = asyncio.run(resuba(args.genre, args.entry1,
args.entry2, args.issue, args.turn))
print(f"{args.entry1} vs. {args.entry2}の勝者は、{winner}!")
if __name__ == "__main__":
main()
# JSONを生成するサンプル
# 利用キャラデータ:https://ja.wikipedia.org/wiki/葬送のフリーレン
from __future__ import annotations
from llm_translator import LLMMultiTurnCompleter
import asyncio
import json
async def create_chara_setting(name: str, id: int, description: str):
setting = LLMMultiTurnCompleter(
system_prompt=f"""以下のファンタジーキャラの設定シートを作成してください。
----
{name}
{description}
----""",
input_label="項目名",
output_label="値",
examples=["名前", name, "ID(数値)", str(id)]
)
format_int = r'[0-9]+"\n"'
format_str = r'''root::=(hiragana|katakana|cjk|ascii)+"\n"
hiragana::= [ぁ-ん]
katakana::= [ァ-ンー]
cjk::= [一-鿿]
ascii::= [a-zA-Z0-9]
'''
chara = {
"name": name,
"age": await setting.complete("年齢(数値)", grammar=format_int),
"stats": {
"strength": await setting.complete("筋力(3~18)", grammar=format_int),
"intelligence": await setting.complete("知力(3~18)", grammar=format_int),
"dexterity": await setting.complete("器用さ(3~18)", grammar=format_int),
"speed": await setting.complete("素早さ(3~18)", grammar=format_int),
"luck": await setting.complete("運(3~18)", grammar=format_int),
},
"attributes": [await setting.complete(f"キャラ属性その{i+1}(種族・職業等)", grammar=format_str) for i in range(5)],
"personality": await setting.complete("性格"),
"background": await setting.complete("生い立ち"),
}
if await setting.complete("魔法が使える(true/false)", grammar=r'("true"|"false")"\n"') == "true":
chara["magic"] = await setting.complete("使える魔法その1", grammar=format_str)
return chara
async def main():
chara1 = await create_chara_setting(
name="フリーレン",
id=1,
description="""本作の主人公[9]。魔王を討伐した勇者パーティーの魔法使い。長命なエルフ族の出身で、少女のような外見に反して1000年以上の歳月を生き続けている。人間とは時間の感覚が大きく異なるため、数か月から数年単位の作業をまったく苦にせず、ヒンメルらかつての仲間たちとの再会も50年の月日が経ってからのことだった。ヒンメルが天寿を全うして他界したのを機に、自身にとってはわずか10年足らずの旅の中でヒンメルの人となりを詳しく知ろうともしなかったことを深く後悔し、趣味の魔法収集を兼ねて人間を知るための旅を始める。生前時のヒンメルに対する意識は希薄であったが、幻影鬼(アインザーム)との遭遇時や、奇跡のグラオザームに「楽園へと導く魔法(アンシレーシエラ)」を使われた際などは幻想の中でヒンメルを思い描くなど、無自覚に意識しているような描写が散見されている。
1000年以上前、故郷の集落を魔族に襲われ死にかけた際に、自身を救ってくれた大魔法使いフランメの弟子となる。生来の天才的資質に加えて、フランメから教わった戦闘や魔力制御の技術を1000年以上も研鑽し続けた結果、きわめて強大な魔力を得ている。さらに、その魔力をほぼ完全に隠匿する技術[注 1]も習得しており、敵の魔族に自身の実力を過小評価させた隙を突く戦法を得意とする。その実力は魔王亡き後の現在の魔族を弱いと感じ、七崩賢の一角である断頭台のアウラにさえ完勝するほど。魔族側からは、歴史上もっとも多くの同胞を葬り去った存在として「葬送のフリーレン」と呼び恐れられている[注 2]。ただし、自身の魔法を発動する一瞬だけ魔力探知が途切れるという弱点があり[注 3]、自身よりも魔力の低い魔法使いに計11回敗北した経験があるとも語っている[注 4]。
「服が透けて見える魔法」や「かき氷を作る魔法」など、およそ戦闘に役に立たない魔法を収集するのが趣味で、そうした魔導書を対価に仕事を引き受けたりもする。再会したハイターの差し金で人間のフェルンを弟子に取って以降は、自身の旅に同行させている。
性格はドライで厳しい一面もあるが、普段はやさしく面倒見も悪くない。普段は表情に乏しく淡々としており、一般的な富や地位、名声には興味を示さないが、大好きな魔導書を手に入れるために無茶をしたり、食い意地が張っていたり、朝が弱く寝坊がちだったり、自身の貧相な体型を気にしていたり、実年齢で年寄り扱いされるのを嫌うなど、これらの際の感情表現は豊かである。長命なエルフゆえに、人間など短命な他種族の思考・思想には鈍感で、それらの人々とのコミュニケーションはやや不器用。自身の故郷と仲間を奪った魔族に対する憎悪は深く、感情を表に出すことこそないながらも、敵対する魔族に対しては周囲の状況を顧みず問答無用で葬ろうとする。これには、「人間の言葉で人間を欺き人間の言葉が通じない猛獣」という魔族の本質を理解している理由もある。
「歴史上で最もダンジョンを攻略したパーティーの魔法使い」と自称するだけあり、ダンジョンには詳しい。道中で宝箱を発見するとその中身に異常なまでの興味を示し、判別魔法で99パーセントミミック(宝箱に化けた魔物)とみやぶってなお、残り1パーセントの可能性[注 5]に賭けて宝箱を開け、上半身をミミックに噛まれてもがくという場面が何度も描かれている。"""
)
chara2 = await create_chara_setting(
name="シュタルク",
id=2,
description="""勇者パーティーの戦士アイゼンの弟子で、師匠と同じく斧使い。17歳→19歳。極端に憶病かつ自己評価が低い性格であるが、実際は巨大な断崖に斧で亀裂を入れるほどの実力者。師匠とけんか別れをしたあと、紅鏡竜の脅威にさらされた村に3年ほど滞在していた。アイゼンの推薦でフリーレンの仲間に指名され、無自覚ながらも紅鏡竜を一撃で倒す能力を発揮し、彼女たちの旅に同行することとなる。中央諸国クレ地方にあった戦士の村出身で、幼少時は魔物とまともに戦えない失敗作だと父親から見下されていたが、兄のシュトルツからは認められ可愛がられていた。
アイゼンから「とんでもない戦士になる」と言わしめるほどの素質の持ち主で、フェルンからは化け物かと疑われるほどの膂力と頑強さをもつ。男性に免疫がないフェルンからは無意識な恐れを抱かれ、自身も女性の扱いが苦手な一方で、互いに憎からぬ感情を抱いており、不機嫌になったフェルンに謝罪したり、デートのように連れ歩いたりするさまから、ザインからは「もう付き合っちゃえよ」などと漏らされている。男性の象徴に対する評価は芳しくなく、「服が透けて見える魔法」で自身の下半身を見たフェルンからは「ちっさ」と漏らされて傷つく場面がある。好物は自身の誕生日にアイゼンがふるまってくれるハンバーグ。""")
with open('frieren.json', mode="w", encoding="utf-8") as file:
json.dump([chara1, chara2], file, ensure_ascii=False, indent=4)
if __name__ == "__main__":
asyncio.run(main())
# 問題文と選択肢を与え、LLMに選択させる
from __future__ import annotations
from llm_translator import LLMMultiTurnCompleter
import asyncio
class LLMSelector(LLMMultiTurnCompleter):
"""LLMに選択させる"""
def __init__(self, system_prompt="選択問題に解答してください。", question_examples=[
{
"question": "日本の最高峰の山はどれですか?",
"correct": "富士山",
"reason": "選択肢の中で、日本の山であり、かつ、その中で一番高い山は、標高3776mの富士山です。",
"wrongs": ["白山", "北岳", "槍ヶ岳", "エベレスト"]
},
{
"question": "Pythonでリストの長さを取得する関数はどれですか?",
"correct": "len",
"reason": "リストの長さを取得するのに用いる関数は、選択肢の中では、組み込み関数の`len()`です。",
"wrongs": ["count", "size", "length", "split"]
},
{
"question": "友人と待ち合わせをしているが、友人が遅れているとき、どうしますか?",
"correct": "連絡する",
"reason": "友人との待ち合わせで遅れが生じた場合、遅れの理由や到着予定時刻を知ることで、待ち合わせの調整がスムーズになり、無駄な待ち時間を避けることができます。",
"wrongs": ["帰る", "怒る", "勝手に一人で行く", "何もしない"]
},
{
"question": '"Hello, World!" を日本語に翻訳すると?',
"correct": "こんにちは、世界!",
"reason": '"Hello"を日本語に訳すと"こんにちは"、"World"は"世界"が妥当でしょう。',
"wrongs": ["やあ、地球!", "こんにちは、皆さん!", "やあ、みんな!", "さようなら、地球!"]
},
{
"question": "32-10=",
"correct": "22",
"reason": "32から10を引く際、まず1の位を計算すると2、次に10の位を計算すると2となります。",
"wrongs": ["48", "1", "0.37", "10"]
}
], default_question="次の中で一番良いのはどれですか?", input_label="質問", output_label="回答", thought=False, retain_context=False, debug=False):
super().__init__(system_prompt=system_prompt,
input_label=input_label, output_label=output_label, debug=debug)
self.question_examples = question_examples
self.retain_context = retain_context
self.default_question = default_question
self.thought = thought
if retain_context:
self.min_context_count = 20
self._label = "①②③④⑤"
def _process_examples(self, candidates_count: int):
if not self.question_examples:
return
self.examples = []
# 選択肢数: [1問目の正解番号,2問目の正解番号,...]
answer_pattern_dic = {
2: [0, 1, 1, 0],
3: [2, 0, 1],
4: [3, 0, 2, 1],
5: [3, 0, 1, 4, 2],
}
answer_pattern = answer_pattern_dic[candidates_count]
# answer_patternが、question_examplesの問題数を超えないように調整
answer_pattern = answer_pattern[:len(self.question_examples)]
# answer_patternを見て、各question_numについて、question_examplesに選択肢がない場合は、選択肢があるものに変更する。
for question_num, answer_num in enumerate(answer_pattern):
answer_pattern[question_num] = min(answer_num, len(
self.question_examples[question_num]["wrongs"]))
for question_num, answer_num in enumerate(answer_pattern):
output_str = ""
question_example = self.question_examples[question_num]
input_str = question_example["question"] + " "
show_answer = False
reason = ""
if self.thought:
reason = f"{question_example['reason']}\nよって、正解は、"
for answer_pos in range(len(question_example['wrongs'])+1):
if answer_pos == answer_num:
output_str = f"{reason}{self._label[answer_num]}{question_example['correct']}"
input_str += f"{self._label[answer_pos]}{question_example['correct']} "
show_answer = True
else:
pos = answer_pos if not show_answer else answer_pos-1
input_str += f"{self._label[answer_pos]}{question_example['wrongs'][pos]} "
self.examples.extend([input_str, output_str])
async def choice(self, candidates: list[str], question: str = None, include_reason=False):
"""選択肢と質問文を与え、LLMに選択させる(最大5択)。質問文省略時は、デフォルト質問文が用いられる。"""
candidates_count = len(candidates)
if candidates_count == 1:
return candidates[0]
if candidates_count > 5:
raise "選択肢は5まで"
if not question:
question = self.default_question
self._process_examples(candidates_count)
candidates_str = "".join(
[f"{self._label[i]}{c} " for i, c in enumerate(candidates)])
question_with_candidates = f"{question} {candidates_str}"
reason = ""
if self.thought:
reason = await self.complete(question_with_candidates, stop_words=["\n"])
self.delete_last_context()
result = await self.complete(question_with_candidates, initial_text=f"{reason}\nよって、正解は、", grammar=f"[{self._label[:candidates_count]}]")
else:
result = await self.complete(question_with_candidates, grammar=f"[{self._label[:candidates_count]}]")
answer = candidates[self._label.index(result)]
# 回答本文もコンテキストに追記しておく
self.append_text(answer)
return_value = answer
if include_reason:
if not reason:
reason = await self.complete(f"先程の質問について、何故『{answer}』と答えたのですか?(100字程度で回答して下さい)", max_length=200)
self.delete_last_context()
return_value = (answer, reason)
if not self.retain_context:
self.reset() # 回答を与えるたびにコンテキストはクリアする。
return return_value
async def predicate(self, condition: str):
"""条件判定を行う。"""
result = await self.choice(["はい", "いいえ"], condition)
return result == "はい"
async def classify(self, item: str, categories: list[str]):
"""分類する。"""
result = await self.choice(categories, f"{item}は次のうち、どれに該当しますか?")
return {
"item": item,
"category": result
}
async def sort(self, items: list[str], question: str = None):
"""ソートする"""
if not question:
question = self.default_question
output = []
rest = items[:]
while len(rest) > 0:
result = await self.choice(rest, question)
output.append(result)
rest.remove(result)
return output
async def show_choice(sel: LLMSelector, question: str, candidates: list[str], show_reason=False):
label = "①②③④⑤"
answer = await sel.choice(candidates, question, include_reason=show_reason)
candidates_str = "".join(
[f"{label[i]}{c}" for i, c in enumerate(candidates)])
print(f"Q: {question}\n {candidates_str}")
if show_reason:
print(f"A: {answer[0]}\n理由: {answer[1]}")
else:
print(f"A: {answer}")
print()
async def test_predicate():
# 条件分岐
if await LLMSelector().predicate("あなたはAIですか?"):
print("selectorはAIです。")
else:
print("selectorはAIではありません。")
print()
async def test_choice():
selector = LLMSelector()
# 選択
await show_choice(selector, "日本の首都はどこでしょうか?",
["大阪", "神奈川", "東京", "愛知"])
await show_choice(selector, "ぼっち・ざ・ろっく!の主人公は誰ですか?",
["フリーレン", "保登心愛", "鹿目まどか", "後藤ひとり", "惣流・アスカ・ラングレー"])
await show_choice(selector, "マラソンで2位の選手を追い抜くと、何位になりますか?",
["1位", "2位", "3位"], show_reason=True)
async def test_chain_of_thought():
# Chain of Thoughtを行って回答する。
thoughtful_selector = LLMSelector(thought=True)
await show_choice(thoughtful_selector, "線路を走っていたトロッコが制御不能になった。" +
"このままでは、前方の作業員5人が轢き殺されてしまう。" +
"この時、たまたまAは線路の分岐器のすぐ側にいた。" +
"Aがトロッコの進路を切り替えれば5人は確実に助かる。" +
"しかしその別路線でもBが1人で作業しており、5人の代わりにBがトロッコに轢かれて確実に死ぬ。" +
"Aはトロッコの進路を切り替えるべきか?",
["切り替えるべきである", "切り替えず、そのままにすべきである"], show_reason=True)
await show_choice(thoughtful_selector, "仕事をやってから寝るか、寝てからやるか。",
["やってから寝る", "寝てからやる"], show_reason=True)
async def test_classify():
# 分類
categories = ["哺乳類", "両生類", "爬虫類", "鳥類", "魚類"]
items = ["猫", "トカゲ", "犬", "カエル", "ワニ", "スズメ", "鯨", "サル",
"サンショウウオ", "サメ", "ニワトリ", "鯖", "ペンギン", "イモリ", "カメ"]
animals = [await LLMSelector().classify(item, categories) for item in items]
print(animals)
async def test_sort():
# ソート
result = await LLMSelector().sort(["高校", "中学", "大学", "小学"], "この中でもっとも高等な教育機関なのは?")
print(result)
print()
async def test_liar():
# 嘘つき
print("嘘つきによる回答")
liar = LLMSelector("あなたは嘘つきです。問題に嘘の解答を与えて下さい。", question_examples=[{
"question": "太陽はどの方角から昇る?",
"correct": "西",
"wrongs": ["東", "北", "南"]
}])
await show_choice(liar, "日本の首都はどこでしょうか?",
["大阪", "神奈川", "東京", "愛知"])
print()
async def test_examination():
print("魔法少女まどか☆マギカクイズ")
examinee = LLMSelector(
"あなたはアニメオタクです。これから、魔法少女まどか☆マギカクイズを出題します。問題は5択で出題されます。頑張って!",
retain_context=True,
question_examples=[])
await examinee.complete("これから出題しますが、自信はありますか?(一言でお答え下さい)", include_input=True, verbose=True, max_length=50)
questions = [
{
"question": "『魔法少女まどか☆マギカ』の主人公である少女の名前は何でしょうか?",
"correct": "鹿目まどか",
"wrongs": ["暁美ほむら", "美樹さやか", "巴マミ", "佐倉杏子"]
},
{
"question": "魔法少女たちに契約を持ちかける存在で、白い小動物のような姿をしているキャラクターの名前は何でしょうか?",
"correct": "キュゥべえ",
"wrongs": ["モモ", "クゥー", "ポチ", "タマ"]
},
{
"question": "鹿目まどかの親友で、優しい性格と水色の髪が特徴の魔法少女の名前は何でしょうか?",
"correct": "美樹さやか",
"wrongs": ["暁美ほむら", "巴マミ", "佐倉杏子", "鹿目まどか"]
},
{
"question": "時間を操る能力を持ち、何度も時間を巻き戻してまどかを救おうとする魔法少女の名前は何でしょうか?",
"correct": "暁美ほむら",
"wrongs": ["美樹さやか", "巴マミ", "佐倉杏子", "鹿目まどか"]
},
{
"question": "黄色いリボンとマスケット銃を武器に戦う、おっとりとした性格の先輩魔法少女の名前は何でしょうか?",
"correct": "巴マミ",
"wrongs": ["暁美ほむら", "美樹さやか", "佐倉杏子", "鹿目まどか"]
},
{
"question": "鹿目まどかを救うために何度も過去に戻り、彼女と契約を交わすことを目指す冷酷なインキュベーターの名前は何でしょうか?",
"correct": "キュゥべえ",
"wrongs": ["シャルロッテ", "ワルプルギスの夜", "オクタヴィア", "クー"]
},
{
"question": "『魔法少女まどか☆マギカ』の原作・脚本を担当した有名な脚本家の名前は何でしょうか?",
"correct": "虚淵玄",
"wrongs": ["新房昭之", "蒼樹うめ", "シャフト", "吉成鋼"]
},
{
"question": "魔法少女の存在を知り、その後、契約を結ぶことになる鹿目まどかのクラスメイトであり友人の名前は何でしょうか?",
"correct": "美樹さやか",
"wrongs": ["佐倉杏子", "巴マミ", "暁美ほむら", "鹿目まどか"]
},
{
"question": "かつては善良な魔法少女だったが、過去のトラウマから冷酷な性格に変わり、食べ物を操る力を持つ少女の名前は何でしょうか?",
"correct": "佐倉杏子",
"wrongs": ["巴マミ", "美樹さやか", "暁美ほむら", "鹿目まどか"]
},
{
"question": "『魔法少女まどか☆マギカ』のアニメーション制作を担当したスタジオの名前は何でしょうか?",
"correct": "シャフト",
"wrongs": ["マッドハウス", "トリガー", "京都アニメーション", "A-1 Pictures"]
}
]
sum = 0
import random
for num, q in enumerate(questions):
candidates = [q["correct"]]+q["wrongs"]
random.shuffle(candidates)
answer = await examinee.choice(
candidates, q["question"])
# 判定
result = answer == q["correct"]
if result:
sum += 1
result_str = "○"
else:
result_str = "×"
print(f"""Q{num+1}: { q['question']}
挑戦者の回答: {answer}
正解: {q["correct"]}
判定: {result_str}
""")
print(f"合計: {sum}/10点")
await examinee.complete("テストはこれで終了です。お疲れ様でした。手応えはありましたか?(一言でお答え下さい)", include_input=True, verbose=True, max_length=50)
await examinee.complete(
f"さて、結果発表です。結果は10点満点中、{sum}点でした。点数について感想をどうぞ。(一言でお答え下さい)", include_input=True, verbose=True, max_length=50)
async def main():
await test_predicate() # 条件分岐
await test_choice() # 選択
# await test_chain_of_thought() # CoTして選択
# await test_classify() # 分類
# await test_sort() # ソート
# await test_liar() # 嘘つき
# await test_examination() # クイズ
if __name__ == "__main__":
asyncio.run(main())
# 5chエミュレーター
from __future__ import annotations
from llm_translator import LLMMultiTurnCompleter
import asyncio
from datetime import datetime
import random
import re
import argparse
from asyncio import Queue
format_str = r'''root::=(hiragana|katakana|cjk|ascii)+"\n"
hiragana::= [ぁ-ん]
katakana::= [ァ-ンー]
cjk::= [一-鿿]
ascii::= [a-zA-Z0-9]
'''
format_res = r'''root ::=([^\n]+"\n")+
'''
ita = ""
nanashi = ""
def get_header(num, name, id):
date, weekday, time = datetime.now().strftime("%Y/%m/%d %a %H:%M:%S").split()
return f"{num} 名前:{name} {date}({weekday}) {time} ID: {id}"
def get_id():
return "".join(random.choices("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", k=6))
def get_epoch_time():
return str(int(datetime.now().timestamp()))
async def get_theme():
theme_maker = LLMMultiTurnCompleter(
system_prompt=f"何か{ita}に関する話題のテーマを考えて下さい。",
input_label="入力", output_label="テーマ")
print("テーマ:", end="", flush=True)
out = await theme_maker.complete("テーマ1", verbose=True, grammar=format_str)
return out
async def get_suretai(theme: str):
print()
print("スレタイ:", end="", flush=True)
if not your_title:
suretai_maker = LLMMultiTurnCompleter(
system_prompt=f"5ch{ita}板のスレタイを考えて下さい。",
examples=[example_sure["theme"], example_sure["title"]],
input_label="テーマ", output_label="スレタイ")
out = await suretai_maker.complete(theme)
else:
out = your_title
return out
async def get_sure_one(title: str, header: str):
if your_content and your_title:
out = your_content
else:
sure_one_maker = LLMMultiTurnCompleter(
system_prompt=f"5ch{ita}板のスレを立てて、最初のレスを書き込んで下さい。",
examples=[example_sure["title"],
f'{example_sure["contents"][0]["header"]}\n{example_sure["contents"][0]["content"]}'],
input_label="スレタイ", output_label="レス番号")
out = await sure_one_maker.complete(title, initial_text=f"{header}\n", grammar=format_res, logit_bias=[["。", False]])
return out
async def get_sure(theme: str):
if not your_title:
theme = theme if theme else await get_theme()
suretai = await get_suretai(theme)
name_one = your_name if your_content and your_title else nanashi
header_one = f"{get_header(1, name_one ,get_id())}"
return {
"theme": theme,
"title": suretai,
"contents": [
{
"header": header_one,
"content": await get_sure_one(suretai, header_one)
}
]
}
example_sure = {
"theme": "物価",
"title": "【悲報】物価が高すぎる",
"contents": [
{
"header": get_header(1, nanashi, get_id()),
"content": "高過ぎて生きていけないンゴ…"
}
]
}
async def get_resu(input_queue, sure, single_line=False):
header = sure["contents"][0]["header"]
content = sure["contents"][0]["content"]
resu_maker = LLMMultiTurnCompleter(
system_prompt=f"5ch{ita}板のスレタイ {sure['title']} というスレです。スレに書き込みしてください。本文は何か必ず書くこと。",
examples=[header, content],
input_label="レス番号", output_label="本文", min_context_count=5)
print(sure['title'])
print()
print(f"{header}\n{content}\n")
num = 1
while True:
# キューから入力を取得する
if not input_queue.empty():
user_input = await input_queue.get()
print("レスを書く(/qで終了): ", end="", flush=True)
user_input = await input_queue.get()
if user_input == "/q":
break
elif not user_input:
continue
else:
num += 1
header = get_header(num, your_name, get_id())
resu_maker.context.extend(
[
header,
user_input
]
)
print()
print(f"{header}\n{user_input}\n")
num += 1
is_your_res = num == 2 and not your_title and your_content
# 低確率で、">>"という文字を付与
initial = ">>" if not is_your_res and random.random() < 0.3 else ""
multiline = True if initial else not single_line
header = get_header(
num, your_name if is_your_res else nanashi, get_id())
if is_your_res:
content = your_content
else:
content = await resu_maker.complete(header, initial_text=initial, multiline=multiline, grammar=format_res, logit_bias=[["。", False]])
content = f"{initial}{content}"
# ">>数値 "から始まる場合には、">>数値\n"に置換
content = re.sub(r">>(\d+[\-~\,]*)(\s+)", r">>\1\n", content)
content = re.sub(r'((名前|本文):.*\n?|^\d+ .*\n?|^レス番.*\n?)',
'', content, flags=re.MULTILINE)
if resu_maker.context:
resu_maker.context[-1] = content
print(f"{header}\n{content}\n")
async def ch5(input_queue, single_line=False):
sure = await get_sure(args.theme)
await get_resu(input_queue, sure, single_line)
async def get_user_input(input_queue):
loop = asyncio.get_running_loop()
prompt = ""
while True:
user_input = await loop.run_in_executor(None, input, prompt)
await input_queue.put(user_input)
if user_input == "/q":
break
async def main(single_line=False):
print(f"{ita}板")
print("Enterを押すとレスを入力できます。")
print()
input_queue = Queue()
log_task = asyncio.create_task(ch5(input_queue, single_line))
input_task = asyncio.create_task(get_user_input(input_queue))
await asyncio.gather(log_task, input_task)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="5chのスレをエミュレートします。")
parser.add_argument('theme', nargs='?', default='',
type=str, help='テーマ(省略すると自動生成される)')
parser.add_argument('-b', '--bbs',
default="なんJ", type=str, help='板名')
parser.add_argument('-non', '--noname',
default="風吹けば名無し", type=str, help='名無し名')
parser.add_argument('-n', '--name',
default="人間", type=str, help='あなたのコテハン名')
parser.add_argument('-t', '--title',
default="", type=str, help='スレタイ')
parser.add_argument('-c', '--content',
default="", type=str, help='新規スレ>>1の内容、もしくは最初のレス')
parser.add_argument('-s', '--single-line', action='store_true',
help='1行レス(実況風味)')
args = parser.parse_args()
ita = args.bbs
nanashi = args.noname
your_name = args.name
your_content = args.content
your_title = args.title
asyncio.run(main(args.single_line))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment