25 Commits

Author SHA1 Message Date
739109e5f7 pux
Some checks failed
Build / build-windows (push) Has been cancelled
Build / build-linux (push) Has been cancelled
2024-10-17 21:15:33 +03:00
4ac7920815 bump rand 2024-10-17 21:04:04 +03:00
47f1ab9348 Fux 2024-10-17 20:58:09 +03:00
28cdf4be2e Fixing shit 2024-10-17 20:55:41 +03:00
0bcb99089b Update README.md
Some checks failed
Build / build-windows (push) Has been cancelled
Build / build-linux (push) Has been cancelled
2024-08-21 15:51:20 +03:00
0bba91486e Fix ci
Some checks failed
Build / build-windows (push) Has been cancelled
Build / build-linux (push) Has been cancelled
2024-08-07 20:10:49 +03:00
207717491c Fix docker build
Some checks failed
Build / build-linux (push) Failing after 31s
Build / build-windows (push) Has been cancelled
2024-08-05 17:18:15 +03:00
f185c31a17 Fix docker build 2024-08-05 17:14:00 +03:00
aeacc15439 Fix docker build 2024-08-05 17:07:38 +03:00
ccf54bc279 Fix docker build 2024-08-05 16:51:59 +03:00
AB
e07f173b7c Fix CI
Some checks are pending
Build / build-windows (push) Waiting to run
Build / build-linux (push) Waiting to run
2024-08-04 23:34:19 +03:00
AB
bcd869273d Fix CI 2024-08-04 23:17:56 +03:00
AB
1ee12fa0c0 Fix CI 2024-08-04 23:14:59 +03:00
76dab182cf pin docker ubuntu version 2024-08-04 23:05:07 +03:00
bacdf559c4 Fix /markov in private chats 2023-07-24 14:38:19 +03:00
82a81fffb6 Rebuild new docker 2023-07-01 04:28:04 +03:00
392669703d Update README.md 2022-12-16 12:29:50 +02:00
2fb5b03fbf Add global, conf stat. 2022-11-23 17:53:56 +02:00
55a7dd6a67 add @all command 2022-11-03 19:01:17 +02:00
AB
ff6e04988e Merge branch 'main' of https://github.com/house-of-vanity/desubot into main 2022-05-05 12:25:10 +03:00
AB
7c067065bd add a few stop words 2022-05-05 12:24:38 +03:00
175f056add Update README.md 2022-01-23 15:09:05 +03:00
AB
20f366572b Add scheme. 2022-01-23 15:02:21 +03:00
e5079fa584 Update db.rs 2021-12-08 17:51:32 +03:00
fdc52b7198 Update README.md
Add deps
2021-12-08 17:46:33 +03:00
9 changed files with 334 additions and 85 deletions

View File

