Beszélgess a mikrovezérlőddel!
A mesterséges intelligencia előretörésével a chatbotok is rohamosan szaporodnak. Cikkünkben bemutatjuk, hogyan készíthetsz saját példányt Arduinóra.
Egyre gyakrabban használják a különféle webes felületek a chatbotok szolgáltatásait, hiszen az előre betáplált minták alapján viszonylag könnyen képesek ezek az interakcióra kifejlesztett alkalmazások a felhasználók számára releváns információkat átadni. Természetesen nagyobb adatbázis bevetésével sokkal több ismerettel töltheted meg digitális beszélgetőtársad tudástárát, ha azonban egy Arduino felületéről szeretnél egy ilyen programot futtatni, a limitált erőforrásoknak köszönhetően sokkal nehezebb dolgod lesz.
Némi kódolással persze egy mikrokontrollerből is remek beszélgetőpartnert faraghatsz. Cikkünkben bemutatjuk, hogyan építhetsz fel és szabhatsz személyre egy alapvető funkciókat tartalmazó chatbotot, amely a Turing-teszten ugyan valószínűleg nem megy át, de a soros monitoron keresztül hatékonyan kommunikál majd veled.
Komolyabb hardveres igényeket ez a projekt nem állít eléd, pusztán a mikrovezérlőd is elegendő ahhoz, hogy belevághass a digitális beszélgetőpartner elkészítésének folyamatába.
Kódolási környezet gyanánt javasoljuk az alapértelmezett Arduino IDE használatát, ettől eltérő felületen is dolgozhatsz, amennyiben a kódfeltöltést képes vagy megfelelően megoldani.
Alapvető célkitűzések
Egy chatbot lényege, hogy a beérkező üzenetekre egy előre meghatározott válaszkupacból képes a megfelelő, emberihez hasonló reakciót előhúzni, így cikkünkben is ennek megvalósítását tűztük ki célul. Ehhez mindössze a megfelelő beszélgetési mintákkal kell táplálnod az aktiválásra váró beszélgetőpartneredet. A limitált hardveres képességeknek köszönhetően - a gépi tanulásról lemondva - mindössze annyi lesz a feladatod, hogy amennyiben egy beírt mondatban szerepel egy kiválasztott szó, akkor arra megfelelő válasszal reagáljon a felületed. Miután nyitottál egy új fájlt, ugorj a setup függvény belsejébe, és nyisd meg a soros portot, hogy a későbbiekben bevethesd majd a megnevezett csatornát.
Ehhez a Serial.begin(9600); utasításra lesz szükséged. A soros monitor beviteli mezőjébe írt első üzenetig várakoztatnod kell a programodat, ezt a loop() függvényen belül a while(Serial.available()>0){ } kóddal érheted el. Ebben fogod ellenőrizni, hogy milyen információ érkezett a beviteli mezőből. Az első adat, amire válaszolni fogsz, a felhasználótól kapott hello üzenet. A kiértékeléshez az egész bemeneti utasítássorozatot be kell olvasnod egy szöveges objektumba (String str = Serial.readString(); ), majd készítened kell egy tömböt, amelynek maximális mérete az str-állomány hossza lesz - hiszen ennél nagyobb karaktermennyiség úgysem kerülhet bele. Amint ezzel megvagy, jöhet a szöveges állomány szeparálása, amihez két segédváltozóra is szükséged lesz (int r=0, t=0;).
Ezek után egy for ciklust kell indítanod, amely karakterenként végiglépked a bemeneti adaton, és a megadott szeparálójelek segítségével szavanként elmenti a kapott információkat. Ha ez sikerült, összevetheted az általad begépelt értékeket a programod megfelelő válaszához tartozó szöveggel. Ehhez ugorj vissza a loopon belül található while-ba, és indíts egy for ciklust, amivel végighaladsz a beolvasott értékeiden (t-ig kell futtatnod a programot), ezen belül pedig egy feltételben ellenőrizd a "hello" kifejezés jelenlétét. Amennyiben találsz egyezést, a Serial.println("Gep: Hello" ); üzenettel írasd ki a chatbotod köszönését.
Fejlesztési útvonal
A következő lépés programod bonyolítása, ennek köszönhetően fogja felismerni a változatos köszönési formákat. Hogy ezt megvalósítsd, a setup()-on kívül hozz létre egy tömböt, majd töltsd fel értékekkel. Első körben elég néhány alapértelmezett üdvözlést kiválasztanod, a későbbiekben kedvedre bonyolíthatod ezeket (String hello[8] = {"hello", "hali", "szia", "szevasz", "hi", "üdv","csá","cső"}; ). A fejlesztés további lépcsőjeként a loopban található ellenőrző forciklust kell kibővítened, hogy képes legyen kezelni a többszörös összehasonlítást is, amihez egy extra for szükséges. A belső feltételt annyiban kell módosítanod, hogy a "hello" kifejezést lecseréled hello[j]-re - vagyis a tömböd aktuális elemére -, és ha a tömbben tárolt szavakat szövöd üdvözlésedbe, akkor a programod egy ,,Hello"-val reagál majd.
Újrahasználható kód
Mivel a későbbiekben több tömb is a rendelkezésedre állhat, ezt a dupla ellenőrző funkciót érdemes kiemelni egy függvénnyé, amit így sokkal egyszerűbben kezelhetsz. Ehhez készíts a loopon kívül egy void vizsgalat(){} függvényt, amelynek bemeneti paraméterei között szükséged lesz egy szám típusú tömbméretre (int tombMeret), a szöveges elemeket tartalmazó inputra (String inputTomb[]), az összehasonlításhoz használt mintákra és elemszámukra (int eredmenyMeret, String eredmenyTomb[]), valamint egy válaszra. A begépelést követően helyezd át a függvény magjába az ellenőrzéshez használt kódrészletet, majd a dupla forciklus mindegyik elemét cseréld a bementi paraméterekre.
Ha elkészültél, a loopon belül a vizsgalat(t,sa,8,hello,"Hello"); utasítással hívhatod meg függvényedet, új tömbök segítségével pedig további szavakra szűrhetsz. Érdemes egy alapértelmezett választ is készítened, amely akkor jelenik meg, ha a program nem talált egyezést. A megvalósításához hozz létre egy globális int valaszok=0; változót, amit minden loopciklus elején állíts 0-ra, és ha érkezik válasz az adott üzenetre, növeld az értékét a valaszok++; utasítással. Végül a loopodon belül található while-ciklus végére írd az if(valaszok==0) { Serial.println("Gep: Sajnálom, nem értettem a kérdést.");} kódot, így elkészül az alapértelmezett üzeneted.
Szeparált kód
Mivel igen hosszúvá és átláthatatlanná válik a kódod, ha mindent az alapvető csomagban tárolsz, érdemes lehet egy headerfájlba különválasztani a mintákat tartalmazó tömböket. Hozz létre valamilyen szövegszerkesztő alkalmazással egy üres szöveges állományt, majd mentsd el valaszok.h néven az INO-állományod mellé. Az Arduino fejlesztői környezetében a készülő alkalmazásod első sorába gépeld be a #include "valaszok.h" utasítást, amivel a fejállományod teljes tartalmát elérhetővé teszed a kódodon belül, így a programod képes lesz az összes információt elérni a külön tárolt adataidból.
A valaszok.h-ban garantáld, hogy minden beemelést csak egyszer hajtson végre a kódod, ezt egy úgynevezett include guard segítségével valósíthatod meg. Az üres állományod első sorába gépeld be a #ifndef VALASZOK_H_INCLUDED kifejezést, majd egy sortörést követően a #define VALASZOK_H_INCLUDED parancsot, két enter leütése után pedig helyezd el az #endif záró utasítást. Az üres sorba aztán beillesztheted a főprogramban elkészített tömböket, amelyek így már elérhetőek a külső állományból, ezt egy futtatással tesztelheted is. Amennyiben tovább bonyolítod a programodat, és a gép válaszait különféle tömbökből véletlenszerűen választod ki, érdemes ezeket a sorokat is átemelned a külső "adatbázisba", ezáltal ugyanis még átláthatóbbá válik a kódod.