# [LangChain] 範例-翻譯機
日期:2023/09/19
## 敘述
- 主題:MultiPromptChain()、LLMRouterChain()
- 使用情境:翻譯機。除了正常的翻譯以外,也可透過自然語言要求程式切換成其他語言種類,讓它在之後依照提供的語言進行翻譯。
- 輸入:1. 想要翻譯的文本。2.要求切換成別種翻譯語言(設定之後希望翻譯的語言)
- 輸出:將在設定的兩種語言中來回進行翻譯
## 目錄
- [1. 主程式](#1-主程式)
- [2. 輸入輸出](#2-輸入輸出)
__________________
## 1. 主程式
導入套件
```python=
from dotenv import load_dotenv
load_dotenv()
from langchain.chat_models import ChatOpenAI
from langchain.prompts import (
PromptTemplate,
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
from langchain import LLMChain
llm = ChatOpenAI(temperature=0.7)
```
```python=
import re
from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE
```
以下為翻譯機的主程式。
在此程式中,比較重要的物件包含MultiPromptChain()、LLMRouterChain()、MULTI_PROMPT_ROUTER_TEMPLATE()。
透過此程式可讓程式自行判斷需要使用帶有甚麼prompt的chain,進而達到不同輸入不同行動的效果。程式可執行的動作包含:1. 翻譯輸入的文本 2. 切換使用的語言。
如上述所說,因此程式中包含了兩個可以使用的chain。
切換使用語言的chain,所使用的prompt即為`language_choice_prompt`變數,會將這個prompt的資訊提供給LLMRouterChain(),讓LLMRouterChain()可以選擇是否使用帶有這個prompt的chain;
而翻譯所使用的chain,則是作為MultiPromptChain()的default_chain。只要輸入不是要求切換語言種類時,就會使用著個chain進行翻譯。
```python=
#先給予預設的翻譯語言。
lang1 = 'en'
lang2 = 'zh'
def translator(input_text):
#將lang1和lang2定義為全域變數,讓語言變數可以在函式內重新定義,並在下一次呼叫函式時一同被使用。
global lang1, lang2
#定義destination prompt
language_choice_prompt = """請確認<>中提及的語言種類,將列舉兩個提及的語言種類。請遵循以下規則,並且不要產生其他以外的回答。
輸出規則:
1. 使用ISO 639語言代碼列舉,例如:en, zh
2. 輸出的語言代碼需不多不少剛好兩個。若只有發現一種語言,則兩個語言輸出則為相同的代號。
<{input}>
"""
#使用以下格式整理所有promtpt
prompt_infos = [
{
"name": "language_choice",
"description": "適用於當輸入為以下幾種時:1.提及要切換翻譯語言 2.提及兩種語言種類。",
"prompt_template": language_choice_prompt,
},
]
#使用所有prompt定義各自的chain
destination_chains = {}
for p_info in prompt_infos:
name = p_info["name"]
prompt_template = p_info["prompt_template"]
prompt = PromptTemplate(template=prompt_template, input_variables=["input"])
chain = LLMChain(llm=llm, prompt=prompt)
destination_chains[name] = chain
#destinations_str包含各個不同prompt的名稱與敘述,router_chain將根據destinations_str選擇使用甚麼prompt
destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos]
destinations_str = "\n".join(destinations)
#定義router_chain
router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str)
router_prompt = PromptTemplate(
template=router_template,
input_variables=["input"],
output_parser=RouterOutputParser(),
)
router_chain = LLMRouterChain.from_llm(OpenAI(), router_prompt)
# #定義default_chain
systemmessage = f'''請擔任翻譯機,而不要回答任何問題,將任何輸入都進行翻譯。
翻譯規則:
<若輸入為語言-{lang1},則翻譯成語言-{lang2};
若輸入為語言-{lang2},則翻譯成語言-{lang1}。>
另外,若需要翻譯成ZHTW,請使用台灣會使用的詞彙。'''
default_prompt = ChatPromptTemplate(
messages = [
SystemMessagePromptTemplate.from_template(systemmessage),
HumanMessagePromptTemplate.from_template("{input}")
]
)
default_chain = LLMChain(llm=llm, prompt=default_prompt)
#將chain都加入到MultiPromptChain()中
chain = MultiPromptChain(
router_chain=router_chain,
destination_chains=destination_chains,
default_chain=default_chain,
verbose=False,
)
#輸入提供到整個chain中
output = chain.run(input=input_text)
#確認輸出是否為語言種類列舉。若是,將利用其中包含的語言代碼重新定義lang1和lang2
if re.match(r'^[a-zA-Z]{2}(?:, [a-zA-Z]{2})*$', output):
lang_list = output.split(", ")
lang1 = lang_list[0]
lang2 = lang_list[1]
return output
```
## 2. 輸入輸出
將以下句子輸入提供給程式進行翻譯。
```python=
input_text = '有沒有可能天空下起血雨?'
print(translator(input_text))
```
:::success
\> Entering new MultiPromptChain chain...
None: {'input': '有沒有可能天空下起血雨?'}
\> Finished chain.
有沒有可能天空下起血雨?
Is it possible for blood rain to fall from the sky?
:::
上面輸出結果中的None,表示程式使用了默認的chain。
```python=
input_text = "今天是美好的星期五。"
print(translator(input_text))
```
:::success
\> Entering new MultiPromptChain chain...
None: {'input': '今天是美好的星期五。'}
\> Finished chain.
Today is a wonderful Friday.
:::
上面輸出結果中的None,表示程式使用了默認的chain。
```python=
input_text = "切換翻譯語言到中文和日文"
print(translator(input_text))
```
:::success
\> Entering new MultiPromptChain chain...
language_choice: {'input': '切換翻譯語言到中文和日文'}
\> Finished chain.
zh, ja
:::
上面輸出結果中的language_choice,表示程式使用了帶有language_choice這個prompt的chain。
輸出為『zh, ja』,表示之後的翻譯語言將使用中文和日文。
___________________
將多個句子供給程式進行翻譯。
為了讓畫面更簡潔,此處已將MultiPromptChain()的verbose參數設為False,僅顯示最終的輸出結果。
```python=
input_list = [
"Switch translation language to Chinese and English",
"你是一位非常優秀的數學家。 你很擅長回答數學問題。",
"有沒有一種可能,是所有人都活在一個虛擬世界當中?",
"切換翻譯語言到中文和日文",
"你都被打到流血了!",
"有沒有可能天空下起血雨?",
"今天是美好的星期五。",
"今天是美好的星期五,下班後去吃點好料。",
"切換翻譯語言,中文和英文",
"Tell me, do you bleed?",
"Please use the latest version of Python",
]
for n in input_list:
print('-'*40)
print('輸入: ', n)
print('輸出: ', translator(n))
```
:::success
\----------------------------------------
輸入: Switch translation language to Chinese and English
輸出: zh, en
\----------------------------------------
輸入: 你是一位非常優秀的數學家。 你很擅長回答數學問題。
輸出: You are a very talented mathematician. You are excellent at solving math problems.
\----------------------------------------
輸入: 有沒有一種可能,是所有人都活在一個虛擬世界當中?
輸出: Is it possible for everyone to live in a virtual world?
\----------------------------------------
輸入: 切換翻譯語言到中文和日文
輸出: zh, ja
\----------------------------------------
輸入: 你都被打到流血了!
輸出: あなたは血を流している!
\----------------------------------------
輸入: 有沒有可能天空下起血雨?
輸出: 血雨が降る可能性はありますか?
\----------------------------------------
輸入: 今天是美好的星期五。
輸出: 今天は素敵な金曜日です。
\----------------------------------------
輸入: 今天是美好的星期五,下班後去吃點好料。
輸出: 今天は素敵な金曜日です、仕事の後に美味しいものを食べに行きましょう。
\----------------------------------------
輸入: 切換翻譯語言,中文和英文
輸出: zh, en
\----------------------------------------
輸入: Tell me, do you bleed?
輸出: 告訴我,你流血嗎?
\----------------------------------------
輸入: Please use the latest version of Python
輸出: 請使用最新版本的Python
:::
關於切換語言的方法,提供以下幾種輸入也能成功切換語言。
```python=
input_list = [
'我想要英翻中',
'我的英文不好,幫我把英文句子成中文',
'今天會使用到的語言有中文和日文',
'我朋友是說義大利語,而我是使用中文',
]
for n in input_list:
print('-'*40)
print(translator(n))
```
:::success
\----------------------------------------
en, zh
\----------------------------------------
en, zh
\----------------------------------------
zh, ja
\----------------------------------------
zh, it
:::