diff --git a/src/translation_agent_Agently/README.md b/src/translation_agent_Agently/README.md new file mode 100644 index 0000000..300c448 --- /dev/null +++ b/src/translation_agent_Agently/README.md @@ -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 git@github.com:Maplemx/translation-agent.git +cd translation-agent/src/translation-agent-Agently +pip install -r requirements.txt +python app.py +``` \ No newline at end of file diff --git a/src/translation_agent_Agently/app.py b/src/translation_agent_Agently/app.py new file mode 100644 index 0000000..ba793ef --- /dev/null +++ b/src/translation_agent_Agently/app.py @@ -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, +}) \ No newline at end of file diff --git a/src/translation_agent_Agently/prompt_yamls/improve_translation.yaml b/src/translation_agent_Agently/prompt_yamls/improve_translation.yaml new file mode 100644 index 0000000..801499a --- /dev/null +++ b/src/translation_agent_Agently/prompt_yamls/improve_translation.yaml @@ -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. \ No newline at end of file diff --git a/src/translation_agent_Agently/prompt_yamls/initial_translation.yaml b/src/translation_agent_Agently/prompt_yamls/initial_translation.yaml new file mode 100644 index 0000000..71cee2e --- /dev/null +++ b/src/translation_agent_Agently/prompt_yamls/initial_translation.yaml @@ -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. \ No newline at end of file diff --git a/src/translation_agent_Agently/prompt_yamls/reflect_on_translation.yaml b/src/translation_agent_Agently/prompt_yamls/reflect_on_translation.yaml new file mode 100644 index 0000000..e509e0e --- /dev/null +++ b/src/translation_agent_Agently/prompt_yamls/reflect_on_translation.yaml @@ -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. diff --git a/src/translation_agent_Agently/requirements.txt b/src/translation_agent_Agently/requirements.txt new file mode 100644 index 0000000..728a02c --- /dev/null +++ b/src/translation_agent_Agently/requirements.txt @@ -0,0 +1 @@ +Agently==3.3.0.0 \ No newline at end of file diff --git a/src/translation_agent_Agently/result_example.txt b/src/translation_agent_Agently/result_example.txt new file mode 100644 index 0000000..33207ba --- /dev/null +++ b/src/translation_agent_Agently/result_example.txt @@ -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*** diff --git a/src/translation_agent_Agently/workflow.py b/src/translation_agent_Agently/workflow.py new file mode 100644 index 0000000..a63a4cb --- /dev/null +++ b/src/translation_agent_Agently/workflow.py @@ -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"]) +) \ No newline at end of file