mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-15 18:01:52 +02:00
Remade replace Speaker module which now takes the premade speaker mapping json and directly replaces speakers in the document. Also refined the Standard documents so consistency is improved
This commit is contained in:
@@ -1,81 +1,72 @@
|
|||||||
// Loading required packages
|
// Loading required packages
|
||||||
require("./requires.js")
|
require("./requires.js");
|
||||||
console.log(start);
|
console.log(start);
|
||||||
|
|
||||||
|
|
||||||
// Initialising map to be used to store the functionality later on for reloadability
|
// Initialising map to be used to store the functionality later on for reloadability
|
||||||
mapFunctions = new Map()
|
mapFunctions = new Map();
|
||||||
|
|
||||||
|
|
||||||
// Loading the Function Map
|
// Loading the Function Map
|
||||||
var path = `${mainDir}/services/modules`
|
var path = `${mainDir}/services/modules`;
|
||||||
var folders = fs.readdirSync(path).filter(function (file) {
|
var folders = fs.readdirSync(path).filter(function (file) {
|
||||||
return fs.statSync(path+'/'+file).isDirectory();
|
return fs.statSync(path + "/" + file).isDirectory();
|
||||||
});
|
});
|
||||||
folders.forEach(element => {
|
folders.forEach((element) => {
|
||||||
var commandFiles = fs.readdirSync(`${path}/${element}`).filter(file => file.endsWith('.js') && !file.startsWith("index"));
|
var commandFiles = fs
|
||||||
for (const file of commandFiles) {
|
.readdirSync(`${path}/${element}`)
|
||||||
delete require.cache[require.resolve(`${path}/${element}/${file}`)];
|
.filter((file) => file.endsWith(".js") && !file.startsWith("index"));
|
||||||
const command = require(`${path}/${element}/${file}`);
|
for (const file of commandFiles) {
|
||||||
mapFunctions.set(command.name, command);
|
delete require.cache[require.resolve(`${path}/${element}/${file}`)];
|
||||||
}
|
const command = require(`${path}/${element}/${file}`);
|
||||||
|
mapFunctions.set(command.name, command);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The startup information for the project, here you can add stuff that might be nice to see when the app starts
|
// The startup information for the project, here you can add stuff that might be nice to see when the app starts
|
||||||
mapFunctions.get("Startup_function").function()
|
mapFunctions.get("Startup_function").function();
|
||||||
console.log("------------------------------------ Status ------------------------------------");
|
console.log(
|
||||||
|
"------------------------------------ Status ------------------------------------"
|
||||||
|
);
|
||||||
console.log(__dirname);
|
console.log(__dirname);
|
||||||
console.log(platform);
|
console.log(platform);
|
||||||
console.log(`The Startup took ${new Date() - start}ms`)
|
console.log(`The Startup took ${new Date() - start}ms`);
|
||||||
console.log(`${mapFunctions.size} Function modules loaded`);
|
console.log(`${mapFunctions.size} Function modules loaded`);
|
||||||
console.log("--------------------------------------------------------------------------------");
|
console.log(
|
||||||
|
"--------------------------------------------------------------------------------"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------- CLI COMMANDS --------------------------------------------------------- //
|
// --------------------------------------------------------- CLI COMMANDS --------------------------------------------------------- //
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
rl.on("line", (data) => {
|
||||||
rl.on("line", data =>{
|
const args = data.trim().split(" ");
|
||||||
const args = data.trim().split(" ");
|
const command = args.shift().toLowerCase();
|
||||||
const command = args.shift().toLowerCase();
|
mapFunctions.get("cliCommands").function(command, args);
|
||||||
mapFunctions.get("cliCommands").function(command, args)
|
});
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- ELECTRON ----------------------------------------------------------- //
|
// ----------------------------------------------------------- ELECTRON ----------------------------------------------------------- //
|
||||||
|
|
||||||
let mainWindow;
|
let mainWindow;
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
mainWindow = new electron.BrowserWindow({
|
mainWindow = new electron.BrowserWindow({
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 800,
|
height: 800,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
preload: `${mainDir}/electron/main/preload.js`
|
preload: `${mainDir}/electron/main/preload.js`,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.loadFile('./electron/main/index.html');
|
mainWindow.loadFile("./electron/main/index.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
electron.app.whenReady().then(createWindow);
|
electron.app.whenReady().then(createWindow);
|
||||||
|
|
||||||
|
|
||||||
// electron.ipcMain.on("extract", (event, args) => {
|
// electron.ipcMain.on("extract", (event, args) => {
|
||||||
// mapFunctions.get("extraction-video-to-audio").function(args)
|
// mapFunctions.get("extraction-video-to-audio").function(args)
|
||||||
// })
|
// })
|
||||||
@@ -84,26 +75,31 @@ electron.app.whenReady().then(createWindow);
|
|||||||
// mainWindow.webContents.send("fuck", "worked uwu")
|
// mainWindow.webContents.send("fuck", "worked uwu")
|
||||||
// }, 5000);
|
// }, 5000);
|
||||||
|
|
||||||
electron.ipcMain.handle('get-module-names', async () => {
|
electron.ipcMain.handle("get-module-names", async () => {
|
||||||
let module_array = {
|
let module_array = {
|
||||||
"ai_modules":[],
|
ai_modules: [],
|
||||||
"transcription_modules":[]
|
transcription_modules: [],
|
||||||
|
};
|
||||||
|
mapFunctions.forEach((e) => {
|
||||||
|
switch (e.type) {
|
||||||
|
case "llm":
|
||||||
|
module_array.ai_modules.push({
|
||||||
|
name: e.name,
|
||||||
|
displayname: e.displayname,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "transcription":
|
||||||
|
module_array.transcription_modules.push({
|
||||||
|
name: e.name,
|
||||||
|
displayname: e.displayname,
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
mapFunctions.forEach(e => {
|
});
|
||||||
switch(e.type){
|
// console.log(module_array);
|
||||||
case "llm":
|
return module_array;
|
||||||
module_array.ai_modules.push({"name": e.name, "displayname": e.displayname})
|
|
||||||
break;
|
|
||||||
case "transcription":
|
|
||||||
module_array.transcription_modules.push({"name": e.name, "displayname": e.displayname})
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// console.log(module_array);
|
|
||||||
return module_array
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// electron.ipcMain.on("get_modules", async (event, args) => {
|
// electron.ipcMain.on("get_modules", async (event, args) => {
|
||||||
// let module_array = {
|
// let module_array = {
|
||||||
// "ai_modules":[],
|
// "ai_modules":[],
|
||||||
@@ -124,165 +120,219 @@ electron.ipcMain.handle('get-module-names', async () => {
|
|||||||
// mainWindow.webContents.send("modules", module_array)
|
// mainWindow.webContents.send("modules", module_array)
|
||||||
// })
|
// })
|
||||||
|
|
||||||
var globalArgs = {}
|
var globalArgs = {};
|
||||||
var globalFinalHtmlPath = ""
|
var globalFinalHtmlPath = "";
|
||||||
|
|
||||||
electron.ipcMain.on("file_submit", async (event, args) => {
|
electron.ipcMain.on("file_submit", async (event, args) => {
|
||||||
try {
|
try {
|
||||||
globalArgs = args
|
globalArgs = args;
|
||||||
let curstep = 0
|
let curstep = 0;
|
||||||
let totalsteps = 4
|
let totalsteps = 4;
|
||||||
|
|
||||||
const TEMPLATE_MAP = {
|
const TEMPLATE_MAP = {
|
||||||
"followup-report": "followup_report.txt",
|
"followup-report": "followup_report.txt",
|
||||||
"agenda": "agenda.txt",
|
agenda: "agenda.txt",
|
||||||
"result-protocol": "result_protocol.txt",
|
"result-protocol": "result_protocol.txt",
|
||||||
"sprint-planning": "sprint_planning_note.txt",
|
"sprint-planning": "sprint_planning_note.txt",
|
||||||
"custom": "custom_document.txt"
|
custom: "custom_document.txt",
|
||||||
};
|
};
|
||||||
|
|
||||||
const templateFile = TEMPLATE_MAP[args.document.type];
|
const templateFile = TEMPLATE_MAP[args.document.type];
|
||||||
|
|
||||||
if (!templateFile) {
|
if (!templateFile) {
|
||||||
throw new Error("Unknown document type: " + args.document.type);
|
throw new Error("Unknown document type: " + args.document.type);
|
||||||
}
|
|
||||||
|
|
||||||
console.log(args);
|
|
||||||
let audiopath = ""
|
|
||||||
let transcriptpath = ""
|
|
||||||
|
|
||||||
console.log("\n\n Running the Video to Audio Extractor");
|
|
||||||
// This code handles the Video to Audio extraction module call
|
|
||||||
await mapFunctions.get("module-handler").function(args.video.module, {inputVideoPath: args.video.inputVideoPath, outputType: mapFunctions.get(args.transcription.module).audioformat}).then(resp => {
|
|
||||||
console.log(resp);
|
|
||||||
audiopath = resp
|
|
||||||
curstep++
|
|
||||||
mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
|
||||||
}).catch(err => {
|
|
||||||
mainWindow.webContents.send("error", err)
|
|
||||||
console.log(err);
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
console.log("\n\n Running the Audio to Transcription module");
|
|
||||||
// TODO implement transcription module
|
|
||||||
// This code handles the Audio to Text transcription module call
|
|
||||||
await mapFunctions.get("module-handler").function(args.transcription.module, audiopath).then(resp => {
|
|
||||||
console.log(resp);
|
|
||||||
transcriptpath = resp
|
|
||||||
curstep++
|
|
||||||
mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
|
||||||
}).catch(err => {
|
|
||||||
mainWindow.webContents.send("error", err)
|
|
||||||
console.log(err);
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
console.log("\n\n Running the Transcription Summarizer module");
|
|
||||||
// This code summarises the transcript, so that it can be used by an llm
|
|
||||||
// await mapFunctions.get("summarize-transcription").function('A:\\programing\\@projects\\video2document\\storage\\transcripts\\IMG_2978.json').then(resp => {
|
|
||||||
await mapFunctions.get("summarize-transcription2").function(transcriptpath).then(resp => {
|
|
||||||
console.log(resp);
|
|
||||||
transcriptpath = resp
|
|
||||||
curstep++
|
|
||||||
mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
|
||||||
}).catch(err => {
|
|
||||||
mainWindow.webContents.send("error", err)
|
|
||||||
console.log(err);
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log("\n\n Running the LLM module");
|
|
||||||
// TODO implement documentation module
|
|
||||||
// This code handles the Text to Document processing module call
|
|
||||||
|
|
||||||
console.log(`\n\n Running the LLM for Document Style ${args.document.type}`);
|
|
||||||
|
|
||||||
await mapFunctions.get("module-handler").function(args.document.module, { inputTranscriptPath: transcriptpath, documentTypePath: "./storage/documentType/" + templateFile, language: "en" }).then(resp => {
|
|
||||||
console.log(resp);
|
|
||||||
globalFinalHtmlPath = resp
|
|
||||||
curstep++
|
|
||||||
mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
|
||||||
}).catch(err => {
|
|
||||||
mainWindow.webContents.send("error", err)
|
|
||||||
console.log(err);
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
await mapFunctions.get("extract-speaker-snippets").function({audioPath: audiopath, jsonPath: transcriptpath }).then(resp => {
|
|
||||||
mainWindow.webContents.send("speakerAudios", resp)
|
|
||||||
}).catch(err => {
|
|
||||||
mainWindow.webContents.send("error", err)
|
|
||||||
console.log(err);
|
|
||||||
return
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
electron.ipcMain.on("file_download", async() => {
|
console.log(args);
|
||||||
await mapFunctions.get("htmlDocumentConverter").convert({inputPath:globalFinalHtmlPath, format: globalArgs.document.outputType, showDialog: true});
|
let audiopath = "";
|
||||||
})
|
let transcriptpath = "";
|
||||||
|
|
||||||
electron.ipcMain.on("speaker_submit", async() => {
|
console.log("\n\n Running the Video to Audio Extractor");
|
||||||
console.log("\n\n\nJa also hier kam was an \n\n\n");
|
// This code handles the Video to Audio extraction module call
|
||||||
})
|
await mapFunctions
|
||||||
|
.get("module-handler")
|
||||||
|
.function(args.video.module, {
|
||||||
|
inputVideoPath: args.video.inputVideoPath,
|
||||||
|
outputType: mapFunctions.get(args.transcription.module).audioformat,
|
||||||
|
})
|
||||||
|
.then((resp) => {
|
||||||
|
console.log(resp);
|
||||||
|
audiopath = resp;
|
||||||
|
curstep++;
|
||||||
|
mainWindow.webContents.send("progress", {
|
||||||
|
curstep: curstep,
|
||||||
|
totalsteps: totalsteps,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
mainWindow.webContents.send("error", err);
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
let q =
|
console.log("\n\n Running the Audio to Transcription module");
|
||||||
{
|
// TODO implement transcription module
|
||||||
video: {
|
// This code handles the Audio to Text transcription module call
|
||||||
module: "String", // The name of the module, idk if we ever implement other extraction modules, the default one is extraction-video-to-audio
|
await mapFunctions
|
||||||
inputVideoPath: "String", // See script.js on line 27 for an example of what this should look like
|
.get("module-handler")
|
||||||
outputType: "String" // The file format to be used for the audio output file, such as wav, mp3, flac and so on
|
.function(args.transcription.module, audiopath)
|
||||||
},
|
.then((resp) => {
|
||||||
transcription:{
|
console.log(resp);
|
||||||
module: "String" // The module name of the transcription model you want to use
|
transcriptpath = resp;
|
||||||
},
|
curstep++;
|
||||||
document:{
|
mainWindow.webContents.send("progress", {
|
||||||
module: "String", // The module name of the AI model you want to use to create the document
|
curstep: curstep,
|
||||||
styles: [ // An array of all the document styles/prompts you want to have the document be processed with
|
totalsteps: totalsteps,
|
||||||
{
|
});
|
||||||
prompt: "String",
|
})
|
||||||
}
|
.catch((err) => {
|
||||||
]
|
mainWindow.webContents.send("error", err);
|
||||||
}
|
console.log(err);
|
||||||
}
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("\n\n Running the Transcription Summarizer module");
|
||||||
|
// This code summarises the transcript, so that it can be used by an llm
|
||||||
|
// await mapFunctions.get("summarize-transcription").function('A:\\programing\\@projects\\video2document\\storage\\transcripts\\IMG_2978.json').then(resp => {
|
||||||
|
await mapFunctions
|
||||||
|
.get("summarize-transcription2")
|
||||||
|
.function(transcriptpath)
|
||||||
|
.then((resp) => {
|
||||||
|
console.log(resp);
|
||||||
|
transcriptpath = resp;
|
||||||
|
curstep++;
|
||||||
|
mainWindow.webContents.send("progress", {
|
||||||
|
curstep: curstep,
|
||||||
|
totalsteps: totalsteps,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
mainWindow.webContents.send("error", err);
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("\n\n Running the LLM module");
|
||||||
|
// TODO implement documentation module
|
||||||
|
// This code handles the Text to Document processing module call
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`\n\n Running the LLM for Document Style ${args.document.type}`
|
||||||
|
);
|
||||||
|
|
||||||
|
await mapFunctions
|
||||||
|
.get("module-handler")
|
||||||
|
.function(args.document.module, {
|
||||||
|
inputTranscriptPath: transcriptpath,
|
||||||
|
documentTypePath: "./storage/documentType/" + templateFile,
|
||||||
|
language: "en",
|
||||||
|
})
|
||||||
|
.then((resp) => {
|
||||||
|
console.log(resp);
|
||||||
|
globalFinalHtmlPath = resp;
|
||||||
|
curstep++;
|
||||||
|
mainWindow.webContents.send("progress", {
|
||||||
|
curstep: curstep,
|
||||||
|
totalsteps: totalsteps,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
mainWindow.webContents.send("error", err);
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
await mapFunctions
|
||||||
|
.get("extract-speaker-snippets")
|
||||||
|
.function({ audioPath: audiopath, jsonPath: transcriptpath })
|
||||||
|
.then((resp) => {
|
||||||
|
mainWindow.webContents.send("speakerAudios", resp);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
mainWindow.webContents.send("error", err);
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
electron.ipcMain.on("file_download", async () => {
|
||||||
|
await mapFunctions
|
||||||
|
.get("htmlDocumentConverter")
|
||||||
|
.convert({
|
||||||
|
inputPath: globalFinalHtmlPath,
|
||||||
|
format: globalArgs.document.outputType,
|
||||||
|
showDialog: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
electron.ipcMain.on("speaker_submit", async (event, args) => {
|
||||||
|
console.log("\n\n\nJa also hier kam was an \n\n\n");
|
||||||
|
console.log(args);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mapFunctions.get("replace_speaker").function(args);
|
||||||
|
event.reply("speaker_submit_response", { success: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error:", error);
|
||||||
|
event.reply("speaker_submit_response", {
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let q = {
|
||||||
|
video: {
|
||||||
|
module: "String", // The name of the module, idk if we ever implement other extraction modules, the default one is extraction-video-to-audio
|
||||||
|
inputVideoPath: "String", // See script.js on line 27 for an example of what this should look like
|
||||||
|
outputType: "String", // The file format to be used for the audio output file, such as wav, mp3, flac and so on
|
||||||
|
},
|
||||||
|
transcription: {
|
||||||
|
module: "String", // The module name of the transcription model you want to use
|
||||||
|
},
|
||||||
|
document: {
|
||||||
|
module: "String", // The module name of the AI model you want to use to create the document
|
||||||
|
styles: [
|
||||||
|
// An array of all the document styles/prompts you want to have the document be processed with
|
||||||
|
{
|
||||||
|
prompt: "String",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let q1 = {
|
let q1 = {
|
||||||
"ai_modules": [
|
ai_modules: [
|
||||||
{name:"abc", displayname:"ABC"},
|
{ name: "abc", displayname: "ABC" },
|
||||||
{name:"qeg", displayname:"aqghegahu"}
|
{ name: "qeg", displayname: "aqghegahu" },
|
||||||
],
|
],
|
||||||
"transcription_modules": [
|
transcription_modules: [
|
||||||
{name:"abc", displayname:"ABC"},
|
{ name: "abc", displayname: "ABC" },
|
||||||
{name:"qeg", displayname:"aqghegahu"}
|
{ name: "qeg", displayname: "aqghegahu" },
|
||||||
]
|
],
|
||||||
}
|
};
|
||||||
|
|
||||||
//gibt Documentfiles an preload zurück
|
//gibt Documentfiles an preload zurück
|
||||||
|
|
||||||
electron.ipcMain.handle('get-txt-files', () => {
|
electron.ipcMain.handle("get-txt-files", () => {
|
||||||
const storagePath = `${mainDir}/storage/documentType`
|
const storagePath = `${mainDir}/storage/documentType`;
|
||||||
|
|
||||||
return fs.readdirSync(storagePath)
|
return fs.readdirSync(storagePath).filter((f) => f.endsWith(".txt"));
|
||||||
.filter(f => f.endsWith('.txt'))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//speichern neuer document types
|
//speichern neuer document types
|
||||||
|
|
||||||
electron.ipcMain.handle('save-txt-file', (event, fileName, content) => {
|
electron.ipcMain.handle("save-txt-file", (event, fileName, content) => {
|
||||||
const filePath = `${mainDir}/storage/documentType/${fileName}.txt`;
|
const filePath = `${mainDir}/storage/documentType/${fileName}.txt`;
|
||||||
fs.writeFileSync(filePath, content, 'utf8');
|
fs.writeFileSync(filePath, content, "utf8");
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
electron.ipcMain.handle('read-txt-file', (event, fileName) => {
|
electron.ipcMain.handle("read-txt-file", (event, fileName) => {
|
||||||
const filePath = `${mainDir}/storage/documentType/${fileName}`;
|
const filePath = `${mainDir}/storage/documentType/${fileName}`;
|
||||||
return fs.readFileSync(filePath, 'utf8');
|
return fs.readFileSync(filePath, "utf8");
|
||||||
});
|
});
|
||||||
@@ -7,35 +7,54 @@ const module_exports = {
|
|||||||
displayname: "Speaker Name Replacer",
|
displayname: "Speaker Name Replacer",
|
||||||
description: "Replaces speaker placeholder names with actual names based on a mapping in HTML files",
|
description: "Replaces speaker placeholder names with actual names based on a mapping in HTML files",
|
||||||
|
|
||||||
async function({ inputHtmlPath, speakerMappingPath }) {
|
async function(speakerMapping) {
|
||||||
return await this.replaceNames(inputHtmlPath, speakerMappingPath);
|
// Relativ von dieser Datei aus
|
||||||
|
const documentsDir = path.resolve(__dirname, '../../../storage/documents');
|
||||||
|
const inputHtmlPath = await this.getNewestFile(documentsDir, '.html');
|
||||||
|
|
||||||
|
if (!inputHtmlPath) {
|
||||||
|
throw new Error(`No HTML files found in ${documentsDir}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.replaceNames(inputHtmlPath, speakerMapping);
|
||||||
},
|
},
|
||||||
|
|
||||||
replaceNames: async function(inputHtmlPath, speakerMappingPath) {
|
getNewestFile: async function(dirPath, extension) {
|
||||||
|
try {
|
||||||
|
const files = await fs.promises.readdir(dirPath);
|
||||||
|
const filtered = files.filter(f => f.endsWith(extension));
|
||||||
|
|
||||||
|
if (filtered.length === 0) return null;
|
||||||
|
|
||||||
|
const filesWithStats = await Promise.all(
|
||||||
|
filtered.map(async (f) => {
|
||||||
|
const fullPath = path.join(dirPath, f);
|
||||||
|
const stats = await fs.promises.stat(fullPath);
|
||||||
|
return { path: fullPath, time: stats.mtimeMs };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return filesWithStats.reduce((newest, curr) =>
|
||||||
|
curr.time > newest.time ? curr : newest
|
||||||
|
).path;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error reading directory:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
replaceNames: async function(inputHtmlPath, speakerMapping) {
|
||||||
try {
|
try {
|
||||||
const htmlContent = await fs.promises.readFile(inputHtmlPath, "utf-8");
|
const htmlContent = await fs.promises.readFile(inputHtmlPath, "utf-8");
|
||||||
const mappingData = await fs.promises.readFile(speakerMappingPath, "utf-8");
|
|
||||||
|
|
||||||
let speakerMap = {};
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(mappingData);
|
|
||||||
if (parsed.speakerId && parsed.speakerName) {
|
|
||||||
speakerMap[parsed.speakerId] = parsed.speakerName;
|
|
||||||
} else {
|
|
||||||
Object.assign(speakerMap, parsed);
|
|
||||||
}
|
|
||||||
} 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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let outputContent = htmlContent;
|
let outputContent = htmlContent;
|
||||||
Object.entries(speakerMap).forEach(([placeholder, realName]) => {
|
Object.entries(speakerMapping).forEach(([placeholder, value]) => {
|
||||||
const regex = new RegExp(`[\$begin:math:text$\\\\\[\]\?\$\{placeholder\}\[\\$end:math:text$\\]]?`, 'g');
|
// Extract name if value is an object
|
||||||
outputContent = outputContent.replace(regex, realName);
|
const displayName = typeof value === 'string' ? value : value.name;
|
||||||
|
|
||||||
|
// Replace speaker placeholder with display name
|
||||||
|
const regex = new RegExp(`\\b${placeholder}\\b`, 'g');
|
||||||
|
outputContent = outputContent.replace(regex, displayName);
|
||||||
});
|
});
|
||||||
|
|
||||||
await fs.promises.writeFile(inputHtmlPath, outputContent, "utf-8");
|
await fs.promises.writeFile(inputHtmlPath, outputContent, "utf-8");
|
||||||
@@ -50,21 +69,3 @@ const module_exports = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
module.exports = module_exports;
|
module.exports = module_exports;
|
||||||
|
|
||||||
if (require.main === module) {
|
|
||||||
(async () => {
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
if (args.length < 2) process.exit(1);
|
|
||||||
|
|
||||||
const [inputHtmlPath, speakerMappingPath] = args;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
@@ -1,26 +1,45 @@
|
|||||||
|
# Meeting Agenda Generator
|
||||||
|
|
||||||
Du bist ein erfahrener Moderator und Projektmanager.
|
Du bist ein erfahrener Moderator und Projektmanager.
|
||||||
|
|
||||||
AUFGABE:
|
## KRITISCH - SPRECHER-PLATZHALTER BEWAHREN:
|
||||||
Erstelle eine sinnvolle Meeting-Agenda basierend auf dem folgenden Transkript.
|
**speakerA, speakerB, speakerC, etc. sind technische Platzhalter und DÜRFEN NICHT verändert werden.**
|
||||||
|
- RICHTIG: "speakerA hat entschieden..."
|
||||||
|
- FALSCH: "Speaker A", "speakerA (Name)", Klammern, Leerzeichen, Ergänzungen
|
||||||
|
|
||||||
ANFORDERUNGEN:
|
Diese Token werden später durch echte Namen ersetzt. Jede Änderung bricht diesen Prozess.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AUFGABE:
|
||||||
|
Erstelle eine sinnvolle Meeting-Agenda basierend auf dem Meeting-Transkript.
|
||||||
|
|
||||||
|
## ANFORDERUNGEN:
|
||||||
- Rekonstruiere die tatsächlichen Themenblöcke
|
- Rekonstruiere die tatsächlichen Themenblöcke
|
||||||
- Ordne sie logisch und chronologisch
|
- Ordne sie logisch und chronologisch
|
||||||
- Fasse ähnliche Diskussionen zusammen
|
- Fasse ähnliche Diskussionen zusammen
|
||||||
- Keine irrelevanten Details aufnehmen
|
- Keine irrelevanten Details aufnehmen
|
||||||
|
- Speicher-Platzhalter (speakerA, speakerB, etc.) exakt beibehalten
|
||||||
|
|
||||||
STRUKTUR:
|
## STRUKTUR:
|
||||||
- Titel der Agenda
|
|
||||||
- Ziel des Meetings (1–2 Sätze)
|
|
||||||
- Agenda-Punkte (nummeriert)
|
|
||||||
- Thema
|
|
||||||
- Kurzbeschreibung
|
|
||||||
- Ziel des Punktes (Information, Entscheidung, Diskussion)
|
|
||||||
|
|
||||||
STIL:
|
### 1. Titel der Agenda
|
||||||
|
|
||||||
|
### 2. Ziel des Meetings
|
||||||
|
- 1–2 präzise Sätze
|
||||||
|
|
||||||
|
### 3. Agenda-Punkte (nummeriert)
|
||||||
|
Für jeden Punkt:
|
||||||
|
- **Thema**
|
||||||
|
- **Kurzbeschreibung**
|
||||||
|
- **Ziel des Punktes:** (Information / Entscheidung / Diskussion)
|
||||||
|
|
||||||
|
## STIL:
|
||||||
- Klar, kompakt
|
- Klar, kompakt
|
||||||
- Business-orientiert
|
- Business-orientiert
|
||||||
- Keine Sprecher- oder Zeitangaben
|
- Keine Sprecher- oder Zeitangaben
|
||||||
- Namen aus dem Transkript speakerA, speakerB etc. sollen weiterhin bestehen bleiben wie sie sind und nicht im Dokument ersetzt werden
|
- Logische Reihenfolge
|
||||||
|
|
||||||
TRANSKRIPT:
|
---
|
||||||
|
|
||||||
|
**TRANSKRIPT:**
|
||||||
@@ -1,22 +1,44 @@
|
|||||||
|
# Custom Document Generator
|
||||||
|
|
||||||
Du bist ein intelligenter Dokumenten-Generator.
|
Du bist ein intelligenter Dokumenten-Generator.
|
||||||
|
|
||||||
AUFGABE:
|
## KRITISCH - SPRECHER-PLATZHALTER BEWAHREN:
|
||||||
|
**speakerA, speakerB, speakerC, etc. sind technische Platzhalter und DÜRFEN NICHT verändert werden.**
|
||||||
|
- RICHTIG: "speakerA hat entschieden..."
|
||||||
|
- FALSCH: "Speaker A", "speakerA (Name)", Klammern, Leerzeichen, Ergänzungen
|
||||||
|
|
||||||
|
Diese Token werden später durch echte Namen ersetzt. Jede Änderung bricht diesen Prozess.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AUFGABE:
|
||||||
Erstelle ein individuelles Dokument basierend auf:
|
Erstelle ein individuelles Dokument basierend auf:
|
||||||
1) dem Meeting-Transkript
|
1. dem Meeting-Transkript
|
||||||
2) der zusätzlichen Nutzeranweisung
|
2. der zusätzlichen Nutzeranweisung
|
||||||
|
|
||||||
WICHTIG:
|
## ANFORDERUNGEN:
|
||||||
- Priorisiere die Nutzeranweisung
|
- **Priorisiere die Nutzeranweisung** über standardisierte Strukturen
|
||||||
- Nutze das Transkript als Wissensquelle
|
- Nutze das Transkript als Wissensquelle
|
||||||
- Struktur, Tonalität und Detailgrad anpassen
|
- Struktur, Tonalität und Detailgrad nach Nutzervorgabe anpassen
|
||||||
- Inhalte logisch zusammenführen
|
- Inhalte logisch zusammenführen
|
||||||
- Namen aus dem Transkript speakerA, speakerB etc. sollen weiterhin bestehen bleiben wie sie sind und nicht im Dokument ersetzt werden
|
- Speicher-Platzhalter (speakerA, speakerB, etc.) exakt beibehalten
|
||||||
|
|
||||||
FORMAT:
|
## VORGEHEN:
|
||||||
- Passe Struktur und Stil an den Nutzerwunsch an
|
1. Lese die Nutzeranweisung sorgfältig
|
||||||
- Klare Überschriften
|
2. Extrahiere aus dem Transkript die relevanten Informationen
|
||||||
- Keine Sprecher- oder Zeitangaben
|
3. Erstelle das Dokument nach der gewünschten Struktur
|
||||||
|
4. Behalte Sprecher-Platzhalter unverändert
|
||||||
|
|
||||||
TRANSKRIPT & NUTZERANWEISUNG:
|
## ALLGEMEINE RICHTLINIEN:
|
||||||
|
- Entferne Redundanzen und Smalltalk
|
||||||
|
- Keine Zeitstempel oder Sprecherangaben (wenn nicht gefordert)
|
||||||
|
- Sachlich, präzise, professionell
|
||||||
|
- Keine Spekulationen oder Meinungen (wenn nicht gefordert)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**NUTZERANWEISUNG:**
|
||||||
|
[Hier kommt die Anforderung des Nutzers hin]
|
||||||
|
|
||||||
|
**TRANSKRIPT:**
|
||||||
|
[Hier kommt das Meeting-Transkript hin]
|
||||||
@@ -1,45 +1,61 @@
|
|||||||
|
# Follow-up Report Generator
|
||||||
|
|
||||||
Du bist ein professioneller Meeting-Analyst und Business Writer.
|
Du bist ein professioneller Meeting-Analyst und Business Writer.
|
||||||
|
|
||||||
AUFGABE:
|
## KRITISCH - SPRECHER-PLATZHALTER BEWAHREN:
|
||||||
Erstelle einen strukturierten Follow-up Report basierend auf dem folgenden Meeting-Transkript.
|
**speakerA, speakerB, speakerC, etc. sind technische Platzhalter und DÜRFEN NICHT verändert werden.**
|
||||||
|
- RICHTIG: "speakerA hat entschieden..."
|
||||||
|
- FALSCH: "Speaker A", "speakerA (Name)", Klammern, Leerzeichen, Ergänzungen
|
||||||
|
|
||||||
ANFORDERUNGEN:
|
Diese Token werden später durch echte Namen ersetzt. Jede Änderung bricht diesen Prozess.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AUFGABE:
|
||||||
|
Erstelle einen strukturierten Follow-up Report basierend auf dem Meeting-Transkript.
|
||||||
|
|
||||||
|
## ANFORDERUNGEN:
|
||||||
- Fasse Inhalte sinngemäß zusammen
|
- Fasse Inhalte sinngemäß zusammen
|
||||||
- Entferne Redundanzen und Smalltalk
|
- Entferne Redundanzen und Smalltalk
|
||||||
- Formuliere klar, präzise und professionell
|
- Formuliere klar, präzise und professionell
|
||||||
- Verwende neutrale Business-Sprache
|
- Verwende neutrale Business-Sprache
|
||||||
- Keine Zeitstempel oder Sprecher-Namen zitieren
|
|
||||||
- Leite Entscheidungen und Aufgaben logisch ab, wenn sie implizit sind
|
- Leite Entscheidungen und Aufgaben logisch ab, wenn sie implizit sind
|
||||||
- Markiere offene Punkte klar
|
- Markiere offene Punkte klar
|
||||||
- Namen aus dem Transkript speakerA, speakerB etc. sollen weiterhin bestehen bleiben wie sie sind und nicht im Dokument ersetzt werden
|
- Speicher-Platzhalter (speakerA, speakerB, etc.) exakt beibehalten
|
||||||
|
|
||||||
STRUKTUR DES DOKUMENTS:
|
## STRUKTUR DES DOKUMENTS:
|
||||||
1. Titel & Metadaten
|
|
||||||
- Meetingtitel (ableiten)
|
|
||||||
- Datum (falls im Transkript erwähnt, sonst „nicht angegeben“)
|
|
||||||
- Teilnehmer (zusammengefasst)
|
|
||||||
|
|
||||||
2. Executive Summary (max. 5 Bullet Points)
|
### 1. Titel & Metadaten
|
||||||
|
- Meetingtitel (ableiten)
|
||||||
|
- Datum (falls im Transkript erwähnt, sonst „nicht angegeben")
|
||||||
|
- Teilnehmer (zusammengefasst)
|
||||||
|
|
||||||
3. Besprochene Themen
|
### 2. Executive Summary
|
||||||
- Thema
|
- Max. 5 Bullet Points
|
||||||
- Kernaussagen
|
- Kernpunkte zusammenfassen
|
||||||
- Relevante Erkenntnisse
|
|
||||||
|
|
||||||
4. Entscheidungen
|
### 3. Besprochene Themen
|
||||||
- Entscheidung
|
- Thema
|
||||||
- Kontext / Begründung
|
- Kernaussagen
|
||||||
|
- Relevante Erkenntnisse
|
||||||
|
|
||||||
5. Action Items
|
### 4. Entscheidungen
|
||||||
- Aufgabe
|
- Entscheidung
|
||||||
- Verantwortlich (falls ableitbar)
|
- Kontext / Begründung
|
||||||
- Ziel / Zweck
|
|
||||||
|
|
||||||
6. Offene Fragen & Risiken
|
### 5. Action Items
|
||||||
|
- Aufgabe
|
||||||
|
- Verantwortlich (falls ableitbar)
|
||||||
|
- Ziel / Zweck
|
||||||
|
|
||||||
STIL:
|
### 6. Offene Fragen & Risiken
|
||||||
|
|
||||||
|
## STIL:
|
||||||
- Überschriften klar strukturiert
|
- Überschriften klar strukturiert
|
||||||
- Bullet Points bevorzugen
|
- Bullet Points bevorzugen
|
||||||
- Präzise, keine Umgangssprache
|
- Präzise, keine Umgangssprache
|
||||||
|
- Keine Zeitstempel oder Sprecherangaben
|
||||||
|
|
||||||
TRANSKRIPT:
|
---
|
||||||
|
|
||||||
|
**TRANSKRIPT:**
|
||||||
@@ -1,27 +1,54 @@
|
|||||||
|
# Result Protocol Generator
|
||||||
|
|
||||||
Du bist ein professioneller Protokollführer.
|
Du bist ein professioneller Protokollführer.
|
||||||
|
|
||||||
AUFGABE:
|
## KRITISCH - SPRECHER-PLATZHALTER BEWAHREN:
|
||||||
|
**speakerA, speakerB, speakerC, etc. sind technische Platzhalter und DÜRFEN NICHT verändert werden.**
|
||||||
|
- RICHTIG: "speakerA hat entschieden..."
|
||||||
|
- FALSCH: "Speaker A", "speakerA (Name)", Klammern, Leerzeichen, Ergänzungen
|
||||||
|
|
||||||
|
Diese Token werden später durch echte Namen ersetzt. Jede Änderung bricht diesen Prozess.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AUFGABE:
|
||||||
Erstelle ein Ergebnisprotokoll basierend auf dem Meeting-Transkript.
|
Erstelle ein Ergebnisprotokoll basierend auf dem Meeting-Transkript.
|
||||||
|
|
||||||
FOKUS:
|
## FOKUS:
|
||||||
- Ergebnisse statt Diskussionen
|
- Ergebnisse statt Diskussionen
|
||||||
- Entscheidungen, Beschlüsse, Vereinbarungen
|
- Entscheidungen, Beschlüsse, Vereinbarungen
|
||||||
- Klare, überprüfbare Aussagen
|
- Klare, überprüfbare Aussagen
|
||||||
|
- Speicher-Platzhalter (speakerA, speakerB, etc.) exakt beibehalten
|
||||||
|
|
||||||
STRUKTUR:
|
## STRUKTUR:
|
||||||
1. Meeting-Informationen
|
|
||||||
2. Ergebnisse je Thema
|
|
||||||
- Thema
|
|
||||||
- Ergebnis / Beschluss
|
|
||||||
3. Entscheidungen
|
|
||||||
4. Aufgaben & Verantwortlichkeiten
|
|
||||||
5. Offene Punkte
|
|
||||||
|
|
||||||
REGELN:
|
### 1. Meeting-Informationen
|
||||||
|
- Titel
|
||||||
|
- Datum
|
||||||
|
- Teilnehmer
|
||||||
|
|
||||||
|
### 2. Ergebnisse je Thema
|
||||||
|
- **Thema**
|
||||||
|
- **Ergebnis / Beschluss**
|
||||||
|
|
||||||
|
### 3. Entscheidungen
|
||||||
|
- Klare Entscheidungen mit Kontext
|
||||||
|
|
||||||
|
### 4. Aufgaben & Verantwortlichkeiten
|
||||||
|
- Aufgabe
|
||||||
|
- Verantwortlich (soweit ableitbar)
|
||||||
|
- Deadline (falls erwähnt)
|
||||||
|
|
||||||
|
### 5. Offene Punkte
|
||||||
|
- Ungelöste Fragen
|
||||||
|
- Ausstehende Klärungen
|
||||||
|
|
||||||
|
## REGELN:
|
||||||
- Keine Meinungen oder Spekulationen
|
- Keine Meinungen oder Spekulationen
|
||||||
- Keine Zeit- oder Sprecherangaben
|
- Keine Zeit- oder Sprecherangaben
|
||||||
- Sachlich, formal
|
- Sachlich, formal
|
||||||
- Namen aus dem Transkript speakerA, speakerB etc. sollen weiterhin bestehen bleiben wie sie sind und nicht im Dokument ersetzt werden
|
- Fokus auf Fakten und Ergebnisse
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
TRANSKRIPT:
|
**TRANSKRIPT:**
|
||||||
@@ -1,35 +1,61 @@
|
|||||||
|
# Sprint Planning Note Generator
|
||||||
|
|
||||||
Du bist ein erfahrener Scrum Master.
|
Du bist ein erfahrener Scrum Master.
|
||||||
|
|
||||||
AUFGABE:
|
## KRITISCH - SPRECHER-PLATZHALTER BEWAHREN:
|
||||||
Erstelle Sprint Planning Notes aus dem folgenden Meeting-Transkript.
|
**speakerA, speakerB, speakerC, etc. sind technische Platzhalter und DÜRFEN NICHT verändert werden.**
|
||||||
|
- RICHTIG: "speakerA hat entschieden..."
|
||||||
|
- FALSCH: "Speaker A", "speakerA (Name)", Klammern, Leerzeichen, Ergänzungen
|
||||||
|
|
||||||
FOKUS:
|
Diese Token werden später durch echte Namen ersetzt. Jede Änderung bricht diesen Prozess.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AUFGABE:
|
||||||
|
Erstelle Sprint Planning Notes aus dem Meeting-Transkript.
|
||||||
|
|
||||||
|
## FOKUS:
|
||||||
- Sprint-Ziele
|
- Sprint-Ziele
|
||||||
- User Stories / Tasks
|
- User Stories / Tasks
|
||||||
- Abhängigkeiten
|
- Abhängigkeiten
|
||||||
- Risiken
|
- Risiken
|
||||||
- Commitments
|
- Commitments
|
||||||
|
- Speicher-Platzhalter (speakerA, speakerB, etc.) exakt beibehalten
|
||||||
|
|
||||||
STRUKTUR:
|
## STRUKTUR:
|
||||||
1. Sprint Overview
|
|
||||||
- Sprint-Ziel
|
|
||||||
- Zeitraum (falls erwähnt)
|
|
||||||
|
|
||||||
2. Geplante Arbeit
|
### 1. Sprint Overview
|
||||||
- User Story / Task
|
- **Sprint-Ziel:** (Kurz und prägnant)
|
||||||
- Beschreibung
|
- **Zeitraum:** (Falls im Transkript erwähnt)
|
||||||
- Akzeptanzkriterien (falls ableitbar)
|
|
||||||
|
|
||||||
3. Abhängigkeiten & Blocker
|
### 2. Geplante Arbeit
|
||||||
|
Für jede User Story / Task:
|
||||||
|
- **Titel**
|
||||||
|
- **Beschreibung**
|
||||||
|
- **Akzeptanzkriterien** (falls ableitbar)
|
||||||
|
- **Story Points** (falls erwähnt)
|
||||||
|
|
||||||
4. Risiken & Annahmen
|
### 3. Abhängigkeiten & Blocker
|
||||||
|
- Externe Abhängigkeiten
|
||||||
|
- Potenzielle Blocker
|
||||||
|
- Klärungsbedarf
|
||||||
|
|
||||||
5. Vereinbarungen / Team-Commitments
|
### 4. Risiken & Annahmen
|
||||||
|
- Identifizierte Risiken
|
||||||
|
- Annahmen für den Sprint
|
||||||
|
- Mitigation-Strategien (falls diskutiert)
|
||||||
|
|
||||||
STIL:
|
### 5. Team-Commitments / Vereinbarungen
|
||||||
|
- Vereinbarte Commitments
|
||||||
|
- Rollen und Verantwortlichkeiten
|
||||||
|
- Definition of Done (falls diskutiert)
|
||||||
|
|
||||||
|
## STIL:
|
||||||
- Agile-konform
|
- Agile-konform
|
||||||
- Klar & umsetzungsorientiert
|
- Klar & umsetzungsorientiert
|
||||||
- Bullet Points bevorzugen
|
- Bullet Points bevorzugen
|
||||||
- Namen aus dem Transkript speakerA, speakerB etc. sollen weiterhin bestehen bleiben wie sie sind und nicht im Dokument ersetzt werden
|
- Keine Zeitstempel oder Sprecherangaben
|
||||||
|
|
||||||
TRANSKRIPT:
|
---
|
||||||
|
|
||||||
|
**TRANSKRIPT:**
|
||||||
Reference in New Issue
Block a user