Die TaskBridge ist eine Webanwendung für verteilte Aufgabenverarbeitung. Clients können Aufgaben registrieren, die anschließend von Workern verarbeitet werden.
Nachdem ein Worker eine Aufgabe abgearbeitet hat, berichtet dieser die Ergebnisse an die TaskBridge, wo sich anschließend der auftraggebende Client das Ergebnis abholen kann.
Es wird derzeit kein HTTPS unterstützt, da die existierenden Worker mit den selbst signierten Zertifikaten nicht klar kommen.
# Aufgaben und Statistiken auf Festplatte unter ./data/tasks.json speichern, diese bleiben über einen Neustart hinweg erhalten
docker run -d --name taskbridge-ondisk -e HTTPSPORT=3443 -e PORT=3000 -e PERSISTENCE=ONDISK -p 42443:3443 -p 42000:3000 hilderonny2024/taskbridge:3.1.0
# Aufgaben und Statistiken nur im Speicher halten, erhöhte Performance durch fehlende Festplattenzugriffe
docker run -d --name taskbridge-inmemory -e HTTPSPORT=3443 -e PORT=3000 -e PERSISTENCE=INMEMORY -p 42443:3443 -p 42000:3000 hilderonny2024/taskbridge:3.1.0Die TaskBridge (sowohl Weboberfläche als auch API) ist anschließend an den Ports 42000 (HTTP) und 42443 (HTTPS) erreichbar.
- NodeJS installieren, siehe https://nodejs.org/en/download/
- Datei
/etc/systemd/system/taskbridge.servicemit folgendem Inhalt erstellen npm ciausführen
[Unit]
Description=taskbridge
[Service]
ExecStart=/usr/bin/node /github/hilderonny/taskbridge/server.mjs
WorkingDirectory=/github/hilderonny/taskbridge
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=taskbridge
Environment="PORT=42000"
Environment="PERSISTENCE=ONDISK"
[Install]
WantedBy=multi-user.target
- Hintergrunddienst registrieren und starten
sudo systemctl enable taskbridge
sudo systemctl start taskbridgeDie TaskBridge bringt eine Weboberfläche mit, welche Standardaufgaben erstellen und die Verarbeitung überwachen lässt.
Bilder nach Synsets retained from ILSVRC2011 klassifizieren
Dateien mit ClamAV nach Viren untersuchen
Derzeit existieren verschiedene Clients als eigenständige Anwendungen oder als Plugins für andere Applikationen, die mit der TaskBridge kompatibel sind.
- Python Task für IPED
- Ruby plugin für NUIX
- X-Tension für X-Ways
| Aufgabenart | Worker |
|---|---|
analyzetext |
taskworker-analyzetext |
classifyimage |
taskworker-classifyimage |
scanforvirus |
taskworker-scanforvirus |
transcribe |
taskworker-transcribe |
translate |
taskworker-translate |
| Client | Aufgabenarten |
|---|---|
| IPED audio translate task | transcribe, translate |
| IPED image classification task | classifyimage |
| IPED virus scan task | scanforvirus |
| NUIX audio translate plugin | transcribe, translate |
| X-Ways audio translate X-Tension | transcribe, translate |
- Stamm-URL für alle APIs ist
/api/, zum Beispielhttp://127.0.0.1:42000/api/. - taskbridge.js enthält Hilfsfunktionen zur einfachen Verwendung der API.
getTaskList()
[
{
"id": "36b8f84d-df4e-4d49-b662-bcde71a8764f",
"type": "translate",
"status": "inprogress",
"progress": 50,
"createdat": 1717394497292,
"startedat": 1717395321826,
"completedat": 1717395345196
},
...
]addTask(type, data, file, requirements)
Der Request muss als MultiPartForm gesendet werden und muss ein Feld json mit folgendem Inhalt enthalten.
{
"type": "translate",
"requirements": {
"sourcelanguage": "en",
"targetlanguage": "de"
},
"data": "Hello World"
}Falls die Daten zu groß sind, können sie anstelle des data Attributes auch direkt im MultiPartForm als Eigenschaft file als Datei angehangen werden.
Das Attribut requirements ist optional und gibt an, welche Fähigkeiten (abilities) ein Worker haben muss, um eine solche Aufgabe zugewiesen zu bekommen.
{
"id": "36b8f84d-df4e-4d49-b662-bcde71a8764f"
}{
"type": "translate",
"worker": "Name of worker",
"abilities": {
"sourcelanguage": "en",
"targetlanguage": "de"
}
}abilities ist optional gibt die Fähigkeiten des Workers an. Wenn eine Aufgabe requirements hat, bekommt der Worker nur dann die Aufgabe, wenn seine abilities die requirements der Aufgabe umfassen.
{
"id": "36b8f84d-df4e-4d49-b662-bcde71a8764f",
"data": "Hello World",
"file": "file_id"
}{
"progress": "50"
}{
"result": "Hallo Welt"
}Antwort ist stets HTTP-Status 200.
Aufgabe wird auf Status "Offen" gesetzt und kann erneut bearbeitet werden.
{
"status": "inprogress",
"progress": 50
}{
"result": "Hallo Welt"
}{
"id": "36b8f84d-df4e-4d49-b662-bcde71a8764f",
"type": "translate",
"file": "nqzv74n3vq7tnz45378qoztn47583qnbzt45",
"worker": "ROG",
"status": "inprogress",
"progress": 50,
"createdat": 1717394497292,
"startedat": 1717395321826,
"completedat": 1717395345196,
"requirements": { ... },
"data": { ... },
"result": { ... }
}Das Ergebnis ist ein Binär-Stream der Datei.
{
"transcribe": 1234,
"translate": 2345,
...
}[
{
"name": "RH-WORKBOOK",
"type": "translate",
"status": "idle",
"taskid": "36b8f84d-df4e-4d49-b662-bcde71a8764f",
"lastping": 292
},
...
]{
"Worker-1": {
"transcribe": 12345,
"translate": 2345
},
"Worker-2": {
"transcribe": 345,
"translate": 34
}
}task = {
id: "36b8f84d-df4e-4d49-b662-bcde71a8764f",
type: "translate",
file: "nqzv74n3vq7tnz45378qoztn47583qnbzt45",
worker: "ROG",
status: "open",
progress: 50,
createdat: 1717394497292,
startedat: 1717395321826,
completedat: 1717395345196,
data: { ... },
result: { ... }
}| Attribut | Beschreibung |
|---|---|
id |
Eindeutige ID der Aufgabe |
type |
Aufgabenart. Wird von Clients und Workern definiert. Beispiele für Standardaufgaben: translate, transcribe, classifyimage, scanforvirus |
file |
Name der Datei, falls die Aufgabe eine Datei angehangen hat |
worker |
Name des Worker, der gerade die Aufgabe bearbeitet oder bearbeitet hat |
status |
Status der Aufgabe. Kann offen, inbearbeitung oder abgeschlossen |
progress |
Bearbeitungsstatus als Zahl zwischen 0 und 100 |
createdat |
Zeitpunkt der Erstellung der Aufgabe in Millisekunden seit 01.01.1970 00:00 |
startedat |
Zeitpunkt, zu dem die Aufgabe von einem Worker zur Bearbeitung abgeholt wurde in Millisekunden seit 01.01.1970 00:00 |
completedat |
Zeitpunkt, zu dem die Aufgabe von einem Worker als "Abgeschlossen" markiert wurde in Millisekunden seit 01.01.1970 00:00 |
data |
Daten der Aufgabe, die Worker anzuarbeiten haben |
result |
Ergebnis der Abarbeitung |
Die zu transkribierende Datei muss als multipart/form-data gesendet werden.
------WebKitFormBoundaryEbHBu6sLT8O0bwlK
Content-Disposition: form-data; name="file"; filename="en.wav"
------WebKitFormBoundaryEbHBu6sLT8O0bwlK
Content-Disposition: form-data; name="json"
{"type":"transcribe"}
------WebKitFormBoundaryEbHBu6sLT8O0bwlK--
{
"result" : {
"language" : "en",
"texts" : [
{
"start" : 0.0,
"end" : 1.0,
"text" : "Line 1"
},
{
"start" : 1.0,
"end" : 2.0,
"text" : "Line 2"
}
],
"device" : "cuda",
"duration" : 12,
"repository" : "https://github.com/hilderonny/taskworker-transcribe",
"version" : "1.1.0",
"library" : "fasterwhisper-0.8.15",
"model" : "large-v2"
}
}| Attribut | Beschreibung |
|---|---|
language |
Anhand der ersten 10 Sekunden erkannte Sprache |
texts |
Liste von Texten. Üblicherweise in Sätze aufgeteilt |
texts.start |
Sekunde, zu der der Text in der Mediendatei beginnt |
texts.end |
Senkunde, an welcher der Text endet |
texts.text |
Text |
device |
cuda, wenn die Transkription auf einer Grafikkarte erfolgte, andernfalls cpu |
duration |
Benötigte Dauer der gesamten Transkription |
repository |
Herkunft des Workers |
version |
Version des Workers |
library |
Bibliothek, mit welcher die Transkription erfolgte |
model |
KI-Modell, welches für die Transkription verwendet wurde |
------WebKitFormBoundaryd3cBH0ciOvHMpqq1
Content-Disposition: form-data; name="json"
{"type":"translate","data":{"targetlanguage":"de","texts":["Hello world!","","Wer bist Du?"]}}
------WebKitFormBoundaryd3cBH0ciOvHMpqq1--
Der json Teil beinhaltet die zu übersetzenden Texte, file wird nicht verwendet.
{
"type": "translate",
"data": {
"sourcelanguage": "en",
"targetlanguage": "de",
"texts": [
"Text of first line in english",
"Текст второй строки на русском языке",
"النص الثالث باللغة العربية"
]
}
}| Attribut | Beschreibung |
|---|---|
type |
Immer transcribe |
data.sourcelanguage |
Optionale Quellsprache für alle Texte. Wenn diese Angabe fehlt, wird versucht, die Sprache anhand des Textes für jeden text separat zu ermitteln |
data.targetlanguage |
Zielsprache |
data.texts |
Liste von Texten. Die Texte sollten in sich geschlossene Kontexte und nicht zu groß sein, z.B. Sätze oder Absätze. |
{
"result" : {
"texts" : [
{
"sourcelanguage" : "en",
"text" : "Text der ersten Zeile auf Englisch"
},
{
"sourcelanguage" : "ru",
"text" : "Text der zweiten Zeile auf Russisch"
},
{
"sourcelanguage" : "ar",
"text" : "Text der dritten Zeile auf Arabisch"
}
],
"device" : "cuda",
"duration" : 1.6,
"repository" : "https://github.com/hilderonny/taskworker-translate",
"version" : "1.3.0",
"library": "transformers-4.44.2",
"model": "facebook/m2m100_1.2B"
}
}| Attribut | Beschreibung |
|---|---|
texts |
Liste aller übersetzten Texte |
texts.sourcelanguage |
Im Text erkannte Quellsprache, falls nicht vorgegeben |
texts.text |
Übersetzter Text |
device |
cuda, wenn die Übersetzung auf einer Grafikkarte erfolgte, andernfalls cpu |
duration |
Benötigte Dauer der gesamten Übersetzung |
repository |
Herkunft des Workers |
version |
Version des Workers |
library |
Bibliothek, mit welcher die Übersetzung erfolgte |
model |
KI-Modell, welches für die Übersetzung verwendet wurde |
Die Klassifizierung erfolgt nach ILSVRC2011.
------WebKitFormBoundaryBa8ASYFEK2ewHAcI
Content-Disposition: form-data; name="file"; filename="Angry cat.jpeg"
------WebKitFormBoundaryBa8ASYFEK2ewHAcI
Content-Disposition: form-data; name="json"
{"type":"classifyimage","data":{"targetlanguage":"de","numberofpredictions":"10"}}
------WebKitFormBoundaryBa8ASYFEK2ewHAcI--
Der file Block muss das zu klassifizierende Bild enthalten
Der json Block muss folgende Angaben enthalten
{
"type": "classifyimage",
"data": {
"numberofpredictions": 10,
"targetlanguage": "de"
}
}| Attribut | Beschreibung |
|---|---|
type |
Immer classifyimage |
data.numberofpredictions |
Anzahl der Vermutungen |
data.targetlanguage |
Zielsprache der Klassifizierungen. Kann en oder de sein |
{
"result" : {
"predictions": [
{
"class": "n02123394",
"name": "Perserkatze",
"probability": 0.8419579267501831
},
{
"class": "n02328150",
"name": "Angorakatze",
"probability": 0.025817258283495903
},
{
"class": "n02124075",
"name": "Aegyptische Katze",
"probability": 0.0048589943908154964
}
],
"duration" : 1.6,
"repository" : "https://github.com/hilderonny/taskworker-imageclassifier",
"version": "1.0.0",
"library": "tensorflow-2.17.0",
"model": "MobileNetV3Large"
}
}| Attribut | Beschreibung |
|---|---|
predictions |
Liste von Klassifizierungen, nach Wahrscheinlichkeit sortiert |
predictions.class |
Klasse nach ILSVRC2011 |
predictions.name |
Name der Klasse in vorgegebener Sprache |
predictions.probability |
Wahrscheinlichkeit zwischen 0.0 (0%) und 1.0 (100%) |
duration |
Benötigte Dauer der gesamten Klassifizierung |
repository |
Herkunft des Workers |
version |
Version des Workers |
library |
Bibliothek, mit welcher die Klassifizierung erfolgte |
model |
KI-Modell, welches für die Klassifizierung verwendet wurde |
------WebKitFormBoundaryJA4SMm9qU1EOlbHO
Content-Disposition: form-data; name="file"; filename="mimikatz.exe"
------WebKitFormBoundaryJA4SMm9qU1EOlbHO
Content-Disposition: form-data; name="json"
{"type":"scanforvirus"}
------WebKitFormBoundaryJA4SMm9qU1EOlbHO--
Im file Block muss die zu scannende Datei enthalten sein.
{
"result" : {
"status": "FOUND",
"detection": "Win.Dropper.Mimikatz-9778171-1",
"duration": 0.018547,
"repository": "https://github.com/hilderonny/taskworker-scanforvirus",
"version": "1.0.0",
"library": "clamd-1.0.2"
}
}| Attribut | Beschreibung |
|---|---|
status |
Scanergebnis. OK, wenn nichts gefunden wurde, FOUND, wenn ein Virus entdeckt wurde |
detection |
Wenn ein Virus gefunden wurde, wird hierin der Name des Virus gemeldet |
duration |
Benötigte Dauer des gesamten Scanvorgangs |
repository |
Herkunft des Workers |
version |
Version des Workers |
library |
Bibliothek, mit welcher der Scan erfolgte |
------WebKitFormBoundaryd3cBH0ciOvHMpqq1
Content-Disposition: form-data; name="json"
{"type":"analyzetext","data":{"messages": [{"role": "user","content": "why is the sky blue?"},{"role": "assistant","content": "due to rayleigh scattering."},{"role": "user","content": "how is that different than mie scattering?"}]}}
------WebKitFormBoundaryd3cBH0ciOvHMpqq1--
Der json Teil enthält die gesamte Chat-Historie und endet üblicherweise mit einer Benutzerfrage.
{
"type": "analyzetext",
"data": {
"messages": [
{
"role": "user",
"content": "why is the sky blue?"
},
{
"role": "assistant",
"content": "due to rayleigh scattering."
},
{
"role": "user",
"content": "how is that different than mie scattering?"
}
]
}
}| Attribut | Beschreibung |
|---|---|
type |
Immer analyzetext |
data.messages |
Liste von Chatnachrichten |
data.messages.role |
Rolle des CHatteilnehmers. user ist der Fragensteller (Benutzer), assistant ist das LLM, welches die Fragen beantwortet |
data.messages.content |
Inhalt der Nachricht |
{
"result" : {
"messages": [
{
"role": "user",
"content": "why is the sky blue?"
},
{
"role": "assistant",
"content": "due to rayleigh scattering."
},
{
"role": "user",
"content": "how is that different than mie scattering?"
},
{
"role": "assistant",
"content": "mie scattering occurs when light interacts with larger particles in the air."
}
],
"duration" : 1.6,
"repository" : "https://github.com/hilderonny/taskworker-analyzetext",
"version" : "1.0.0",
"library": "Ollama 0.4",
"model": "llama3.2"
}
}| Attribut | Beschreibung |
|---|---|
messages |
Liste von Chatnachrichten |
messages.role |
Rolle des CHatteilnehmers. user ist der Fragensteller (Benutzer), assistant ist das LLM, welches die Fragen beantwortet |
messages.content |
Inhalt der Nachricht |
duration |
Benötigte Dauer der gesamten Verarbeitung |
repository |
Herkunft des Workers |
version |
Version des Workers |
library |
Bibliothek, mit welcher die Analyse erfolgte |
model |
KI-Modell, welches für den Chat verwendet wurde |
- Visual Studio Code einrichten
- Repository mit GIT klonen
- NodeJS installieren
npm ci
Zum lokalen Testen existieren für Visual Studio Code die Startprofile Mit Persistenz (speichert die Aufgaben über Neustarts hinweg auf Festplatte) und In Memory (Aufgaben werden nur im Speicher gehalten, kein Festplattenzugriff).
docker login
docker build -t hilderonny2024/taskbridge:3.1.0 .
docker push hilderonny2024/taskbridge:3.1.0









