Added: vosk functionality

This commit is contained in:
Markus Schmidt 2021-10-08 15:18:30 +02:00
parent f4dcd34574
commit 118ba785e2
9 changed files with 152 additions and 72 deletions

View File

@ -4,59 +4,21 @@
# this file is released under public domain and you can use without limitations
# -------------------------------------------------------------------------
#from transcription_tools import create_vtt
transcription_tools = local_import('transcription_tools', reload=True)
# ---- example index page ----
def index():
images = db().select(db.image.ALL, orderby=db.image.title)
return dict(images=images)
media_files = db().select(db.media_file.ALL, orderby=db.media_file.title)
return dict(media_files=media_files)
@auth.requires_membership('manager')
def manage():
grid = SQLFORM.smartgrid(db.image, linked_tables=['post'])
grid = SQLFORM.smartgrid(db.media_file, linked_tables=['post'])
return dict(grid=grid)
# ---- API (example) -----
@auth.requires_login()
def api_get_user_email():
if not request.env.request_method == 'GET': raise HTTP(403)
return response.json({'status':'success', 'email':auth.user.email})
def vtt():
return dict(message=transcription_tools.create_vtt())
# ---- Smart Grid (example) -----
@auth.requires_membership('admin') # can only be accessed by members of admin groupd
def grid():
response.view = 'generic.html' # use a generic view
tablename = request.args(0)
if not tablename in db.tables: raise HTTP(403)
grid = SQLFORM.smartgrid(db[tablename], args=[tablename], deletable=False, editable=False)
return dict(grid=grid)
# ---- Embedded wiki (example) ----
def wiki():
auth.wikimenu() # add the wiki to the menu
return auth.wiki()
# ---- Action for login/register/etc (required for auth) -----
def user():
"""
exposes:
http://..../[app]/default/user/login
http://..../[app]/default/user/logout
http://..../[app]/default/user/register
http://..../[app]/default/user/profile
http://..../[app]/default/user/retrieve_password
http://..../[app]/default/user/change_password
http://..../[app]/default/user/bulk_register
use @auth.requires_login()
@auth.requires_membership('group name')
@auth.requires_permission('read','table name',record_id)
to decorate functions that need access control
also notice there is http://..../[app]/appadmin/manage/auth to allow administrator to manage users
"""
return dict(form=auth())
# ---- action to server uploaded static content (required) ---
@cache.action()
def download():
"""
allows downloading of uploaded files
http://..../[app]/default/download/[filename]
"""
return response.download(request, db)

