Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a replication of one chunk translation workflow using Agently development framework #13

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/translation_agent_Agently/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# INSTRUCTION

This dir `translation_agent_Agently` is a replication of one chunk translation workflow using [Agently development framework](https://github.com/Maplemx/Agently) with some extra features:

- You can switch models easily by changing the settings in `./app.py` to test the workflow
- Clearly expression of workflow using Agently Workflow in `./workflow.py`
- You can edit prompt yaml files in `./prompt_yamls` to optimize prompt instructions without coding, these prompt yaml files will be loaded into model request when the workflow start
- Add a command line user input interface (enter 3 times to ensure programe know source text input is over)

# HOW TO RUN

```shell
git clone [email protected]:Maplemx/translation-agent.git
cd translation-agent/src/translation-agent-Agently
pip install -r requirements.txt
python app.py
```
16 changes: 16 additions & 0 deletions src/translation_agent_Agently/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Agently
from workflow import translation_workflow

# Choose model you like and set settings according:
# http://agently.tech/features/model_request.html
agent_factory = (
Agently.AgentFactory()
.set_settings("current_model", "OAIClient")
.set_settings("model.OAIClient.url", "https://api.deepseek.com/")
.set_settings("model.OAIClient.auth", { "api_key": "" })
.set_settings("model.OAIClient.options", { "model": "deepseek-chat" })
)

translation_workflow.start({
"agent_factory": agent_factory,
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
input:
source_text: ${source_text}
initial_translation: ${initial_translation}
expert_suggestions: ${reflection}
instruct: |
Your task is to carefully read, then edit, a translation from ${source_language} to ${target_language}, taking into account a list of expert suggestions and constructive criticisms.

Please take into account the expert suggestions when editing the translation. Edit the translation by ensuring:

(i) accuracy (by correcting errors of addition, mistranslation, omission, or untranslated text),
(ii) fluency (by applying ${target_language} grammar, spelling and punctuation rules and ensuring there are no unnecessary repetitions),
(iii) style (by ensuring the translations reflect the style of the source text)
(iv) terminology (inappropriate for context, inconsistent use), or
(v) other errors.

Output only the new translation and nothing else.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set_role: You are an expert linguist, specializing in translation from ${source_language} to ${target_language}.
input:
source_text: ${source_text}
instruct: This is an ${source_language} to ${target_language} translation, please provide the ${target_language} translation for {input.source_text}.Do not provide any explanations or text apart from the translation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
input:
source_text: ${source_text}
initial_translation: ${initial_translation}
instruct:
- Your task is to carefully read {input.source_text} and {input.initial_translation} from ${source_language} to ${target_language}, and then give constructive criticism and helpful suggestions to improve the translation.
- |
When writing suggestions, pay attention to whether there are ways to improve the translation's
(i) accuracy (by correcting errors of addition, mistranslation, omission, or untranslated text),
(ii) fluency (by applying {target_language} grammar, spelling and punctuation rules, and ensuring there are no unnecessary repetitions),
(iii) style (by ensuring the translations reflect the style of the source text and takes into account any cultural context),
(iv) terminology (by ensuring terminology use is consistent and reflects the source text domain; and by only ensuring you use equivalent idioms {target_language}).

Write a list of specific, helpful and constructive suggestions for improving the translation.
Each suggestion should address one specific part of the translation.
Output only the suggestions and nothing else.
1 change: 1 addition & 0 deletions src/translation_agent_Agently/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Agently==3.3.0.0
23 changes: 23 additions & 0 deletions src/translation_agent_Agently/result_example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[Source Language]: English
[Target Language]: Chinese
[Country](Optional):
[Source Text]:
This is not mature software, and is the result of Andrew playing around with translations on weekends the past few months, plus collaborators (Joaquin Dominguez, Nedelina Teneva, John Santerre) helping refactor the code.

According to our evaluations using BLEU score on traditional translation datasets, this workflow is sometimes competitive with, but also sometimes worse than, leading commercial offerings. However, we’ve also occasionally gotten fantastic results (superior to commercial offerings) with this approach. We think this is just a starting point for agentic translations, and that this is a promising direction for translation, with significant headroom for further improvement, which is why we’re releasing this demonstration to encourage more discussion, experimentation, research and open-source contributions.



[Initial Translation]:
这不是成熟的软件,而是安德鲁在过去几个月的周末里玩转翻译的成果,加上合作者(华金·多明格斯、内德莉娜·特内娃、约翰·桑特雷)帮助重构代码。根据我们使用传统翻译数据集上的BLEU分数进行的评估,这种工作流程有时能与领先的商业产品竞争,但有时也表现得更差。然而,我们也偶尔获得了出色的结果(优于商业产品)。我们认为这只是自主翻译的起点,这是一个有前景的翻译方向,有巨大的改进空间,这也是我们发布这个演示以鼓励更多讨论、实验、研究和开源贡献的原因。
[Reflection]:
1. 将“这不是成熟的软件,而是安德鲁在过去几个月的周末里玩转翻译的成果”中的“玩转翻译”改为“尝试翻译”,以更准确地表达原文的含义,即安德鲁是在尝试而非游戏般地进行翻译。
2. 在“加上合作者(华金·多明格斯、内德莉娜·特内娃、约翰·桑特雷)帮助重构代码”中,建议将“帮助重构代码”改为“协助重构代码”,使表达更加流畅和正式。
3. “根据我们使用传统翻译数据集上的BLEU分数进行的评估”中,“传统翻译数据集”可能需要进一步明确其含义,以避免歧义。
4. “这种工作流程有时能与领先的商业产品竞争,但有时也表现得更差”中,建议将“表现得更差”改为“表现不如人意”,以避免直接贬低自己的工作,同时保持中性的表达。
5. “然而,我们也偶尔获得了出色的结果(优于商业产品)”中,建议将“偶尔获得了出色的结果”改为“偶尔也取得了优于商业产品的出色结果”,以增强句子的连贯性和强调效果。
6. “我们认为这只是自主翻译的起点,这是一个有前景的翻译方向,有巨大的改进空间”中,建议将“起点”改为“初步尝试”,以更准确地描述当前阶段的工作性质。
7. 在“这也是我们发布这个演示以鼓励更多讨论、实验、研究和开源贡献的原因”中,建议将“发布这个演示”改为“发布此演示版本”,使表达更加清晰和专业。
[Final Translation]:
这不是成熟的软件,而是安德鲁在过去几个月的周末里尝试翻译的成果,加上合作者(华金·多明格斯、内德莉娜·特内娃、约翰·桑特雷)协助重构代码。根据我们使用传统翻译数据集上的BLEU分数进行的评估,这种工作流程有时能与领先的商业产品竞争,但有时也表现不如人意。然而,我们也偶尔也取得了优于商业产品的出色结果。我们认为这只是自主翻译的初步尝试,这是一个有前景的翻译方向,有巨大的改进空间,这也是我们发布此演示版本以鼓励更多讨论、实验、研究和开源贡献的原因。
***Repl Closed***
155 changes: 155 additions & 0 deletions src/translation_agent_Agently/workflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import Agently

translation_workflow = Agently.Workflow()

@translation_workflow.chunk()
def user_input(inputs, storage):
# get agent_factory from start data and put it into storage
storage.set("agent_factory", inputs["default"]["agent_factory"])
# get translation settings from user input
source_language = input("[Source Language]: ")
target_language = input("[Target Language]: ")
country = input("[Country](Optional): ")
source_text = []
# get multi lines text from user input
print("[Source Text]:")
enter_count = 0
while True:
line = input()
if line:
source_text.append(line)
enter_count = 0
elif enter_count >= 2:
break
else:
enter_count += 1
source_text = "\n".join(source_text)
# pass all user input data to next chunk
return {
"source_language": source_language,
"target_language": target_language,
"country": country,
"source_text": source_text,
}

@translation_workflow.chunk()
def initial_translation(inputs, storage):
# get data from user_input chunk
source_language = inputs["default"]["source_language"]
target_language = inputs["default"]["target_language"]
country = inputs["default"]["country"]
source_text = inputs["default"]["source_text"]

# create translation agent
agent_factory = storage.get("agent_factory")
translation_agent = agent_factory.create_agent()
# set role (system-prompt-like)
translation_agent.set_role(f"You are an expert linguist, specializing in translation from {source_language} to {target_language}.")
# load commands from P-YAML to agent and get initial translation result
print("[Initial Translation]:")
initial_translation = (
translation_agent
.load_yaml_prompt(
path = "./prompt_yamls/initial_translation.yaml",
variables = {
"source_language": source_language,
"target_language": target_language,
"source_text": source_text,
}
)
# Streaming Output
.on_delta(lambda data: print(data, end=""))
.start()
)

# save translation_agent to storage because it will be reused in improve_translation chunk
storage.set("translation_agent", translation_agent)

# save other data to storage because they will be reused in next chunks
storage.set("source_language", source_language)
storage.set("target_language", target_language)
storage.set("country", country)
storage.set("initial_translation", initial_translation)
return

@translation_workflow.chunk()
def reflect_on_translation(inputs, storage):
# get data from storage
source_language = storage.get("source_language")
target_language = storage.get("target_language")
country = storage.get("country")
source_text = storage.get("source_text")
initial_translation = storage.get("initial_translation")

# create another agent because it has different role settings
agent_factory = storage.get("agent_factory")
reflect_on_translation_agent = agent_factory.create_agent()
# set role (system-prompt-like)
reflect_on_translation_agent.set_role(f"You are an expert linguist specializing in translation from {source_language} to {target_language}. You will be provided with a source text and its translation and your goal is to improve the translation.")
# load commands from P-YAML to agent
(
reflect_on_translation_agent
.load_yaml_prompt(
path = "./prompt_yamls/reflect_on_translation.yaml",
variables = {
"source_language": source_language,
"target_language": target_language,
"source_text": source_text,
"initial_translation": initial_translation
}
)
)
# append additional instruction when `country` is not empty
if country and len(country) > 0:
reflect_on_translation_agent.instruct([f"\nThe final style and tone of the translation should match the style of {target_language} colloquially spoken in {country}."])
# give commands of current task and get reflection result
print("\n[Reflection]:")
reflection = (
reflect_on_translation_agent
# Streaming Output
.on_delta(lambda data: print(data, end=""))
.start()
)
# save reflection result to storage
storage.set("reflection", reflection)
return

@translation_workflow.chunk()
def improve_translation(inputs, storage):
# get data from storage
source_language = storage.get("source_language")
target_language = storage.get("target_language")
source_text = storage.get("source_text")
initial_translation = storage.get("initial_translation")
reflection = storage.get("reflection")

# reuse translation agent
translation_agent = storage.get("translation_agent")
# get final translation result
print("\n[Final Translation]:")
final_translation = (
translation_agent
.load_yaml_prompt(
path = "./prompt_yamls/improve_translation.yaml",
variables = {
"source_language": source_language,
"target_language": target_language,
"source_text": source_text,
"initial_translation": initial_translation,
"reflection": reflection,
}
)
# Streaming Output
.on_delta(lambda data: print(data, end=""))
.start()
)
return final_translation

(
translation_workflow.chunks["start"]
.connect_to(translation_workflow.chunks["user_input"])
.connect_to(translation_workflow.chunks["initial_translation"])
.connect_to(translation_workflow.chunks["reflect_on_translation"])
.connect_to(translation_workflow.chunks["improve_translation"])
.connect_to(translation_workflow.chunks["end"])
)