Chatbot reagující na připravené otázky. Cílem projektu bylo pracovat systematicky a psát testovatelný a rozšiřitelný kód. Semestrální projekt ve 2. ročníku vysoké školy, předmět Softwarové inženýrství.
Popis projektu
Dle zadaných požadavků bylo potřeba nejdřívě vypracovat dokument s funkčními i systémovými požadavky, popisem funkcí a chování. Aplikace musela mít unit testy s minimálním pokrytím 80%. 2 týdny před koncem semestru byla oznámena změna, kterou jsme museli do aplikace začlenit s co nejmenší prací.
Uživatelské požadavky
- Ověření uživatele
- Uživatel přistupuje do aplikace s tokenem v URL adrese.
- Pokud je klíč správný, je uživatel vpustěn
- Pokud není, je uživateli zobrana chybová hláška
- Komunikace s chatbotem
- Uživatel do textového vstupu zadá svojí otázku a stisknutím tlačítka "Odeslat" u textového vstupu či tlačítka "Enter" na klávesnici je otázka odeslána
- Otázka se zpracuje na serveru a vrátí do chatovacího okna odpověď
- Komunikace s chatbotem probíhá jen v českém jazyce
- Server si nepamatuje předchozí otázky, nelze tedy vázat otázky na předchozí kontext
- Otázky
- Mělo by být snadné přidávat další příkazy, i s parametrem
- Aktuální otázky:
- "Jaký je čas?"
- Server vrátí aktuální čas
- "Jak se jmenuješ?"
- Server vrátí jméno chatbota
- "Jaký je kurz /CURRENCY/?"
- Vstupní parametr /CURRENCY/ musí být ve formátu shodném s API ČNB, tj. dle ISO 4217
- Vrátí aktuální kurz měny
- Seznam měn je limitován nabídkou API ČNB
- Jako /CURRENCY/ očekává server kód měny dle ISO 4217 (EUR, USD, CZK atd.)
- "Jaký je čas?"
Technologie
Aplikaci jsem vypracoval v čistém PHP, využil jsem knihovny pro routování, CSV, HTTP apod. Klíčovým prvkem byla struktura kolem příkazů, která umožňovala definování masky:
public static function getMask(): array
{
// '[neco]' značí volitelné slovo, '__nazev__' značí parametr
return ['Jaký je [nedávn] [kurz __currency__]','[historie __currency__]','[historii __currency__]'];
}
Parametry jsou do třídy při inicializaci vloženy, může tak s nimi pracovat:
public function __construct(string $currency)
{
$this->currency = $currency;
}
/**
* @inheritDoc
*/
public function run(): ICommandResponse
{
$factory = new CurrencyContainerFactory(new FileStorage(), new ApiRetriever(new CnbSource(), new Client()));
try {
$container = $factory->get();
} catch (CurrencyContainerException | InvalidDatetimeException) {
return new SimpleResponse('V tuto chvíli nemohu tento příkaz zpracovat', IResponse::HTTP_SERVER_ERROR);
}
$currency = $container->get($this->currency);
if ($currency) {
return new SimpleResponse(
sprintf(
'Kurz pro %s je %.2f Kč (%s)',
$currency->getName(),
$currency->getExchangeRate(),
$currency->getDateTime()->format('d.m.Y')
)
);
} else {
return new SimpleResponse(sprintf('Nenalezl jsem měnu %s.', $this->currency), IResponse::HTTP_NOT_FOUND);
}
}