foxbot/src/handlers/photo.rs

138 lines
4.0 KiB
Rust

use super::Status::*;
use crate::needs_field;
use async_trait::async_trait;
use telegram::*;
use crate::utils::{continuous_action, find_best_photo, get_message, match_image};
pub struct PhotoHandler;
#[async_trait]
impl super::Handler for PhotoHandler {
fn name(&self) -> &'static str {
"photo"
}
async fn handle(
&self,
handler: &crate::MessageHandler,
update: &Update,
_command: Option<&Command>,
) -> Result<super::Status, failure::Error> {
let message = needs_field!(update, message);
let photos = needs_field!(message, photo);
let now = std::time::Instant::now();
if message.chat.chat_type != ChatType::Private {
return Ok(Ignored);
}
let action = continuous_action(
handler.bot.clone(),
12,
message.chat_id(),
message.from.clone(),
ChatAction::Typing,
);
let best_photo = find_best_photo(&photos).unwrap();
let matches = match_image(&handler.bot, &handler.conn, &handler.fapi, &best_photo).await?;
let first = match matches.get(0) {
Some(item) => item,
_ => {
no_results(&handler, &message, now).await?;
return Ok(Completed);
}
};
let similar: Vec<&fautil::File> = matches
.iter()
.skip(1)
.take_while(|m| m.distance.unwrap() == first.distance.unwrap())
.collect();
tracing::debug!("match has distance of {}", first.distance.unwrap());
let name = if first.distance.unwrap() < 5 {
"reverse-good-result"
} else {
"reverse-bad-result"
};
let mut args = fluent::FluentArgs::new();
args.insert(
"distance",
fluent::FluentValue::from(first.distance.unwrap()),
);
if similar.is_empty() {
args.insert("link", fluent::FluentValue::from(first.url()));
} else {
let mut links = vec![format!("· {}", first.url())];
links.extend(similar.iter().map(|s| format!("· {}", s.url())));
let mut s = "\n".to_string();
s.push_str(&links.join("\n"));
args.insert("link", fluent::FluentValue::from(s));
}
let text = handler
.get_fluent_bundle(
message.from.as_ref().unwrap().language_code.as_deref(),
|bundle| get_message(&bundle, name, Some(args)).unwrap(),
)
.await;
drop(action);
let send_message = SendMessage {
chat_id: message.chat_id(),
text,
disable_web_page_preview: Some(first.distance.unwrap() > 5),
reply_to_message_id: Some(message.message_id),
..Default::default()
};
handler.bot.make_request(&send_message).await?;
let point = influxdb::Query::write_query(influxdb::Timestamp::Now, "source")
.add_tag("good", first.distance.unwrap() < 5)
.add_field("matches", matches.len() as i64)
.add_field("duration", now.elapsed().as_millis() as i64);
let _ = handler.influx.query(&point).await;
Ok(Completed)
}
}
async fn no_results(
handler: &crate::MessageHandler,
message: &Message,
start: std::time::Instant,
) -> failure::Fallible<()> {
let text = handler
.get_fluent_bundle(
message.from.as_ref().unwrap().language_code.as_deref(),
|bundle| get_message(&bundle, "reverse-no-results", None).unwrap(),
)
.await;
let send_message = SendMessage {
chat_id: message.chat_id(),
text,
reply_to_message_id: Some(message.message_id),
..Default::default()
};
handler.bot.make_request(&send_message).await?;
let point = influxdb::Query::write_query(influxdb::Timestamp::Now, "source")
.add_field("matches", 0)
.add_field("duration", start.elapsed().as_millis() as i64);
let _ = handler.influx.query(&point).await;
Ok(())
}