mirror of
https://github.com/house-of-vanity/desubot.git
synced 2025-07-08 04:54:08 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
2fb5b03fbf | |||
55a7dd6a67 | |||
ff6e04988e | |||
7c067065bd | |||
175f056add | |||
20f366572b | |||
e5079fa584 | |||
fdc52b7198 |
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "desubot"
|
||||
version = "0.5.8"
|
||||
version = "0.5.9"
|
||||
authors = ["AB <ab@hexor.ru>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -13,8 +13,12 @@ Telegram bot with light group statistic and heavy spy features.
|
||||
|
||||
== Important ==
|
||||
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH.
|
||||
On Windows it may be placed on working directory. Both Linux and Windows mystem binary is in repo.
|
||||
* ubuntu deps: libssl-dev libsqlite3-dev cmake libfreetype-dev
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## License
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot?ref=badge_large)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#[allow(dead_code)]
|
||||
static CODE_HELP: &str = "<b>Code highlighter</b>
|
||||
pub(crate) static CODE_HELP: &str = "<b>Code highlighter</b>
|
||||
|
||||
<i>Usage</i>
|
||||
<pre>/code
|
||||
@ -7,7 +7,7 @@ static CODE_HELP: &str = "<b>Code highlighter</b>
|
||||
#<lang - JS by default> #<theme - Dracula by default></pre>
|
||||
|
||||
Language may be defined by both name and extension - Rust, rs...
|
||||
Max lines - 80
|
||||
Max length - 4000
|
||||
|
||||
List of themes:
|
||||
1337
|
||||
|
@ -11,6 +11,10 @@
|
||||
т
|
||||
у
|
||||
я
|
||||
чо
|
||||
че
|
||||
ща
|
||||
ваще
|
||||
бы
|
||||
stat
|
||||
вообще
|
||||
|
155
src/commands.rs
155
src/commands.rs
@ -21,6 +21,7 @@ use syntect::highlighting::Theme;
|
||||
use syntect::parsing::SyntaxReference;
|
||||
use syntect::util::LinesWithEndings;
|
||||
use telegram_bot::prelude::*;
|
||||
use telegram_bot::*;
|
||||
use telegram_bot::{Api, Message, ParseMode, UserId};
|
||||
|
||||
include!("../assets/help_text.rs");
|
||||
@ -31,6 +32,12 @@ pub struct Here {
|
||||
pub struct Top {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct ConfTop {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct GlobalTop {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct MarkovAll {
|
||||
pub data: String,
|
||||
}
|
||||
@ -46,6 +53,9 @@ pub struct Sql {
|
||||
pub struct Code {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct Scheme {
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Execute {
|
||||
@ -59,6 +69,68 @@ pub trait Execute {
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for Scheme {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
match api
|
||||
.send(
|
||||
message
|
||||
.text_reply(format!(
|
||||
"{}{}{}",
|
||||
"<pre>",
|
||||
include_str!("../assets/scheme.sql").to_string(),
|
||||
"</pre>"
|
||||
))
|
||||
.parse_mode(ParseMode::Html),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/scheme command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/scheme command sent failed to {}", message.chat.id()),
|
||||
};
|
||||
match {
|
||||
Code {
|
||||
data: format!(
|
||||
"{}{}",
|
||||
include_str!("../assets/scheme.sql").to_string(),
|
||||
"\n#sql"
|
||||
),
|
||||
}
|
||||
.exec_with_result(&api, &message)
|
||||
.await
|
||||
} {
|
||||
Ok(path) => {
|
||||
let file = InputFileUpload::with_path(path.clone());
|
||||
// api.send(message.chat.document(&file)).await?;
|
||||
//
|
||||
// // Send an image from disk
|
||||
api.send(message.chat.document(&file)).await?;
|
||||
//debug!("{:#?}", formatter);
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
Err(_) => {
|
||||
let _ = api
|
||||
.send(message.text_reply(CODE_HELP).parse_mode(ParseMode::Html))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for Sql {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
@ -281,6 +353,84 @@ impl Execute for Top {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for GlobalTop {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
let top = db::get_global_top().await?;
|
||||
let mut msg = "<b>Global top words:</b>\n<pre>".to_string();
|
||||
let mut counter = 1;
|
||||
for word in top.iter() {
|
||||
msg = format!(
|
||||
"{} <b>{}</b> {} - {}\n",
|
||||
msg, counter, word.word, word.count
|
||||
);
|
||||
counter += 1;
|
||||
}
|
||||
msg = format!("{}{}", msg, "</pre>");
|
||||
match api
|
||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/global_top command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/global_top command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for ConfTop {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
let top = db::get_conf_top(&message).await?;
|
||||
let mut msg = "<b>Conf top words:</b>\n<pre>".to_string();
|
||||
let mut counter = 1;
|
||||
for word in top.iter() {
|
||||
msg = format!(
|
||||
"{} <b>{}</b> {} - {}\n",
|
||||
msg, counter, word.word, word.count
|
||||
);
|
||||
counter += 1;
|
||||
}
|
||||
msg = format!("{}{}", msg, "</pre>");
|
||||
match api
|
||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/conf_top command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/conf_top command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for MarkovAll {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
@ -571,9 +721,6 @@ impl Execute for Code {
|
||||
.split("\n")
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
if lines.len() >= 81 {
|
||||
return Err(CodeHighlightningError);
|
||||
}
|
||||
let last_line = &lines[lines.len() - 1];
|
||||
|
||||
let tags = last_line
|
||||
@ -613,7 +760,7 @@ impl Execute for Code {
|
||||
.collect();
|
||||
|
||||
let theme = if theme.len() != 1 {
|
||||
ts.themes.get("Dracula").unwrap()
|
||||
ts.themes.get("gruvbox").unwrap()
|
||||
} else {
|
||||
theme[0]
|
||||
};
|
||||
|
70
src/db.rs
70
src/db.rs
@ -1,3 +1,5 @@
|
||||
#[allow(unused_mut)]
|
||||
#[allow(dead_code)]
|
||||
use crate::errors;
|
||||
use crate::utils;
|
||||
use rusqlite::{named_params, params, Connection, Error, Result};
|
||||
@ -35,18 +37,23 @@ pub(crate) fn update_scheme() -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn load_stopwords() -> Result<()> {
|
||||
info!("Populating stop words wait please.");
|
||||
let conn = open()?;
|
||||
for table in include_str!("../assets/stop-words.txt").split('\n').into_iter() {
|
||||
for table in include_str!("../assets/stop-words.txt")
|
||||
.split('\n')
|
||||
.into_iter()
|
||||
{
|
||||
let word = table.trim();
|
||||
if word != "" {
|
||||
let mut stmt = conn.prepare_cached(
|
||||
"
|
||||
let mut _stmt = conn
|
||||
.prepare_cached(
|
||||
"
|
||||
INSERT OR IGNORE INTO
|
||||
stop_words('word')
|
||||
VALUES (:word)
|
||||
",
|
||||
)?.insert(params![word]);
|
||||
//let mut rows = stmt.word(named_params! {":conf_id": conf_id})?;
|
||||
)?
|
||||
.insert(params![word]);
|
||||
}
|
||||
}
|
||||
info!("Stop words updated.");
|
||||
@ -505,3 +512,56 @@ pub(crate) async fn get_top(
|
||||
}
|
||||
Ok(top)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_global_top() -> Result<Vec<TopWord>, errors::Error> {
|
||||
let conn = open()?;
|
||||
let mut stmt = conn.prepare_cached(
|
||||
"
|
||||
SELECT w.word, COUNT(*) as count FROM relations r
|
||||
LEFT JOIN word w ON w.id = r.word_id
|
||||
GROUP BY w.word
|
||||
ORDER BY count DESC
|
||||
LIMIT 50
|
||||
",
|
||||
)?;
|
||||
|
||||
let mut rows = stmt.query_named(named_params! {})?;
|
||||
let mut top = Vec::new();
|
||||
|
||||
while let Some(row) = rows.next()? {
|
||||
top.push(TopWord {
|
||||
word: row.get(0)?,
|
||||
count: row.get(1)?,
|
||||
})
|
||||
}
|
||||
Ok(top)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_conf_top(
|
||||
message: &telegram_bot::Message,
|
||||
) -> Result<Vec<TopWord>, errors::Error> {
|
||||
let conf_id = i64::from(message.chat.id());
|
||||
|
||||
let conn = open()?;
|
||||
let mut stmt = conn.prepare_cached(
|
||||
"
|
||||
SELECT w.word, COUNT(*) as count FROM relations r
|
||||
LEFT JOIN word w ON w.id = r.word_id
|
||||
WHERE r.conf_id = :conf_id
|
||||
GROUP BY w.word
|
||||
ORDER BY count DESC
|
||||
LIMIT 10
|
||||
",
|
||||
)?;
|
||||
|
||||
let mut rows = stmt.query_named(named_params! {":conf_id": conf_id})?;
|
||||
let mut top = Vec::new();
|
||||
|
||||
while let Some(row) = rows.next()? {
|
||||
top.push(TopWord {
|
||||
word: row.get(0)?,
|
||||
count: row.get(1)?,
|
||||
})
|
||||
}
|
||||
Ok(top)
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
//use crate::commands::Command;
|
||||
use crate::commands::{Code, Execute, Here, Markov, MarkovAll, Omedeto, Sql, Top};
|
||||
use crate::commands::{
|
||||
Code, ConfTop, Execute, GlobalTop, Here, Markov, MarkovAll, Omedeto, Scheme, Sql, Top,
|
||||
};
|
||||
use crate::db;
|
||||
use crate::errors;
|
||||
use crate::utils;
|
||||
@ -38,11 +40,30 @@ pub async fn handler(
|
||||
.await
|
||||
} {
|
||||
Ok(path) => {
|
||||
let mut cnt_lines = 0;
|
||||
for _ in s.lines() {
|
||||
cnt_lines = cnt_lines + 1;
|
||||
}
|
||||
let mut cnt_chars = 0;
|
||||
for _ in s.chars() {
|
||||
cnt_chars = cnt_chars + 1;
|
||||
}
|
||||
let file = InputFileUpload::with_path(path.clone());
|
||||
info!("lines: {}, chars: {}", cnt_lines, cnt_chars);
|
||||
// api.send(message.chat.document(&file)).await?;
|
||||
//
|
||||
// // Send an image from disk
|
||||
api.send(message.chat.photo(&file)).await?;
|
||||
if cnt_chars > 4000 {
|
||||
let _ = api
|
||||
.send(message.text_reply(CODE_HELP).parse_mode(ParseMode::Html))
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
if cnt_lines < 81 {
|
||||
api.send(message.chat.photo(&file)).await?;
|
||||
} else {
|
||||
api.send(message.chat.document(&file)).await?;
|
||||
}
|
||||
//debug!("{:#?}", formatter);
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
@ -57,6 +78,8 @@ pub async fn handler(
|
||||
|| s.contains("@here")
|
||||
|| s.contains("/хере")
|
||||
|| s.contains("@хере")
|
||||
|| s.contains("@all")
|
||||
|| s.contains("\"руку")
|
||||
|| s.contains("\"хере") =>
|
||||
{
|
||||
db::add_sentence(&message, mystem).await?;
|
||||
@ -88,15 +111,22 @@ pub async fn handler(
|
||||
.await?;
|
||||
}
|
||||
},
|
||||
"/top" => {
|
||||
"/top" | "/stat" => {
|
||||
Top {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
"/stat" => {
|
||||
Top {
|
||||
"/global_top" | "/global_stat" => {
|
||||
GlobalTop {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
"/conf_stat" | "/conf_top" => {
|
||||
ConfTop {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
@ -116,6 +146,13 @@ pub async fn handler(
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
s if s == "/scheme" || s == "/schema" => {
|
||||
Scheme {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
"/omedeto" => {
|
||||
Omedeto {
|
||||
data: "".to_string(),
|
||||
|
Reference in New Issue
Block a user