@ -11,26 +11,15 @@ jobs:
build-linux: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Build - name: Build
run: cargo build --verbose --release run: cargo build --verbose --release
- name: Upload Linux binary - name: Upload Linux binary
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: desubot name: desubot
path: ./target/release/desubot path: ./target/release/desubot
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose --release
- name: Upload Windows binary
uses: actions/upload-artifact@v1
with:
name: desubot.exe
path: ./target/release/desubot.exe
build-push-docker: build-push-docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -42,42 +31,45 @@ jobs:
echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/} echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/}
- -
name: Set up QEMU name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v3
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v3
- -
name: Login to DockerHub name: Login to DockerHub
uses: docker/login-action@v1 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- -
name: Build and push name: Build and push
id: docker_build_latest id: docker_build_latest
uses: docker/build-push-action@v2 uses: docker/build-push-action@v6
with: with:
push: true push: true
tags: ultradesu/desubot:latest tags: ultradesu/desubot:latest
- -
name: Build and push name: Build and push
id: docker_build_tag id: docker_build_tag
uses: docker/build-push-action@v2 uses: docker/build-push-action@v6
with: with:
push: true push: true
tags: ultradesu/desubot:${{ steps.branch_name.outputs.SOURCE_TAG }} tags: ultradesu/desubot:${{ steps.branch_name.outputs.SOURCE_TAG }}
publish: publish:
name: Publish release name: Publish release
needs: [build-windows, build-linux] needs: [build-linux]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
# - name: Checkout
# uses: actions/checkout@v4
- name: Get the version (git tag) - name: Get the version (git tag)
id: get_version id: get_version
run: | run: |
echo ${GITHUB_REF/refs\/tags\/v/} echo ${GITHUB_REF/refs\/tags\/v/}
echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/v/} echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/v/}
echo ::set-output name=FULL_TAG::${GITHUB_REF/refs\/tags\//} echo ::set-output name=FULL_TAG::${GITHUB_REF/refs\/tags\//}
- name: Get the repo data (git tag) - name: Get the repo data (git tag)
id: get_repo_data id: get_repo_data
run: | run: |
@ -85,40 +77,25 @@ jobs:
echo ::set-output name=AUTHOR::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $1}') echo ::set-output name=AUTHOR::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $1}')
echo ::set-output name=REPO_NAME::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}') echo ::set-output name=REPO_NAME::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}')
shell: bash shell: bash
- name: Create Release
id: create_release - name: Prepare release downloading
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Upload binary assets
run: | run: |
mkdir artifacts mkdir artifacts
- name: Download Linux binary - name: Download Linux binary
uses: actions/download-artifact@v1 uses: actions/download-artifact@v4
with: with:
name: desubot name: desubot
path: ./artifacts/ path: ./artifacts/
- name: Download Windows binary
uses: actions/download-artifact@v1
with:
name: desubot.exe
path: ./artifacts/
- name: Upload binary assets
run: |
wget https://github.com/aktau/github-release/releases/download/v0.7.2/linux-amd64-github-release.tar.bz2
tar xjf linux-amd64-github-release.tar.bz2
export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
for artifact in ./artifacts/*; do
./bin/linux/amd64/github-release upload \
-u ${{ steps.get_repo_data.outputs.AUTHOR }} \
-r ${{ steps.get_repo_data.outputs.REPO_NAME }} \
--tag ${{ steps.get_version.outputs.FULL_TAG }} \
--name ${artifact} \
--file ${artifact}
done
- name: Build
run: echo ${{ github.sha }} > Release.txt
- name: Test
run: cat Release.txt
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: './artifacts/*'

View File

@ -1,6 +1,6 @@
[package] [package]
name = "desubot" name = "desubot"
version = "0.5.8" version = "0.5.12"
authors = ["AB <ab@hexor.ru>"] authors = ["AB <ab@hexor.ru>"]
edition = "2018" edition = "2018"
@ -30,7 +30,7 @@ log = { version = "^0.4.5", features = ["std"] }
subprocess = "0.2.6" subprocess = "0.2.6"
serde_json = "1.0" serde_json = "1.0"
markov = "1.1.0" markov = "1.1.0"
rand = "0.7.3" rand = "0.8.5"
mystem = "^0.2" mystem = "^0.2"
#mystem = { path = "../mystem-rs" } #mystem = { path = "../mystem-rs" }
async-trait = "0.1.42" async-trait = "0.1.42"

View File

@ -1,11 +1,11 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM rust:latest AS builder FROM rust:bookworm AS builder
WORKDIR /desubot WORKDIR /desubot
ADD ./ /desubot/ ADD ./ /desubot/
RUN cargo build --release RUN cargo build --release
FROM ubuntu:latest FROM debian:bookworm
WORKDIR /storage WORKDIR /storage
COPY --from=builder /desubot/target/release/desubot /usr/bin/ COPY --from=builder /desubot/target/release/desubot /usr/bin/
COPY mystem /usr/bin/ COPY mystem /usr/bin/

View File

@ -1,20 +1,34 @@
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot?ref=badge_shield) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot?ref=badge_shield)
Desubot # Desubot Telegram Bot
Telegram bot with light group statistic and heavy spy features.
== Features == **Desubot** is a Telegram bot with light group statistics and powerful spy features.
* Collect all the messages sent to group.
* Collect all the media sent to group including voice, stickers, video, video notes, documents.
* /here command to mention all members.
* Alongside with saving whole message bot perform blacklist filter and stemming for every word (only Russian). "Красивую собаку мыли негры" -> "красивый собака мыть негр"
* Generate sentences using Markov Chains trained on history with /markov_all.
* Syntax highlighting for CODE exported to image.
== Important == ## Features
* 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.
- **Collect all messages**: The bot collects all messages sent to the group.
- **Collect all media**: The bot saves all media sent to the group, including voice messages, stickers, videos, video notes, and documents.
- **/here command**: Mention all group members.
- **Blacklist filter and stemming**: The bot saves the entire message, performs blacklist filtering, and stems every word (Russian only). For example, "Красивую собаку мыли негры" -> "красивый собака мыть негр".
- **Markov Chain sentence generation**: The bot generates sentences using Markov Chains trained on the history with the `/markov_all` command.
- **Syntax highlighting for CODE**: Export code with syntax highlighting to an image.
## Important
- **MyStem**: Desubot uses MyStem by Yandex for word stemming and assumes that the `mystem` binary is available in the PATH.
- **Ubuntu dependencies**: The following packages are required:
```bash
libssl-dev libsqlite3-dev cmake libfreetype-dev pkg-config
[Docker Hub](https://hub.docker.com/repository/docker/ultradesu/desubot/general)
![image](https://user-images.githubusercontent.com/4666566/150677613-32bdedf9-4b4c-4ec5-99cd-3d0221e56fb5.png)
![image](https://user-images.githubusercontent.com/4666566/150677660-183572b4-2a69-425f-a32c-dba5ec97e438.png)
## License ## License
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot?ref=badge_large) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot?ref=badge_large)

View File

@ -1,5 +1,5 @@
#[allow(dead_code)] #[allow(dead_code)]
static CODE_HELP: &str = "<b>Code highlighter</b> pub(crate) static CODE_HELP: &str = "<b>Code highlighter</b>
<i>Usage</i> <i>Usage</i>
<pre>/code <pre>/code
@ -7,7 +7,7 @@ static CODE_HELP: &str = "<b>Code highlighter</b>
#&lt;lang - JS by default&gt; #&lt;theme - Dracula by default&gt;</pre> #&lt;lang - JS by default&gt; #&lt;theme - Dracula by default&gt;</pre>
Language may be defined by both name and extension - Rust, rs... Language may be defined by both name and extension - Rust, rs...
Max lines - 80 Max length - 4000
List of themes: List of themes:
1337 1337

View File

@ -11,6 +11,10 @@
т т
у у
я я
чо
че
ща
ваще
бы бы
stat stat
вообще вообще

View File

@ -21,6 +21,7 @@ use syntect::highlighting::Theme;
use syntect::parsing::SyntaxReference; use syntect::parsing::SyntaxReference;
use syntect::util::LinesWithEndings; use syntect::util::LinesWithEndings;
use telegram_bot::prelude::*; use telegram_bot::prelude::*;
use telegram_bot::*;
use telegram_bot::{Api, Message, ParseMode, UserId}; use telegram_bot::{Api, Message, ParseMode, UserId};
include!("../assets/help_text.rs"); include!("../assets/help_text.rs");
@ -31,6 +32,12 @@ pub struct Here {
pub struct Top { pub struct Top {
pub data: String, pub data: String,
} }
pub struct ConfTop {
pub data: String,
}
pub struct GlobalTop {
pub data: String,
}
pub struct MarkovAll { pub struct MarkovAll {
pub data: String, pub data: String,
} }
@ -46,6 +53,9 @@ pub struct Sql {
pub struct Code { pub struct Code {
pub data: String, pub data: String,
} }
pub struct Scheme {
pub data: String,
}
#[async_trait] #[async_trait]
pub trait Execute { pub trait Execute {
@ -59,6 +69,68 @@ pub trait Execute {
) -> Result<(), Error>; ) -> 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] #[async_trait]
impl Execute for Sql { impl Execute for Sql {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> { 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] #[async_trait]
impl Execute for MarkovAll { impl Execute for MarkovAll {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> { async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
@ -289,7 +439,7 @@ impl Execute for MarkovAll {
chain.feed(messages); chain.feed(messages);
let mut sentences = chain.generate(); let mut sentences = chain.generate();
let mut msg = String::new(); let mut msg = String::new();
for _ in 1..rand::thread_rng().gen_range(2, 10) { for _ in 1..rand::thread_rng().gen_range(2..10) {
msg = format!("{} {}", msg, sentences.pop().unwrap()); msg = format!("{} {}", msg, sentences.pop().unwrap());
} }
match api match api
@ -327,7 +477,7 @@ impl Execute for Markov {
chain.feed(messages); chain.feed(messages);
let mut sentences = chain.generate(); let mut sentences = chain.generate();
let mut msg = String::new(); let mut msg = String::new();
for _ in 1..rand::thread_rng().gen_range(2, 10) { for _ in 1..rand::thread_rng().gen_range(2..10) {
msg = format!("{} {}", msg, sentences.pop().unwrap_or(" ".into())); msg = format!("{} {}", msg, sentences.pop().unwrap_or(" ".into()));
} }
match api match api
@ -571,9 +721,6 @@ impl Execute for Code {
.split("\n") .split("\n")
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(); .collect();
if lines.len() >= 81 {
return Err(CodeHighlightningError);
}
let last_line = &lines[lines.len() - 1]; let last_line = &lines[lines.len() - 1];
let tags = last_line let tags = last_line
@ -613,7 +760,7 @@ impl Execute for Code {
.collect(); .collect();
let theme = if theme.len() != 1 { let theme = if theme.len() != 1 {
ts.themes.get("Dracula").unwrap() ts.themes.get("gruvbox").unwrap()
} else { } else {
theme[0] theme[0]
}; };

View File

@ -1,3 +1,5 @@
#[allow(unused_mut)]
#[allow(dead_code)]
use crate::errors; use crate::errors;
use crate::utils; use crate::utils;
use rusqlite::{named_params, params, Connection, Error, Result}; use rusqlite::{named_params, params, Connection, Error, Result};
@ -35,18 +37,23 @@ pub(crate) fn update_scheme() -> Result<()> {
} }
pub(crate) fn load_stopwords() -> Result<()> { pub(crate) fn load_stopwords() -> Result<()> {
info!("Populating stop words wait please.");
let conn = open()?; 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(); let word = table.trim();
if word != "" { if word != "" {
let mut stmt = conn.prepare_cached( let mut _stmt = conn
.prepare_cached(
" "
INSERT OR IGNORE INTO INSERT OR IGNORE INTO
stop_words('word') stop_words('word')
VALUES (:word) VALUES (:word)
", ",
)?.insert(params![word]); )?
//let mut rows = stmt.word(named_params! {":conf_id": conf_id})?; .insert(params![word]);
} }
} }
info!("Stop words updated."); info!("Stop words updated.");
@ -505,3 +512,56 @@ pub(crate) async fn get_top(
} }
Ok(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)
}

View File

@ -1,5 +1,7 @@
//use crate::commands::Command; //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::db;
use crate::errors; use crate::errors;
use crate::utils; use crate::utils;
@ -38,11 +40,30 @@ pub async fn handler(
.await .await
} { } {
Ok(path) => { 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()); let file = InputFileUpload::with_path(path.clone());
info!("lines: {}, chars: {}", cnt_lines, cnt_chars);
// api.send(message.chat.document(&file)).await?; // api.send(message.chat.document(&file)).await?;
// //
// // Send an image from disk // // Send an image from disk
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?; api.send(message.chat.photo(&file)).await?;
} else {
api.send(message.chat.document(&file)).await?;
}
//debug!("{:#?}", formatter); //debug!("{:#?}", formatter);
let _ = std::fs::remove_file(&path); let _ = std::fs::remove_file(&path);
} }
@ -57,6 +78,8 @@ pub async fn handler(
|| s.contains("@here") || s.contains("@here")
|| s.contains("/хере") || s.contains("/хере")
|| s.contains("@хере") || s.contains("@хере")
|| s.contains("@all")
|| s.contains("\"руку")
|| s.contains("\"хере") => || s.contains("\"хере") =>
{ {
db::add_sentence(&message, mystem).await?; db::add_sentence(&message, mystem).await?;
@ -88,15 +111,22 @@ pub async fn handler(
.await?; .await?;
} }
}, },
"/top" => { "/top" | "/stat" => {
Top { Top {
data: "".to_string(), data: "".to_string(),
} }
.exec(&api, &message) .exec(&api, &message)
.await? .await?
} }
"/stat" => { "/global_top" | "/global_stat" => {
Top { GlobalTop {
data: "".to_string(),
}
.exec(&api, &message)
.await?
}
"/conf_stat" | "/conf_top" => {
ConfTop {
data: "".to_string(), data: "".to_string(),
} }
.exec(&api, &message) .exec(&api, &message)
@ -110,11 +140,28 @@ pub async fn handler(
.await? .await?
} }
"/markov" => { "/markov" => {
if title != "PRIVATE" {
Markov { Markov {
data: "".to_string(), data: "".to_string(),
} }
.exec(&api, &message) .exec(&api, &message)
.await? .await?
} else {
let _ = api
.send(
message
.text_reply("Allowed in groups only")
.parse_mode(ParseMode::Html),
)
.await?;
}
}
"/scheme" | "/schema" => {
Scheme {
data: "".to_string(),
}
.exec(&api, &message)
.await?
} }
"/omedeto" => { "/omedeto" => {
Omedeto { Omedeto {