View File

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
{
'!=': '!=',
'!langcode!': 'de',
'!langname!': 'Deutsch (DE)',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Update" ist ein optionaler Ausdruck wie "feld1=\'newvalue\'". JOIN Ergebnisse können nicht aktualisiert oder gelöscht werden',
'%(nrows)s records found': '%(nrows)s records found',
'%s %%{row} deleted': '%s %%{row} gelöscht',
'%s %%{row} updated': '%s %%{row} aktualisiert',
'%s selected': '%s ausgewählt',
@ -12,6 +14,13 @@
'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{Item(Items)}, **%(bytes)s** %%{Byte(Bytes)}',
'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** Items, **%(bytes)s** %%{Byte(Bytes)}',
'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**nicht verfügbar** (benötigt die Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] Bibliothek)',
'+ And': '+ And',
'+ Or': '+ Or',
'<': '<',
'<=': '<=',
'=': '=',
'>': '>',
'>=': '>=',
'?': '?',
'@markmin\x01(**%.0d MB**)': '(**%.0d\xa0MB**)',
'@markmin\x01**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{Item(items)}, **%(bytes)s** %%{Byte(bytes)}',
@ -28,6 +37,10 @@
'A new password was emailed to you': 'Ein neues Passwort wurde per E-Mail an Sie gesendet',
'About': 'Über',
'Access Control': 'Zugangskontrolle',
'Add Record': 'Add Record',
'Add record to database': 'Add record to database',
'Add this to the search as an AND term': 'Add this to the search as an AND term',
'Add this to the search as an OR term': 'Add this to the search as an OR term',
'admin': 'admin',
'Ajax Recipes': 'Ajax Rezepte',
'An error occured, please [[reload %s]] the page': 'Ein Fehler ist aufgetreten, bitte [[laden %s]] Sie die Seite neu',
@ -37,6 +50,7 @@
'Are you sure you want to delete this object?': 'Sind Sie sich sicher, dass Sie dieses Objekt löschen wollen?',
'Authentication code': 'Authentifizierungs code',
'Available Databases and Tables': 'Verfügbare Datenbanken und Tabellen',
'Back': 'Back',
"Buy web2py's book": "web2py's Buch kaufen",
'Cache': 'Zwischenspeicher',
'cache': 'zwischenspeicher',
@ -44,20 +58,27 @@
'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache enthält items die bis zu **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} alt sind.',
'Cache Keys': 'Cache Schlüssel',
'Cannot be empty': 'Darf nicht leer sein',
'Change Password': 'Canviï la Contrasenya',
'Change Password': 'Passwort ändern',
'Change password': 'Canviï la contrasenya',
'Check to delete': 'Auswählen um zu löschen',
'Clear': 'Clear',
'Clear CACHE?': 'CACHE löschen?',
'Clear DISK': 'DISK löschen',
'Clear RAM': 'RAM löschen',
'Click on the link %(link)s to reset your password': 'Klicke auf den Link %(link)s um das Passwort zurückzusetzen',
'Client IP': 'Client IP',
'Close': 'Close',
'Comma-separated export including columns not shown; fields from other tables are exported as raw values for faster export': 'Comma-separated export including columns not shown; fields from other tables are exported as raw values for faster export',
'Comma-separated export of visible columns. Fields from other tables are exported as they appear on-screen but this may be slow for many rows': 'Comma-separated export of visible columns. Fields from other tables are exported as they appear on-screen but this may be slow for many rows',
'Community': 'Community',
'Components and Plugins': 'Komponenten und Plugins',
'Config.ini': 'Config.ini',
'Confirm Password': 'Passwort bestätigen',
'contains': 'contains',
'Controller': 'Controller',
'Copyright': 'Urheberrechte',
'CSV': 'CSV',
'CSV (hidden cols)': 'CSV (hidden cols)',
'Current request': 'Derzeitiger Request',
'Current response': 'Derzeitige Response',
'Current session': 'Derzeitige Session',
@ -67,6 +88,7 @@
'Database Administration (appadmin)': 'Datenbankadministration (appadmin)',
'db': 'db',
'DB Model': 'Muster-DB',
'Delete': 'Delete',
'Delete:': 'Lösche:',
'Demo': 'Demo',
'Deployment Recipes': 'Entwicklungsrezepte',
@ -82,6 +104,8 @@
'done!': 'Fertig!',
'Download': 'Download',
'E-mail': 'Email',
'Edit': 'Edit',
'Edit %(entity)s': 'Edit %(entity)s',
'Edit current record': 'Diesen Eintrag editieren',
'Email and SMS': 'Email und SMS',
'Email sent': 'Email gesendet',
@ -89,7 +113,11 @@
'Email verified': 'Email-Verifiziert',
'Errors': 'Fehlermeldungen',
'export as csv file': 'als csv Datei exportieren',
'Export:': 'Export:',
'FAQ': 'FAQ',
'file': 'file',
'file ## download': 'file ',
'File Filename': 'File Filename',
'First name': 'Vorname',
'Forms and Validators': 'Forms und Validators',
'Free Applications': 'Kostenlose Anwendungen',
@ -98,7 +126,7 @@
'Grid Example': 'Rasterbeispiel',
'Group %(group_id)s created': 'Grupo %(group_id)s creat',
'Group %(group_id)s deleted': 'Gruppe %(group_id)s gelöscht',
'Group ID': 'ID de Grup',
'Group ID': 'ID Benutzergruppe',
'Group uniquely assigned to user %(id)s': 'Gruppe eindeutig dem Benutzer zugewiesen %(id)s',
'Groups': 'Gruppen',
'Hello World': 'Hallo Welt',
@ -106,10 +134,15 @@
'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Trefferquote: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} und **%(misses)s** %%{miss(misses)})',
'Home': 'Startseite',
'How did you get here?': 'Wie sind Sie hier her gelangt?',
'HTML': 'HTML',
'HTML export of visible columns': 'HTML export of visible columns',
'Id': 'Id',
'Images': 'Images',
'import': 'Importieren',
'Import/Export': 'Importieren/Exportieren',
'in': 'in',
'Incorrect code. {0} more attempt(s) remaining.': 'Falscher Code. {0} weitere Versuche verbleiben.',
'Insufficient privileges': 'Privilegis insuficients',
'Insufficient privileges': 'Unzureichende Berechtigungen',
'Internal State': 'Innerer Zustand',
'Introduction': 'Einführung',
'Invalid email': 'Ungültige Email',
@ -122,6 +155,8 @@
'Invalid user': 'Ungültiger Benutzer',
'Invalid username': 'Ungültiger Benutzername',
'Invitation to join %(site)s': 'Einladung um %(site)s zujoinen',
'JSON': 'JSON',
'JSON export of visible columns': 'JSON export of visible columns',
'Key': 'Schlüssel',
'Key verified': 'Schlüssel verifiziert',
'Last name': 'Nachname',
@ -138,15 +173,22 @@
'Manage %(action)s': '%(action)s verwalten',
'Manage Access Control': 'Zugangskontrolle verwalten',
'Manage Cache': 'Cache verwalten',
'Media files': 'Media files',
'Memberships': 'Mitgliedschaften',
'Menu Model': 'Menü-Muster',
'Movies': 'Movies',
'My Sites': 'Meine Seiten',
'Name': 'Nombre',
'New %(entity)s': 'New %(entity)s',
'New password': 'Contrasenya nova',
'New Record': 'Neuer Eintrag',
'new record inserted': 'Neuer Eintrag hinzugefügt',
'New Search': 'New Search',
'next %s rows': 'nächste %s Reihen',
'No databases in this application': 'Keine Datenbank in dieser Anwendung',
'No records found': 'No records found',
'Not Authorized': 'Zugriff verweigert',
'not in': 'not in',
'Number of entries: **%s**': 'Nummer der Einträge: **%s**',
'Object or table name': 'Objekt oder Tabellenname',
'Old password': 'Altes Passwort',
@ -165,10 +207,11 @@
'Permissions': 'Erlaubnisse',
'please input your password again': 'si us plau, entri un altre cop la seva contrasenya',
'Plugins': 'Plugins',
'Posts': 'Posts',
'Powered by': 'Unterstützt von',
'Preface': 'Allgemeines',
'previous %s rows': 'vorherige %s Reihen',
'Profile': 'Perfil',
'Profile': 'Profil',
'Profile updated': 'Profil aktualisiert',
'pygraphviz library not found': 'pygraphviz Bibliothek wurde nicht gefunden',
'Python': 'Python',
@ -205,10 +248,15 @@
'Rows in Table': 'Tabellenreihen',
'Rows selected': 'Reihen ausgewählt',
'Save model as...': 'Speichere Vorlage als...',
'Search': 'Search',
'Services': 'Dienste',
'Sign Up': 'Registrieren',
'Sign up': 'Registrieren',
'Size of cache:': 'Cachegröße:',
'Spreadsheet-optimised export of tab-separated content including hidden columns. May be slow': 'Spreadsheet-optimised export of tab-separated content including hidden columns. May be slow',
'Spreadsheet-optimised export of tab-separated content, visible columns only. May be slow.': 'Spreadsheet-optimised export of tab-separated content, visible columns only. May be slow.',
'Start building a new search': 'Start building a new search',
'starts with': 'starts with',
'state': 'Status',
'Statistics': 'Statistik',
'Stylesheet': 'Stylesheet',
@ -225,7 +273,10 @@
'This email already has an account': 'Zu dieser Email gehört bereits ein Account',
'Time in Cache (h:m:s)': 'Zeit im Cache (h:m:s)',
'Timestamp': 'Zeitstempel',
'Title': 'Title',
'Traceback': 'Zurückverfolgen',
'TSV (Spreadsheets)': 'TSV (Spreadsheets)',
'TSV (Spreadsheets, hidden cols)': 'TSV (Spreadsheets, hidden cols)',
'Twitter': 'Twitter',
'Two-step Login Authentication Code': 'Zweistufiger Login-Authentifizierungscode',
'unable to parse csv file': 'csv Datei konnte nicht geparst werden',
@ -244,19 +295,24 @@
'User %(id)s Username retrieved': 'Se ha recuperat el nom de usuari del usuari %(id)s',
'User %(id)s Verification email sent': 'Benutzer %(id)s Bestätigungs-Email gesendet',
'User %(id)s verified registration key': 'Benutzer %(id)s verifizierter Registrierungsschlüssel',
'User ID': 'ID de Usuari',
'User ID': 'ID des Benutzers',
'Username': 'Benutzername',
'Username already taken': 'Benutzername schon vergeben',
'Username retrieve': 'Recuperar nom de usuari',
'Users': 'Benutzer',
'Value already in database or empty': 'Value already in database or empty',
'Verify Password': 'Verificar Contrasenya',
'Videos': 'Videos',
'View': 'Ansicht',
'View %(entity)s': 'View %(entity)s',
'Vtt Url': 'Vtt Url',
'Welcome %(username)s! Click on the link %(link)s to verify your email': 'Willkommen %(username)s! Klicken Sie auf den Link %(link)s, um Ihre Email zu bestätigen',
'Welcome to web2py!': 'Willkommen bei web2py!',
'Which called the function %s located in the file %s': 'Welche die Funktion %s in der Datei %s aufrief',
'Wiki Example': 'Wiki Beispiel',
'Working...': 'Arbeite...',
'XML': 'XML',
'XML export of columns shown': 'XML export of columns shown',
'You are successfully running web2py': 'web2py wird erfolgreich ausgeführt',
'You can modify this application and adapt it to your needs': 'Sie können diese Anwendung verändern und Ihren Bedürfnissen anpassen',
'You have been invited to join %(site)s, click %(link)s to complete the process': 'Sie wurden eingeladen,%(site)s beizutreten. Klicken Sie auf %(link)s, um den Vorgang abzuschließen',

View File

@ -155,21 +155,11 @@ if configuration.get('scheduler.enabled'):
# auth.enable_record_versioning(db)
db = DAL("sqlite://storage.sqlite")
db.define_table('image',
db.define_table('media_file',
Field('title', unique=True),
Field('file', 'upload'),
Field('vtt_url'),
Field('file', 'upload', autodelete=True),
format = '%(title)s')
db.define_table('post',
Field('image_id', 'reference image'),
Field('author'),
Field('email'),
Field('body', 'text'))
db.image.title.requires = IS_NOT_IN_DB(db, db.image.title)
db.post.image_id.requires = IS_IN_DB(db, db.image.id, '%(title)s')
db.post.author.requires = IS_NOT_EMPTY()
db.post.email.requires = IS_EMAIL()
db.post.body.requires = IS_NOT_EMPTY()
db.post.image_id.writable = db.post.image_id.readable = False
auth = Auth(db)
auth.define_tables(username=True)

13
modules/.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
/_cffi_backend.cpython-36m-x86_64-linux-gnu.so
/bin/
/cffi-1.14.6.dist-info/
/cffi.libs/
/cffi/
/pycparser-2.20.dist-info/
/pycparser/
/srt-3.5.0.dist-info/
/srt.py
/srt_tools/
/vosk/
/vosk-0.3.31.dist-info/
/vosk.libs/

View File

@ -0,0 +1,50 @@
from vosk import Model, KaldiRecognizer, SetLogLevel
import sys
import os
import wave
import subprocess
import srt
import json
import datetime
def create_vtt():
sample_rate = 16000
model = Model("applications/transcription/private/model")
rec = KaldiRecognizer(model, sample_rate)
rec.SetWords(True)
process = subprocess.Popen(['ffmpeg', '-loglevel', 'quiet', '-i',
'/home/mschmidt/Videos/100-Meinungen-Video-erstellen.mp4',
'-ar', str(sample_rate) , '-ac', '1', '-f', 's16le', '-'],
stdout=subprocess.PIPE)
WORDS_PER_LINE = 7
def transcribe():
results = []
subs = []
while True:
data = process.stdout.read(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
results.append(rec.Result())
results.append(rec.FinalResult())
for i, res in enumerate(results):
jres = json.loads(res)
if not 'result' in jres:
continue
words = jres['result']
for j in range(0, len(words), WORDS_PER_LINE):
line = words[j : j + WORDS_PER_LINE]
s = srt.Subtitle(index=len(subs),
content=" ".join([l['word'] for l in line]),
start=datetime.timedelta(seconds=line[0]['start']),
end=datetime.timedelta(seconds=line[-1]['end']))
subs.append(s)
return subs
return (srt.compose(transcribe()))

1
private/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/model/

View File

@ -2,10 +2,10 @@
<div class="row">
<div class="col-md-12">
<h1>Current Images</h1>
<h1>Mediendateien</h1>
<ul>
{{for image in images:}}
{{=LI(A(image.title, _href=URL("show", args=image.id)))}}
{{for media_file in media_files:}}
{{=LI(A(media_file.title, _href=URL("show", args=media_file.id)))}}
{{pass}}
</ul>
</div>

8
views/default/vtt.html Normal file
View File

@ -0,0 +1,8 @@
{{extend 'layout.html'}}
<div class="row">
<div class="col-md-12">
<p>{{=message}}</p>
</div>
</div>