Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Ko-TTS-Arena Contributors
commited on
Commit
·
c741502
1
Parent(s):
8878a7e
feat: Remove login requirement - allow anonymous TTS generation and voting
Browse files- app.py +6 -12
- security.py +2 -1
- templates/arena.html +2 -70
app.py
CHANGED
|
@@ -587,10 +587,6 @@ def generate_tts():
|
|
| 587 |
if app.config["TURNSTILE_ENABLED"] and not session.get("turnstile_verified"):
|
| 588 |
return jsonify({"error": "Turnstile verification required"}), 403
|
| 589 |
|
| 590 |
-
# Require user to be logged in to generate audio
|
| 591 |
-
if not current_user.is_authenticated:
|
| 592 |
-
return jsonify({"error": "You must be logged in to generate audio"}), 401
|
| 593 |
-
|
| 594 |
data = request.json
|
| 595 |
text = data.get("text", "").strip() # Ensure text is stripped
|
| 596 |
|
|
@@ -776,16 +772,14 @@ def submit_vote():
|
|
| 776 |
if app.config["TURNSTILE_ENABLED"] and not session.get("turnstile_verified"):
|
| 777 |
return jsonify({"error": "Turnstile verification required"}), 403
|
| 778 |
|
| 779 |
-
# Require user to be logged in to vote
|
| 780 |
-
if not current_user.is_authenticated:
|
| 781 |
-
return jsonify({"error": "You must be logged in to vote"}), 401
|
| 782 |
-
|
| 783 |
# Security checks for vote manipulation prevention
|
| 784 |
client_ip = get_client_ip()
|
| 785 |
-
|
|
|
|
| 786 |
|
| 787 |
if not vote_allowed:
|
| 788 |
-
|
|
|
|
| 789 |
return jsonify({"error": f"Vote not allowed: {security_reason}"}), 403
|
| 790 |
|
| 791 |
data = request.json
|
|
@@ -832,7 +826,7 @@ def submit_vote():
|
|
| 832 |
|
| 833 |
# Record vote in database with analytics data
|
| 834 |
vote, error = record_vote(
|
| 835 |
-
|
| 836 |
session_data["text"],
|
| 837 |
chosen_id,
|
| 838 |
rejected_id,
|
|
@@ -871,7 +865,7 @@ def submit_vote():
|
|
| 871 |
"rejected_model_id": rejected_model_obj.id if rejected_model_obj else "Unknown",
|
| 872 |
"session_id": session_id,
|
| 873 |
"timestamp": datetime.utcnow().isoformat(),
|
| 874 |
-
"username": current_user.username,
|
| 875 |
"model_type": "TTS"
|
| 876 |
}
|
| 877 |
with open(os.path.join(vote_dir, "metadata.json"), "w") as f:
|
|
|
|
| 587 |
if app.config["TURNSTILE_ENABLED"] and not session.get("turnstile_verified"):
|
| 588 |
return jsonify({"error": "Turnstile verification required"}), 403
|
| 589 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 590 |
data = request.json
|
| 591 |
text = data.get("text", "").strip() # Ensure text is stripped
|
| 592 |
|
|
|
|
| 772 |
if app.config["TURNSTILE_ENABLED"] and not session.get("turnstile_verified"):
|
| 773 |
return jsonify({"error": "Turnstile verification required"}), 403
|
| 774 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 775 |
# Security checks for vote manipulation prevention
|
| 776 |
client_ip = get_client_ip()
|
| 777 |
+
user_id = current_user.id if current_user.is_authenticated else None
|
| 778 |
+
vote_allowed, security_reason, security_score = is_vote_allowed(user_id, client_ip)
|
| 779 |
|
| 780 |
if not vote_allowed:
|
| 781 |
+
username = current_user.username if current_user.is_authenticated else "anonymous"
|
| 782 |
+
app.logger.warning(f"Vote blocked for user {username} (ID: {user_id}): {security_reason} (Score: {security_score})")
|
| 783 |
return jsonify({"error": f"Vote not allowed: {security_reason}"}), 403
|
| 784 |
|
| 785 |
data = request.json
|
|
|
|
| 826 |
|
| 827 |
# Record vote in database with analytics data
|
| 828 |
vote, error = record_vote(
|
| 829 |
+
user_id,
|
| 830 |
session_data["text"],
|
| 831 |
chosen_id,
|
| 832 |
rejected_id,
|
|
|
|
| 865 |
"rejected_model_id": rejected_model_obj.id if rejected_model_obj else "Unknown",
|
| 866 |
"session_id": session_id,
|
| 867 |
"timestamp": datetime.utcnow().isoformat(),
|
| 868 |
+
"username": current_user.username if current_user.is_authenticated else "anonymous",
|
| 869 |
"model_type": "TTS"
|
| 870 |
}
|
| 871 |
with open(os.path.join(vote_dir, "metadata.json"), "w") as f:
|
security.py
CHANGED
|
@@ -406,8 +406,9 @@ def is_vote_allowed(user_id, ip_address=None):
|
|
| 406 |
Check if a vote should be allowed based on security factors.
|
| 407 |
Returns (allowed, reason, security_score)
|
| 408 |
"""
|
|
|
|
| 409 |
if not user_id:
|
| 410 |
-
return
|
| 411 |
|
| 412 |
# Check if user is currently timed out
|
| 413 |
try:
|
|
|
|
| 406 |
Check if a vote should be allowed based on security factors.
|
| 407 |
Returns (allowed, reason, security_score)
|
| 408 |
"""
|
| 409 |
+
# Allow anonymous voting when user is not authenticated
|
| 410 |
if not user_id:
|
| 411 |
+
return True, "Anonymous vote allowed", 50
|
| 412 |
|
| 413 |
# Check if user is currently timed out
|
| 414 |
try:
|
templates/arena.html
CHANGED
|
@@ -5,23 +5,6 @@
|
|
| 5 |
{% block current_page %}Arena{% endblock %}
|
| 6 |
|
| 7 |
{% block content %}
|
| 8 |
-
<!-- Authentication status for JavaScript -->
|
| 9 |
-
<div id="auth-status" data-authenticated="{% if current_user.is_authenticated %}true{% else %}false{% endif %}" style="display: none;"></div>
|
| 10 |
-
|
| 11 |
-
{% if not current_user.is_authenticated %}
|
| 12 |
-
<!-- Login prompt overlay -->
|
| 13 |
-
<div id="login-prompt-overlay" class="login-prompt-overlay" style="display: none;">
|
| 14 |
-
<div class="login-prompt-content">
|
| 15 |
-
<h3>로그인 필요</h3>
|
| 16 |
-
<p>TTS Arena를 사용하려면 로그인이 필요합니다. 로그인하여 음성을 생성하고 투표하세요!</p>
|
| 17 |
-
<div class="login-prompt-actions">
|
| 18 |
-
<button class="login-prompt-close">나중에</button>
|
| 19 |
-
<a href="{{ url_for('auth.login', next=request.path) }}" class="login-prompt-btn">Hugging Face로 로그인</a>
|
| 20 |
-
</div>
|
| 21 |
-
</div>
|
| 22 |
-
</div>
|
| 23 |
-
{% endif %}
|
| 24 |
-
|
| 25 |
<div id="tts-tab" class="tab-content active">
|
| 26 |
<form class="input-container">
|
| 27 |
<div class="input-group">
|
|
@@ -691,40 +674,6 @@
|
|
| 691 |
<script src="{{ url_for('static', filename='js/waveplayer.js') }}"></script>
|
| 692 |
<script>
|
| 693 |
document.addEventListener('DOMContentLoaded', function() {
|
| 694 |
-
// Check authentication status
|
| 695 |
-
const authStatus = document.getElementById('auth-status');
|
| 696 |
-
const isAuthenticated = authStatus ? authStatus.dataset.authenticated === 'true' : false;
|
| 697 |
-
const loginPromptOverlay = document.getElementById('login-prompt-overlay');
|
| 698 |
-
const loginPromptClose = document.querySelector('.login-prompt-close');
|
| 699 |
-
|
| 700 |
-
// Function to show login prompt
|
| 701 |
-
function showLoginPrompt() {
|
| 702 |
-
if (loginPromptOverlay) {
|
| 703 |
-
loginPromptOverlay.style.display = 'flex';
|
| 704 |
-
}
|
| 705 |
-
}
|
| 706 |
-
|
| 707 |
-
// Function to hide login prompt
|
| 708 |
-
function hideLoginPrompt() {
|
| 709 |
-
if (loginPromptOverlay) {
|
| 710 |
-
loginPromptOverlay.style.display = 'none';
|
| 711 |
-
}
|
| 712 |
-
}
|
| 713 |
-
|
| 714 |
-
// Add event listener to close button
|
| 715 |
-
if (loginPromptClose) {
|
| 716 |
-
loginPromptClose.addEventListener('click', hideLoginPrompt);
|
| 717 |
-
}
|
| 718 |
-
|
| 719 |
-
// Close prompt when clicking outside
|
| 720 |
-
if (loginPromptOverlay) {
|
| 721 |
-
loginPromptOverlay.addEventListener('click', function(e) {
|
| 722 |
-
if (e.target === loginPromptOverlay) {
|
| 723 |
-
hideLoginPrompt();
|
| 724 |
-
}
|
| 725 |
-
});
|
| 726 |
-
}
|
| 727 |
-
|
| 728 |
const synthForm = document.querySelector('.input-container');
|
| 729 |
const synthBtn = document.querySelector('.synth-btn');
|
| 730 |
const mobileSynthBtn = document.querySelector('.mobile-synth-btn');
|
|
@@ -786,12 +735,6 @@
|
|
| 786 |
e.preventDefault();
|
| 787 |
}
|
| 788 |
|
| 789 |
-
// Check authentication first
|
| 790 |
-
if (!isAuthenticated) {
|
| 791 |
-
showLoginPrompt();
|
| 792 |
-
return;
|
| 793 |
-
}
|
| 794 |
-
|
| 795 |
const text = textInput.value.trim();
|
| 796 |
if (!text) {
|
| 797 |
openToast("텍스트를 입력해주세요", "warning");
|
|
@@ -883,13 +826,7 @@
|
|
| 883 |
})
|
| 884 |
.catch(error => {
|
| 885 |
loadingContainer.style.display = 'none';
|
| 886 |
-
|
| 887 |
-
// Handle authentication errors specially
|
| 888 |
-
if (error.message.includes('logged in to generate') || error.message.includes('logged in to vote')) {
|
| 889 |
-
openToast("로그인이 필요합니다. <a href='{{ url_for('auth.login', next=request.path) }}' style='color: white; text-decoration: underline;'>지금 로그인</a>", "error");
|
| 890 |
-
} else {
|
| 891 |
-
openToast(error.message, "error");
|
| 892 |
-
}
|
| 893 |
console.error('Error:', error);
|
| 894 |
});
|
| 895 |
}
|
|
@@ -962,12 +899,7 @@
|
|
| 962 |
btn.querySelector('.vote-loader').style.display = 'none';
|
| 963 |
});
|
| 964 |
|
| 965 |
-
|
| 966 |
-
if (error.message.includes('logged in to vote')) {
|
| 967 |
-
openToast("로그인이 필요합니다. <a href='{{ url_for('auth.login', next=request.path) }}' style='color: white; text-decoration: underline;'>지금 로그인</a>", "error");
|
| 968 |
-
} else {
|
| 969 |
-
openToast(error.message, "error");
|
| 970 |
-
}
|
| 971 |
console.error('Error:', error);
|
| 972 |
});
|
| 973 |
}
|
|
|
|
| 5 |
{% block current_page %}Arena{% endblock %}
|
| 6 |
|
| 7 |
{% block content %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
<div id="tts-tab" class="tab-content active">
|
| 9 |
<form class="input-container">
|
| 10 |
<div class="input-group">
|
|
|
|
| 674 |
<script src="{{ url_for('static', filename='js/waveplayer.js') }}"></script>
|
| 675 |
<script>
|
| 676 |
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
const synthForm = document.querySelector('.input-container');
|
| 678 |
const synthBtn = document.querySelector('.synth-btn');
|
| 679 |
const mobileSynthBtn = document.querySelector('.mobile-synth-btn');
|
|
|
|
| 735 |
e.preventDefault();
|
| 736 |
}
|
| 737 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 738 |
const text = textInput.value.trim();
|
| 739 |
if (!text) {
|
| 740 |
openToast("텍스트를 입력해주세요", "warning");
|
|
|
|
| 826 |
})
|
| 827 |
.catch(error => {
|
| 828 |
loadingContainer.style.display = 'none';
|
| 829 |
+
openToast(error.message, "error");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 830 |
console.error('Error:', error);
|
| 831 |
});
|
| 832 |
}
|
|
|
|
| 899 |
btn.querySelector('.vote-loader').style.display = 'none';
|
| 900 |
});
|
| 901 |
|
| 902 |
+
openToast(error.message, "error");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 903 |
console.error('Error:', error);
|
| 904 |
});
|
| 905 |
}
|