"Chatbot" [API]

PHP

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.)

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);
    }
}