Feat whisper opts (#1368)

This commit is contained in:
Markos Gogoulos 2025-09-04 13:39:41 +03:00 committed by GitHub
parent 6cee02085c
commit 8d982ace92
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 91 additions and 46 deletions

View File

@ -222,12 +222,12 @@ class WhisperSubtitlesForm(forms.ModelForm):
"allow_whisper_transcribe_and_translate",
)
labels = {
"allow_whisper_transcribe": "automatic transcription",
"allow_whisper_transcribe_and_translate": "automatic transcription and translation",
"allow_whisper_transcribe": "Transcription",
"allow_whisper_transcribe_and_translate": "English Translation",
}
help_texts = {
"allow_whisper_transcribe": "Request automatic transcription for this media.",
"allow_whisper_transcribe_and_translate": "Request automatic transcription and translation for this media.",
"allow_whisper_transcribe": "",
"allow_whisper_transcribe_and_translate": "",
}
def __init__(self, user, *args, **kwargs):
@ -281,7 +281,7 @@ class SubtitleForm(forms.ModelForm):
fields = ["language", "subtitle_file"]
labels = {
"subtitle_file": "Subtitle or Closed Caption File",
"subtitle_file": "Upload Caption File",
}
help_texts = {
"subtitle_file": "SubRip (.srt) and WebVTT (.vtt) are supported file formats.",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "ترجمات",
"Tags": "العلامات",
"Terms": "الشروط",
"This works in Chrome, Safari and Edge browsers.": "هذا يعمل في متصفحات Chrome و Safari و Edge.",
"Trim": "قص",
"UPLOAD": "رفع",
"Up next": "التالي",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "সাবটাইটেল",
"Tags": "ট্যাগ",
"Terms": "শর্তাবলী",
"This works in Chrome, Safari and Edge browsers.": "এটি ক্রোম, সাফারি এবং এজ ব্রাউজারে কাজ করে।",
"Trim": "ছাঁটাই",
"UPLOAD": "আপলোড করুন",
"Up next": "পরবর্তী",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Undertekster",
"Tags": "Tags",
"Terms": "Vilkår",
"This works in Chrome, Safari and Edge browsers.": "Dette virker i Chrome, Safari og Edge browsere.",
"Trim": "Beskær",
"UPLOAD": "UPLOAD",
"Up next": "Næste",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Untertitel",
"Tags": "Tags",
"Terms": "Bedingungen",
"This works in Chrome, Safari and Edge browsers.": "Dies funktioniert in den Browsern Chrome, Safari und Edge.",
"Trim": "Trimmen",
"UPLOAD": "HOCHLADEN",
"Up next": "Als nächstes",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Υπότιτλοι",
"Tags": "Ετικέτες",
"Terms": "Όροι",
"This works in Chrome, Safari and Edge browsers.": "Αυτό λειτουργεί σε προγράμματα περιήγησης Chrome, Safari και Edge.",
"Trim": "Περικοπή",
"UPLOAD": "ΑΝΕΒΑΣΜΑ",
"Up next": "Επόμενο",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitle was added": "",
"Tags": "",
"Terms": "",
"This works in Chrome, Safari and Edge browsers.": "",
"Trim": "",
"UPLOAD": "",
"Up next": "",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Subtítulos",
"Tags": "Etiquetas",
"Terms": "Términos",
"This works in Chrome, Safari and Edge browsers.": "Esto funciona en los navegadores Chrome, Safari y Edge.",
"Trim": "Recortar",
"UPLOAD": "SUBIR",
"Up next": "A continuación",

View File

@ -66,6 +66,7 @@ translation_strings = {
"Subtitles": "Sous-titres",
"Tags": "Tags",
"Terms": "Conditions",
"This works in Chrome, Safari and Edge browsers.": "Cela fonctionne dans les navigateurs Chrome, Safari et Edge.",
"Trim": "Couper",
"UPLOAD": "TÉLÉCHARGER",
"Up next": "À suivre",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "כתוביות",
"Tags": "תגיות",
"Terms": "תנאים",
"This works in Chrome, Safari and Edge browsers.": "זה עובד בדפדפני Chrome, Safari ו-Edge.",
"Trim": "גזירה",
"UPLOAD": "העלה",
"Up next": "הבא בתור",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "उपशीर्षक",
"Tags": "टैग",
"Terms": "शर्तें",
"This works in Chrome, Safari and Edge browsers.": "यह क्रोम, सफारी और एज ब्राउज़र में काम करता है।",
"Trim": "छांटें",
"UPLOAD": "अपलोड करें",
"Up next": "अगला",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Subtitel",
"Tags": "Tag",
"Terms": "Ketentuan",
"This works in Chrome, Safari and Edge browsers.": "Ini berfungsi di browser Chrome, Safari, dan Edge.",
"Trim": "Potong",
"UPLOAD": "UNGGAH",
"Up next": "Selanjutnya",

View File

@ -66,6 +66,7 @@ translation_strings = {
"Subtitles": "Sottotitoli",
"Tags": "Tag",
"Terms": "Termini e condizioni",
"This works in Chrome, Safari and Edge browsers.": "Questo funziona nei browser Chrome, Safari e Edge.",
"Trim": "Taglia",
"UPLOAD": "CARICA",
"Up next": "A seguire",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "字幕",
"Tags": "タグ",
"Terms": "利用規約",
"This works in Chrome, Safari and Edge browsers.": "これはChrome、Safari、Edgeブラウザで動作します。",
"Trim": "トリム",
"UPLOAD": "アップロード",
"Up next": "次に再生",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "자막",
"Tags": "태그",
"Terms": "약관",
"This works in Chrome, Safari and Edge browsers.": "이 기능은 Chrome, Safari 및 Edge 브라우저에서 작동합니다.",
"Trim": "자르기",
"UPLOAD": "업로드",
"Up next": "다음",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Ondertitels",
"Tags": "Tags",
"Terms": "Voorwaarden",
"This works in Chrome, Safari and Edge browsers.": "Dit werkt in Chrome, Safari en Edge browsers.",
"Trim": "Bijsnijden",
"UPLOAD": "UPLOADEN",
"Up next": "Hierna",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Legendas",
"Tags": "Tags",
"Terms": "Termos",
"This works in Chrome, Safari and Edge browsers.": "Isso funciona nos navegadores Chrome, Safari e Edge.",
"Trim": "Cortar",
"UPLOAD": "CARREGAR",
"Up next": "A seguir",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Субтитры",
"Tags": "Теги",
"Terms": "Условия",
"This works in Chrome, Safari and Edge browsers.": "Это работает в браузерах Chrome, Safari и Edge.",
"Trim": "Обрезать",
"UPLOAD": "ЗАГРУЗИТЬ",
"Up next": "Далее",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Podnapisi",
"Tags": "Oznake",
"Terms": "Pogoji",
"This works in Chrome, Safari and Edge browsers.": "To deluje v brskalnikih Chrome, Safari in Edge.",
"Trim": "Obreži",
"UPLOAD": "NALOŽI",
"Up next": "Naslednji",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "Altyazılar",
"Tags": "Etiketler",
"Terms": "Şartlar",
"This works in Chrome, Safari and Edge browsers.": "Bu, Chrome, Safari ve Edge tarayıcılarında çalışır.",
"Trim": "Kırp",
"UPLOAD": "YÜKLE",
"Up next": "Sıradaki",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "سب ٹائٹلز",
"Tags": "ٹیگز",
"Terms": "شرائط",
"This works in Chrome, Safari and Edge browsers.": "یہ کروم، سفاری اور ایج براؤزرز میں کام کرتا ہے۔",
"Trim": "تراشیں",
"UPLOAD": "اپ لوڈ کریں",
"Up next": "اگلا",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "字幕",
"Tags": "标签",
"Terms": "条款",
"This works in Chrome, Safari and Edge browsers.": "此功能适用于 Chrome、Safari 和 Edge 浏览器。",
"Trim": "修剪",
"UPLOAD": "上传",
"Up next": "接下来",

View File

@ -65,6 +65,7 @@ translation_strings = {
"Subtitles": "字幕",
"Tags": "標籤",
"Terms": "使用條款",
"This works in Chrome, Safari and Edge browsers.": "此功能適用於 Chrome、Safari 和 Edge 瀏覽器。",
"Trim": "修剪",
"UPLOAD": "上傳",
"Up next": "即將播放",

View File

@ -484,11 +484,11 @@ def whisper_transcribe(friendly_token, translate_to_english=False):
if translate_to_english:
language = Language.objects.filter(code="whisper-translation").first()
if not language:
language = Language.objects.create(code="whisper-translation", title="Automatic Transcription and Translation")
language = Language.objects.create(code="whisper-translation", title="English Translation")
else:
language = Language.objects.filter(code="whisper").first()
if not language:
language = Language.objects.create(code="whisper", title="Automatic Transcription")
language = Language.objects.create(code="whisper", title="Transcription")
cwd = os.path.dirname(os.path.realpath(media.media_file.path))
request.status = "running"

View File

@ -88,7 +88,7 @@ def add_subtitle(request):
subtitle = form.save()
try:
subtitle.convert_to_srt()
messages.add_message(request, messages.INFO, "Subtitle was added!")
messages.add_message(request, messages.INFO, "Caption was added!")
return HttpResponseRedirect(subtitle.media.get_absolute_url())
except Exception as e: # noqa
subtitle.delete()
@ -147,7 +147,7 @@ def edit_subtitle(request):
elif request.method == "POST":
confirm = request.GET.get("confirm", "").strip()
if confirm == "true":
messages.add_message(request, messages.INFO, "Subtitle was deleted")
messages.add_message(request, messages.INFO, "Caption was deleted")
redirect_url = subtitle.media.get_absolute_url()
subtitle.delete()
return HttpResponseRedirect(redirect_url)
@ -156,7 +156,7 @@ def edit_subtitle(request):
with open(subtitle.subtitle_file.path, "w") as ff:
ff.write(subtitle_text)
messages.add_message(request, messages.INFO, "Subtitle was edited")
messages.add_message(request, messages.INFO, "Caption was edited")
return HttpResponseRedirect(subtitle.media.get_absolute_url())
return render(request, "cms/edit_subtitle.html", context)

View File

@ -7,6 +7,23 @@
{% block innercontent %}
{% include "cms/media_nav.html" with active_tab="subtitles" %}
{% if whisper_form %}
<div class="user-action-form-wrap">
<div class="user-action-form-inner">
<h3 style="display: flex; align-items: center; gap: 0.25rem;">Request Automatic Transcription and Translation
<span title="This is Automatic Transcription using a Whisper model that is loaded locally" style="cursor: help;">
<i class="material-icons">info_outline</i>
</span>
</h3>
<form enctype="multipart/form-data" action="" method="post" class="post-form">
{% csrf_token %}
{% crispy whisper_form %}
</form>
</div>
</div>
{% endif %}
<div class="user-action-form-wrap">
<div class="user-action-form-inner">
<form enctype="multipart/form-data" action="" method="post" class="post-form">
@ -20,7 +37,7 @@
{% if subtitles %}
<div class="user-action-form-wrap">
<div class="user-action-form-inner">
<h3>Existing Subtitles</h3>
<h3>Edit existing Captions</h3>
<ul>
{% for subtitle in subtitles %}
<li><a href="{{subtitle.url}}">{{subtitle.language.title}}</a></li>
@ -30,20 +47,5 @@
</div>
{% endif %}
{% if whisper_form %}
<div class="user-action-form-wrap">
<div class="user-action-form-inner">
<h3 style="display: flex; align-items: center; gap: 0.25rem;">Request Automatic Tranascription
<span title="This is Automatic Transcription using a Whisper model that is loaded locally" style="cursor: help;">
<i class="material-icons">info_outline</i>
</span>
</h3>
<form enctype="multipart/form-data" action="" method="post" class="post-form">
{% csrf_token %}
{% crispy whisper_form %}
</form>
</div>
</div>
{% endif %}
{% endblock innercontent %}

View File

@ -59,24 +59,43 @@
</style>
<div class="form-group{% if field.errors %} has-error{% endif %}">
<div class="control-label-container">
{% if field.label %}
<label for="{{ field.id_for_label }}" class="control-label">
{{ field.label }}
{% if field.field.widget.input_type == 'checkbox' and field.field.choices|length <= 1 %}
<div class="controls">
<label for="{{ field.id_for_label }}" class="control-label" style="font-weight: normal;">
{% crispy_field field %}
<span style="margin-left: 5px;">{{ field.label }}</span>
{% if field.help_text %}
<span class="help-text-inline">- {{ field.help_text|safe }}</span>
{% endif %}
</label>
{% endif %}
</div>
<div class="controls {% if field.name == 'title' or field.name == 'new_tags' or field.name == 'description' %}full-width{% endif %}">
{% crispy_field field %}
{% if field.errors %}
<div class="error-container">
{% for error in field.errors %}
<p class="invalid-feedback">{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
</div>
{% if field.errors %}
<div class="error-container">
{% for error in field.errors %}
<p class="invalid-feedback">{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
{% else %}
<div class="control-label-container">
{% if field.label %}
<label for="{{ field.id_for_label }}" class="control-label">
{{ field.label }}
{% if field.help_text %}
<span class="help-text-inline">- {{ field.help_text|safe }}</span>
{% endif %}
</label>
{% endif %}
</div>
<div class="controls {% if field.name == 'title' or field.name == 'new_tags' or field.name == 'description' %}full-width{% endif %}">
{% crispy_field field %}
{% if field.errors %}
<div class="error-container">
{% for error in field.errors %}
<p class="invalid-feedback">{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
</div>

View File

@ -28,7 +28,7 @@
{% else %}
<div class="user-action-form-wrap">
<h1>Edit {{subtitle.language.title}} subtitle</h1>
<h1>{{subtitle.language.title}}</h1>
<div class="user-action-form-inner">
Media: <a href="{{subtitle.media.get_absolute_url}}">{{subtitle.media.title}}</a>
<form action="" method="post" class="post-form">

View File

@ -15,7 +15,7 @@
<li style="display: inline-block;">
<a href="{% url 'add_subtitle' %}?m={{media_object.friendly_token}}"
style="text-decoration: none; {% if active_tab == 'subtitles' %}font-weight: bold; color: #333; padding-bottom: 3px; border-bottom: 2px solid #333;{% else %}color: #666;{% endif %}">
{{ "Subtitles" | custom_translate:LANGUAGE_CODE}}
{{ "Captions" | custom_translate:LANGUAGE_CODE}}
</a>
</li>
<li style="display: inline-block;">

View File

@ -16,6 +16,7 @@
<div style="text-align: center; padding: 40px 0;">
<p style="margin-bottom: 20px;">{{ "Click 'Start Recording' and select the screen or tab to record. Once recording is finished, click 'Stop Recording,' and the recording will be uploaded." | custom_translate:LANGUAGE_CODE}}</p>
<p style="margin-bottom: 20px;">{{ "This works in Chrome, Safari and Edge browsers." | custom_translate:LANGUAGE_CODE}}</p>
<button id="startBtn" class="qq-upload-button-selector" style="padding: 10px 20px; font-size: 16px; margin-right: 10px; cursor: pointer;">{{ "Start Recording" | custom_translate:LANGUAGE_CODE}}</button>
<button id="stopBtn" class="qq-upload-button-selector" disabled style="padding: 10px 20px; font-size: 16px; cursor: pointer;">{{ "Stop Recording" | custom_translate:LANGUAGE_CODE}}</button>
<div id="spinner" style="display: none; margin-top: 20px;">
@ -81,7 +82,8 @@ document.addEventListener("DOMContentLoaded", function(event) {
const displayStream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream = new MediaStream([...displayStream.getTracks(), ...audioStream.getTracks()]);
audioStream.getAudioTracks().forEach(track => displayStream.addTrack(track));
stream = displayStream;
}
// When user stops sharing screen via browser UI