Skip to content

Commit

Permalink
✨ Implement opt-out and user blacklisting (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisliebaer authored Feb 17, 2024
1 parent 12c94aa commit a6534b4
Show file tree
Hide file tree
Showing 14 changed files with 974 additions and 302 deletions.
587 changes: 318 additions & 269 deletions Cargo.lock

Large diffs are not rendered by default.

59 changes: 44 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
[workspace]
members = [".", "entity", "migration"]
resolver = "2"

[package]
name = "cheapt"
description = "OpenAI based chat bot for discord. Plain and simple. Requires OpenAI API key."
repository = "https://github.com/chrisliebaer/cheapt"
version = "0.1.0"
keywords = ["discord", "chat", "bot", "openai"]
edition = "2021"
license = "MIT"
categories = ["games"]
publish = false


[dependencies]
[workspace.dependencies]
entity = { path = "entity" }
migration = { path = "migration" }

async-trait = "0.1"
tracing = "0.1"
tracing-subscriber = "0.3"
miette = { version = "5.10", features = ["fancy"] }
miette = { version = "7.0", features = ["fancy"] }
semver = "1.0"
chrono = "0.4"
serde = "1.0"
toml = "0.8"
uuid = "1.6"
uuid = "1.7"
lazy_static = "1.4"
tokio = { version = "1.35", features = ["macros", "rt", "time"] }
sea-orm = { version = "0.12", features = ["sqlx-mysql", "runtime-tokio-rustls", "macros", "debug-print", "with-chrono", "with-uuid"] }
Expand All @@ -35,6 +24,46 @@ envconfig = "0.10"
poise = "0.6"
regex = "1.10"
tera = "1"
rand = "0.8"
humantime = "2.1"

[package]
name = "cheapt"
description = "OpenAI based chat bot for discord. Plain and simple. Requires OpenAI API key."
repository = "https://github.com/chrisliebaer/cheapt"
version = "0.1.0"
keywords = ["discord", "chat", "bot", "openai"]
edition = "2021"
license = "MIT"
categories = ["games"]
publish = false


[dependencies]
entity.workspace = true
migration.workspace = true

async-trait.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
miette.workspace = true
semver.workspace = true
chrono.workspace = true
serde.workspace = true
toml.workspace = true
uuid.workspace = true
lazy_static.workspace = true
tokio.workspace = true
sea-orm.workspace = true

async-openai.workspace = true
envconfig.workspace = true
poise.workspace = true
regex.workspace = true
tera.workspace = true
rand.workspace = true
humantime.workspace = true
log = "0.4.20"

[dev-dependencies]
ctor = "0.2"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ The bot is in a very early stage of development but already usable.
- Message caching
- Summarization for more context over multiple messages
- Tenor GIF support
- More permissions

## Environment Variables

Expand All @@ -29,6 +28,7 @@ The project requires the following environment variables:
- `RATE_LIMIT_CONFIG`: The path to your rate limit configuration file. Defaults to `rate_limits.toml`.
- `DATABASE_URL`: The URL to your database. For example `mysql://user:password@localhost/database`.
- `WHITELIST_CHANNEL`: A comma separated list of channel IDs that the bot is allowed to respond in. If not set, the bot will respond in all channels.
- `OPT_OUT_LOCKOUT`: The time in seconds a user is locked out from the bot after opting out. Defaults to `30d`. Can use any time format supported by the `humantime` crate.


## License
Expand Down
2 changes: 1 addition & 1 deletion entity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ name = "entity"
path = "src/lib.rs"

[dependencies]
sea-orm = { version = "0.12", features = ["sqlx-mysql", "runtime-tokio-rustls", "macros", "debug-print", "with-chrono", "with-uuid"] }
sea-orm.workspace = true
1 change: 1 addition & 0 deletions entity/src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub struct Model {
pub discord_user_id: u64,
#[sea_orm(column_type = "Text")]
pub username: String,
pub opt_out_since: Option<DateTimeUtc>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
Expand Down
4 changes: 2 additions & 2 deletions migration/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
pub use sea_orm_migration::prelude::*;

mod m20220101_000001_create_table;
mod m20240114_000001_create_table;

pub struct Migrator;

#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![Box::new(m20220101_000001_create_table::Migration)]
vec![Box::new(m20240114_000001_create_table::Migration)]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ impl MigrationTrait for Migration {
.col(ColumnDef::new(User::Uuid).uuid().not_null().unique_key())
.col(ColumnDef::new(User::DiscordUserId).big_unsigned().not_null().unique_key())
.col(ColumnDef::new(User::Username).text().not_null())
.col(ColumnDef::new(User::OptOutSince).timestamp().null())
.to_owned(),
)
.await?;
Expand Down Expand Up @@ -109,7 +110,12 @@ impl MigrationTrait for Migration {
.unique_key(),
)
.col(ColumnDef::new(Blacklist::Reason).text().not_null())
.col(ColumnDef::new(Blacklist::CreatedAt).timestamp().not_null())
.col(
ColumnDef::new(Blacklist::CreatedAt)
.timestamp()
.default(Expr::current_timestamp())
.not_null(),
)
.to_owned(),
)
.await?;
Expand Down Expand Up @@ -148,6 +154,9 @@ enum User {

/// Discord Username, not guaranteed to be unique, since users can change their name.
Username,

/// Timestamp when the user opted out. Can be null if the user never opted out.
OptOutSince,
}

/// Message cache.
Expand Down Expand Up @@ -200,7 +209,7 @@ enum RateLimit {
enum Blacklist {
Table,

/// Discord ID for primary key.
/// Database ID for primary key.
Id,

/// Discord ID of the user.
Expand Down
6 changes: 6 additions & 0 deletions src/context_extraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ impl InvocationContextSettings {
.into_diagnostic()
.wrap_err("failed to fetch reply chain window")?;

// filter out messages that are not from the same author as the replied message
let window = window
.into_iter()
.filter(|m| m.author.id == center.author.id)
.collect::<Vec<_>>();

// expand window around replied message by alternating between messages before and after the replied message
let expanding_window = {
let mut shrinking_window = Vec::<Message>::new();
Expand Down
Loading

0 comments on commit a6534b4

Please sign in to comment.