Spaces:
Running
Running
use browser cookie for cached samples
Browse files
app.py
CHANGED
@@ -437,9 +437,9 @@ Vote to help the community find the best available text-to-speech model!
|
|
437 |
INSTR = """
|
438 |
## π³οΈ Vote
|
439 |
|
440 |
-
* Input text (English only) to synthesize audio.
|
441 |
-
* Press β‘ to get cached
|
442 |
-
* Press π² to randomly
|
443 |
* Listen to the two audio clips, one after the other.
|
444 |
* Vote on which audio sounds more natural to you.
|
445 |
* _Note: Model names are revealed after the vote is cast._
|
@@ -665,7 +665,7 @@ def make_link_to_space(model_name):
|
|
665 |
title = model_name
|
666 |
else:
|
667 |
style += 'font-style: italic;'
|
668 |
-
title = '
|
669 |
|
670 |
model_basename = model_name
|
671 |
if model_name in HF_SPACES:
|
@@ -970,8 +970,8 @@ def synthandreturn(text):
|
|
970 |
attempt_count += 1
|
971 |
print(repr(e))
|
972 |
print(f"{model}: Unable to call API (attempt: {attempt_count})")
|
973 |
-
# sleep for
|
974 |
-
time.sleep(
|
975 |
|
976 |
# Fetch and store client again
|
977 |
#hf_clients[model] = Client(model, hf_token=hf_token)
|
@@ -1141,25 +1141,30 @@ def unlock_vote(btn_index, aplayed, bplayed):
|
|
1141 |
def play_other(bplayed):
|
1142 |
return bplayed
|
1143 |
|
1144 |
-
def get_userid(request):
|
|
|
|
|
|
|
|
|
|
|
1145 |
if request.username:
|
1146 |
# print('auth by username')
|
1147 |
-
# by HuggingFace username
|
1148 |
-
return sha1(bytes(request.username.encode('ascii'))).hexdigest()
|
1149 |
else:
|
1150 |
# print('auth by ip')
|
1151 |
-
# by IP address
|
1152 |
-
return sha1(bytes(request.client.host.encode('ascii'))).hexdigest()
|
1153 |
-
# by browser session
|
1154 |
-
#
|
1155 |
-
#
|
|
|
1156 |
|
1157 |
# Give user a cached audio sample pair they have yet to vote on
|
1158 |
-
def give_cached_sample(request: gr.Request):
|
1159 |
# add new userid to voting_users from Browser session hash
|
1160 |
# stored only in RAM
|
1161 |
-
userid = get_userid(request)
|
1162 |
-
print(f'userid asked for cached: {userid}')
|
1163 |
|
1164 |
if userid not in voting_users:
|
1165 |
voting_users[userid] = User(userid)
|
@@ -1183,7 +1188,11 @@ def give_cached_sample(request: gr.Request):
|
|
1183 |
|
1184 |
pair = get_next_pair(voting_users[userid])
|
1185 |
if pair is None:
|
1186 |
-
return [
|
|
|
|
|
|
|
|
|
1187 |
|
1188 |
return (
|
1189 |
pair[0].transcript,
|
@@ -1206,8 +1215,8 @@ def give_cached_sample(request: gr.Request):
|
|
1206 |
)
|
1207 |
|
1208 |
# note the vote on cached sample pair
|
1209 |
-
def voted_on_cached(modelName1: str, modelName2: str, transcript: str, request: gr.Request):
|
1210 |
-
userid = get_userid(request)
|
1211 |
print(f'userid voted on cached: {userid}')
|
1212 |
|
1213 |
if userid not in voting_users:
|
@@ -1242,7 +1251,11 @@ def disable():
|
|
1242 |
return [gr.update(interactive=False), gr.update(interactive=False), gr.update(interactive=False), gr.update(interactive=False)]
|
1243 |
def enable():
|
1244 |
return [gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)]
|
|
|
|
|
1245 |
with gr.Blocks() as vote:
|
|
|
|
|
1246 |
# sample played, using Checkbox so that JS can fetch the value
|
1247 |
aplayed = gr.Checkbox(visible=False, value=False)
|
1248 |
bplayed = gr.Checkbox(visible=False, value=False)
|
@@ -1285,7 +1298,7 @@ with gr.Blocks() as vote:
|
|
1285 |
)
|
1286 |
bbetter = gr.Button("B is better", variant='primary', interactive=False)
|
1287 |
prevmodel2 = gr.HTML(show_label=False, value="Vote to reveal model B", visible=False)
|
1288 |
-
nxtroundbtn = gr.Button('Next round', visible=False)
|
1289 |
# outputs = [text, btn, r2, model1, model2, prevmodel1, aud1, prevmodel2, aud2, abetter, bbetter]
|
1290 |
outputs = [
|
1291 |
text,
|
@@ -1320,13 +1333,17 @@ with gr.Blocks() as vote:
|
|
1320 |
.click(disable, outputs=[btn, abetter, bbetter, cachedt])\
|
1321 |
.then(synthandreturn, inputs=[text], outputs=outputs)\
|
1322 |
.then(enable, outputs=[btn, gr.State(), gr.State(), cachedt])
|
1323 |
-
nxtroundbtn
|
|
|
|
|
|
|
1324 |
|
1325 |
# fetch a comparison pair from cache
|
1326 |
cachedt\
|
1327 |
.click(disable, outputs=[btn, abetter, bbetter, cachedt])\
|
1328 |
-
.then(give_cached_sample, outputs=[*outputs, cachedt])\
|
1329 |
-
.then(enable, outputs=[btn, gr.State(), gr.State(),
|
|
|
1330 |
|
1331 |
# Allow interaction with the vote buttons only when both audio samples have finished playing
|
1332 |
aud1\
|
@@ -1352,16 +1369,21 @@ with gr.Blocks() as vote:
|
|
1352 |
nxt_outputs = [abetter, bbetter, prevmodel1, prevmodel2, nxtroundbtn]
|
1353 |
abetter\
|
1354 |
.click(a_is_better, outputs=nxt_outputs, inputs=[model1, model2, useridstate])\
|
1355 |
-
.then(voted_on_cached, inputs=[model1, model2, text])
|
1356 |
bbetter\
|
1357 |
.click(b_is_better, outputs=nxt_outputs, inputs=[model1, model2, useridstate])\
|
1358 |
-
.then(voted_on_cached, inputs=[model1, model2, text])
|
1359 |
# skipbtn.click(b_is_better, outputs=outputs, inputs=[model1, model2, useridstate])
|
1360 |
|
1361 |
# bothbad.click(both_bad, outputs=outputs, inputs=[model1, model2, useridstate])
|
1362 |
# bothgood.click(both_good, outputs=outputs, inputs=[model1, model2, useridstate])
|
1363 |
|
1364 |
-
|
|
|
|
|
|
|
|
|
|
|
1365 |
|
1366 |
with gr.Blocks() as about:
|
1367 |
gr.Markdown(ABOUT)
|
@@ -1372,7 +1394,7 @@ with gr.Blocks() as about:
|
|
1372 |
# dbtext = gr.Textbox(label="Type \"delete db\" to confirm", placeholder="delete db")
|
1373 |
# ddb = gr.Button("Delete DB")
|
1374 |
# ddb.click(del_db, inputs=dbtext, outputs=ddb)
|
1375 |
-
with gr.Blocks(theme=theme, css="footer {visibility: hidden}textbox{resize:none}", title="TTS Arena") as demo:
|
1376 |
gr.Markdown(DESCR)
|
1377 |
# gr.TabbedInterface([vote, leaderboard, about, admin], ['Vote', 'Leaderboard', 'About', 'Admin (ONLY IN BETA)'])
|
1378 |
gr.TabbedInterface([vote, leaderboard, about], ['π³οΈ Vote', 'π Leaderboard', 'π About'])
|
@@ -1382,4 +1404,6 @@ with gr.Blocks(theme=theme, css="footer {visibility: hidden}textbox{resize:none}
|
|
1382 |
gr.Markdown(f"If you use this data in your publication, please cite us!\n\nCopy the BibTeX citation to cite this source:\n\n```bibtext\n{CITATION_TEXT}\n```\n\nPlease remember that all generated audio clips should be assumed unsuitable for redistribution or commercial use.")
|
1383 |
|
1384 |
|
1385 |
-
demo
|
|
|
|
|
|
437 |
INSTR = """
|
438 |
## π³οΈ Vote
|
439 |
|
440 |
+
* Input text (πΊπΈ English only) to synthesize audio.
|
441 |
+
* Press β‘ to get cached sample pairs you've yet to vote on. (Fast π)
|
442 |
+
* Press π² to randomly use text from a preselected list. (Slow π)
|
443 |
* Listen to the two audio clips, one after the other.
|
444 |
* Vote on which audio sounds more natural to you.
|
445 |
* _Note: Model names are revealed after the vote is cast._
|
|
|
665 |
title = model_name
|
666 |
else:
|
667 |
style += 'font-style: italic;'
|
668 |
+
title = 'Got disabled for Arena (See AVAILABLE_MODELS within code for why)'
|
669 |
|
670 |
model_basename = model_name
|
671 |
if model_name in HF_SPACES:
|
|
|
970 |
attempt_count += 1
|
971 |
print(repr(e))
|
972 |
print(f"{model}: Unable to call API (attempt: {attempt_count})")
|
973 |
+
# sleep for three seconds
|
974 |
+
time.sleep(3)
|
975 |
|
976 |
# Fetch and store client again
|
977 |
#hf_clients[model] = Client(model, hf_token=hf_token)
|
|
|
1141 |
def play_other(bplayed):
|
1142 |
return bplayed
|
1143 |
|
1144 |
+
def get_userid(session_hash: str, request):
|
1145 |
+
# JS cookie
|
1146 |
+
if (session_hash != ''):
|
1147 |
+
# print('auth by session cookie')
|
1148 |
+
return sha1(bytes(session_hash.encode('ascii')), usedforsecurity=False).hexdigest()
|
1149 |
+
|
1150 |
if request.username:
|
1151 |
# print('auth by username')
|
1152 |
+
# by HuggingFace username - requires `auth` to be enabled therefore denying access to anonymous users
|
1153 |
+
return sha1(bytes(request.username.encode('ascii')), usedforsecurity=False).hexdigest()
|
1154 |
else:
|
1155 |
# print('auth by ip')
|
1156 |
+
# by IP address - unreliable when gradio within HTML iframe
|
1157 |
+
# return sha1(bytes(request.client.host.encode('ascii')), usedforsecurity=False).hexdigest()
|
1158 |
+
# by browser session cookie - Gradio on HF is run in an HTML iframe, access to parent session required to reach session token
|
1159 |
+
# return sha1(bytes(request.headers.encode('ascii'))).hexdigest()
|
1160 |
+
# by browser session hash - Not a cookie, session hash changes on page reload
|
1161 |
+
return sha1(bytes(request.session_hash.encode('ascii')), usedforsecurity=False).hexdigest()
|
1162 |
|
1163 |
# Give user a cached audio sample pair they have yet to vote on
|
1164 |
+
def give_cached_sample(session_hash: str, request: gr.Request):
|
1165 |
# add new userid to voting_users from Browser session hash
|
1166 |
# stored only in RAM
|
1167 |
+
userid = get_userid(session_hash, request)
|
|
|
1168 |
|
1169 |
if userid not in voting_users:
|
1170 |
voting_users[userid] = User(userid)
|
|
|
1188 |
|
1189 |
pair = get_next_pair(voting_users[userid])
|
1190 |
if pair is None:
|
1191 |
+
return [
|
1192 |
+
*clear_stuff(),
|
1193 |
+
# disable get cached sample button
|
1194 |
+
gr.update(interactive=False)
|
1195 |
+
]
|
1196 |
|
1197 |
return (
|
1198 |
pair[0].transcript,
|
|
|
1215 |
)
|
1216 |
|
1217 |
# note the vote on cached sample pair
|
1218 |
+
def voted_on_cached(modelName1: str, modelName2: str, transcript: str, session_hash: str, request: gr.Request):
|
1219 |
+
userid = get_userid(session_hash, request)
|
1220 |
print(f'userid voted on cached: {userid}')
|
1221 |
|
1222 |
if userid not in voting_users:
|
|
|
1251 |
return [gr.update(interactive=False), gr.update(interactive=False), gr.update(interactive=False), gr.update(interactive=False)]
|
1252 |
def enable():
|
1253 |
return [gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)]
|
1254 |
+
|
1255 |
+
|
1256 |
with gr.Blocks() as vote:
|
1257 |
+
session_hash = gr.Textbox(visible=False, value='')
|
1258 |
+
|
1259 |
# sample played, using Checkbox so that JS can fetch the value
|
1260 |
aplayed = gr.Checkbox(visible=False, value=False)
|
1261 |
bplayed = gr.Checkbox(visible=False, value=False)
|
|
|
1298 |
)
|
1299 |
bbetter = gr.Button("B is better", variant='primary', interactive=False)
|
1300 |
prevmodel2 = gr.HTML(show_label=False, value="Vote to reveal model B", visible=False)
|
1301 |
+
nxtroundbtn = gr.Button('β‘ Next round', visible=False)
|
1302 |
# outputs = [text, btn, r2, model1, model2, prevmodel1, aud1, prevmodel2, aud2, abetter, bbetter]
|
1303 |
outputs = [
|
1304 |
text,
|
|
|
1333 |
.click(disable, outputs=[btn, abetter, bbetter, cachedt])\
|
1334 |
.then(synthandreturn, inputs=[text], outputs=outputs)\
|
1335 |
.then(enable, outputs=[btn, gr.State(), gr.State(), cachedt])
|
1336 |
+
nxtroundbtn\
|
1337 |
+
.click(disable, outputs=[btn, abetter, bbetter, cachedt])\
|
1338 |
+
.then(give_cached_sample, inputs=[session_hash], outputs=[*outputs, cachedt])\
|
1339 |
+
.then(enable, outputs=[btn, gr.State(), gr.State(), gr.State()])
|
1340 |
|
1341 |
# fetch a comparison pair from cache
|
1342 |
cachedt\
|
1343 |
.click(disable, outputs=[btn, abetter, bbetter, cachedt])\
|
1344 |
+
.then(give_cached_sample, inputs=[session_hash], outputs=[*outputs, cachedt])\
|
1345 |
+
.then(enable, outputs=[btn, gr.State(), gr.State(), gr.State()])
|
1346 |
+
# TODO: await download of sample before allowing playback
|
1347 |
|
1348 |
# Allow interaction with the vote buttons only when both audio samples have finished playing
|
1349 |
aud1\
|
|
|
1369 |
nxt_outputs = [abetter, bbetter, prevmodel1, prevmodel2, nxtroundbtn]
|
1370 |
abetter\
|
1371 |
.click(a_is_better, outputs=nxt_outputs, inputs=[model1, model2, useridstate])\
|
1372 |
+
.then(voted_on_cached, inputs=[model1, model2, text, session_hash])
|
1373 |
bbetter\
|
1374 |
.click(b_is_better, outputs=nxt_outputs, inputs=[model1, model2, useridstate])\
|
1375 |
+
.then(voted_on_cached, inputs=[model1, model2, text, session_hash])
|
1376 |
# skipbtn.click(b_is_better, outputs=outputs, inputs=[model1, model2, useridstate])
|
1377 |
|
1378 |
# bothbad.click(both_bad, outputs=outputs, inputs=[model1, model2, useridstate])
|
1379 |
# bothgood.click(both_good, outputs=outputs, inputs=[model1, model2, useridstate])
|
1380 |
|
1381 |
+
vote.load(
|
1382 |
+
None,
|
1383 |
+
None,
|
1384 |
+
session_hash,
|
1385 |
+
js="() => { return getArenaCookie('session') }",
|
1386 |
+
)
|
1387 |
|
1388 |
with gr.Blocks() as about:
|
1389 |
gr.Markdown(ABOUT)
|
|
|
1394 |
# dbtext = gr.Textbox(label="Type \"delete db\" to confirm", placeholder="delete db")
|
1395 |
# ddb = gr.Button("Delete DB")
|
1396 |
# ddb.click(del_db, inputs=dbtext, outputs=ddb)
|
1397 |
+
with gr.Blocks(theme=theme, css="footer {visibility: hidden}textbox{resize:none}", js="cookie.js", title="TTS Arena") as demo:
|
1398 |
gr.Markdown(DESCR)
|
1399 |
# gr.TabbedInterface([vote, leaderboard, about, admin], ['Vote', 'Leaderboard', 'About', 'Admin (ONLY IN BETA)'])
|
1400 |
gr.TabbedInterface([vote, leaderboard, about], ['π³οΈ Vote', 'π Leaderboard', 'π About'])
|
|
|
1404 |
gr.Markdown(f"If you use this data in your publication, please cite us!\n\nCopy the BibTeX citation to cite this source:\n\n```bibtext\n{CITATION_TEXT}\n```\n\nPlease remember that all generated audio clips should be assumed unsuitable for redistribution or commercial use.")
|
1405 |
|
1406 |
|
1407 |
+
demo\
|
1408 |
+
.queue(api_open=False, default_concurrency_limit=40)\
|
1409 |
+
.launch(show_api=False, show_error=True)
|
cookie.js
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function () {
|
2 |
+
window.getArenaCookie = function getArenaCookie(cname) {
|
3 |
+
let name = cname + "=";
|
4 |
+
let decodedCookie = decodeURIComponent(window.document.cookie);
|
5 |
+
let ca = decodedCookie.split(';');
|
6 |
+
for (let i = 0; i < ca.length; i++) {
|
7 |
+
let c = ca[i];
|
8 |
+
while (c.charAt(0) == ' ') {
|
9 |
+
c = c.substring(1);
|
10 |
+
}
|
11 |
+
if (c.indexOf(name) == 0) {
|
12 |
+
return c.substring(name.length, c.length);
|
13 |
+
}
|
14 |
+
}
|
15 |
+
return "";
|
16 |
+
}
|
17 |
+
|
18 |
+
window.setArenaCookie = function setArenaCookie(cname, cvalue, exdays) {
|
19 |
+
const d = new Date();
|
20 |
+
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
|
21 |
+
let expires = "expires=" + d.toUTCString();
|
22 |
+
window.document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
|
23 |
+
}
|
24 |
+
|
25 |
+
if (window.getArenaCookie('session').length == 0)
|
26 |
+
{
|
27 |
+
const d = new Date();
|
28 |
+
window.setArenaCookie('session', d.getTime().toString(), 90);
|
29 |
+
console.log('Session cookie created')
|
30 |
+
}
|
31 |
+
}
|