Skip to content

Commit

Permalink
improve error message, customizable listen port, fix set tagging, oth…
Browse files Browse the repository at this point in the history
…er minor improvements
  • Loading branch information
avoonix committed Jun 24, 2024
1 parent 5a2ad5b commit 00d1f71
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 82 deletions.
38 changes: 24 additions & 14 deletions fuzzle/src/bot/bot_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ pub enum InternalError {
Other(#[from] anyhow::Error),
}

#[derive(PartialEq)]
pub enum UserErrorSeverity {
Error,
Info,
}

impl InternalError {
pub fn is_timeout_error(&self) -> bool {
match self {
Expand Down Expand Up @@ -77,33 +83,37 @@ pub enum UserError {
ParseError(usize, String),

#[error("tags did not closely match existing tags")]
TagsNotFound(Vec<String>)
TagsNotFound(Vec<String>),

#[error("no results found")]
ListHasZeroResults(String),
}

impl InternalError {
pub fn end_user_error(&self) -> String {
"Aw, something's wrong. ".to_string()
pub fn end_user_error(&self) -> (String, UserErrorSeverity) {
("Aw, something's wrong. ".to_string(), UserErrorSeverity::Error)
}
}

impl UserError {
pub fn end_user_error(&self) -> String {
pub fn end_user_error(&self) -> (String, UserErrorSeverity) {
match self {
UserError::NoPermissionForAction(action) => format!("Oh no, I can't let you do this ({action}) yet."),
UserError::InvalidMode => "Can't do that here!".to_string(),
UserError::UnsupportedStickerType => "Those don't look like regular stickers.".to_string(),
UserError::StickerNotPartOfSet => "Stickers must be part of a set!".to_string(),
UserError::UnhandledMessageType => "I have no idea what to do with this. Send me text messages containing commands, stickers, or t.me/addsticker links!".to_string(),
UserError::CommandError(ParseError::UnknownCommand(input)) => format!("What the heck is a \"{input}\"?"),
UserError::CommandError(error) => "Invalid arguments!".to_string(),
UserError::ParseError(position, rest) => format!("Invalid input at position {position}: {}", rest.chars().take(10).collect::<String>()),
UserError::TagsNotFound(tags) => format!("Could not find tags: {}", tags.join(", ")),
UserError::NoPermissionForAction(action) => (format!("Oh no, I can't let you do this ({action}) yet."), UserErrorSeverity::Error),
UserError::InvalidMode => ("Can't do that here!".to_string(), UserErrorSeverity::Info),
UserError::UnsupportedStickerType => ("Those don't look like regular stickers.".to_string(), UserErrorSeverity::Error),
UserError::StickerNotPartOfSet =>( "Stickers must be part of a set!".to_string(), UserErrorSeverity::Error),
UserError::UnhandledMessageType =>( "I have no idea what to do with this. Send me text messages containing commands, stickers, or t.me/addsticker links!".to_string(),UserErrorSeverity::Error),
UserError::CommandError(ParseError::UnknownCommand(input)) => (format!("What the heck is a \"{input}\"?"),UserErrorSeverity::Error),
UserError::CommandError(error) => ("Invalid arguments!".to_string(),UserErrorSeverity::Error),
UserError::ParseError(position, rest) => (format!("Invalid input at position {position}: {}", rest.chars().take(10).collect::<String>()),UserErrorSeverity::Error),
UserError::TagsNotFound(tags) => (format!("Could not find tags: {}", tags.join(", ")),UserErrorSeverity::Error),
UserError::ListHasZeroResults(name) => (format!("No {name} here :("),UserErrorSeverity::Info),
}
}
}

impl BotError {
pub fn end_user_error(&self) -> String {
pub fn end_user_error(&self) -> (String, UserErrorSeverity) {
match self {
BotError::InternalError(err) => err.end_user_error(),
BotError::UserError(err) => err.end_user_error(),
Expand Down
1 change: 1 addition & 0 deletions fuzzle/src/bot/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Config {
pub inference_url: String,

pub domain_name: String,
pub http_listen_address: String,

pub admin_telegram_user_id: u64,
pub telegram_bot_token: String,
Expand Down
7 changes: 4 additions & 3 deletions fuzzle/src/callback/callback_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use teloxide::types::{
InlineKeyboardMarkup, InputFile, MediaKind, MessageCommon, MessageKind, ReplyMarkup,
};

use crate::bot::{report_bot_error, report_internal_error, report_internal_error_result, BotError, BotExt, RequestContext, UserError};
use crate::bot::{report_bot_error, report_internal_error, report_internal_error_result, BotError, BotExt, RequestContext, UserError, UserErrorSeverity};
use crate::callback::TagOperation;

use crate::database::{MergeStatus};
Expand Down Expand Up @@ -199,9 +199,10 @@ pub async fn show_error(
request_context: RequestContext,
error: BotError,
) -> Result<(), BotError> {
let error = error.end_user_error();
request_context.bot.answer_callback_query(&q.id)
.text(error.end_user_error())
.show_alert(true)
.text(error.0)
.show_alert(error.1 == UserErrorSeverity::Error)
.into_future()
.instrument(tracing::info_span!("telegram_bot_answer_callback_query"))
.await?;
Expand Down
5 changes: 3 additions & 2 deletions fuzzle/src/database/queries/sticker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ impl Database {
Ok(result)
}

/// including itself (so there's always at least one entry in the list)
#[tracing::instrument(skip(self), err(Debug))]
pub async fn get_overlapping_sets(
&self,
Expand All @@ -321,7 +322,7 @@ impl Database {
let (sticker1, sticker2) = diesel::alias!(sticker as sticker1, sticker as sticker2);
Ok(sticker1
.group_by(sticker1.field(sticker::sticker_set_id))
.filter(sticker1.field(sticker::sticker_set_id).ne(&set_id))
// .filter(sticker1.field(sticker::sticker_set_id).ne(&set_id))
.filter(
sticker1.field(sticker::sticker_file_id).eq_any(
sticker2
Expand Down Expand Up @@ -481,7 +482,7 @@ impl Database {
) -> Result<(), DatabaseError> {
Ok(self.pool.get()?.transaction(|conn| {
let stickers_affected_merge = sql_query("INSERT INTO merged_sticker (canonical_sticker_file_id, removed_sticker_file_id, removed_sticker_id, removed_set_id, created_by_user_id)
SELECT ?1, sticker_file_id, id, set_id, ?2 FROM sticker WHERE sticker_file_id = ?3")
SELECT ?1, sticker_file_id, id, sticker_set_id, ?2 FROM sticker WHERE sticker_file_id = ?3")
.bind::<Text, _>(canonical_file_id)
.bind::<Nullable<BigInt>, _>(user_id)
.bind::<Text, _>(duplicate_file_id)
Expand Down
2 changes: 1 addition & 1 deletion fuzzle/src/database/queries/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl Database {
// TODO: translate to proper diesel query?
tags_affected += sql_query("INSERT INTO sticker_file_tag (sticker_file_id, tag, added_by_user_id)
SELECT DISTINCT sticker_file_id, ?1, ?2 FROM sticker
WHERE set_id = ?3 AND NOT EXISTS (SELECT * FROM sticker_file WHERE sticker.sticker_file_id = sticker_file.id AND sticker_file.tags_locked_by_user_id IS NOT NULL)
WHERE sticker.sticker_set_id = ?3 AND NOT EXISTS (SELECT * FROM sticker_file WHERE sticker.sticker_file_id = sticker_file.id AND sticker_file.tags_locked_by_user_id IS NOT NULL)
ON CONFLICT (sticker_file_id, tag) DO NOTHING")
.bind::<Text, _>(tag)
.bind::<BigInt, _>(user)
Expand Down
44 changes: 36 additions & 8 deletions fuzzle/src/inline/inline_query_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ async fn search_tags_for_sticker_set(
)
})
.collect::<Result<Vec<_>, _>>()?;
require_some_results("tags", current_offset, results.len())?;
request_context
.bot
.answer_inline_query(q.id, results.clone())
Expand All @@ -192,6 +193,14 @@ async fn search_tags_for_sticker_set(
Ok(())
}

fn require_some_results(name: &str, offset: QueryPage, current_result_count: usize) -> Result<(), UserError> {
if offset.is_first_page() && current_result_count == 0 {
Err(UserError::ListHasZeroResults(name.to_string()))
} else {
Ok(())
}
}

async fn search_tags_for_sticker(
current_offset: QueryPage,
tags: Vec<Vec<String>>,
Expand Down Expand Up @@ -229,6 +238,7 @@ async fn search_tags_for_sticker(
)
})
.collect::<Result<Vec<_>, _>>()?;
require_some_results("tags", current_offset, results.len())?;
request_context
.bot
.answer_inline_query(q.id, results.clone())
Expand Down Expand Up @@ -345,12 +355,11 @@ async fn handle_similar_sticker_query(
// TODO: cache?
// TODO: blacklist?
let result = compute_similar(
request_context.database.clone(),
request_context.clone(),
sticker_unique_id,
aspect,
current_offset.page_size() as u64,
current_offset.skip() as u64,
request_context.vector_db.clone(),
)
.await?;
let sticker_ids = result.into_iter().map(|m| m.sticker_id).collect_vec();
Expand All @@ -371,6 +380,7 @@ async fn handle_similar_sticker_query(
})
.collect_vec();

require_some_results("stickers", current_offset, sticker_result.len())?;
request_context
.bot
.answer_inline_query(q.id, sticker_result.clone())
Expand Down Expand Up @@ -416,6 +426,7 @@ async fn search_stickers(
})
.collect_vec();

require_some_results("stickers", current_offset, sticker_result.len())?;
request_context
.bot
.answer_inline_query(q.id, sticker_result.clone())
Expand Down Expand Up @@ -457,6 +468,7 @@ async fn search_tags_for_blacklist(
})
.collect::<Result<Vec<_>, _>>()?;

require_some_results("tags", current_offset, results.len())?;
request_context
.bot
.answer_inline_query(q.id, results.clone())
Expand Down Expand Up @@ -503,6 +515,7 @@ async fn handle_continuous_tag_query(
})
.collect::<Result<Vec<_>, _>>()?;

require_some_results("tags", current_offset, results.len())?;
request_context
.bot
.answer_inline_query(q.id, results.clone())
Expand Down Expand Up @@ -534,17 +547,21 @@ pub async fn show_error(
request_context: RequestContext,
error: BotError,
) -> Result<(), BotError> {
let thumbnail_url =
format!("https://placehold.co/{THUMBNAIL_SIZE}/ff0000/white.png?text=Error");
let error = error.end_user_error();
let (text, color) = match error.1 {
crate::bot::UserErrorSeverity::Error => ("Error", "red"),
crate::bot::UserErrorSeverity::Info => (\\_(ツ)_/¯", "lightblue")
};
let thumbnail_url = format!("https://placehold.co/{THUMBNAIL_SIZE}/{color}/black.png?text={text}");
let thumbnail_url = Url::parse(&thumbnail_url)?;

let content = InputMessageContent::Text(InputMessageContentText::new(Markdown::escaped(
error.end_user_error(),
&error.0,
)));

let error_message = InlineQueryResultArticle::new(
InlineQueryResultId::Other("error".to_string()).to_string(),
error.end_user_error(),
&error.0,
content,
)
.thumb_url(thumbnail_url)
Expand Down Expand Up @@ -662,6 +679,7 @@ async fn handle_sticker_contained_query(
.map(|set| create_query_set(set, None, None))
.collect::<Result<Vec<_>, _>>()?;

require_some_results("sets", current_offset, results.len())?;
request_context
.bot
.answer_inline_query(q.id, results.clone())
Expand Down Expand Up @@ -702,6 +720,7 @@ async fn handle_all_set_tags(
})
.collect::<Result<Vec<_>, _>>()?;

require_some_results("tags", current_offset, r.len())?;
request_context
.bot
.answer_inline_query(q.id, r.clone())
Expand All @@ -723,6 +742,7 @@ async fn handle_overlapping_sets(
.get_sticker_set_by_sticker_id(&sticker_id)
.await?
.required()?;
let set_sticker_count = request_context.database.get_all_stickers_in_set(&set.id).await?.len().max(1); // TODO: separate query would probably be more efficient
let sets = request_context
.database
.get_overlapping_sets(set.id)
Expand All @@ -745,12 +765,16 @@ async fn handle_overlapping_sets(
Some(if count == 1 {
"1 overlapping sticker".to_string()
} else {
format!("{} overlapping stickers", count)
format!("{count}/{set_sticker_count} overlapping stickers")
}),
Some({
let percentage = (((count as f32 / set_sticker_count as f32) * 100.0).round() as i64);
format!("{percentage}%")
}),
Some(count.to_string()),
)?);
}

require_some_results("sets", current_offset, r.len())?;
request_context
.bot
.answer_inline_query(q.id, r.clone())
Expand Down Expand Up @@ -826,6 +850,7 @@ async fn handle_embedding_query(
})
.collect_vec();

require_some_results("stickers", current_offset, sticker_result.len())?;
request_context
.bot
.answer_inline_query(q.id, sticker_result.clone())
Expand Down Expand Up @@ -878,6 +903,7 @@ async fn handle_most_used_emojis(
})
.collect::<Result<Vec<_>, _>>()?;

require_some_results("emojis", current_offset, articles.len())?;
request_context
.bot
.answer_inline_query(q.id, articles.clone())
Expand Down Expand Up @@ -914,6 +940,7 @@ async fn handle_most_duplicated_stickers(
})
.collect_vec();

require_some_results("stickers", current_offset, sticker_result.len())?;
request_context
.bot
.answer_inline_query(q.id, sticker_result.clone())
Expand Down Expand Up @@ -983,6 +1010,7 @@ async fn handle_recommendations(
})
.collect_vec();

require_some_results("stickers", current_offset, sticker_result.len())?;
request_context
.bot
.answer_inline_query(q.id, sticker_result.clone())
Expand Down
4 changes: 4 additions & 0 deletions fuzzle/src/inline/pagination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ impl QueryPage {
pub fn seed(&self) -> i32 {
self.seed
}

pub fn is_first_page(&self) -> bool {
self.current_offset == 0
}
}
2 changes: 1 addition & 1 deletion fuzzle/src/message/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ InlineKeyboardButton::switch_inline_query_current_chat(
CallbackData::NoAction,
)],
[InlineKeyboardButton::switch_inline_query_current_chat(
format!("🪞 Duplicates from other sets"),
format!("🪞 Set overlaps"),
InlineQueryData::overlapping_sets(sticker_id.to_string()),
)],
[InlineKeyboardButton::switch_inline_query_current_chat(
Expand Down
7 changes: 6 additions & 1 deletion fuzzle/src/message/message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,14 @@ pub async fn show_error(
request_context: RequestContext,
error: BotError,
) -> Result<(), BotError> {
let error = error.end_user_error();
let icon = match error.1 {
crate::bot::UserErrorSeverity::Error => "⚠️",
crate::bot::UserErrorSeverity::Info => "ℹ️",
};
request_context
.bot
.send_markdown(msg.chat.id, Markdown::escaped(error.end_user_error()))
.send_markdown(msg.chat.id, Markdown::escaped(format!("{icon} {}", error.0)))
.reply_to_message_id(msg.id)
.allow_sending_without_reply(true)
.disable_notification(false)
Expand Down
Loading

0 comments on commit 00d1f71

Please sign in to comment.