>A jó gépi hang nem a hangmotoron múlik
A jó gépi felolvasás nem ott kezdődik, hogy melyik hangmotort választjuk. Sokkal inkább ott, hogy a gép nem nyers cikket kap, hanem bemondásra előkészített szövegkönyvet.
01A gomb egyszerűnek látszik
Az adminfelületen ez végül egy egyszerű gombnak látszik. Ott van a cikk, mellette az audió mező, alul pedig a művelet: audió generálása. Az ember megnyomja, a rendszer elküldi a szöveget az ElevenLabsnak, visszajön az MP3, a publikus oldalon pedig megjelenik egy lejátszó.
Ebből a nézőpontból ez egy átlagos integrációs feladat. Van egy API, van egy szöveg, van egy fájl, amit el kell menteni. A kellemetlen rész csak akkor derül ki, amikor az első verziót meg is hallgatjuk.
A Műhely cikkek írott szövegként működtek. Voltak bennük rövidítések, számok, dátumok, technikai kifejezések, URL-ek, zárójeles pontosítások, olyan mondatszerkezetek, amelyek olvasva teljesen természetesek. A szem ezeket könnyen kezeli: átugrik egy webcímen, fejben kiegészít egy százalékjelet, és érti, hogy az API-t nem magyar szóként kell olvasni.
02A nyers szöveg nem hanganyag
A felolvasómodell viszont nem szemmel olvas. Neki minden karakter bemeneti anyag. Amit mi csak jelölésnek látunk, azt neki valahogy ki kell mondania.
Itt csúszik el a kézenfekvő megoldás. A nyers HTML-ből kiszedett szöveg technikailag alkalmas arra, hogy hang készüljön belőle. Csak nem feltétlenül alkalmas arra, hogy jó legyen hallgatni.
A 15% könnyen furcsa alakban szólal meg, a backlog.hu nyers webcímként törik meg a mondatot, a rövidítések hol magyarosan, hol angolosan, hol egyszerűen rosszul hangzanak. A probléma nem az, hogy a motor használhatatlan. Hanem az, hogy nem azt az anyagot kapja, amiből természetes hangot lehet készíteni.
Ez elsőre technikai részletnek tűnik, de valójában termékdöntés. Eldönthettük volna, hogy a kódban próbálunk minden esetet kezelni: százalékokat, forintokat, évszámokat, URL-eket, rövidítéseket és magyar toldalékokat. Ez az út is működhet egy darabig, csak hamar egy félkész nyelvi feldolgozóvá nő.
03Kellett egy köztes réteg
A másik út az volt, hogy nem a nyers cikket próbáljuk okosabban felolvastatni, hanem készítünk belőle egy külön, felolvasásra szánt változatot. Így került be a rendszerbe az AUDIO JSON.
Az AUDIO JSON nem egyszerűen a cikk szövegének másolata. Inkább egy bemondásra kész szövegkönyv: köztes réteg az írott cikk és a hangmotor között. Ebben már nem az szerepel, hogy 15%, hanem az, hogy tizenöt százalék. Nem az, hogy backlog.hu, hanem az, hogy backlog pont hu. Nem az, hogy API, hanem az, hogy é-pí-áj.
A dátumok, pénznemek, mértékegységek és rövidítések kimondható alakra vannak írva, a szöveg pedig kisebb szegmensekre van bontva. Ez a bontás legalább annyira fontos, mint a normalizálás.
Egy cikk olvasás közben vizuálisan tagolódik. Van cím, deck, szakaszcím, bekezdés, kiemelés, esetleg ábra vagy kódblokk. Hangban ezek közül sok eltűnik. Ha nem teszünk a helyükre ritmust, a felolvasás egy hosszú, egyenletes szövegfolyammá válik.
Ezért a szegmensek közé szünetek kerültek. Nem nagy, színpadias megállások, csak annyi levegő, amennyi egy emberi felolvasásban is természetes lenne. A cél nem az volt, hogy a hang dramatizálja a cikket, hanem hogy ne kelljen az olvasónak fejben újratördelnie, miközben hallgatja.
04A kód szűkebb feladatot kapott
A fejlesztés egyik tanulsága az volt, hogy a hangminőség kérdését nem érdemes teljesen a kódba zárni. A kódnak világos, szűk feladata lett: validálja az AUDIO JSON-t, eltárolja a cikk mellett, a generáláskor szöveggé alakítja, mondathatáron darabolja, meghívja az ElevenLabs API-t, majd a kész MP3-at feltölti a Vercel Blob tárolóba.
Azt viszont, hogy mitől lesz a szöveg jól hallgatható, jobb volt egy külön szabványba tenni. Ebben lehet pontosítani, hogyan mondjuk ki a százalékokat, mit kezdünk a fájlnevekkel, mi történjen egy URL-lel, hogyan kezeljük a magyar rövidítéseket, és mikor kell szünetet adni.
Ha egy új cikkben előkerül egy rosszul hangzó minta, nem feltétlenül kell kódot írni. Elég lehet a formátum-specen javítani, majd az LLM már jobb szövegkönyvet készít.
Ez a felelősségmegosztás azért működik, mert nem keveri össze a két problémát. Az egyik probléma az, hogy hogyan kell megbízhatóan audiót generálni egy adminfelületen keresztül. A másik az, hogy milyen szövegből lesz jó audió. Az első mérnöki feladat. A második szerkesztési feladat is.
A kettő között az LLM lett a fordító. Nem azért, mert AI-al mindent meg lehet oldani, hanem mert ez a feladat pont olyan, amiben a nyelvi rugalmasság hasznos. Az LLM itt nem a cikket írja újra, hanem egy meglévő cikkből készít hallgatható változatot.
05Nem a gomb a lényeg
Fontos, hogy maradt fallback is. Ha egy cikkhez még nincs AUDIO JSON, a rendszer a nyers cikkszövegből is tud hangot generálni. Ez nem ugyanaz a minőség, de működik. Termékoldalon sokat számít, hogy lehet iterálni a jobb minőség felé, miközben az alapfunkció nem áll le attól, hogy egy szerkesztő még nem töltötte ki a felolvasási szkriptet.
A konfigurálhatóság ugyanezért került be. A hang és a modell környezeti változóval állítható, de cikkenként is felülírható. Ez nem azért fontos, mert minden cikkhez más hangot kell választani, hanem azért, mert a hanggenerálásnál sok apró kísérletből derül ki, mi működik.
A végén a funkció egyszerű maradt. Az admin beilleszti vagy feltölti az AUDIO JSON-t, a felület validálja, mentés után lehet audiót generálni, a publikus cikkoldalon pedig megjelenik a lejátszó. Aki használja, ebből legfeljebb annyit lát, hogy a cikk már hallgatható is.
De a lényeg nem a gomb. A lényeg az a felismerés volt, hogy a jó gépi felolvasás nem elsősorban hangmotor-kérdés. Persze számít a modell, számít a hang, számít az API minősége. De a legnagyobb ugrást nem az hozta, hogy lecseréltük a motort egy drágábbra, hanem az, hogy komolyan vettük az inputot.
Egy emberi felolvasónak sem adnánk oda a nyers HTML-t azzal, hogy majd megoldja. Készítenénk neki egy tiszta, tagolt, kimondható szöveget. Kihúznánk belőle azt, ami csak vizuálisan működik. Átírnánk a számokat, jeleznénk a szüneteket, és figyelnénk arra, hogy a mondatok hallás után is követhetők legyenek.
A gépnél ugyanez történt. Nem okosabbnak kellett elképzelni, hanem pontosabban kellett instruálni. Nem cikket kellett adni neki, hanem szövegkönyvet.