diff --git a/services/modules/jsonTools/transcriptionSummarizer.js b/services/modules/jsonTools/transcriptionSummarizer.js index 742075b..e6e1318 100644 --- a/services/modules/jsonTools/transcriptionSummarizer.js +++ b/services/modules/jsonTools/transcriptionSummarizer.js @@ -7,6 +7,7 @@ if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } +//Speaker, ALL-Sentences, Start, End module.exports = { name: "summarize-transcription", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()" @@ -34,8 +35,7 @@ module.exports = { return { error: "Invalid JSON" }; } } - // console.log(inputJson); - console.log(outputDir); + const words = inputJson.words; if (!Array.isArray(words)) { return { error: "No words Array found" }; diff --git a/services/modules/jsonTools/transcriptionSummarizer2.js b/services/modules/jsonTools/transcriptionSummarizer2.js new file mode 100644 index 0000000..12d00bf --- /dev/null +++ b/services/modules/jsonTools/transcriptionSummarizer2.js @@ -0,0 +1,121 @@ +const fs = require("fs"); +const path = require("path"); + +// Prepare output directory (always storage/transcriptionSummaries under project root) +const outputDir = `${__dirname}/../../../storage/transcriptionSummaries`; +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); +} + +//Speaker, Sentence, Start, End + +module.exports = { + name: "summarize-transcription2", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()" + type: "summarizer", // value used to differentiate each module to order them in the UI + displayname: "Summarizer", // The displayname used within the UI + async function(args) { + let inputJson = args.json; + + //JSON Path + if (args.jsonPath) { + try { + const raw = fs.readFileSync(args.jsonPath, "utf-8"); + inputJson = JSON.parse(raw); + } catch (e) { + console.error("Failed to load JSON from file:", e); + return { error: "Could not read JSON from file path." }; + } + } + // JSON parsen + if (typeof inputJson === "string") { + try { + inputJson = JSON.parse(inputJson); + } catch (e) { + console.log("Invalid JSON in summarize-transcription"); + return { error: "Invalid JSON" }; + } + } + + const words = inputJson.words; + if (!Array.isArray(words)) { + return { error: "No words Array found" }; + } + + const ENDINGS = [".", "!", "?"]; // '...' auch als Satzende ? + const ABBREVIATIONS = new Set(["z.B.", "bzw.", "u.a.", "Dr.", "Mr.", "Mrs.", "Prof.", "etc."]); //TODO weitere Ergaenzen + + const result = []; + let currentSentence = ""; + let currentSpeaker = null; + let startTime = null; + let endTime = null; + + for (const w of words) { + if (!currentSpeaker) currentSpeaker = w.speaker; + if (startTime === null) startTime = w.start; + endTime = w.end; + + //speaker changing + if (currentSpeaker !== w.speaker && currentSentence) { + result.push({ + speaker: currentSpeaker, + sentence: currentSentence, + start: startTime, + end: endTime + }); + currentSentence = ""; + startTime = w.start; + } + currentSpeaker = w.speaker; + currentSentence += (currentSentence ? " " : "") + w.text; //sentence beginning or not + const lastWord = w.text.trim(); + const lastChar = lastWord.slice(-1); + const isAbbreviation = ABBREVIATIONS.has(lastWord); + + //sentence ending + if (ENDINGS.includes(lastChar) && !isAbbreviation) { + result.push({ + speaker: currentSpeaker, + sentence: currentSentence, + start: startTime, + end: endTime + }); + currentSentence = ""; + startTime = null; + endTime = null; + currentSpeaker = null; + } + } + + // safe last sentence + if (currentSentence) { + result.push({ + speaker: currentSpeaker, + sentence: currentSentence, + start: startTime, + end: endTime + }); + } + + + // Output as Text + const output = result.map(r => + `Sprecher ${r.speaker} [${r.start.toFixed(2)} - ${r.end.toFixed(2)}]: ${r.sentence}` + ); + + // Output on cosole + //console.log("\n------------\nMerged Transcription Result:\n", output, "\n------------\n"); + + try { + const jsonPath = path.join(outputDir, "transcription_result.json"); + fs.writeFileSync(jsonPath, JSON.stringify(result, null, 2), "utf-8"); + + const txtPath = path.join(outputDir, "transcription_result.txt"); + fs.writeFileSync(txtPath, output.join("\n"), "utf-8"); + + console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`); + } catch (err) { + console.error("Error saving Summary:", err); + } + } +} diff --git a/services/modules/transcription-remote/assembly.js b/services/modules/transcription-remote/assembly.js index bf72e1f..d31a67b 100644 --- a/services/modules/transcription-remote/assembly.js +++ b/services/modules/transcription-remote/assembly.js @@ -1,9 +1,6 @@ -//require('dotenv').config(); -//const axios = require('axios'); -//const fs = require('fs'); -const path = require('path'); +require('dotenv').config(); -const API_KEY = process.env.ASSEMBLYAI_API_KEY; +const API_KEY = process.env.API_KEY; const BASE_URL = 'https://api.assemblyai.com/v2'; //---------------------------------------------------Upload audio--------------------------------------------------- @@ -93,7 +90,7 @@ module.exports = { type: 'transcription', displayname: 'AssemblyAI', - run: async (audioFileName) => { + async function(audioFileName) { try { // audioFileName ist nur "datei.mp3" const audioPath = path.join( diff --git a/services/modules/utility/@startup.js b/services/modules/utility/@startup.js index dcf64c8..cfa200e 100644 --- a/services/modules/utility/@startup.js +++ b/services/modules/utility/@startup.js @@ -6,6 +6,13 @@ module.exports = { // We are now calling the example function from the example folder mapFunctions.get("example").function("Startup") + 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'}); + + + + // mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./a.mp4", outputType:"wav"}) // mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./b.mp4", outputType:"wav"}) // mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./b.mp4", outputType:"flac"}) diff --git a/test/integration/assemblyTest.js b/test/integration/assemblyTest.js new file mode 100644 index 0000000..76a17ba --- /dev/null +++ b/test/integration/assemblyTest.js @@ -0,0 +1,18 @@ +require('dotenv').config(); +const path = require('path'); +const assemblyModule = require('../../services/modules/transcription-remote/assembly.js'); + +// Audio-Datei oder URL aus Kommandozeile, Standard: test.wav +const audioPath = process.argv[2] || './storage/audio/IMG_2978.wav'; + +(async () => { + try { + const transcript = await assemblyModule.run(audioPath); + + console.log('Transcription succesful'); + console.log('Transcript ID:', transcript?.id); + console.log('Speaker labels:', transcript?.utterances?.length || 0); + } catch (error) { + console.error('Error in Transcription:', error?.message || error); + } +})();