В этой статье я напишу чатбота на 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