diff --git a/electron/.DS_Store b/electron/.DS_Store
new file mode 100644
index 0000000..0098130
Binary files /dev/null and b/electron/.DS_Store differ
diff --git a/electron/main/index.html b/electron/main/index.html
index 6d045ab..0fa59e0 100644
--- a/electron/main/index.html
+++ b/electron/main/index.html
@@ -19,7 +19,7 @@
diff --git a/electron/main/preload.js b/electron/main/preload.js
index 356ada0..90573fb 100644
--- a/electron/main/preload.js
+++ b/electron/main/preload.js
@@ -3,35 +3,39 @@ const { contextBridge, ipcRenderer, webUtils } = require('electron')
try {
contextBridge.exposeInMainWorld("explorer", {
onFileDrop: (file) => webUtils.getPathForFile(file)
- })
+ });
+
contextBridge.exposeInMainWorld("submit", {
- submit: (meeting_specifications) => {ipcRenderer.send("file_submit", meeting_specifications)}
- })
+ submit: (meeting_specifications) => ipcRenderer.send("file_submit", meeting_specifications)
+ });
+
+ // ALLE electronAPI Funktionen in EINEM Objekt
contextBridge.exposeInMainWorld("electronAPI", {
- getFilePath: (file) => {return webUtils.getPathForFile(file)}
- })
+ getFilePath: (file) => webUtils.getPathForFile(file),
+ saveSpeakerMapping: (data) => ipcRenderer.send("save-speaker-mapping", data)
+ });
contextBridge.exposeInMainWorld("onStartup", {
getModuleNames: () => ipcRenderer.invoke('get-module-names')
- })
+ });
contextBridge.exposeInMainWorld('electron', {
progress: (callback) => ipcRenderer.on('progress', callback)
- })
+ });
contextBridge.exposeInMainWorld('audios', {
speakerAudios: (callback) => ipcRenderer.on('speakerAudios', callback)
- })
+ });
+
contextBridge.exposeInMainWorld("submitSpeaker", {
- speaker_submit: (speaker_names) => {ipcRenderer.send("speaker_submit", speaker_names)}
- })
+ speaker_submit: (speaker_names) => ipcRenderer.send("speaker_submit", speaker_names)
+ });
contextBridge.exposeInMainWorld("download", {
- file_download: () => {ipcRenderer.send("file_download")}
- })
+ file_download: () => ipcRenderer.send("file_download")
+ });
-
- ipcRenderer.on("error", (event, err) => {alert(err)})
+ ipcRenderer.on("error", (event, err) => { alert(err) });
} catch (error) {
- console.log("Error in preload.js");
-}
+ console.log("Error in preload.js", error);
+}
\ No newline at end of file
diff --git a/electron/main/script.js b/electron/main/script.js
index d2ff938..016e2b6 100644
--- a/electron/main/script.js
+++ b/electron/main/script.js
@@ -5,8 +5,8 @@ function checkBoxes() {
const checkboxes = document.querySelectorAll('input[name="docFormat"]');
let isChecked = false;
var checkedCounter = 0;
- checkboxes.forEach(function(checkbox){
- if(checkbox.checked){
+ checkboxes.forEach(function (checkbox) {
+ if (checkbox.checked) {
isChecked = true;
checkedCounter++;
}
@@ -15,24 +15,24 @@ function checkBoxes() {
if (isChecked) {
//Code to submit the video
var selectedCheckboxes = {};
- checkboxes.forEach(function(checkbox){
- if(checkbox.checked){
+ checkboxes.forEach(function (checkbox) {
+ if (checkbox.checked) {
selectedCheckboxes[checkbox.nextElementSibling.textContent] = "";
- }
+ }
});
const testEndings = [".mp4", ".mov", ".avi", ".mkv"];
var pathTest = window.electronAPI.getFilePath(videoUpload.files[0]);
var pathToLower = pathTest.toLowerCase();
- if(testEndings.some(e => pathToLower.endsWith(e))){
+ if (testEndings.some(e => pathToLower.endsWith(e))) {
//assembly of the json for the main
var typeCheckbox;
- if(document.getElementById("docFormat").checked) typeCheckbox = document.getElementById("docFormat").value;
- if(document.getElementById("docFormatSummary1").checked) typeCheckbox = document.getElementById("docFormatSummary1").value;
- if(document.getElementById("docFormatSummary2").checked) typeCheckbox = document.getElementById("docFormatSummary2").value;
- if(document.getElementById("docFormatSummary3").checked) typeCheckbox = document.getElementById("docFormatSummary3").value;
- if(document.getElementById("docFormatCustom").checked) typeCheckbox = document.getElementById("docFormatCustom").value;
+ if (document.getElementById("docFormat").checked) typeCheckbox = document.getElementById("docFormat").value;
+ if (document.getElementById("docFormatSummary1").checked) typeCheckbox = document.getElementById("docFormatSummary1").value;
+ if (document.getElementById("docFormatSummary2").checked) typeCheckbox = document.getElementById("docFormatSummary2").value;
+ if (document.getElementById("docFormatSummary3").checked) typeCheckbox = document.getElementById("docFormatSummary3").value;
+ if (document.getElementById("docFormatCustom").checked) typeCheckbox = document.getElementById("docFormatCustom").value;
document.getElementById("testy").style.visibility = "visible"
document.getElementById("box1").style.backgroundColor = "red";
@@ -45,20 +45,20 @@ function checkBoxes() {
const aiType = document.getElementById("ai_type");
const sendingPackage = {
"video": {
- "module":"extraction-video-to-audio",
+ "module": "extraction-video-to-audio",
"inputVideoPath": pathTest
},
"transcription": {
"module": transcriptionType.value
},
"document": {
- "module":aiType.value,
+ "module": aiType.value,
"type": typeCheckbox,
"outputType": outputType.value
}
};
window.submit.submit(sendingPackage)
- }else{
+ } else {
alert('The given file is not compatible. These are the available types: [".mp4", ".mov", ".avi", ".mkv"].');
}
@@ -71,7 +71,7 @@ function checkBoxes() {
console.log("Error in script.js checkBoxes function");
console.log(error);
}
-
+
}
//language changing feature
@@ -95,7 +95,7 @@ function changeLanguage(language) {
console.log("Error in script.js changeLanguage function");
console.log(error);
}
-
+
}
//function to display the file path in the drop down box
@@ -129,17 +129,17 @@ function updateProgressBar(bar, value) {
console.log("Error in scripts.js updateProgressBar function");
console.log(error);
}
-
+
}
//function to load ai options to the drop down list
-function loadAiOptions(options){
+function loadAiOptions(options) {
try {
var menu = document.getElementById('ai_type');
var object_holdy;
- var choice ;
+ var choice;
object_holdy = options
- for(i = 0; i < options.length; i++){
+ for (i = 0; i < options.length; i++) {
choice = document.createElement('option');
choice.textContent = object_holdy[i].displayname;
choice.value = object_holdy[i].name;
@@ -152,13 +152,13 @@ function loadAiOptions(options){
}
//function to load transcription options to the drop down list
-function loadTranscriptionOptions(options){
+function loadTranscriptionOptions(options) {
try {
var menu = document.getElementById('transkript_type');
var object_holdy;
- var choice ;
+ var choice;
object_holdy = options
- for(i = 0; i < options.length; i++){
+ for (i = 0; i < options.length; i++) {
choice = document.createElement('option');
choice.textContent = object_holdy[i].displayname;
choice.value = object_holdy[i].name;
@@ -171,13 +171,13 @@ function loadTranscriptionOptions(options){
}
//function to load data type options to the drop down list
-function loadDataTypeOptions(options){
+function loadDataTypeOptions(options) {
try {
var menu = document.getElementById('output_type');
var object_holdy;
- var choice ;
+ var choice;
object_holdy = options
- for(i = 0; i < options.length; i++){
+ for (i = 0; i < options.length; i++) {
choice = document.createElement('option');
choice.textContent = object_holdy[i].displayname;
choice.value = object_holdy[i].name;
@@ -190,13 +190,13 @@ function loadDataTypeOptions(options){
}
//function to load language options to the drop down list
-function loadLanguageOptions(){
+function loadLanguageOptions() {
try {
var menu = document.getElementById('language_option');
var object_holdy;
- var choice ;
+ var choice;
object_holdy = Object.keys(languageOptions);
- for(i = 0; i < object_holdy.length; i++){
+ for (i = 0; i < object_holdy.length; i++) {
choice = document.createElement('option');
choice.textContent = object_holdy[i];
choice.value = object_holdy[i];
@@ -209,17 +209,17 @@ function loadLanguageOptions(){
}
//function to load speaker options to the drop down list
-function loadSpeakerOptions(options){
+function loadSpeakerOptions(options) {
try {
var menu = document.getElementById('cur_speaker');
- var l = document.getElementById('cur_speaker').options.length -1;
- for(i = l; i >= 0; i--){
+ var l = document.getElementById('cur_speaker').options.length - 1;
+ for (i = l; i >= 0; i--) {
menu.remove(i);
}
var object_holdy;
var choice;
object_holdy = Object.keys(options);
- for(i = 0; i < object_holdy.length; i++){
+ for (i = 0; i < object_holdy.length; i++) {
choice = document.createElement('option');
choice.textContent = options[object_holdy[i]].name;
choice.value = object_holdy[i];
@@ -233,7 +233,7 @@ function loadSpeakerOptions(options){
}
//function to load speaker audio file options to the drop down list
-function loadSpeakerAudio(option){
+function loadSpeakerAudio(option) {
try {
var menu = document.getElementById('speakerAudioViewer');
var aud = document.createElement("source");
@@ -246,7 +246,7 @@ function loadSpeakerAudio(option){
}
-function activateSubmitBtn(hasFile){
+function activateSubmitBtn(hasFile) {
try {
document.getElementById("submitButton").disabled = !hasFile;
} catch (error) {
@@ -254,7 +254,7 @@ function activateSubmitBtn(hasFile){
}
}
-function deaktivateProgressbar(){
+function deaktivateProgressbar() {
try {
document.getElementById("progressbar").style.visibility = "hidden";
} catch (error) {
@@ -263,7 +263,7 @@ function deaktivateProgressbar(){
}
//Video thumbnail generation
-function generateThumbnail(path){
+function generateThumbnail(path) {
const videoElement = document.getElementById("previewThumbnail");
while (videoElement.firstChild) videoElement.removeChild(videoElement.firstChild);
videoElement.src = path;
@@ -281,7 +281,7 @@ let currentStep = 1;
const totalSteps = steps.length;
function showStep(stepNumber) {
- if (stepNumber < 1 || stepNumber > totalSteps){
+ if (stepNumber < 1 || stepNumber > totalSteps) {
console.error("StepNumber out of Bounds", stepNumber);
return;
}
@@ -292,7 +292,7 @@ function showStep(stepNumber) {
document.querySelector(`.step-item[data-step="${stepNumber}"]`).classList.add("active");
const activeBtn = document.querySelector(`.step-item[data-step="${stepNumber}"]`);
- if(activeBtn) activeBtn.classList.add("active");
+ if (activeBtn) activeBtn.classList.add("active");
prevBtn.disabled = stepNumber == 1;
nextBtn.disabled = stepNumber === totalSteps;
@@ -303,31 +303,40 @@ function showStep(stepNumber) {
//Audio value setter
var speakerAudios = {};
var speakerEndValues = {};
-function setSpeakerAudiosValue(valy){
+function setSpeakerAudiosValue(valy) {
try {
speakerAudios = valy;
speakerRewriten = valy;
document.getElementById("speakerAudioViewer").src = valy.speakerA.src;
} catch (error) {
-
+
}
}
-function rewriteSpeakerName(){
+function rewriteSpeakerName() {
try {
- var tempy = document.getElementById("cur_speaker").value;
- speakerAudios[tempy].name = document.getElementById("newSpeaker").value;
+ const oldKey = document.getElementById("cur_speaker").value;
+ const newName = document.getElementById("newSpeaker").value;
+
+ speakerAudios[oldKey].name = newName;
loadSpeakerOptions(speakerAudios);
+
+ // IPC-Aufruf an Electron main process
+ window.electronAPI.saveSpeakerMapping({
+ speakerId: oldKey,
+ speakerName: newName
+ });
+
} catch (error) {
- console.log("\n\n\n" + error + "\n\n\n")
+ console.log(error);
}
}
-function sendSpeakerPackages(){
+function sendSpeakerPackages() {
try {
window.submitSpeaker.speaker_submit(speakerAudios);
} catch (error) {
-
+
}
}
@@ -338,7 +347,3 @@ function fileDownload() {
console.error("Download failed:", error);
}
}
-
-function rewriteSpeakerName(){
- console.log("Rewriting speaker name...");
-}
diff --git a/main.js b/main.js
index 7e2dd9a..262b906 100644
--- a/main.js
+++ b/main.js
@@ -103,7 +103,23 @@ electron.ipcMain.handle('get-module-names', async () => {
return module_array
});
+electron.ipcMain.on("save-speaker-mapping", (event, data) => {
+ const filePath = "/Users/mikehughes/PROJ/video2document/storage/speakerMapping/speakerMapping.json";
+
+ const payload = {
+ speakerId: data.speakerId,
+ speakerName: data.speakerName,
+ updated: new Date().toISOString()
+ };
+
+ try {
+ fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
+ console.log("Speaker mapping saved!");
+ } catch (error) {
+ console.error("Failed to save speaker mapping", error);
+ }
+});
// electron.ipcMain.on("get_modules", async (event, args) => {
// let module_array = {
// "ai_modules":[],
diff --git a/services/modules/replace_speaker/replaceSpeaker.js b/services/modules/replace_speaker/replaceSpeaker.js
index 3101c6b..34a0e44 100644
--- a/services/modules/replace_speaker/replaceSpeaker.js
+++ b/services/modules/replace_speaker/replaceSpeaker.js
@@ -1,120 +1,70 @@
const fs = require('fs');
const path = require('path');
-const outputDir = path.join(__dirname, "../../../storage/documents"); // path for output directory
-
-if (!fs.existsSync(outputDir)) {
- fs.mkdirSync(outputDir, { recursive: true }); // Create output directory if it doesn't exist
-}
-
const module_exports = {
name: "replace_speaker",
type: "processor",
displayname: "Speaker Name Replacer",
description: "Replaces speaker placeholder names with actual names based on a mapping in HTML files",
- async function(parameter) {
- return new Promise(async (resolve, reject) => {
- try {
- // console.log("Speaker replacer module invoked with parameters:", parameter);
-
- resolve(await this.replaceNames(
- parameter.inputHtmlPath, // Path to input HTML file
- parameter.speakerMappingPath // Path to speaker mapping file (JSON)
- ));
-
- } catch (error) {
- // console.error("Error in speaker replacer module:", error);
- reject(error)
- }
- })
+ async function({ inputHtmlPath, speakerMappingPath }) {
+ return await this.replaceNames(inputHtmlPath, speakerMappingPath);
},
replaceNames: async function(inputHtmlPath, speakerMappingPath) {
- return new Promise(async(resolve, reject) => {
+ try {
+ const htmlContent = await fs.promises.readFile(inputHtmlPath, "utf-8");
+ const mappingData = await fs.promises.readFile(speakerMappingPath, "utf-8");
+
+ let speakerMap = {};
try {
- const htmlContent = await fs.promises.readFile(inputHtmlPath, "utf-8"); // read HTML file
- const mappingData = await fs.promises.readFile(speakerMappingPath, "utf-8"); // read mapping file
-
- // Parse mapping - supports JSON or simple format
- let speakerMap = {};
- try {
- speakerMap = JSON.parse(mappingData); // Try to parse as JSON
- } catch (e) {
- // If not JSON, try simple format: "Speaker A,Mike\nSpeaker B,Stefan"
- const lines = mappingData.trim().split('\n');
- lines.forEach(line => {
- const [placeholder, realName] = line.split(',').map(s => s.trim());
- if (placeholder && realName) {
- speakerMap[placeholder] = realName;
- }
- });
+ const parsed = JSON.parse(mappingData);
+ if (parsed.speakerId && parsed.speakerName) {
+ speakerMap[parsed.speakerId] = parsed.speakerName;
+ } else {
+ Object.assign(speakerMap, parsed);
}
-
- // Replace all speaker names in HTML content
- let outputContent = htmlContent;
- Object.entries(speakerMap).forEach(([placeholder, realName]) => {
- // Create regex to replace all occurrences (case-sensitive)
- const regex = new RegExp(`\\b${placeholder}\\b`, 'g');
- outputContent = outputContent.replace(regex, realName);
+ } catch (e) {
+ const lines = mappingData.trim().split('\n');
+ lines.forEach(line => {
+ const [placeholder, realName] = line.split(',').map(s => s.trim());
+ if (placeholder && realName) speakerMap[placeholder] = realName;
});
-
- // Generate output file path based on input file name
- const inputFileName = path.basename(inputHtmlPath, path.extname(inputHtmlPath));
- const outPath = path.join(outputDir, `${inputFileName}_replaced.html`);
-
- // Write output to file
- fs.writeFileSync(outPath, outputContent, "utf8");
-
- // console.log("Replaced HTML file written to:", outPath);
- resolve(outPath)
-
- } catch (error) {
- // console.error("Error replacing speaker names:", error);
- reject(error)
}
- })
+
+ let outputContent = htmlContent;
+ Object.entries(speakerMap).forEach(([placeholder, realName]) => {
+ const regex = new RegExp(`[\$begin:math:text$\\\\\[\]\?\$\{placeholder\}\[\\$end:math:text$\\]]?`, 'g');
+ outputContent = outputContent.replace(regex, realName);
+ });
+
+ await fs.promises.writeFile(inputHtmlPath, outputContent, "utf-8");
+
+ return inputHtmlPath;
+
+ } catch (error) {
+ console.error("Error replacing speaker names:", error);
+ throw error;
+ }
}
};
module.exports = module_exports;
-// CLI Mode: Allow direct execution
if (require.main === module) {
(async () => {
const args = process.argv.slice(2);
-
- if (args.length < 2) {
- console.error("Usage: node string-replacer.js ");
- console.error("Example: node string-replacer.js ./document.html ./speaker_mapping.json");
- console.error("\nMapping file formats:");
- console.error("JSON: {\"Speaker A\": \"Mike\", \"Speaker B\": \"Stefan\"}");
- console.error("or simple: Speaker A,Mike\\nSpeaker B,Stefan");
- process.exit(1);
- }
+ if (args.length < 2) process.exit(1);
const [inputHtmlPath, speakerMappingPath] = args;
- // Check if files exist
- if (!fs.existsSync(inputHtmlPath)) {
- console.error(`ERROR: HTML file not found: ${inputHtmlPath}`);
+ if (!fs.existsSync(inputHtmlPath)) process.exit(1);
+ if (!fs.existsSync(speakerMappingPath)) process.exit(1);
+
+ try {
+ await module_exports.replaceNames(inputHtmlPath, speakerMappingPath);
+ } catch (err) {
process.exit(1);
}
-
- if (!fs.existsSync(speakerMappingPath)) {
- console.error(`ERROR: Speaker mapping file not found: ${speakerMappingPath}`);
- process.exit(1);
- }
-
- console.log("Starting speaker name replacement...");
- console.log(`HTML file: ${inputHtmlPath}`);
- console.log(`Mapping file: ${speakerMappingPath}`);
-
- await module_exports.replaceNames(
- inputHtmlPath,
- speakerMappingPath
- );
-
- console.log("Done!");
})();
}
\ No newline at end of file
diff --git a/storage/speakerMapping/speakerMapping.json b/storage/speakerMapping/speakerMapping.json
new file mode 100644
index 0000000..5a213f6
--- /dev/null
+++ b/storage/speakerMapping/speakerMapping.json
@@ -0,0 +1,5 @@
+{
+ "speakerId": "speakerB",
+ "speakerName": "Peter",
+ "updated": "2026-01-10T13:54:55.608Z"
+}
\ No newline at end of file