
Teilen Sie:
Karl ist Developer Advocate bei Vonage und kümmert sich um die Wartung unserer Ruby Server SDKs und die Verbesserung der Entwicklererfahrung für unsere Community. Er liebt es zu lernen, Dinge zu entwickeln, Wissen zu teilen und alles, was allgemein mit Webtechnologie zu tun hat.
Video + AI: Konfigurierbare Audioverarbeitung für Video-Applikationen
Lesedauer: 5 Minuten
Anfang dieses Jahres habe ich über eine Node-Anwendung geschrieben, die ich gebaut habe, um Audio von einem Videoanruf mit der Audio-Connector-Funktion der Video API von Vonage zu transkribieren. Das Hauptziel der Anwendung und des zugehörigen Blogbeitrags war es, einen grundlegenden Anwendungsfall für den Audio Connector zu demonstrieren. Wenn man an Audioverarbeitung denkt, ist die Transkription wahrscheinlich eines der ersten Dinge, die einem in den Sinn kommen, daher war es sinnvoll, sich auf diesen Anwendungsfall als Einführung in die Funktion zu konzentrieren. Es gibt jedoch noch so viel mehr, was man mit der Audioverarbeitung machen kann, wie Sie vielleicht schon in anderen Artikeln dieser Serie gesehen haben, also dachte ich, es wäre interessant, einige weitere Funktionen in diese Anwendung einzubauen, um ein paar andere Anwendungsfälle zu demonstrieren. Sie können sich die aktualisierte Anwendung auf GitHub.
In diesem Artikel werde ich kurz die hinzugefügten Funktionen skizzieren, bevor ich einen Teil der Implementierung im Code erläutere. Der Artikel geht nicht auf die Gesamtarchitektur oder die Implementierung der ersten Iteration der Anwendung ein, daher sollten Sie den Artikel diesen Artikel zuerst lesen. Sie können den Code (wie er zu diesem Zeitpunkt der Geschichte war) auch auf unserer Vonage Community GitHub org.
Bevor wir Ihnen die neuen Funktionen der Anwendung vorstellen, möchten wir Ihnen kurz erklären, was Audio Connector ist. Audio Connector ist eine Funktion der Vonage Video API, mit der Sie einen oder mehrere Roh-Audioströme (entweder einzeln oder gemischt) aus einer Vonage Video-Sitzung über Ihren eigenen WebSocket-Server an externe Dienste zur weiteren Verarbeitung senden können.
Audio Connector process flow diagram
Sie verwenden ihn, indem Sie einen REST-API-Aufruf an die Video API von Vonage tätigen und dabei den oder die Streams angeben, für die Sie die Audiodaten benötigen, sowie die WebSocket-Adresse, an die sie gesendet werden sollen. Im Wesentlichen besteht die Funktion des Audio Connectors darin, Audiodaten aus einem Videoanruf zu extrahieren und diese Daten an einen WebSocket zu senden. Was Sie dann mit den Audiodaten machen, bleibt ganz Ihnen überlassen.
Weitere Informationen über Audio Connector finden Sie in der Video API Dokumentation.
In der ersten Iteration der Anwendung haben wir das Symbl.ai JavaScript SDK um die Audiodaten an Symbl's Streaming-API für die Transkription. Schauen wir uns nun einige der neuen Audioverarbeitungsfunktionen in der aktuellen Iteration der App an.
Was gibt es Neues?
Neben der Transkription bietet die Demo-App nun auch eine Reihe spezifischer Einblicke, die auf dem Audio eines Videoanrufs basieren.
Fragen: Fragen werden aus dem Audiomaterial extrahiert, wenn ein Teilnehmer des Videoanrufs im Rahmen des Gesprächs etwas sagt, das als Frage formuliert ist, z. B. "Wann steht das Budget für dieses Projekt fest?"
Aktionspunkte: Ähnlich wie Fragen werden diese aus einem Gespräch extrahiert, wenn etwas als spezifische Aufgabe formuliert wird, die erledigt werden muss, z. B. "Ich werde den Blogbeitrag bis zum Ende des aktuellen Sprints fertig stellen."
Themen: Themen werden aus einer Konversation extrahiert, wenn ein Wort oder eine Phrase erkannt wird, die als wichtiges Schlüsselwort eingestuft wird.
Anwendungsablauf
Die neuen Funktionen wurden so implementiert, dass der Endbenutzer konfigurieren kann, welche Teile des Audios er verarbeiten möchte.
Der Anwendungsablauf beginnt mit einem Formular, das eine Reihe von Kontrollkästchen enthält, die jeweils einer Verarbeitungsoption entsprechen. Der Benutzer wählt die gewünschten Optionen aus und klickt auf die Schaltfläche "Videoanruf mit Audioverarbeitung".
Application Config Options Screen
Sie gelangen dann zum Hauptbildschirm des Anrufs, wo sie ihren Namen eingeben und den Anruf starten können. Es gibt eine Schaltfläche zum Starten der Audioverarbeitung und Links zu Seiten, die das verarbeitete Audio für die ausgewählten Optionen anzeigen.
Main call screen
Ein Klick auf den Link "Fragen abrufen" würde den Nutzer beispielsweise auf eine Seite führen, auf der alle während des Videoanrufs erkannten Fragen aufgelistet sind.
Questions output screen
Code Erläuterung
In der ersten Iteration der App wurde die Transkriptionsverarbeitung über die Symbl.ai's Streaming-APIabgewickelt, genauer gesagt, durch die Verwendung des JavaScript SDK, um eine Anfrage an die API mit der sendAudio Methode. Es gab zwei Hauptaspekte bei der Implementierung dieser Methode:
Definition eines Handlers für die Spracherkennung durch den Methodenaufruf des Symbl SDK
startRealtimeRequestMethodenaufruf erkannt wird.Etwas mit den zurückgegebenen Daten zu tun (was in diesem Fall bedeutete, sie in einem
transcriptionsArray). Dieses Array wurde über dasapp.contextObjekt zur Verfügung gestellt, so dass sein Inhalt später nach Bedarf gerendert werden konnte.
Die neuen Verarbeitungsfunktionen (Fragen, Aktionspunkte und Themen) sind auch über die Streaming-API von Symbl verfügbar, erfordern aber zusätzliche Handler. Ich habe mich auch entschieden, die Antwortdaten für die verschiedenen Handler in separaten Arrays zu speichern (obwohl ich sie alternativ auch in demselben Array hätte speichern und beim Rendern filtern können).
Ein weiterer Aspekt der neuen Funktionen ist die Tatsache, dass sie konfigurierbar sind. Beim Aufrufen von startRealtimeRequestwollte ich nur die Handler hinzufügen, die notwendig waren.
Die Logik zur Verwaltung all dessen wurde in eine SymblProcessor Klasse ausgelagert, und anstatt ein transcriptions Array definiert wird auf app.context innerhalb der index.js Datei definiert wird, wird ein SymblProcessor Objekt instanziiert und dem Kontext hinzugefügt:
app.context.symblProcessor = new SymblProcessor();Ein Großteil der neuen Implementierung wird von dieser SymblProcessor Klasse.
class SymblProcessor {
constructor() {
this.messages = [];
this.insights = [];
this.topics = [];
this.config = {
transcription: false,
actionItems: false,
questions: false,
topics: false
};
}
setConfig(config) {
config.forEach(option => this.config[option] = true);
}
sethandlers() {
let handlers = {};
if (this.config.transcription) { handlers.onMessageResponse = this.onMessageResponseHandler; }
if (this.config.actionItems || this.config.questions) { handlers.onInsightResponse = this.onInsightResponseHandler; }
if (this.config.topics) { handlers.onTopicResponse = this.onTopicResponseHandler; }
return handlers;
}
setInsightTypes() {
let insightTypes = [];
if (this.config.actionItems) { insightTypes.push('action_item'); }
if (this.config.questions) { insightTypes.push('question'); }
return insightTypes;
}
getTranscriptions() {
return this.messages.map(message => ({id: message[0].from.id, name: message[0].from.name, transcription: message[0].payload.content}));
}
getActionItems() {
let actionItems = this.insights.filter(insight => insight[0].type == 'action_item');
return actionItems.map(item => item[0].payload.content);
}
getQuestions() {
let questions = this.insights.filter(insight => insight[0].type == 'question');
return questions.map(question => question[0].payload.content);
}
getTopics() {
return this.topics.map(topic => topic[0].phrases);
}
onMessageResponseHandler = (data) => {
this.messages.push(data);
}
onInsightResponseHandler = (data) => {
this.insights.push(data);
}
onTopicResponseHandler = (data) => {
this.topics.push(data);
}
}
Die Klasse definiert eine constructor mit separaten Arrays für messages (Transkriptionen), insights (das sowohl Fragen als auch Aktionspunkte enthält), und topicssowie das Setzen eines Standard config.
Es hat dann drei Methoden (setConfig, sethandlers, und setInsightTypes) zum Aktualisieren des config Objekts (auf der Grundlage der vom Benutzer gewählten Optionen) und dann die Verwendung dieser aktualisierten config zur Bestimmung der handlers und insightTypes Einstellungen für den symblSdk.startRealtimeRequest Aufruf.
Die verbleibenden Methoden sind die Definitionen für die Handler selbst (die im Wesentlichen nur die zurückgegebenen Daten in das entsprechende Array schieben) und Methoden zum Abrufen von Daten aus den Arrays und zum Filtern und/oder Zuordnen der Daten, damit sie dann in den entsprechenden Ansichten angezeigt werden können.
Es gibt einige zusätzliche Änderungen an der App, wie z. B. Aktualisierungen des postSymblCall Controller, postSymblProcessing Controller, zusätzliche Routen, Routehandler und Ansichten sowie einige Umstrukturierungen/Umbenennungen von Dateien, Funktionen usw. Ich werde nicht näher auf diese Änderungen eingehen, da sie in erster Linie nur dazu dienen, die Auslagerung eines Großteils der Verarbeitungslogik in die SymblProcessor Klasse zu erleichtern.
Audio-Anschluss: Einzelne vs. kombinierte Streams
Abschließend möchte ich noch einen Aspekt der Verwendung der Audio-Connector-Funktion hervorheben, der entscheidend dafür sein kann, wie Sie eine Anwendung implementieren, die diese Funktion nutzt.
Der /connect Endpunkt der Vonage Video API, der zum Starten einer Audio Connector WebSocket-Verbindung verwendet wird, gibt Ihnen die Möglichkeit, ein streams Array als Teil des Anfragekörpers zu übergeben, das die IDs der Streams enthält, für die das Audio an den WebSocket gesendet werden soll.
{
"sessionId": "Vonage Video API session ID",
"token": "A valid Vonage Video API token",
"websocket": {
"uri": "wss://service.com/ws-endpoint",
"streams": [
"streamId-1",
"streamId-2"
],
"headers": {
"headerKey": "headerValue"
},
"audioRate" : 8000
}
}Wenn diese streams weggelassen wird, wird das kombinierte Audio aller Streams in der Sitzung gesendet.
Da sich die ursprüngliche Implementierung dieser Anwendung auf die Transkription konzentrierte und ich wollte, dass bestimmte transkribierte Audiostücke einzelnen identifizierten Sprechern innerhalb des Videoanrufs zugeordnet werden, wurde die Anwendung implementiert, indem mehrere Anfragen an diesen Endpunkt gestellt wurden, wobei jede einen einzelnen Stream angab und für jeden Stream ein anderer Websocket definiert wurde.
Wenn die Anforderungen Ihrer Anwendung es jedoch nicht erforderlich machen, dass Sie die transkribierten Audiodaten einzelnen identifizierten Sprechern zuordnen können (z. B. wenn Sie die in der Telefonkonferenz aufgeworfenen Fragen zusammenfassen möchten, aber nicht wissen müssen, wer die Frage gestellt hat), dann wäre es wahrscheinlich sinnvoller, die Audiodaten zu kombinieren und an einen einzigen Websocket-Endpunkt zu senden.
Nächste Schritte
Wir hoffen, dass dieser Artikel Ihnen einige Ideen für die Funktionen gegeben hat, die Sie mit Audio Connector erstellen können, und Sie vielleicht dazu inspiriert hat, etwas Tolles zu erstellen!
Wenn Sie Kommentare oder Fragen haben oder einfach nur ein Projekt vorstellen möchten, das Sie mit dem Audio Connector erstellt haben, können Sie uns gerne in unserem Vonage Entwickler Slack.
Teilen Sie:
Karl ist Developer Advocate bei Vonage und kümmert sich um die Wartung unserer Ruby Server SDKs und die Verbesserung der Entwicklererfahrung für unsere Community. Er liebt es zu lernen, Dinge zu entwickeln, Wissen zu teilen und alles, was allgemein mit Webtechnologie zu tun hat.