Rakenna täysin automaattinen litterointityönkulku n8n:llä
Useimmat tiimit litteroivat yhä käsin: joku lataa nauhoitteen, vie sen jonnekin, odottaa, lataa SRT-tiedoston, nimeää sen uudelleen ja siirtää oikeaan kansioon. Se toimii hyvin — kunnes sitä tapahtuu neljäkymmentä kertaa viikossa.
Tämä opas korvaa sen ihmisen työnkululla. Heti kun uusi nauhoite saapuu, se litteroidaan, tekstitetään ja toimitetaan — ilman että kukaan seuraa vieressä. Käytämme n8n:ää, koska se toimii missä tahansa, sen voi ajaa omassa infrastruktuurissasi ja se keskustelee minkä tahansa HTTP-rajapinnan kanssa — myös meidän.
Lopuksi sinulla on työnkulku, joka:
- käynnistyy heti kun uusi video- tai äänitiedosto ilmestyy
- lähettää sen Inwistan API:iin litteroitavaksi
- odottaa työn valmistumista arvaamatta etukäteen, kauanko siinä menee
- lataa valmiin SRT-tiedoston
- toimittaa sen sinne, missä tiimisi sitä tarvitsee
Kaikki alla kuvattu toimii julkisen Inwista API v1 -rajapinnan päällä. Ei lisäosia, ei omia koodisolmuja.
Ennen kuin aloitat
Tarvitset kolme asiaa:
- n8n-instanssin — pilvessä tai omalla palvelimella, versio 1.x
- Inwistan API-avaimen — luo se kohdassa Oma työtila → API-avaimet. Se alkaa merkeillä
inw_live_ - Mediaa, johon API pääsee käsiksi — API ottaa vastaan julkisen
https-osoitteen, joten Dropboxissa, Google Drivessa, S3:ssa tai omassa julkaisujärjestelmässäsi olevat tiedostot tarvitsevat jaettavan tai allekirjoitetun linkin
Sana kustannuksista ennen kuin rakennat jotain, joka pyörii valvomatta: litterointi maksaa 4 krediittiä alkavalta mediaminuutilta, ja veloitus tapahtuu kun työ otetaan vastaan. Epäonnistuneet työt hyvitetään automaattisesti. Testaa työnkulku parilla lyhyellä tiedostolla ennen kuin päästät sen koko arkistosi kimppuun.
Vaihe 1: valitse liipaisin
Putki alkaa siitä tapahtumasta, joka tarkoittaa ”nyt on jotain uutta litteroitavaa”. Yleisimmät vaihtoehdot:
- Google Drive Trigger / Dropbox Trigger — valvottu kansio, johon tiimisi pudottaa nauhoitteet
- Webhook — oma julkaisu- tai oppimisjärjestelmäsi kutsuu n8n:ää, kun lataus valmistuu
- Schedule Trigger — kysele RSS-syötettä, podcast-palvelua tai tietokantaa, jossa on käsittelemättömiä rivejä
- Manual Trigger — rakentamiseen ja testaamiseen, ja siitä me aloitamme
Lisää toistaiseksi Manual Trigger. Vaihda se oikeaan, kun muu toimii.
Valitsitpa minkä tahansa: liipaisimen tehtävä on tuottaa yksi ainoa asia — julkisesti saavutettava osoite mediatiedostoon. Tallenna se kenttään nimeltä mediaUrl, niin loppuosa oppaasta vastaa työnkulkuasi.
Vaihe 2: lähetä litterointi
Lisää HTTP Request -solmu nimeltä Submit transcription.
- Menetelmä —
POST - Osoite —
https://api.inwista.ai/v1/transcriptions - Todennus — Generic Credential Type → Header Auth
- Otsakkeen nimi —
Authorization - Otsakkeen arvo —
Bearer inw_live_avaimesi_tahan - Send body — päällä, JSON
Pyynnön runko:
{
"source_url": "{{ $json.mediaUrl }}",
"language": "fi",
"diarization": true,
"metadata": { "source": "n8n", "folder": "{{ $json.folderName }}" }
}
Kolme kenttää, jotka kannattaa ymmärtää:
languageon kieli, jota tiedostossa puhutaan — ei se kieli, jonka haluat ulos. Litterointi lähdekielellä on juuri se, mikä tuottaa tarkat aikakoodit ja siistin tekstin; käännös tulee vasta jälkeenpäin, omana vaiheenaan valmiiseen litterointiin. Jos putkesi käsittelee useita kieliä, johda tämä kenttä liipaisimen kansiosta tai metatiedoista.
diarizationkytkee puhujatunnisteet päälle. Jätä se pois yhden puhujan sisällöstä — se vie käsittelyaikaa, jota et tarvitse.
metadataon sinun. Enintään 1 kt mitä tahansa, palautetaan sellaisenaan jokaisella haulla. Käytä sitä tunnisteisiin, joista omat järjestelmäsi välittävät — kurssin tunniste, asianumero, jakson slug — jotta myöhempien vaiheiden ei tarvitse rakentaa asiayhteyttä uudelleen.
Lisää samalla vielä yksi otsake:
Idempotency-Key—{{ $execution.id }}
Jos n8n yrittää solmua uudelleen verkkokatkon jälkeen, API tunnistaa avaimen ja palauttaa alkuperäisen työn sen sijaan, että aloittaisi — ja veloittaisi — uuden.
Vastaus tulee heti, mukanaan status: "processing" ja id. Litterointi ei ole valmis; se on otettu vastaan.
Vaihe 3: odota valmistumista oikein
Tässä useimmat putket menevät pieleen. Kiinteä ”odota viisi minuuttia” on luennolle liian lyhyt ja ääniviestille tuhlausta. Kysele mieluummin tilaa.
Lisää Wait-solmu (Wait 15s), asetuksena 15 sekuntia.
Lisää HTTP Request -solmu (Check status):
- Menetelmä —
GET - Osoite —
https://api.inwista.ai/v1/transcriptions/{{ $('Submit transcription').item.json.id }} - Todennus — sama otsake kuin aiemmin
Lisää IF-solmu (Is it done?) tällä ehdolla:
{{ $json.status }} equals completed
Kytke false-haara takaisin solmuun Wait 15s. Siinä on silmukkasi: tarkista, odota, tarkista uudelleen, kunnes työ ilmoittaa completed. True-haara jatkaa seuraavaan vaiheeseen.
Vastauksessa on myös progress-luku, joka kertoo putken todellisen tilanteen — jos siis haluat edistymispalkin Slackiin tai omaan näkymääsi, se on jo olemassa.
Kaksi asiaa kannattaa lisätä ennen kuin tämä lähestyy tuotantoa:
- Käsittele virheet. Lisää toinen IF, joka tarkistaa
{{ $json.status }} equals failedja ohjaa käyttämääsi hälytykseen. Epäonnistuneet työt hyvitetään automaattisesti, mutta haluat silti tietää siitä. - Rajaa silmukka. n8n:n silmukkasuojaus auttaa, mutta selkeä yläraja — laskuri, joka luovuttaa vaikkapa 80 kierroksen jälkeen — muuttaa jumiin jääneen työn hälytykseksi eikä ajoksi, joka jauhaa koko yön.
Vaihe 4: hae tekstitykset
Lisää HTTP Request -solmu nimeltä Get SRT:
- Menetelmä —
GET - Osoite —
https://api.inwista.ai/v1/transcriptions/{{ $('Submit transcription').item.json.id }}/captions?format=srt - Response format — File (tai Text, jos haluat sisällön mukaan työnkulkuun)
Päätepiste palauttaa itse tekstitystiedoston, ei JSON-kuorta — solmun tuloste on siis valmis kirjoitettavaksi levylle, liitettäväksi sähköpostiin tai ladattavaksi eteenpäin.
Vaihda format sen mukaan, mitä vastaanottaja tarvitsee:
Muoto — mihin käytetään
srt— videosoittimet, editointiohjelmat, YouTube, useimmat julkaisujärjestelmätvtt— HTML5-<track>, verkkosoittimettxt— hakuindeksit, kielimalliputket, dokumentaatiojson— aikakoodit sanatasolla, puhujatunnisteet, oma esitystapa
Jokainen muoto on vain näkymä samaan valmiiseen työhön. Neljän hakeminen ei maksa mitään ylimääräistä.
Vaihe 5: toimita tulos
Viimeinen solmu on se, mitä ”valmis” tiimillesi tarkoittaa:
- Google Drive / Dropbox / S3 — kirjoita tiedosto lähdevideon viereen
- Slack — julkaise litterointi kanavalle, joka sitä pyysi
- HTTP Request — työnnä se julkaisujärjestelmääsi, oppimisalustallesi tai tekstityskenttään
- Postgres / Airtable / Notion — tallenna
txt-versio haettavana tekstinä
Jos vastaanottajasi on jokin niistä, joihin Inwista integroituu suoraan — Google Drive, OneDrive, SharePoint, Dropbox, Box, YouTube, Vimeo, Wistia ja muut — voit jättää tämän solmun kokonaan pois ja määrittää pilvitoimituksen kohdassa Oma työtila → Integraatiot. Silloin tiedostot saapuvat automaattisesti jokaisesta valmistuneesta työstä, työnkulun kanssa tai ilman.
Seuraava taso: käännä ennen toimitusta
Lisää kaksi solmua ennen toimitusta, niin sama putki tuottaa tekstitykset niin monella kielellä kuin tarvitset.
POST /v1/transcriptions/{id}/translate ja runko:
{ "target_language": "en" }
Se vastaa 202 Accepted — käännös ajetaan valmiiseen litterointiin, joten ajoitukset ovat jo kohdallaan ja vain teksti muuttuu. Kysele GET /v1/transcriptions/{id}/translations/en samaan tapaan kuin kyselit työtä, ja hae sitten:
GET /v1/transcriptions/{id}/captions?format=srt&language=en
Aja tuo läpi kohdekielten listan, ja yhdestä nauhoitteesta syntyy täysi monikielinen tekstityssarja yhdellä ajolla. Huomaa, että kielipyyntö on tiukka: jos pyydät kieltä, jolla ei ole valmista käännöstä, saat selkeän virheen etkä hiljaisuudessa lähdekieltä. Juuri sitä haluat putkessa, joka pyörii valvomatta.
Seuraava taso: lähetystason tekstitykset
Raaka litterointi on sanatarkka. Tekstitys on käsityötä: rivien pituudet, lukunopeus, kohta jossa lause katkeaa kahden ruudun välillä.
POST /v1/transcriptions/{id}/enhance ajaa valmiin litteroinnin juuri sen käsittelyn läpi — tiivistää tekstiä, tasapainottaa rivinvaihdot uudelleen, muotoilee dialogin ja pakottaa lohkojen vähimmäis- ja enimmäiskeston:
{
"settings": {
"maxLinesPerBlock": "2",
"maxCharactersPerLine": 42,
"textCondensation": "smart",
"speakerDialogueFormat": "hyphens",
"gapBetweenBlocks": "broadcasting"
}
}
Se vastaa 202; kysele GET /v1/transcriptions/{id}/enhancements/{enhancementId}, kunnes se on valmis. Sen jälkeen tekstityspäätepisteet tarjoavat automaattisesti parannellun version — toimitussolmuun ei tarvitse koskea.
Arkaluonteiset nauhoitteet
Jos putkesi käsittelee aineistoa, jota et mieluummin haluaisi meidän säilyttävän — potilaskeskusteluja, oikeudellisia nauhoitteita, sisäisiä henkilöstötilaisuuksia — lisää yksi kenttä vaiheen 2 lähetykseen:
{
"source_url": "{{ $json.mediaUrl }}",
"language": "fi",
"retention": "none"
}
Kun retention: "none" on käytössä, lähdemedia poistetaan heti litteroinnin valmistuttua. Litterointi, tekstitykset, käännökset ja myöhemmät parannukset toimivat aivan normaalisti — vain ääni ja video ovat poissa. Lisäksi on store_media: false, joka säilyttää tiedoston käsittelyä varten mutta ei luo toistokopioita.
Ja kun työn säilytysaika päättyy sinun puolellasi, DELETE /v1/transcriptions/{id} poistaa kaiken siihen liittyvän — mediat, litteroinnin, versiot, käännökset — yhdellä kutsulla. Ajastettu n8n-työnkulku, joka poistaa käytäntöäsi vanhemmat työt, on noin neljä solmua, ja se tekee säilytyskäytännöstäsi jotain, jonka voit näyttää sen sijaan että kuvailisit sitä.
Webhookit: vastinpari
Tilan kysely on oikea ohjaustapa yhden n8n-ajon sisällä: se on itsenäinen, ei vaadi julkista osoitetta ja pitää koko putken yhdessä paikassa, jota voit selvittää.
Webhookit ratkaisevat toisen ongelman: valmiin työn saamisen yhdelle keskitetylle vastaanottajalle riippumatta siitä, mistä työ tuli. Nauhoitteet, joita kollegasi lataavat käyttöliittymässä, toisesta järjestelmästä lähetetyt työt, tunteja myöhemmin valmistuvat viennit — kaikki voi päätyä yhteen päätepisteeseen sen sijaan, että jokainen työnkulku hoitaisi omansa. Määritä se kohdassa Oma työtila → Integraatiot.
Osoita se n8n:n Webhook-solmuun, niin saat allekirjoitetun transcript.completed-tapahtuman:
{
"event": "transcript.completed",
"id": "evt_...",
"timestamp": 1786902819,
"workspaceId": "...",
"project": {
"id": "...",
"name": "hallituksen-kokous-elokuu.mp4",
"language": "fi",
"durationSeconds": 3184
},
"files": [
{ "format": "srt", "name": "hallituksen-kokous-elokuu.srt", "url": "https://...", "expiresAt": 1786989219 }
]
}
Jokainen pyyntö on allekirjoitettu HMAC-SHA256:lla raakarungon yli, otsakkeessa X-Inwista-Signature muodossa sha256=<hex>. Tarkista se ennen kuin luotat sisältöön — n8n:ssä riittää Crypto-solmu ja IF-vertailu. Tiedosto-osoitteet ovat allekirjoitettuja ja voimassa 24 tuntia, joten hae tarvitsemasi sen sijaan että tallentaisit linkit.
Toimitus yritetään kolme kertaa, ja jatkuvasti epäonnistuva päätepiste kytketään automaattisesti pois päältä, syy näkyvissä integraatioasetuksissa — rikkinäinen vastaanottaja näkyy siis tilana, jonka voit nähdä, eikä tapahtumina, jotka katoavat hiljaisuudessa.
Asiat, jotka puraisevat ennemmin tai myöhemmin
Pyyntörajat. 300 luku- ja 60 kirjoituspyyntöä minuutissa avainta kohden. Runsaasti tavalliseen käyttöön, nopeasti täynnä jos päästät koko arkiston rinnakkain liikkeelle ilman jonoa. Jos kurot umpeen satoja tiedostoja, aja ne erissä.
Lähdeosoitteiden on oltava saavutettavissa. API tutkii mediatiedoston ennen työn vastaanottamista — juuri siksi kesto ja hinta tiedetään etukäteen. Drive-linkki, joka vaatii kirjautumisen, palauttaa unreadable_source, eikä mitään veloiteta. Käytä suoria tai allekirjoitettuja osoitteita.
Virheet ovat rakenteisia. Jokainen epäonnistuminen palauttaa saman kuoren:
{ "error": { "code": "insufficient_credits", "message": "..." } }
Haaraudu code-kentän perusteella, älä koskaan viestin tekstin. Koodeja vain lisätään v1:n sisällä eikä niitä koskaan nimetä uudelleen; viestit sen sijaan voidaan muotoilla uusiksi.
Idempotenssiavaimet ovat pyyntökohtaisia, eivät tiedostokohtaisia. Ne suojaavat kaksinkertaiselta veloitukselta, kun sama solmun ajo yritetään uudelleen. Saman nauhoitteen karsiminen, kun kaksi eri ajoa lähettää sen, on työnkulkusi tehtävä — hakutaulukko tiedostotunnisteen perusteella on tavallinen ratkaisu.
Valmis työnkulku
Tässä on runko tuotavaksi ja muokattavaksi. Korvaa credential-viittaus omalla Header Auth -tunnistetiedollasi sen sijaan, että liittäisit avaimen suoraan solmuun.
{
"name": "Inwista — automated transcription",
"nodes": [
{
"parameters": {},
"id": "trigger",
"name": "When clicking Test workflow",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0]
},
{
"parameters": {
"method": "POST",
"url": "https://api.inwista.ai/v1/transcriptions",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"source_url\": \"{{ $json.mediaUrl }}\", \"language\": \"fi\", \"diarization\": true}",
"options": {}
},
"id": "submit",
"name": "Submit transcription",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [220, 0]
},
{
"parameters": { "amount": 15 },
"id": "wait",
"name": "Wait 15s",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [440, 0]
},
{
"parameters": {
"url": "=https://api.inwista.ai/v1/transcriptions/{{ $('Submit transcription').item.json.id }}",
"options": {}
},
"id": "status",
"name": "Check status",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [660, 0]
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true, "version": 2 },
"conditions": [
{
"leftValue": "={{ $json.status }}",
"rightValue": "completed",
"operator": { "type": "string", "operation": "equals" }
}
],
"combinator": "and"
},
"options": {}
},
"id": "isdone",
"name": "Is it done?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [880, 0]
},
{
"parameters": {
"url": "=https://api.inwista.ai/v1/transcriptions/{{ $('Submit transcription').item.json.id }}/captions?format=srt",
"options": { "response": { "response": { "responseFormat": "text" } } }
},
"id": "srt",
"name": "Get SRT",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1100, -100]
}
],
"connections": {
"When clicking Test workflow": { "main": [[{ "node": "Submit transcription", "type": "main", "index": 0 }]] },
"Submit transcription": { "main": [[{ "node": "Wait 15s", "type": "main", "index": 0 }]] },
"Wait 15s": { "main": [[{ "node": "Check status", "type": "main", "index": 0 }]] },
"Check status": { "main": [[{ "node": "Is it done?", "type": "main", "index": 0 }]] },
"Is it done?": {
"main": [
[{ "node": "Get SRT", "type": "main", "index": 0 }],
[{ "node": "Wait 15s", "type": "main", "index": 0 }]
]
}
}
}
Kuusi solmua. Kaikki muu — käännös, parannus, toimitus, poisto — rakentuu saman rungon päälle.
Mitä tämä oikeasti muuttaa
Kiinnostavinta ei ole se, että litterointi automatisoituu. Kiinnostavinta on se, mikä lakkaa olemasta päätös.
Kun tekstitykset maksavat jonkun iltapäivän, niitä annostellaan: tärkeät videot saavat ne, loput eivät. Kun ne eivät maksa tiedostoa kohden mitään ja ovat valmiina ennen kuin kukaan ehtii pyytää, ne lakkaavat olemasta projekti ja muuttuvat sisältösi ominaisuudeksi — jokainen nauhoite haettavissa, jokainen video saavutettava, jokainen kurssi vaatimusten mukainen, ilman että siitä pitää pitää palaveria.
Se on arvokkaampaa kuin säästyneet tunnit.
Valmis rakentamaan? Luo API-avain — ilmaistaso riittää tämän läpikäymiseen alusta loppuun. Täydellisen päätepisteluettelon löydät API-dokumentaatiosta.