diff --git a/README.md b/README.md
index 725c3f2..ba04a77 100644
--- a/README.md
+++ b/README.md
@@ -124,6 +124,27 @@ This mask is used internally by "Merge Image Tile", but it can also be useful as
## Miscellaneous Nodes
+
+### Translate Text
+
+Node which translates a string into English. The language to translate from is indicated with a
+_language directive_ of the form `lang:xx` where xx is a 2-letter language code. Multiple
+directives are allowed and change language for any text that comes after, until the next
+directive. `lang:en` (the default) passes through text fragments untouched. Useful
+for keywords, tags and such.
+
+Examples:
+| Input | Output |
+|:-|:-|
+| lang:de eine modische handtasche aus grünem kunstleder | a fashionable handbag made of green suede |
+| origami paperwork, lang:zh 狐狸和鹤, lang:en mountain view | origami paperwork, Fox and crane, mountain view |
+
+Translation happens entirely local, powered by [argosopentech/argos-translate](https://github.com/argosopentech/argos-translate):
+* Install with `pip install argostranslate` or `pip install -r requirements.txt`
+* Models are automatically downloaded on first use.
+
+There is also a [translation API](#api-translation) for immediate feedback in tool UI.
+
### NSFW Filter
Checks images for NSFW content using [Safety-Checker](https://huggingface.co/CompVis/stable-diffusion-safety-checker). Images which don't pass the check are blurred to
@@ -134,12 +155,12 @@ Inputs: image and sensitivity (0.5 for explicit content only, 0.7+ to include pa
**Important:** the filter isn't perfect. Some explicit content may slip through.
-## API for model inspection
-
-There are various types of models that can be loaded as checkpoint, LoRA, ControlNet, etc. which cannot be used interchangeably. The following API helps to categorize and filter them.
+## API extensions
### /api/etn/model_info
+There are various types of models that can be loaded as checkpoint, LoRA, ControlNet, etc. which cannot be used interchangeably. This endpoint helps to categorize and filter them.
+
Lists available models with additional classification info.
* Paramters: _none_
* Output: list of model files
@@ -157,6 +178,16 @@ Lists available models with additional classification info.
_Note: currently only supports checkpoints. May add other models in the future._
+
+### /api/etn/translate/{lang}/{text}
+
+Translates `text` into English. `lang` is a 2-letter code indicating the language to translate
+from. `text` may also contain _language directives_ to only translate some fragments.
+See the [node documentation](#node-translate) for details.
+
+* Output: JSON string
+* Example: `/api/etn/translate/de/eine%20modische%20Handtasche` -> `"a fashionable handbag"`
+
## Installation
Download the repository and unpack into the `custom_nodes` folder in the ComfyUI installation directory.
diff --git a/api.py b/api.py
index f5b947d..2f57896 100644
--- a/api.py
+++ b/api.py
@@ -111,7 +111,7 @@ if _server := getattr(server.PromptServer, "instance", None):
try:
language = request.match_info.get("lang", "en")
text = request.match_info.get("text", "")
- result = translate(text, language)
+ result = translate(f"lang:{language} {text}")
return web.json_response(result)
except Exception as e:
return web.json_response(dict(error=str(e)), status=500)
diff --git a/pyproject.toml b/pyproject.toml
index 704de65..f64ba63 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[project]
name = "comfyui-tooling-nodes"
description = "Provides nodes and server API extensions geared towards using ComfyUI as a backend for external tools."
-version = "1.2.0"
+version = "1.3.0"
license = "LICENSE"
[project.urls]
diff --git a/translation.py b/translation.py
index 8787dfb..2e6eea9 100644
--- a/translation.py
+++ b/translation.py
@@ -23,7 +23,7 @@ def available_languages():
return [("NOT INSTALLED", "NOT INSTALLED")]
-def translate(text: str, language: str):
+def translate_chunk(text: str, language: str):
if text.strip() == "":
return text
@@ -55,6 +55,11 @@ def translate(text: str, language: str):
)
+def translate(text: str):
+ chunks = Chunk.parse(text)
+ return " ".join(translate_chunk(c.text, c.lang) for c in chunks)
+
+
class Translate:
@staticmethod
def INPUT_TYPES():
@@ -65,9 +70,7 @@ class Translate:
FUNCTION = "translate"
def translate(self, text: str):
- chunks = Chunk.parse(text)
- translated = " ".join(translate(c.text, c.lang) for c in chunks)
- return (translated,)
+ return (translate(text),)
_lang_regex = re.compile(r"(lang:\w\w)")