Compare commits

..

6 Commits

Author SHA1 Message Date
Spanier, Pit 6cff6b9981 Merge branch 'develop' into 'feature/38-sprecher-audio-snippets-s4-11'
# Conflicts:
#   main.js
2025-12-16 16:18:17 +01:00
santa 0003d99041 extract speaker snippets mit main verknüpft. 2025-12-16 15:32:31 +01:00
Hughes, Mike 6a94f88e86 Merge branch 'feature/meeting_document_types' into 'develop'
Added Meeting Document Forms

See merge request proj-wise2526-video2document/video2document!55
2025-12-16 14:43:54 +01:00
MikeHughes-BIN 30f73f7bb7 Added Meeting Document Forms 2025-12-16 14:24:13 +01:00
Hughes, Mike 74439d680e Merge branch 'fix/download-button' into 'develop'
oopsies missed a </div>

See merge request proj-wise2526-video2document/video2document!53
2025-12-15 18:49:19 +01:00
Hughes, Mike 363ba2d1b5 Merge branch 'fix/download-button' into 'develop'
Enable download button functionality and improve error handling in file download

See merge request proj-wise2526-video2document/video2document!52
2025-12-15 18:43:50 +01:00
11 changed files with 248 additions and 214 deletions
+7 -2
View File
@@ -197,7 +197,12 @@ electron.ipcMain.on("file_submit", async (event, args) => {
return
})
}
await mapFunctions.get("extract-speaker-snippets").function({audioPath: audiopath, jsonPath: transcriptpath }).then(resp => {
mainWindow.webContents.send("submitSpeaker", resp)
console.log(resp)
})
// TODO actually implement this functionality
// Module to get the first few lines for each speaker to send to the frontend
// await mapFunctions.get("speaker-getter-idfk").function(transcriptpath).then(resp => {
@@ -210,7 +215,7 @@ electron.ipcMain.on("file_submit", async (event, args) => {
// // speakerA: {source: "Pfad zur Audio File"},
// // speakerB:.....
// // }
mainWindow.webContents.send("speakers", {speakerA:"pfad1", speakerB:"pfad2"})
// mainWindow.webContents.send("speakers", {speakerA:"pfad1", speakerB:"pfad2"})
// }).catch(err => {
// mainWindow.webContents.send("error", err)
// return
+5 -4
View File
@@ -15,7 +15,7 @@
"dotenv": "^17.2.3",
"electron": "^39.1.1",
"express": "^5.1.0",
"ffmpeg-static": "^5.2.0",
"ffmpeg-static": "^5.3.0",
"fluent-ffmpeg": "^2.1.3",
"html-to-docx": "^1.8.0",
"mocha": "^11.7.5",
@@ -1773,9 +1773,9 @@
}
},
"node_modules/ffmpeg-static": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz",
"integrity": "sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.3.0.tgz",
"integrity": "sha512-H+K6sW6TiIX6VGend0KQwthe+kaceeH/luE8dIZyOP35ik7ahYojDuqlTV1bOrtEwl01sy2HFNGQfi5IDJvotg==",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
@@ -1832,6 +1832,7 @@
"resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz",
"integrity": "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"license": "MIT",
"dependencies": {
"async": "^0.2.9",
"which": "^1.1.1"
+1 -1
View File
@@ -6,7 +6,7 @@
"dotenv": "^17.2.3",
"electron": "^39.1.1",
"express": "^5.1.0",
"ffmpeg-static": "^5.2.0",
"ffmpeg-static": "^5.3.0",
"fluent-ffmpeg": "^2.1.3",
"html-to-docx": "^1.8.0",
"mocha": "^11.7.5",
@@ -0,0 +1,95 @@
const ffmpeg = require("fluent-ffmpeg");
const ffmpegPath = require("ffmpeg-static");
ffmpeg.setFfmpegPath(ffmpegPath);
module.exports = {
name: "extract-speaker-snippets",
type: "audio",
displayname: "Extract Speaker Snippets",
async function(parameter) {
return new Promise(async (resolve, reject) => {
let output = {}
console.log("Extract Speaker Snippets\n");
// Pfade
const AUDIO_PATH = parameter.audioPath; // Gesamt-Audio
const JSON_PATH = parameter.jsonPath; // json summary
const OUTPUT_DIR = path.join(__dirname, "/../../../storage/audio/speakerSnippets");
if (!AUDIO_PATH || !JSON_PATH) {
console.error("no audioPath or jsonPath available");
return;
}
// Output-Ordner
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
// JSON laden
let entries;
try {
entries = JSON.parse(fs.readFileSync(JSON_PATH, "utf8"));
} catch (err) {
console.error("JSON reading failed", err);
return;
}
if (!Array.isArray(entries)) {
console.error("JSON is not an Array");
return;
}
// Pro Speaker genau EINEN Satz merken
const speakerMap = {};
for (const item of entries) {
if (!speakerMap[item.speaker]) {
speakerMap[item.speaker] = item;
}
}
// FFmpeg pro Speaker ausführen (sequenziell)
for (const speaker of Object.keys(speakerMap)) {
const data = speakerMap[speaker];
// ms → Sekunden
const startSec = data.start / 1000;
const durationSec = (data.end - data.start) / 1000;
if (durationSec <= 0) {
console.log(`invalid times for Speaker ${speaker}`);
continue;
}
const outFile = path.join(OUTPUT_DIR, `speaker_${speaker}.wav`);
await new Promise((res, rej) => {
ffmpeg(AUDIO_PATH)
.setStartTime(startSec)
.setDuration(durationSec)
.output(outFile)
.on("end", () => {
output[`speaker${speaker}`] = {src: outFile, name: `speaker${speaker}`}
console.log(`Snippet erstellt: speaker_${speaker}.wav`);
res();
})
.on("error", (err) => {
console.error(`FFmpeg Fehler (${speaker})`, err.message);
rej();
})
.run();
});
}
resolve(output)
console.log("\nAlle Speaker-Snippets erstellt\n");
})
}
};
+1
View File
@@ -10,6 +10,7 @@ module.exports = {
// let transcript = await mapFunctions.get("assembly").function('../../storage/audio/IMG_2978.wav');
// let summary = await mapFunctions.get("summarize-transcription").function({jsonPath:'/Users/santa/Proj25/video2document/storage/transcripts/IMG_2978.json'});
// let snippets = await mapFunctions.get("extract-speaker-snippets").function({audioPath:'/Users/santa/Proj25/video2document/storage/audio/KittyKat.wav', jsonPath1: '/Users/santa/Proj25/video2document/storage/transcriptionSummaries/KittyKat-1765806474958.json' });
BIN
View File
Binary file not shown.
+25
View File
@@ -0,0 +1,25 @@
Du bist ein erfahrener Moderator und Projektmanager.
AUFGABE:
Erstelle eine sinnvolle Meeting-Agenda basierend auf dem folgenden Transkript.
ANFORDERUNGEN:
- Rekonstruiere die tatsächlichen Themenblöcke
- Ordne sie logisch und chronologisch
- Fasse ähnliche Diskussionen zusammen
- Keine irrelevanten Details aufnehmen
STRUKTUR:
- Titel der Agenda
- Ziel des Meetings (12 Sätze)
- Agenda-Punkte (nummeriert)
- Thema
- Kurzbeschreibung
- Ziel des Punktes (Information, Entscheidung, Diskussion)
STIL:
- Klar, kompakt
- Business-orientiert
- Keine Sprecher- oder Zeitangaben
TRANSKRIPT:
+21
View File
@@ -0,0 +1,21 @@
Du bist ein intelligenter Dokumenten-Generator.
AUFGABE:
Erstelle ein individuelles Dokument basierend auf:
1) dem Meeting-Transkript
2) der zusätzlichen Nutzeranweisung
WICHTIG:
- Priorisiere die Nutzeranweisung
- Nutze das Transkript als Wissensquelle
- Struktur, Tonalität und Detailgrad anpassen
- Inhalte logisch zusammenführen
FORMAT:
- Passe Struktur und Stil an den Nutzerwunsch an
- Klare Überschriften
- Keine Sprecher- oder Zeitangaben
TRANSKRIPT & NUTZERANWEISUNG:
+25
View File
@@ -0,0 +1,25 @@
Du bist ein professioneller Protokollführer.
AUFGABE:
Erstelle ein Ergebnisprotokoll basierend auf dem Meeting-Transkript.
FOKUS:
- Ergebnisse statt Diskussionen
- Entscheidungen, Beschlüsse, Vereinbarungen
- Klare, überprüfbare Aussagen
STRUKTUR:
1. Meeting-Informationen
2. Ergebnisse je Thema
- Thema
- Ergebnis / Beschluss
3. Entscheidungen
4. Aufgaben & Verantwortlichkeiten
5. Offene Punkte
REGELN:
- Keine Meinungen oder Spekulationen
- Keine Zeit- oder Sprecherangaben
- Sachlich, formal
TRANSKRIPT:
@@ -0,0 +1,34 @@
Du bist ein erfahrener Scrum Master.
AUFGABE:
Erstelle Sprint Planning Notes aus dem folgenden Meeting-Transkript.
FOKUS:
- Sprint-Ziele
- User Stories / Tasks
- Abhängigkeiten
- Risiken
- Commitments
STRUKTUR:
1. Sprint Overview
- Sprint-Ziel
- Zeitraum (falls erwähnt)
2. Geplante Arbeit
- User Story / Task
- Beschreibung
- Akzeptanzkriterien (falls ableitbar)
3. Abhängigkeiten & Blocker
4. Risiken & Annahmen
5. Vereinbarungen / Team-Commitments
STIL:
- Agile-konform
- Klar & umsetzungsorientiert
- Bullet Points bevorzugen
TRANSKRIPT:
+34 -207
View File
@@ -1,217 +1,44 @@
Generate a structured meeting report in HTML using STRUCTURE and STYLE.
Output ONLY the final .md document — no meta comments, no explanations.
Du bist ein professioneller Meeting-Analyst und Business Writer.
Follow exactly the STRUCTURE defined below.
Follow exactly the STYLE rules.
Use timestamps in HH:MM:SS format.
If information is missing, use: Unclear:<reason>.
AUFGABE:
Erstelle einen strukturierten Follow-up Report basierend auf dem folgenden Meeting-Transkript.
==================== STRUCTURE & RULES ====================
ANFORDERUNGEN:
- Fasse Inhalte sinngemäß zusammen
- Entferne Redundanzen und Smalltalk
- Formuliere klar, präzise und professionell
- Verwende neutrale Business-Sprache
- Keine Zeitstempel oder Sprecher-Namen zitieren
- Leite Entscheidungen und Aufgaben logisch ab, wenn sie implizit sind
- Markiere offene Punkte klar
{
"FORMAT": "HTML",
STRUKTUR DES DOKUMENTS:
1. Titel & Metadaten
- Meetingtitel (ableiten)
- Datum (falls im Transkript erwähnt, sonst „nicht angegeben“)
- Teilnehmer (zusammengefasst)
"STRUCTURE": {
"titlepage": [
"title",
"date",
"start",
"end",
"duration",
"location",
"host",
"participants"
],
2. Executive Summary (max. 5 Bullet Points)
"toc": "[section](#anchor) — HH:MM:SS",
3. Besprochene Themen
- Thema
- Kernaussagen
- Relevante Erkenntnisse
"section": {
"h2": "<topic> — HH:MM:SS",
"summary": "exactly 1 concise sentence",
"key_points": "maximum 5 bullet points; quotes optional",
"decisions": "list items formatted as: decision text | owner | due date",
"actions": "HTML table: id | task | owner | due | status"
},
4. Entscheidungen
- Entscheidung
- Kontext / Begründung
"exec_summary": "exactly 3 short sentences",
5. Action Items
- Aufgabe
- Verantwortlich (falls ableitbar)
- Ziel / Zweck
"consolidated": [
"decisions",
"actions"
],
6. Offene Fragen & Risiken
"appendix": "optional"
},
STIL:
- Überschriften klar strukturiert
- Bullet Points bevorzugen
- Präzise, keine Umgangssprache
"STYLE": {
"tone": "neutral, concise, professional",
"ts_format": "HH:MM:SS",
"no_meta": true
},
"PROCESS": {
"timestamps": "use transcript timestamps if present; otherwise estimate minimal",
"speakers": "use names if available; else Speaker X",
"long_transcripts": "split → summarize → merge",
"unclear": "Unclear:<reason>"
},
"PROMPT_SNIPPET": "Generate meeting report in HTML using STRUCTURE and STYLE. Output only the report."
}
============================================================
Insert all generated content into the following HTML TEMPLATE:
# {{title}}
**Date:** {{date}}
**Start:** {{start}}
**End:** {{end}}
**Duration:** {{duration}}
**Location:** {{location}}
**Host:** {{host}}
**Participants:** {{participants}}
---
## Table of Contents
{{toc}}
---
Generate a structured meeting report in HTML using STRUCTURE and STYLE.
Output ONLY the final .md document — no meta comments, no explanations.
Follow exactly the STRUCTURE defined below.
Follow exactly the STYLE rules.
Use timestamps in HH:MM:SS format.
If information is missing, use: UNKLAR:<reason>.
==================== STRUCTURE & RULES ====================
{
"FORMAT": "HTML",
"STRUCTURE": {
"titlepage": [
"title",
"date",
"start",
"end",
"duration",
"location",
"host",
"participants"
],
"toc": "[section](#anchor) — HH:MM:SS",
"section": {
"h2": "<topic> — HH:MM:SS",
"summary": "exactly 1 concise sentence",
"key_points": "maximum 5 bullet points; quotes optional",
"decisions": "list items formatted as: decision text | owner | due date",
"actions": "HTML table: id | task | owner | due | status"
},
"exec_summary": "exactly 3 short sentences",
"consolidated": [
"decisions",
"actions"
],
"appendix": "optional"
},
"STYLE": {
"tone": "neutral, concise, professional",
"ts_format": "HH:MM:SS",
"no_meta": true
},
"PROCESS": {
"timestamps": "use transcript timestamps if present; otherwise estimate minimal",
"speakers": "use names if available; else Speaker X",
"long_transcripts": "split → summarize → merge",
"unclear": "UNKLAR:<reason>"
},
"PROMPT_SNIPPET": "Generate meeting report in HTML using STRUCTURE and STYLE. Output only the report."
}
============================================================
Insert all generated content into the following HTML TEMPLATE:
# {{title}}
**Date:** {{date}}
**Start:** {{start}}
**End:** {{end}}
**Duration:** {{duration}}
**Location:** {{location}}
**Host:** {{host}}
**Participants:** {{participants}}
---
## Table of Contents
{{toc}}
---
## Executive Summary
{{exec_summary}}
---
## Sections
{{sections}}
---
## Consolidated Decisions
{{consolidated_decisions}}
---
## Consolidated Actions
{{consolidated_actions}}
---
## Appendix
{{appendix}}
============================================================
Final Requirement:
Output ONLY the completed HTML meeting report.
## Executive Summary
{{exec_summary}}
---
## Sections
{{sections}}
---
## Consolidated Decisions
{{consolidated_decisions}}
---
## Consolidated Actions
{{consolidated_actions}}
---
## Appendix
{{appendix}}
============================================================
Final Requirement:
Output ONLY the completed HTML meeting report.
TRANSKRIPT: