Как стать автором
Обновить

CLI чатбот, который запустится даже на телефоне

Уровень сложностиПростой

В этой статье я напишу чатбота на Rust который будет запускаться даже на телефоне.

Чатбот будет работать на марковских цепях, его нужно будет обучать самому.

Взаимодействие с чатботом будет с помощью 5ти команд:

  • save (filename) - сохранить бота в файл

  • load (filename) - загрузить бота из файла

  • /(text..) - покормить бота

  • ? - сгенерировать текст

  • ?(text..) - сгенерировать текст начинающийся с (text..)

    Приступаем к написанию кода.

Для начала нужно добавить bincode (для сериализации и десериализации) и markov в Cargo.toml:

[package]
name = "chatbot"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/

[dependencies]
bincode = "1.3.3"
markov = "1.1.0"
use markov::Chain;

fn process(input: String) {
  unimplemented!();
}

fn main() {
  let mut current_chain: Chain<String> = Chain::of_order(1);
  loop {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
    input.pop(); // remove '\n' from input
    process(input);
  }
}

В начале функции main создается объект цепи Маркова. Затем запускается цикл чтения пользовательского ввода, который вызывает функцию process для обработки каждой введенной строки. В случае использования операционной системы Windows, необходимо продублировать вызов метода input.pop(), так как конец строки в этой ОС обозначается двумя символами.

Функция process выполняет обработку введенного текста в соответствии с командой, указанной пользователем.

use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};

fn process(input: String, chain: &mut Chain<String>) -> Result<(), Box<dyn Error>> {
    if let Some(filename) = input.strip_prefix("save ") {
        let serzed = bincode::serialize(&chain)?;
        let mut filetoser = OpenOptions::new()
            .truncate(true)
            .create(true)
            .write(true)
            .read(true)
            .open(filename)?;
        filetoser.write_all(&serzed)?;
    } else if let Some(filename) = input.strip_prefix("load ") {
        let mut serzed = Vec::new();
        File::open(filename)?.read_to_end(&mut serzed)?;
        *chain = bincode::deserialize(&serzed)?;
    } else if input == "?" {
        println!("\nrgpt0.5mb > {}", chain.generate_str());
    } else if let Some(input) = input.strip_prefix('?') {
        println!(
            "\nrgpt0.5mb > {}\n",
            chain.generate_str_from_token(input.trim())
        );
    } else if let Some(input) = input.strip_prefix('/') {
        chain.feed_str(input);
    } else if input == "i" {
        println!("\n? - Generate\n?(text..) - Generate from text\n/(text..) - Feed AI\nload (filename) - Load AI\nsave (filename) - Save AI\n");
    } else {
        println!("\nrgpt0.5mb > Oh shit, I'm sorry! Incorrect command!\n");
    }
    Ok(())
}

Функция process обрабатывает все перечисленные команды, включая команду "i", которая выводит список доступных команд.

В случае некорректного ввода команды пользователем будет выведено сообщение: " rgpt0.5mb > Oh shit, I'm sorry! Incorrect command!"

source code
use markov::Chain;

use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};

fn process(input: String, chain: &mut Chain<String>) -> Result<(), Box<dyn Error>> {
    if let Some(filename) = input.strip_prefix("save ") {
        let serzed = bincode::serialize(&chain)?;
        let mut filetoser = OpenOptions::new()
            .truncate(true)
            .create(true)
            .write(true)
            .read(true)
            .open(filename)?;
        filetoser.write_all(&serzed)?;
    } else if let Some(filename) = input.strip_prefix("load ") {
        let mut serzed = Vec::new();
        File::open(filename)?.read_to_end(&mut serzed)?;
        *chain = bincode::deserialize(&serzed)?;
    } else if input == "?" {
        println!("\nrgpt0.5mb > {}", chain.generate_str());
    } else if let Some(input) = input.strip_prefix('?') {
        println!(
            "\nrgpt0.5mb > {}\n",
            chain.generate_str_from_token(input.trim())
        );
    } else if let Some(input) = input.strip_prefix('/') {
        chain.feed_str(input);
    } else if input == "i" {
        println!("\n? - Generate\n?(text..) - Generate from text\n/(text..) - Feed AI\nload (filename) - Load AI\nsave (filename) - Save AI\n");
    } else {
        println!("\nrgpt0.5mb > Oh shit, I'm sorry! Incorrect command!\n");
    }
    Ok(())
}



fn main() {
    let mut chain: Chain<String> = Chain::of_order(1);
    loop {
        let mut input = String::new();
        std::io::stdin().read_line(&mut input).unwrap();
        input.pop();
        process(input, &mut chain).unwrap();
    }
}

Можно использовать его разными способами, например:

  • Обучать его коммуникации, то есть научить общаться с людьми.

  • Создавать тексты из нескольких источников, чтобы получить новый уникальный текст.

  • Использовать его для других целей, которые могут прийти в голову.

Как поставить chatbot на телефон?

  • Скачать Termux

  • На Termux скачать Rust (если возникнут проблемы, то нужно полазить по гуглу)

  • Установить любой текстовый редактор (например Vim), сделать это можно так: pkg install vim

  • Прописать несколько команд:

    cargo new chatbot

    cd chatbot

    vim src/main.rs

    нажать i, стереть всё, вставить туда весь код бота, аналогично с Cargo.toml

    далее нажать CTRL+C, написать :wqa

  • cargo run --release

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.