Skip to content

Commit

Permalink
Initial attempt at transcribe-only role
Browse files Browse the repository at this point in the history
  • Loading branch information
tazz4843 committed Dec 2, 2023
1 parent 739d7bc commit 4fc893c
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Add migration script here
ALTER TABLE guilds ADD COLUMN transcript_only_role BIGINT DEFAULT NULL;
42 changes: 27 additions & 15 deletions scripty_audio_handler/src/audio_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use dashmap::{DashMap, DashSet};
use parking_lot::RwLock;
use scripty_automod::types::AutomodServerConfig;
use serenity::{
all::RoleId,
client::Context,
model::{
id::{ChannelId, GuildId},
Expand Down Expand Up @@ -49,20 +50,21 @@ pub type ArcSsrcMaps = Arc<SsrcMaps>;

#[derive(Clone)]
pub struct AudioHandler {
ssrc_state: Arc<SsrcMaps>,
guild_id: GuildId,
channel_id: ChannelId,
voice_channel_id: ChannelId,
thread_id: Option<ChannelId>,
webhook: Arc<Webhook>,
context: Context,
premium_level: Arc<AtomicU8>,
verbose: Arc<AtomicBool>,
language: Arc<RwLock<String>>,
transcript_results: TranscriptResults,
seen_users: SeenUsers,
automod_server_cfg: Arc<AutomodServerConfig>,
auto_detect_lang: Arc<AtomicBool>,
ssrc_state: ArcSsrcMaps,
guild_id: GuildId,
channel_id: ChannelId,
voice_channel_id: ChannelId,
thread_id: Option<ChannelId>,
webhook: Arc<Webhook>,
context: Context,
premium_level: Arc<AtomicU8>,
verbose: Arc<AtomicBool>,
language: Arc<RwLock<String>>,
transcript_results: TranscriptResults,
seen_users: SeenUsers,
automod_server_cfg: Arc<AutomodServerConfig>,
auto_detect_lang: Arc<AtomicBool>,
transcribe_only_role: Arc<RwLock<Option<RoleId>>>,
}

impl AudioHandler {
Expand Down Expand Up @@ -103,6 +105,7 @@ impl AudioHandler {
.then(|| Arc::new(DashSet::with_hasher(RandomState::new()))),
automod_server_cfg: Arc::new(automod_server_cfg),
auto_detect_lang: Arc::new(AtomicBool::new(false)),
transcribe_only_role: Arc::new(RwLock::new(None)),
};
this.reload_config().await?;

Expand All @@ -129,7 +132,8 @@ impl AudioHandler {
pub async fn reload_config(&self) -> Result<(), sqlx::Error> {
let db = scripty_db::get_db();
let mut guild_res = sqlx::query!(
"SELECT be_verbose, language, auto_detect_lang FROM guilds WHERE guild_id = $1",
"SELECT be_verbose, language, auto_detect_lang, transcript_only_role FROM guilds \
WHERE guild_id = $1",
self.guild_id.get() as i64
)
.fetch_one(db)
Expand All @@ -146,6 +150,12 @@ impl AudioHandler {
self.auto_detect_lang.store(false, Ordering::Relaxed);
}
std::mem::swap(&mut *self.language.write(), &mut guild_res.language);
std::mem::swap(
&mut *self.transcribe_only_role.write(),
&mut guild_res
.transcript_only_role
.map(|x| RoleId::new(x as u64)),
);

Ok(())
}
Expand All @@ -160,6 +170,8 @@ impl EventHandler for AudioHandler {
self.context.clone(),
Arc::clone(&self.ssrc_state),
self.seen_users.clone(),
self.guild_id,
self.transcribe_only_role.read().clone(),
)),
EventContext::VoiceTick(voice_data) => tokio::spawn(voice_tick(
voice_data.clone(),
Expand Down
2 changes: 1 addition & 1 deletion scripty_audio_handler/src/events/client_disconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub async fn client_disconnect(
ssrc_state.ssrc_stream_map.remove(&ssrc);
ssrc_state.ssrc_ignored_map.remove(&ssrc);
ssrc_state.ssrc_voice_ingest_map.remove(&ssrc);
let Some((_, (username, avatar_url))) = ssrc_state.ssrc_user_data_map.remove(&ssrc) else {
let Some((_, (username, avatar_url, _))) = ssrc_state.ssrc_user_data_map.remove(&ssrc) else {
warn!(%ssrc, "got no user data for ssrc");
return;
};
Expand Down
17 changes: 15 additions & 2 deletions scripty_audio_handler/src/events/speaking_state_update.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use serenity::prelude::Context;
use serenity::{
all::{GuildId, RoleId},
prelude::Context,
};
use songbird::model::payload::Speaking;

use crate::{audio_handler::ArcSsrcMaps, types::SeenUsers};
Expand All @@ -8,6 +11,8 @@ pub async fn speaking_state_update(
ctx: Context,
ssrc_state: ArcSsrcMaps,
seen_users: SeenUsers,
guild_id: GuildId,
transcribe_only_role: Option<RoleId>,
) {
let ssrc = state_update.ssrc;
debug!(?state_update.speaking, ?state_update.ssrc, ?state_update.user_id, "SpeakingStateUpdate event fired");
Expand Down Expand Up @@ -50,8 +55,16 @@ pub async fn speaking_state_update(
}
};

let has_role = if let Some(transcribe_only_role) = transcribe_only_role {
user.has_role(&ctx, guild_id, transcribe_only_role)
.await
.unwrap_or(true) // shouldn't happen often, but if it does, assume they have the role
} else {
true
};

let ignored = user.bot;
let user_data = (user.tag(), user.face());
let user_data = (user.tag(), user.face(), has_role);

ssrc_state.ssrc_ignored_map.insert(ssrc, ignored);
ssrc_state.ssrc_user_data_map.insert(ssrc, user_data);
Expand Down
9 changes: 9 additions & 0 deletions scripty_audio_handler/src/events/voice_tick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,15 @@ async fn handle_speakers(
continue;
}

// user does not have the transcribe-only role, so we can skip them
if ssrc_state
.ssrc_user_data_map
.get(&ssrc)
.map_or(false, |x| x.value().2)
{
continue;
}

// add to those speaking this tick
ssrc_state.ssrc_speaking_set.insert(ssrc);

Expand Down
5 changes: 4 additions & 1 deletion scripty_audio_handler/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use dashmap::{DashMap, DashSet};
use parking_lot::RwLock;
use scripty_data_storage::VoiceIngest;
use scripty_stt::Stream;
use serenity::all::RoleId;

/// Type alias for a `DashMap` containing SSRCs mapped to `UserId`s.
pub type SsrcUserIdMap = DashMap<u32, u64, RandomState>;
Expand All @@ -17,7 +18,9 @@ pub type SsrcStreamMap = DashMap<u32, Stream, RandomState>;
/// Field 0 of the internal tuple is the formatted username (name#0000)
///
/// Field 1 of the internal tuple is the user's avatar URL
pub type SsrcUserDataMap = DashMap<u32, (String, String), RandomState>;
///
/// Field 2 of the internal tuple is whether the user has the transcribe-only role
pub type SsrcUserDataMap = DashMap<u32, (String, String, bool), RandomState>;

/// Type alias for a `DashMap` containing SSRCs mapped to whether they should be ignored
pub type SsrcIgnoredMap = DashMap<u32, bool, RandomState>;
Expand Down
2 changes: 2 additions & 0 deletions scripty_commands/src/cmds/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod auto_detect_lang;
mod language;
mod transcribe_audio;
mod transcribe_only_role;
mod transcribe_video;
mod transcribe_voice_messages;
mod verbose;
Expand All @@ -11,6 +12,7 @@ use poise::CreateReply;
use scripty_bot_utils::{checks::is_guild, Context, Error};
use serenity::builder::CreateEmbed;
pub use transcribe_audio::config_transcribe_audio;
pub use transcribe_only_role::config_transcribe_only_role;
pub use transcribe_video::config_transcribe_video;
pub use transcribe_voice_messages::config_transcribe_voice_messages;
pub use verbose::config_verbose;
Expand Down
49 changes: 49 additions & 0 deletions scripty_commands/src/cmds/config/transcribe_only_role.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use poise::CreateReply;
use scripty_bot_utils::{checks::is_guild, Context, Error};
use serenity::{all::RoleId, builder::CreateAllowedMentions};

/// Limit Scripty's transcriptions to only users with this role in a voice chat.
#[poise::command(
prefix_command,
slash_command,
check = "is_guild",
required_permissions = "MANAGE_GUILD",
rename = "transcribe_only_role"
)]
pub async fn config_transcribe_only_role(
ctx: Context<'_>,
#[description = "Role to limit to: set empty to disable."] transcribe_only_role: Option<RoleId>,
) -> Result<(), Error> {
let guild_id = ctx
.guild_id()
.map(|g| g.get())
.ok_or_else(Error::expected_guild)?;
let resolved_language =
scripty_i18n::get_resolved_language(ctx.author().id.get(), Some(guild_id)).await;

sqlx::query!(
"INSERT INTO guilds (guild_id, transcript_only_role) VALUES ($1, $2) ON CONFLICT \
(guild_id) DO UPDATE SET transcript_only_role = $2",
guild_id as i64,
transcribe_only_role.map(|x| x.get() as i64)
)
.execute(scripty_db::get_db())
.await?;

ctx.send(
CreateReply::new()
.allowed_mentions(CreateAllowedMentions::new().empty_roles())
.content(format_message!(
resolved_language,
if transcribe_only_role.is_some() {
"config-transcribe-only-role-enabled"
} else {
"config-transcribe-only-role-disabled"
},
roleId: transcribe_only_role.map_or(0, |x| x.get() as i64)
)),
)
.await?;

Ok(())
}
1 change: 1 addition & 0 deletions scripty_commands/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub fn build_commands() -> Vec<poise::Command<Data, Error>> {
cmds::config::config_transcribe_voice_messages(),
cmds::config::config_verbose(),
cmds::config::config_auto_detect_lang(),
cmds::config::config_transcribe_only_role(),
],
subcommand_required: true,
..cmds::config::config_root()
Expand Down
13 changes: 11 additions & 2 deletions scripty_i18n/locales/en.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,24 @@ config-transcribe-video-requires-premium = Transcribing video files is a Premium
## config - auto detect language command
config_auto_detect_lang = auto_detect_lang
.description = Try to automatically detect the language being spoken? Very inaccurate vs setting a language.
.transcribe_video = auto_detect_lang
.transcribe_video-description = Defaults to false
.auto_detect_lang = auto_detect_lang
.auto_detect_lang-description = Defaults to false
config-auto-detect-lang-enabled = Scripty will now automatically detect the language being spoken.
config-auto-detect-lang-disabled = Scripty will no longer automatically detect the language being spoken.
config-auto-detect-lang-requires-premium = Automatically detecting the language is a Premium feature, as it is extremely computationally expensive to re-run the model twice to figure out the language.
If you would like to upgrade to Premium, head to https://dash.scripty.org/premium. You can also request a free trial of Premium by DMing the bot.
If this feature was enabled before, it is now disabled.
## config - transcribe only role command
config_transcribe_only_role = transcribe_only_role
.description = Limit Scripty's transcriptions to only users with this role in a voice chat.
.transcribe_only_role = transcribe_only_role
.transcribe_only_role-description = Role to limit to: set empty to disable.
config-transcribe-only-role-enabled = Scripty will now only transcribe messages from users in { $roleId }.
config-transcribe-only-role-disabled = Scripty will now transcribe all users, regardless of role.
## Help menu translation strings

command-not-found = No command with name `{ $commandName }` found.
Expand Down

0 comments on commit 4fc893c

Please sign in to comment.