1
Fork 0
mirror of https://github.com/Steffo99/patched-porobot.git synced 2024-12-22 17:44:22 +00:00

Keep building the skeleton of the bot

This commit is contained in:
Steffo 2022-08-01 00:49:44 +02:00
parent 6810e1acc7
commit b14f85022b
Signed by: steffo
GPG key ID: 6965406171929D01
7 changed files with 137 additions and 25 deletions

View file

@ -15,3 +15,4 @@ pretty_env_logger = "0.4.0"
glob = "0.3.0"
itertools = "0.10.2"
tantivy = "0.18.0"
reqwest = "0.11.11"

View file

@ -1,5 +1,6 @@
//! This module contains functions to load **Set Bundles** from [Data Dragon](https://developer.riotgames.com/docs/lol).
use log::*;
use itertools::Itertools;
use crate::data::schema::Card;
@ -13,6 +14,7 @@ enum LoadingError {
/// Load a single Set Bundle and create a [Vec] with the cards contained in it.
fn load_setbundle(path: std::path::PathBuf) -> Result<Vec<Card>, LoadingError> {
debug!("Loading Set Bundle {:?}", &path);
let file = std::fs::File::open(path)
.map_err(LoadingError::IO)?;
let data = serde_json::de::from_reader::<std::fs::File, Vec<Card>>(file)

14
src/data/map.rs Normal file
View file

@ -0,0 +1,14 @@
use std::collections::HashMap;
use crate::data::schema::Card;
/// Build a [HashMap] mapping card codes strings to [Card] structs.
pub fn build_card_code_hashmap(cards: &Vec<Card>) -> HashMap<String, Card> {
let mut map = HashMap::<String, Card>::new();
for card in cards {
map.insert(card.card_code.to_owned(), card.to_owned());
}
map
}

View file

@ -1,2 +1,3 @@
pub mod schema;
pub mod load;
pub mod map;

View file

@ -1,52 +1,96 @@
#[macro_use] extern crate tantivy;
#[macro_use] extern crate log;
use teloxide::prelude::*;
use teloxide::types::*;
use log::*;
use tantivy::{IndexReader, ReloadPolicy};
use reqwest::Url;
use itertools::Itertools;
mod data;
mod search;
/// Run the bot.
#[tokio::main]
async fn main() {
pretty_env_logger::init();
debug!("Loading Set Bundles...");
let cards = data::load::load_setbundles_infallible("./data/*/en_us/data/*-en_us.json");
let cards = data::load::load_setbundles_infallible("./data/*/en_us/data/set*-en_us.json");
debug!("Loaded {} cards!", &cards.len());
debug!("Creating Tantivy index...");
debug!("Creating Card index...");
let card_index = search::index::build_card_index();
debug!("Card index created successfully!");
debug!("Writing cards to the index...");
debug!("Creating Card hashmap...");
let card_map = data::map::build_card_code_hashmap(&cards);
debug!("Card hashmap contains {} cards!", &card_map.len());
debug!("Writing Cards to the Card index...");
search::index::write_cards_to_index(&card_index, &cards);
debug!("Wrote Cards to the Card index!");
debug!("Creating Tantivy reader...");
debug!("Creating Card query parser...");
let card_query_parser = search::query::build_query_parser(&card_index);
debug!("Created Card query parser!");
debug!("Creating Card reader...");
let card_reader = search::index::build_reader(&card_index);
debug!("Created Card reader!");
let inline_query_closure = |query: InlineQuery, bot: AutoSend<Bot>| async move {
bot.answer_inline_query(&query.id, handle_query(&query, &card_reader)).await;
respond(())
};
info!("patched-porobot is starting...");
debug!("Creating Telegram Bot with parameters from the environment...");
let bot = Bot::from_env().auto_send();
let bot_me = bot.get_me().await.expect("Telegram Bot parameters to be valid");
debug!("Created Telegram Bot @{}!", &bot_me.username.as_ref().unwrap());
let handler = Update::filter_inline_query().branch(dptree::endpoint(inline_query_closure));
let handler = Update::filter_inline_query().branch(dptree::endpoint(move |query: InlineQuery, bot: AutoSend<Bot>| {
let card_schema = card_index.schema();
let card_query_parser = &card_query_parser;
let card_reader = &card_reader;
let card_map = &card_map;
let results = search::query::search_card(
&card_schema,
&card_query_parser,
&card_reader,
&card_map,
&query.query
);
async move {
let reply = results.iter()
/*
.map(|card| InlineQueryResult::Photo(InlineQueryResultPhoto {
id: card.card_code.to_owned(),
title: Some(card.name.to_owned()),
description: Some(card.description_raw.to_owned()),
caption: Some(card.description_raw.to_owned()),
photo_url: Url::parse( & card.assets.get(0).expect("card to have assets").game_absolute_path).expect("card to have a valid asset URL"),
thumb_url: Url::parse( & card.assets.get(0).expect("card to have assets").full_absolute_path).expect("card to have a valid asset URL"),
photo_width: None,
photo_height: None,
parse_mode: None,
caption_entities: None,
reply_markup: None,
input_message_content: None,
}))
*/
.map(|card| InlineQueryResult::Article(InlineQueryResultArticle::new(
card.card_code.to_owned(),
card.name.to_owned(),
InputMessageContent::Text(InputMessageContentText::new(
format!("<b>{}<b>\n\n{}", &card.name, &card.description_raw)
))
)))
.collect_vec();
if let Err(e) = bot.answer_inline_query(&query.id, reply).send().await {
error!("{:?}", e);
};
respond(())
}
}));
Dispatcher::builder(bot, handler).enable_ctrlc_handler().build().dispatch().await;
}
/// Handle a [InlineQuery] incoming from Telegram.
fn handle_query(query: &InlineQuery, reader: &IndexReader) -> Vec<InlineQueryResult> {
debug!("Creating Tantivy searcher...");
let card_searcher = reader.searcher();
let result = InlineQueryResult::Article(InlineQueryResultArticle::new("test", "Test", InputMessageContent::Text(InputMessageContentText::new("Qui è dove metterei la mia carta, se solo ne avessi una!"))));
vec![result]
}

View file

@ -1,2 +1,3 @@
pub mod schema;
pub mod index;
pub mod query;

49
src/search/query.rs Normal file
View file

@ -0,0 +1,49 @@
use log::*;
use std::collections::HashMap;
use tantivy::Index;
use tantivy::IndexReader;
use tantivy::LeasedItem;
use tantivy::Searcher;
use tantivy::collector::TopDocs;
use tantivy::query::QueryParser;
use tantivy::schema::Schema;
use crate::data::schema::Card;
use itertools::Itertools;
pub fn build_query_parser(index: &Index) -> QueryParser {
let schema = index.schema();
let name = schema.get_field("name").unwrap();
let description = schema.get_field("description").unwrap();
let code = schema.get_field("code").unwrap();
QueryParser::for_index(&index, vec![name, description, code])
}
pub fn build_searcher(reader: &IndexReader) -> LeasedItem<Searcher> {
reader.searcher()
}
pub fn search_card(schema: &Schema, parser: &QueryParser, reader: &IndexReader, map: &HashMap<String, Card>, q: &str) -> Vec<Card> {
debug!("Searching for `{}`...", &q);
let code = schema.get_field("code").unwrap();
debug!("Building Card searcher...");
let searcher = build_searcher(reader);
let query = parser.parse_query(q)
.expect("to be able to parse the query");
let search = searcher.search(&*query, &TopDocs::with_limit(50))
.expect("to be able to search for a card");
debug!("Retrieved {} results!", &search.len());
search.iter().filter_map(|(_score, address)| searcher.doc(address.to_owned()).ok())
.filter_map(|doc| doc.get_first(code).cloned())
.filter_map(|field| field.as_text().map(String::from))
.filter_map(|code| map.get(&*code))
.cloned()
.collect_vec()
}