From 8d4e35bb51bd12885e61e4e56748a6a7667fbb31 Mon Sep 17 00:00:00 2001 From: Chris Angelico Date: Fri, 10 Jan 2025 21:59:18 +1100 Subject: [PATCH] Implement premium account status for TTS rate improvement --- modules/http/chan_alertbox.pike | 16 ++++++++++------ modules/http/tts_hack.pike | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/modules/http/chan_alertbox.pike b/modules/http/chan_alertbox.pike index 9f683fc5..39d0c019 100644 --- a/modules/http/chan_alertbox.pike +++ b/modules/http/chan_alertbox.pike @@ -557,10 +557,12 @@ __async__ mapping(string:mixed) http_request(Protocols.HTTP.Server.Request req) "personals": cfg->personals || ({ }), ])); } + mapping premium = await(G->G->DB->load_config(0, "premium_accounts")); + mapping prem = premium[(string)req->misc->channel->userid] || ([]); return render(req, ([ "vars": (["ws_group": "control", "maxfilesize": MAX_PER_FILE, "maxtotsize": MAX_TOTAL_STORAGE, - "avail_voices": tts_config->avail_voices[?RATE_STANDARD] || ({ }), //For now, only expose standard rate + "avail_voices": tts_config->avail_voices[?prem->tts_rate] || ({ }), "follower_alert_scopes": req->misc->channel->name != "#!demo" && ensure_bcaster_token(req, "moderator:read:followers"), ]), ]) | req->misc->chaninfo); @@ -1267,12 +1269,14 @@ __async__ string filter_bad_words(string text, string mode) { return words * " "; } -__async__ string|zero text_to_speech(string text, string voice, string origin) { +__async__ string|zero text_to_speech(string text, string voice, int|void userid) { string token = tts_config->?access_token; if (!token) return 0; array v = voice / "/"; - //TODO: Allow different whitelists for different origins - if (!tts_config->voices[RATE_STANDARD][v[1]]) return 0; + //Different whitelists for different userids (default to rate 0 aka Standard if not recognized) + mapping premium = await(G->G->DB->load_config(0, "premium_accounts")); + mapping prem = premium[(string)userid] || ([]); + if (!tts_config->voices[prem->tts_rate][v[1]]) return 0; object reqargs = Protocols.HTTP.Promise.Arguments((["headers": ([ "Authorization": "Bearer " + token, "Content-Type": "application/json; charset=utf-8", @@ -1288,7 +1292,7 @@ __async__ string|zero text_to_speech(string text, string voice, string origin) { System.Timer tm = System.Timer(); object res = await(Protocols.HTTP.Promise.post_url("https://texttospeech.googleapis.com/v1/text:synthesize", reqargs)); float delay = tm->get(); - Stdio.append_file("tts_stats.log", sprintf("%s text %O fetch time %.3f\n", origin, text, delay)); + Stdio.append_file("tts_stats.log", sprintf("User %d text %O fetch time %.3f\n", userid, text, delay)); mixed data; catch {data = Standards.JSON.decode_utf8(res->get());}; if (mappingp(data) && data->error->?details[?0]->?reason == "ACCESS_TOKEN_EXPIRED") { Stdio.append_file("tts_error.log", sprintf("%sTTS access key expired after %d seconds\n", @@ -1334,7 +1338,7 @@ __async__ void send_with_tts(object channel, mapping args, string|void destgroup text += fmt; string voice = inh->tts_voice || ""; if (sizeof(voice / "/") != 3) voice = tts_config->default_voice; - if (string tts = text != "" && await(text_to_speech(text, voice, sprintf("Channel %O", channel->name)))) args->tts = tts; + if (string tts = text != "" && await(text_to_speech(text, voice, channel->userid))) args->tts = tts; send_updates_all((destgroup || cfg->authkey) + "#" + channel->userid, args); } diff --git a/modules/http/tts_hack.pike b/modules/http/tts_hack.pike index c13a05e0..6824d1fe 100644 --- a/modules/http/tts_hack.pike +++ b/modules/http/tts_hack.pike @@ -9,8 +9,16 @@ constant markdown = #"# TTS hack
"; -mapping(string:mixed) http_request(Protocols.HTTP.Server.Request req) { - return render(req, (["vars": (["ws_group": req->variables->key || ""])])); +//Map a group name to the last-sighted TTS rate schedule +//This won't be perfect, but it's only for the drop-down, so it's not that big a deal if it's wrong. +mapping tts_rate = ([]); +__async__ mapping(string:mixed) http_request(Protocols.HTTP.Server.Request req) { + string key = req->variables->key || ""; + if (key != "") { + mapping premium = await(G->G->DB->load_config(0, "premium_accounts")); + tts_rate[key] = premium[(string)req->misc->session->user->?id]->?tts_rate; + } + return render(req, (["vars": (["ws_group": key])])); } @retain: multiset tts_hack_valid_keys = (<>); @@ -19,7 +27,7 @@ string websocket_validate(mapping(string:mixed) conn, mapping(string:mixed) msg) } mapping get_state(string group) { - return (["voices": G->G->tts_config->avail_voices[?0] || ({ })]); //0 == RATE_STANDARD + return (["voices": G->G->tts_config->avail_voices[?tts_rate[group]] || ({ })]); //If no TTS rate set, use RATE_STANDARD (0) } __async__ mapping|zero websocket_cmd_speak(mapping(string:mixed) conn, mapping(string:mixed) msg) { @@ -28,7 +36,7 @@ __async__ mapping|zero websocket_cmd_speak(mapping(string:mixed) conn, mapping(s object alertbox = G->G->websocket_types->chan_alertbox; text = await(alertbox->filter_bad_words(text, "replace")); werror("TTS Hack %O -> %O\n", msg->voice, msg->text); - string tts = await(alertbox->text_to_speech(text, msg->voice || "en-GB/en-GB-Standard-A/FEMALE", "tts_hack")); + string tts = await(alertbox->text_to_speech(text, msg->voice || "en-GB/en-GB-Standard-A/FEMALE", (int)conn->session->user->?id)); return (["cmd": "speak", "text": text, "tts": tts]); }