mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-16 02:11:52 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e543438592 | |||
| 4d850bf6a6 |
Binary file not shown.
@@ -9,22 +9,9 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="mitte" id="mitte">
|
<div class="mitte" id="mitte">
|
||||||
<div class="labelDiv" id="labelDiv">
|
<div class="flagsBtns" id="flagsBtns">
|
||||||
<label id="labelKI">Select ki:</label>
|
|
||||||
<label id="labelTranscription">Select transcription:</label>
|
|
||||||
<label id="labelLanguage">Select language:</label>
|
|
||||||
<img id="labelLanguageFlag" src="flags/united-kingdom-flag-png-large.jpg" width="20" height="10" >
|
|
||||||
</div>
|
|
||||||
<div class="dropdownMenus" id="dropdownMenus">
|
|
||||||
<select name="ai_type" id="ai_type">
|
<select name="ai_type" id="ai_type">
|
||||||
</select>
|
</select>
|
||||||
<select name="transkript_type" id="transkript_type">
|
|
||||||
</select>
|
|
||||||
<select name="output_type" id="output_type">
|
|
||||||
<option value="flac">flac</option>
|
|
||||||
<option value="mp3">mp3</option>
|
|
||||||
<option value="wav">wav</option>
|
|
||||||
</select>
|
|
||||||
<select name="language_option" id="language_option">
|
<select name="language_option" id="language_option">
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,32 +20,28 @@
|
|||||||
|
|
||||||
<div class="upload-container" id="uploadContainer">
|
<div class="upload-container" id="uploadContainer">
|
||||||
<p id="p1">Drag and drop video file</p>
|
<p id="p1">Drag and drop video file</p>
|
||||||
<video id="previewThumbnail" autoplay="false">
|
|
||||||
</video>
|
|
||||||
<div class="file-name" id="fileName">No video chosen</div>
|
<div class="file-name" id="fileName">No video chosen</div>
|
||||||
<div id="thumbnailContainer">
|
|
||||||
<img id="thumbnailImage" style="display:none;">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="custom-btn" id="manualUploadBtn">Search video</button>
|
<button class="custom-btn" id="manualUploadBtn">Search video</button>
|
||||||
<input type="file" id="videoUpload" accept="video/*">
|
<input type="file" id="videoUpload" accept="video/*">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="checkbox-group">
|
<div class="checkbox-group">
|
||||||
<label id="checkbox_group" for="checkbox-group">Choose prefered document style:</label>
|
<label id="checkbox_group" for="checkbox-group">Choose prefered document style:</label>
|
||||||
<div class="checkbox-container">
|
<div class="checkbox-container">
|
||||||
<input type="checkbox" name ="docFormat" id="docFormat" value="Meeting report">
|
<input type="checkbox" name ="docFormat" id="docFormat">
|
||||||
<label id="label_format" for="docFormat">Meeting report</label>
|
<label id="label_format" for="docFormat">Meeting report</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="checkbox-container">
|
<div class="checkbox-container">
|
||||||
<input type="checkbox" name="docFormat" id="docFormatSummary" value="Summary with timestamps">
|
<input type="checkbox" name="docFormat" id="docFormatSummary">
|
||||||
<label id="label_summary" for="docFormatSummary">Summary with timestamps</label>
|
<label id="label_summary" for="docFormatSummary">Summary with timestamps</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="submit-btn" id="submitButton" onclick="checkBoxes()" disabled>Submit</button>
|
<button class="submit-btn" id="submitButton" onclick="checkBoxes()">Submit</button>
|
||||||
|
|
||||||
<div class="progressbar" id="progressbar">
|
<div class="progressbar">
|
||||||
<div class="progress_fill"></div>
|
<div class="progress_fill"></div>
|
||||||
<span class="progress_text">0%</span>
|
<span class="progress_text">0%</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
var languageOptions = {
|
var languageOptions = {
|
||||||
"eng":{
|
"eng":{
|
||||||
"flagPath": "flags/united-kingdom-flag-png-large.jpg",
|
|
||||||
"labelKI": "Select ki:",
|
|
||||||
"labelTranscription": "Select transcription:",
|
|
||||||
"labelLanguage": "Select language:",
|
|
||||||
"title": "Video to document",
|
"title": "Video to document",
|
||||||
"h1": "Video to document",
|
"h1": "Video to document",
|
||||||
"p1": "Drag and drop video file",
|
"p1": "Drag and drop video file",
|
||||||
@@ -15,10 +11,6 @@ var languageOptions = {
|
|||||||
"submitButton": "Submit"
|
"submitButton": "Submit"
|
||||||
},
|
},
|
||||||
"de":{
|
"de":{
|
||||||
"flagPath": "flags/germany-flag-png-large.jpg",
|
|
||||||
"labelKI": "Waehle KI:",
|
|
||||||
"labelTranscription": "Waehle Transkription:",
|
|
||||||
"labelLanguage": "Waehle Sprache:",
|
|
||||||
"title": "Video zu Dokument",
|
"title": "Video zu Dokument",
|
||||||
"h1": "Video zu Dokument",
|
"h1": "Video zu Dokument",
|
||||||
"p1": "Video per Drag & Drop ablegen",
|
"p1": "Video per Drag & Drop ablegen",
|
||||||
@@ -30,10 +22,6 @@ var languageOptions = {
|
|||||||
"submitButton": "Absenden"
|
"submitButton": "Absenden"
|
||||||
},
|
},
|
||||||
"in":{
|
"in":{
|
||||||
"flagPath": "flags/india-flag-png-large.png",
|
|
||||||
"labelKI": "की का चयन करें:",
|
|
||||||
"labelTranscription": "प्रतिलेखन चुनें:",
|
|
||||||
"labelLanguage": "भाषा चुने:",
|
|
||||||
"title": "दस्तावेज़ के लिए वीडियो",
|
"title": "दस्तावेज़ के लिए वीडियो",
|
||||||
"h1": "दस्तावेज़ के लिए वीडियो",
|
"h1": "दस्तावेज़ के लिए वीडियो",
|
||||||
"p1": "वीडियो फ़ाइल खींचें और छोड़ें",
|
"p1": "वीडियो फ़ाइल खींचें और छोड़ें",
|
||||||
|
|||||||
@@ -4,24 +4,12 @@ try {
|
|||||||
contextBridge.exposeInMainWorld("explorer", {
|
contextBridge.exposeInMainWorld("explorer", {
|
||||||
onFileDrop: (file) => webUtils.getPathForFile(file)
|
onFileDrop: (file) => webUtils.getPathForFile(file)
|
||||||
})
|
})
|
||||||
contextBridge.exposeInMainWorld("submit", {
|
contextBridge.exposeInMainWorld("extractor", {
|
||||||
submit: (meeting_specifications) => {ipcRenderer.send("file_submit", meeting_specifications)}
|
extract: (file) => ipcRenderer.send("extract", file)
|
||||||
})
|
})
|
||||||
contextBridge.exposeInMainWorld("electronAPI", {
|
contextBridge.exposeInMainWorld("electronAPI", {
|
||||||
getFilePath: (file) => {return webUtils.getPathForFile(file)}
|
getFilePath: (file) => {return webUtils.getPathForFile(file)}
|
||||||
})
|
})
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("onStartup", {
|
|
||||||
getModuleNames: () => ipcRenderer.invoke('get-module-names')
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ipcRenderer.on("progress", (event, resp) => {
|
|
||||||
alert(`Finished step ${resp.curstep} of ${resp.totalsteps}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcRenderer.on("error", (event, err) => {alert(err)})
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in preload.js");
|
console.log("Error in preload.js");
|
||||||
}
|
}
|
||||||
@@ -16,72 +16,26 @@ uploadContainer.addEventListener("drop", (e) => {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const files = e.dataTransfer.files
|
const files = e.dataTransfer.files
|
||||||
const filePath = window.explorer.onFileDrop(files[0])
|
const filePath = window.explorer.onFileDrop(files[0])
|
||||||
const testEndings = [".mp4", ".mov", ".avi", ".mkv"];
|
var holdy = filePath + "";
|
||||||
var pathToLower = filePath.toLowerCase();
|
if(holdy.endsWith(".mp4") || holdy.endsWith(".mov") || holdy.endsWith(".avi") || holdy.endsWith( ".mkv")){
|
||||||
if(testEndings.some(e => pathToLower.endsWith(e))){
|
console.log(filePath)
|
||||||
document.getElementById("progressbar").style.visibility = "visible";
|
|
||||||
const files1 = e.dataTransfer.files;
|
const files1 = e.dataTransfer.files;
|
||||||
handleFiles(files1);
|
handleFiles(files1);
|
||||||
}else{
|
|
||||||
alert('The given file is not compatible. These are the available types: [".mp4", ".mov", ".avi", ".mkv"].');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in renderer.js with the listerner for the drop function");
|
console.log("Error in renderer.js with the listerner for the drop function");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
window.addEventListener('load', async (e) => {
|
|
||||||
try {
|
window.addEventListener('load', (e) => {
|
||||||
console.log("test");
|
console.log("test");
|
||||||
loadLanguageOptions();
|
loadLanguageOptions();
|
||||||
const value = await window.onStartup.getModuleNames();
|
|
||||||
loadAiOptions(value.ai_modules);
|
|
||||||
loadTranscriptionOptions(value.transcription_modules);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
language_option.addEventListener('change', (e)=>{
|
language_option.addEventListener('change', (e)=>{
|
||||||
try {
|
|
||||||
const select = document.getElementById('language_option');
|
const select = document.getElementById('language_option');
|
||||||
|
console.log(select.value);
|
||||||
changeLanguage(select.value);
|
changeLanguage(select.value);
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
videoUpload.addEventListener("change", () => {
|
|
||||||
try {
|
|
||||||
activateSubmitBtn(videoUpload.files.length > 0);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
//listener for the file explorer search when something got selected
|
|
||||||
videoUpload.addEventListener('change', () => {
|
|
||||||
try {
|
|
||||||
handleFiles(videoUpload.files);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error in manualBtn EventListener change");
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
//listener for the file explorer search
|
|
||||||
manualUploadBtn.addEventListener('click', () => {
|
|
||||||
try {
|
|
||||||
videoUpload.click();
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error in manualBtn EventListener click");
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
+31
-115
@@ -1,84 +1,45 @@
|
|||||||
|
//listener for the file explorer search
|
||||||
|
manualUploadBtn.addEventListener('click', () => {
|
||||||
|
try {
|
||||||
|
videoUpload.click();
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error in manualBtn EventListener click");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
//function to check if one checkbox is at least klicked
|
//function to check if one checkbox is at least klicked
|
||||||
function checkBoxes() {
|
function checkBoxes() {
|
||||||
try {
|
try {
|
||||||
const checkboxes = document.querySelectorAll('input[name="docFormat"]');
|
const checkboxes = document.querySelectorAll('input[name="docFormat"]');
|
||||||
let isChecked = false;
|
let isChecked = false;
|
||||||
var checkedCounter = 0;
|
|
||||||
checkboxes.forEach(function(checkbox){
|
checkboxes.forEach(function(checkbox){
|
||||||
if(checkbox.checked){
|
if(checkbox.checked){
|
||||||
isChecked = true;
|
isChecked = true;
|
||||||
checkedCounter++;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isChecked) {
|
if(isChecked){
|
||||||
//Code to submit the video
|
//Code to submit the video
|
||||||
var selectedCheckboxes = {};
|
|
||||||
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 pathTest = window.electronAPI.getFilePath(videoUpload.files[0]);
|
||||||
var pathToLower = pathTest.toLowerCase();
|
if(pathTest.endsWith(".mp4") || holdy.endsWith(".mov") || holdy.endsWith(".avi") || holdy.endsWith( ".mkv")){
|
||||||
if(testEndings.some(e => pathToLower.endsWith(e))){
|
window.extractor.extract({inputVideoPath: pathTest, outputType:"wav"})
|
||||||
document.getElementById("progressbar").style.visibility = "visible";
|
|
||||||
//assembly of the json for the main
|
|
||||||
|
|
||||||
const selectedStyles = [checkedCounter];
|
|
||||||
var iter = 0;
|
|
||||||
checkboxes.forEach(function(checkbox){
|
|
||||||
if(checkbox.checked){
|
|
||||||
console.log(checkbox.value);
|
|
||||||
selectedStyles[iter] = {iter: checkbox.value};
|
|
||||||
iter++;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
console.log(selectedCheckboxes);
|
|
||||||
const outputType = document.getElementById("output_type");
|
|
||||||
const transcriptionType = document.getElementById("transkript_type");
|
|
||||||
const aiType = document.getElementById("ai_type");
|
|
||||||
const sendingPackage = {
|
|
||||||
"video": {
|
|
||||||
"module":"extraction-video-to-audio",
|
|
||||||
"inputVideoPath": pathTest,
|
|
||||||
"outputType": outputType.value
|
|
||||||
},
|
|
||||||
"transcription": {
|
|
||||||
"module": transcriptionType.value
|
|
||||||
},
|
|
||||||
"document": {
|
|
||||||
"module":aiType.value,
|
|
||||||
"styles": selectedStyles
|
|
||||||
}
|
|
||||||
};
|
|
||||||
window.submit.submit(sendingPackage)
|
|
||||||
}else{
|
|
||||||
alert('The given file is not compatible. These are the available types: [".mp4", ".mov", ".avi", ".mkv"].');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//language only english at the moment
|
//language only english at the moment
|
||||||
alert('Please select at least one document type.');
|
alert('Please select at least one document type.');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in script.js checkBoxes function");
|
console.log(error)
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./a.mp4", outputType:"wav"})
|
||||||
}
|
}
|
||||||
|
|
||||||
//language changing feature
|
//language changing feature
|
||||||
function changeLanguage(language) {
|
function changeLanguage(language) {
|
||||||
try {
|
try {
|
||||||
document.getElementById('labelLanguageFlag').src = languageOptions[language].flagPath;
|
|
||||||
document.getElementById('labelKI').textContent = languageOptions[language].labelKI;
|
|
||||||
document.getElementById('labelTranscription').textContent = languageOptions[language].labelTranscription;
|
|
||||||
document.getElementById('labelLanguage').textContent = languageOptions[language].labelLanguage;
|
|
||||||
document.getElementById('title').textContent = languageOptions[language].title;
|
document.getElementById('title').textContent = languageOptions[language].title;
|
||||||
document.getElementById('h1').textContent = languageOptions[language].h1;
|
document.getElementById('h1').textContent = languageOptions[language].h1;
|
||||||
document.getElementById('p1').textContent = languageOptions[language].p1;
|
document.getElementById('p1').textContent = languageOptions[language].p1;
|
||||||
@@ -88,43 +49,46 @@ function changeLanguage(language) {
|
|||||||
document.getElementById('label_format').textContent = languageOptions[language].label_format;
|
document.getElementById('label_format').textContent = languageOptions[language].label_format;
|
||||||
document.getElementById('label_summary').textContent = languageOptions[language].label_summary;
|
document.getElementById('label_summary').textContent = languageOptions[language].label_summary;
|
||||||
document.getElementById('submitButton').textContent = languageOptions[language].submitButton;
|
document.getElementById('submitButton').textContent = languageOptions[language].submitButton;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in script.js changeLanguage function");
|
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//listener for the file explorer search when something got selected
|
||||||
|
videoUpload.addEventListener('change', () => {
|
||||||
|
try {
|
||||||
|
handleFiles(videoUpload.files);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error in manualBtn EventListener change");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
//function to display the file path in the drop down box
|
//function to display the file path in the drop down box
|
||||||
function handleFiles(files) {
|
function handleFiles(files) {
|
||||||
try {
|
try {
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
const file = files[0];
|
const file = files[0];
|
||||||
if (file.type.startsWith('video/')) {
|
if (file.type.startsWith('video/')) {
|
||||||
const filePath = window.explorer.onFileDrop(files[0])
|
|
||||||
videoUpload.files = files;
|
videoUpload.files = files;
|
||||||
fileName.textContent = `Chosen video: ${file.name}`;
|
fileName.textContent = `Chosen video: ${file.name}`;
|
||||||
generateThumbnail(filePath);
|
|
||||||
activateSubmitBtn(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in script.js handleFiles function");
|
console.log("Error in script.js handleFiles function");
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//function to regulate the progress on the progressbar
|
//function to regulate the progress on the progressbar
|
||||||
function updateProgressBar(bar, value) {
|
function updateProgressBar(bar, value){
|
||||||
try {
|
try {
|
||||||
value = Math.round(value);
|
value = Math.round(value);
|
||||||
bar.querySelector(".progress_fill").style.width = `${value}%`;
|
bar.querySelector(".progress_fill").style.width = `${value}%`;
|
||||||
bar.querySelector(".progress_text").textContent = `${value}%`;
|
bar.querySelector(".progress_text").textContent = `${value}%`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in scripts.js updateProgressBar function");
|
console.log("Error in scripts.js updateProgressBar function");
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -133,13 +97,12 @@ function updateProgressBar(bar, value) {
|
|||||||
function loadAiOptions(options){
|
function loadAiOptions(options){
|
||||||
try {
|
try {
|
||||||
var menu = document.getElementById('ai_type');
|
var menu = document.getElementById('ai_type');
|
||||||
var object_holdy;
|
|
||||||
var choice ;
|
|
||||||
object_holdy = options
|
|
||||||
for(i = 0; i < options.length; i++){
|
for(i = 0; i < options.length; i++){
|
||||||
choice = document.createElement('option');
|
var opty = options[i];
|
||||||
choice.textContent = object_holdy[i].displayname;
|
var namey = "option" + i;
|
||||||
choice.value = object_holdy[i].name;
|
var choice = document.createElement(namey);
|
||||||
|
choice.textContent = "t";
|
||||||
|
choice.value = i;
|
||||||
menu.appendChild(choice);
|
menu.appendChild(choice);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -148,25 +111,6 @@ function loadAiOptions(options){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//function to load transcription options to the drop down list
|
|
||||||
function loadTranscriptionOptions(options){
|
|
||||||
try {
|
|
||||||
var menu = document.getElementById('transkript_type');
|
|
||||||
var object_holdy;
|
|
||||||
var choice ;
|
|
||||||
object_holdy = options
|
|
||||||
for(i = 0; i < options.length; i++){
|
|
||||||
choice = document.createElement('option');
|
|
||||||
choice.textContent = object_holdy[i].displayname;
|
|
||||||
choice.value = object_holdy[i].name;
|
|
||||||
menu.appendChild(choice);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error in script.js function loadTranscriptionOptions");
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//function to load language options to the drop down list
|
//function to load language options to the drop down list
|
||||||
function loadLanguageOptions(){
|
function loadLanguageOptions(){
|
||||||
try {
|
try {
|
||||||
@@ -186,31 +130,3 @@ function loadLanguageOptions(){
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function activateSubmitBtn(hasFile){
|
|
||||||
try {
|
|
||||||
submitButton.disabled = !hasFile;
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function deaktivateProgressbar(){
|
|
||||||
try {
|
|
||||||
document.getElementById("progressbar").style.visibility = "hidden";
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Video thumbnail generation
|
|
||||||
function generateThumbnail(path){
|
|
||||||
const videoElement = document.getElementById("previewThumbnail");
|
|
||||||
while (videoElement.firstChild) videoElement.removeChild(videoElement.firstChild);
|
|
||||||
videoElement.src = path;
|
|
||||||
videoElement.type = "video/mov";
|
|
||||||
videoElement.load();
|
|
||||||
videoElement.style.maxWidth = 40;
|
|
||||||
videoElement.style.maxHeight = 40;
|
|
||||||
videoElement.autoplay = false;
|
|
||||||
}
|
|
||||||
|
|||||||
+12
-53
@@ -5,7 +5,7 @@ body {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background-color: #f2f3f4;
|
background-color: #555;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -17,10 +17,9 @@ body {
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 350px;
|
width: 400px;
|
||||||
height: 200px;
|
|
||||||
transition: border 0.3s, background-color 0.3s;
|
transition: border 0.3s, background-color 0.3s;
|
||||||
border: 2px dashed #7378c9;
|
border: 2px dashed #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -41,35 +40,11 @@ body {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #333;
|
color: #333;
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#thumbnailContainer {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#thumbnailImage {
|
|
||||||
width: 200px;
|
|
||||||
height: auto;
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0px 4px 10px rgba(0,0,0,0.1);
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
#previewThumbnail {
|
|
||||||
width: 150px;
|
|
||||||
height: 100px;
|
|
||||||
/*border: 1px dashed black;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-btn {
|
.custom-btn {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin-top: 10px;
|
|
||||||
background-color: #007BFF;
|
background-color: #007BFF;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -109,8 +84,6 @@ gap: 5px;
|
|||||||
|
|
||||||
.submit-btn {
|
.submit-btn {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
background-color: #007BFF;
|
background-color: #007BFF;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -119,26 +92,17 @@ gap: 5px;
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submit-btn:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mitte {
|
.mitte {
|
||||||
background-color: #FDFCFA;
|
background-color: #f2f3f4;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 700px;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 5% 50px;
|
padding: 5% 50px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
border: 0px;
|
border: 1px;
|
||||||
border-color: black;
|
border-color: black;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 0px 4px 10px rgba(0,0,0,0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -152,7 +116,6 @@ h1 {
|
|||||||
background: rgb(42, 46, 78);
|
background: rgb(42, 46, 78);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
visibility: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress_fill{
|
.progress_fill{
|
||||||
@@ -170,19 +133,15 @@ h1 {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flagsBtns {
|
||||||
.dropdownMenus {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-top: 1px;
|
|
||||||
gap: 150px;
|
|
||||||
padding: 2px 10px 2px 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ai_type, #transkript_type, #language_option {
|
.de_Btn, .eng_Btn, .in_Btn {
|
||||||
padding: 3px;
|
padding: 8px 16px;
|
||||||
}
|
color: white;
|
||||||
|
border: none;
|
||||||
.labelDiv {
|
border-radius: 8px;
|
||||||
gap: 200px;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@@ -35,8 +35,6 @@ console.log("-------------------------------------------------------------------
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------- CLI COMMANDS --------------------------------------------------------- //
|
// --------------------------------------------------------- CLI COMMANDS --------------------------------------------------------- //
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
@@ -62,7 +60,7 @@ let mainWindow;
|
|||||||
function createWindow() {
|
function createWindow() {
|
||||||
mainWindow = new electron.BrowserWindow({
|
mainWindow = new electron.BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 800,
|
height: 600,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
@@ -76,160 +74,6 @@ function createWindow() {
|
|||||||
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)
|
||||||
// })
|
|
||||||
|
|
||||||
// setTimeout(() => {
|
|
||||||
// mainWindow.webContents.send("fuck", "worked uwu")
|
|
||||||
// }, 5000);
|
|
||||||
|
|
||||||
electron.ipcMain.handle('get-module-names', async () => {
|
|
||||||
let module_array = {
|
|
||||||
"ai_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;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// console.log(module_array);
|
|
||||||
return module_array
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// electron.ipcMain.on("get_modules", async (event, args) => {
|
|
||||||
// let module_array = {
|
|
||||||
// "ai_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;
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// console.log(module_array);
|
|
||||||
|
|
||||||
// mainWindow.webContents.send("modules", module_array)
|
|
||||||
// })
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
electron.ipcMain.on("file_submit", async (event, args) => {
|
|
||||||
try {
|
|
||||||
let curstep = 0
|
|
||||||
let totalsteps = 3 + args.document.styles.length
|
|
||||||
|
|
||||||
if(args.document.styles.length == 0)
|
|
||||||
throw new Error("At least one Document Style needed");
|
|
||||||
|
|
||||||
|
|
||||||
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: args.video.outputType}).then(resp => {
|
|
||||||
console.log(resp);
|
|
||||||
audiopath = resp
|
|
||||||
curstep++
|
|
||||||
mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
|
||||||
}).catch(err => {
|
|
||||||
mainWindow.webContents.send("error", 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)
|
|
||||||
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)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log("\n\n Running the LLM module");
|
|
||||||
// TODO implement documentation module
|
|
||||||
// This code handles the Text to Document processing module call
|
|
||||||
for (let i = 0; i < args.document.styles.length; i++) {
|
|
||||||
await mapFunctions.get("module-handler").function(args.document.module, {prompt: args.document.styles[i].prompt, transcript: transcriptpath}).then(resp => {
|
|
||||||
console.log(resp);
|
|
||||||
transcriptpath = resp
|
|
||||||
curstep++
|
|
||||||
mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
|
||||||
}).catch(err => {
|
|
||||||
mainWindow.webContents.send("error", err)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 = {
|
|
||||||
"ai_modules": [
|
|
||||||
{name:"abc", displayname:"ABC"},
|
|
||||||
{name:"qeg", displayname:"aqghegahu"}
|
|
||||||
],
|
|
||||||
"transcription_modules": [
|
|
||||||
{name:"abc", displayname:"ABC"},
|
|
||||||
{name:"qeg", displayname:"aqghegahu"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
Generated
+1
-812
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,6 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/genai": "^1.30.0",
|
|
||||||
"@types/axios": "^0.9.36",
|
"@types/axios": "^0.9.36",
|
||||||
"axios": "^1.13.2",
|
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"electron": "^39.1.1",
|
"electron": "^39.1.1",
|
||||||
|
|||||||
@@ -16,8 +16,3 @@ cliProgress = require('cli-progress');
|
|||||||
// { app, BrowserWindow, ipcMain, dialog } = require('electron');
|
// { app, BrowserWindow, ipcMain, dialog } = require('electron');
|
||||||
|
|
||||||
electron = require('electron');
|
electron = require('electron');
|
||||||
genai = require("@google/genai");
|
|
||||||
|
|
||||||
axios = require("axios")
|
|
||||||
|
|
||||||
console.log(require('dotenv').config({path: __dirname + '/.env'}));
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
// Ensure ffmpeg binary is available
|
// Ensure ffmpeg binary is available
|
||||||
if (!ffmpegPath) {
|
if (!ffmpegPath) {
|
||||||
throw new Error('FFmpeg binary not found!');
|
throw new Error('FFmpeg binary not found!');
|
||||||
@@ -31,11 +32,11 @@ module.exports = {
|
|||||||
hideCursor: true
|
hideCursor: true
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
return new Promise((resolve, reject) => {
|
// if (meta.url === `file://${process.argv[1]}`) {
|
||||||
this.extractAudioFromVideo(parameter.inputVideoPath, progressBar, parameter.outputType)
|
this.extractAudioFromVideo(parameter.inputVideoPath, progressBar, parameter.outputType)
|
||||||
.then((resp) => resolve(resp))
|
.then(() => console.log('Audio extraction successful.'))
|
||||||
.catch((err) => console.error(err));
|
.catch((err) => console.error(err));
|
||||||
})
|
// }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(parameter.outputType);
|
console.log(parameter.outputType);
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ module.exports = {
|
|||||||
progressBar.update(100, { timemark: 'done' });
|
progressBar.update(100, { timemark: 'done' });
|
||||||
progressBar.stop();
|
progressBar.stop();
|
||||||
console.log(`Extraction completed: ${outputAudioPath}`);
|
console.log(`Extraction completed: ${outputAudioPath}`);
|
||||||
resolve(outputAudioPath);
|
resolve();
|
||||||
})
|
})
|
||||||
.on('error', (err) => {
|
.on('error', (err) => {
|
||||||
progressBar.stop();
|
progressBar.stop();
|
||||||
@@ -88,4 +89,5 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
|
|
||||||
// Prepare output directory (always storage/transcriptionSummaries under project root)
|
|
||||||
const outputDir = `${__dirname}/../../../storage/transcriptionSummaries`;
|
|
||||||
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()"
|
|
||||||
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) {
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
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 args === "string") {
|
|
||||||
try {
|
|
||||||
await new Promise((res) => {
|
|
||||||
fs.readFile(args, 'utf8', function (err, data) {
|
|
||||||
if (err) throw err;
|
|
||||||
inputJson = JSON.parse(data);
|
|
||||||
res()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Invalid JSON in summarize-transcription");
|
|
||||||
console.log(e)
|
|
||||||
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) {
|
|
||||||
const lastEntry = result[result.length - 1];
|
|
||||||
if (lastEntry && lastEntry.speaker === currentSpeaker) {
|
|
||||||
lastEntry.sentence += " " + currentSentence;
|
|
||||||
lastEntry.end = endTime;
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
const lastEntry = result[result.length - 1];
|
|
||||||
if (lastEntry && lastEntry.speaker === currentSpeaker) {
|
|
||||||
lastEntry.sentence += " " + currentSentence;
|
|
||||||
lastEntry.end = endTime;
|
|
||||||
} else {
|
|
||||||
result.push({
|
|
||||||
speaker: currentSpeaker,
|
|
||||||
sentence: currentSentence,
|
|
||||||
start: startTime,
|
|
||||||
end: endTime
|
|
||||||
});
|
|
||||||
}
|
|
||||||
currentSentence = "";
|
|
||||||
startTime = null;
|
|
||||||
endTime = null;
|
|
||||||
currentSpeaker = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// safe last sentence
|
|
||||||
if (currentSentence) {
|
|
||||||
const lastEntry = result[result.length - 1];
|
|
||||||
if (lastEntry && lastEntry.speaker === currentSpeaker) {
|
|
||||||
lastEntry.sentence += " " + currentSentence;
|
|
||||||
lastEntry.end = endTime;
|
|
||||||
} else {
|
|
||||||
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}`);
|
|
||||||
|
|
||||||
resolve(jsonPath);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error saving Summary:", err);
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
|
|
||||||
// Prepare output directory (always storage/transcriptionSummaries under project root)
|
|
||||||
const outputDir = `${__dirname}/../../../storage/transcriptionSummaries`;
|
|
||||||
if (!fs.existsSync(outputDir)) {
|
|
||||||
fs.mkdirSync(outputDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSessionId(inputPath) {
|
|
||||||
try {
|
|
||||||
const parsed = new URL(inputPath);
|
|
||||||
const base = path.basename(parsed.pathname);
|
|
||||||
return base.replace(/\.[^.]+$/, '');
|
|
||||||
} catch {
|
|
||||||
return path.basename(inputPath, path.extname(inputPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//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) {
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
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 args === "string") {
|
|
||||||
try {
|
|
||||||
await new Promise((res) => {
|
|
||||||
fs.readFile(args, 'utf8', function (err, data) {
|
|
||||||
if (err) throw err;
|
|
||||||
inputJson = JSON.parse(data);
|
|
||||||
res()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Invalid JSON in summarize-transcription");
|
|
||||||
console.log(e)
|
|
||||||
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 {
|
|
||||||
|
|
||||||
let filename = getSessionId(args);
|
|
||||||
|
|
||||||
const jsonPath = path.join(outputDir, `${filename}-${new Date().getTime()}.json`);
|
|
||||||
fs.writeFileSync(jsonPath, JSON.stringify(result, null, 2), "utf-8");
|
|
||||||
|
|
||||||
const txtPath = path.join(outputDir, `${filename}-${new Date().getTime()}.txt`);
|
|
||||||
fs.writeFileSync(txtPath, output.join("\n"), "utf-8");
|
|
||||||
|
|
||||||
console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`);
|
|
||||||
resolve(jsonPath);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error saving Summary:", err);
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name:"chatgpt", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()"
|
name:"chatgpt", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()"
|
||||||
type:"llm", // value used to differentiate each module to order them in the UI
|
type:"document", // value used to differentiate each module to order them in the UI
|
||||||
displayname:"ChatGPT", // The displayname used within the UI
|
displayname:"ChatGPT", // The displayname used within the UI
|
||||||
async function(parameter){
|
async function(parameter){
|
||||||
// TODO add code to actually send the transcript to ChatGPT and get a response back
|
// TODO add code to actually send the transcript to ChatGPT and get a response back
|
||||||
|
|||||||
@@ -1,123 +1,8 @@
|
|||||||
const API_KEY = process.env.ASSEMBLYAI_API_KEY;
|
|
||||||
const BASE_URL = 'https://api.assemblyai.com/v2';
|
|
||||||
|
|
||||||
//---------------------------------------------------Upload audio---------------------------------------------------
|
|
||||||
|
|
||||||
async function uploadAudio(audioPath) {
|
|
||||||
const audioData = fs.readFileSync(audioPath);
|
|
||||||
|
|
||||||
const response = await axios.post(`${BASE_URL}/upload`, audioData, {
|
|
||||||
headers: {
|
|
||||||
authorization: API_KEY,
|
|
||||||
'content-type': 'application/octet-stream'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return response.data.upload_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
////---------------------------------------------------Extract session id---------------------------------------------------
|
|
||||||
|
|
||||||
function getSessionId(inputPath) {
|
|
||||||
try {
|
|
||||||
const parsed = new URL(inputPath);
|
|
||||||
const base = path.basename(parsed.pathname);
|
|
||||||
return base.replace(/\.[^.]+$/, '');
|
|
||||||
} catch {
|
|
||||||
return path.basename(inputPath, path.extname(inputPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------Create transcript---------------------------------------------------
|
|
||||||
|
|
||||||
async function createTranscript(audioUrl) {
|
|
||||||
const response = await axios.post(
|
|
||||||
`${BASE_URL}/transcript`,
|
|
||||||
{
|
|
||||||
audio_url: audioUrl,
|
|
||||||
speaker_labels: true,
|
|
||||||
language_detection: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
authorization: API_KEY,
|
|
||||||
'content-type': 'application/json'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return response.data.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------Poll transcript---------------------------------------------------
|
|
||||||
|
|
||||||
async function pollTranscript(transcriptId) {
|
|
||||||
while (true) {
|
|
||||||
const response = await axios.get(`${BASE_URL}/transcript/${transcriptId}`, {
|
|
||||||
headers: { authorization: API_KEY }
|
|
||||||
});
|
|
||||||
|
|
||||||
const status = response.data.status;
|
|
||||||
|
|
||||||
if (status === 'completed') return response.data;
|
|
||||||
if (status === 'error') throw new Error(`Transcription failed: ${response.data.error}`);
|
|
||||||
|
|
||||||
await new Promise(res => setTimeout(res, 3000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------Save transcript---------------------------------------------------
|
|
||||||
|
|
||||||
function saveTranscript(transcript, sessionId) {
|
|
||||||
const outputDir = path.join(__dirname, '../../../storage/transcripts');
|
|
||||||
|
|
||||||
if (!fs.existsSync(outputDir)) {
|
|
||||||
fs.mkdirSync(outputDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const outputPath = path.join(outputDir, `${sessionId}.json`);
|
|
||||||
fs.writeFileSync(outputPath, JSON.stringify(transcript, null, 2));
|
|
||||||
|
|
||||||
console.log(`Transcript saved: ${outputPath}`);
|
|
||||||
|
|
||||||
return outputPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------Modul---------------------------------------------------
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'assembly',
|
name:"assembly", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()"
|
||||||
type: 'transcription',
|
type:"transcription", // value used to differentiate each module to order them in the UI
|
||||||
displayname: 'AssemblyAI',
|
displayname:"Assembly", // The displayname used within the UI
|
||||||
|
async function(parameter){
|
||||||
async function(audioFileName) {
|
// TODO add code to actually process the audio file
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
try {
|
|
||||||
// audioFileName ist nur "datei.mp3"
|
|
||||||
const audioPath = audioFileName;
|
|
||||||
|
|
||||||
let audioUrl;
|
|
||||||
|
|
||||||
if (/^https?:\/\//i.test(audioFileName)) {
|
|
||||||
audioUrl = audioFileName;
|
|
||||||
} else {
|
|
||||||
if (!fs.existsSync(audioPath)) {
|
|
||||||
throw new Error(`Audio file not found: ${audioPath}`);
|
|
||||||
}
|
}
|
||||||
audioUrl = await uploadAudio(audioPath);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const transcriptId = await createTranscript(audioUrl);
|
|
||||||
const transcript = await pollTranscript(transcriptId);
|
|
||||||
|
|
||||||
const sessionId = getSessionId(audioFileName);
|
|
||||||
|
|
||||||
resolve(saveTranscript(transcript, sessionId));
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Transcription error:', error.message);
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -6,18 +6,8 @@ module.exports = {
|
|||||||
// We are now calling the example function from the example folder
|
// We are now calling the example function from the example folder
|
||||||
mapFunctions.get("example").function("Startup")
|
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:"./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:"wav"})
|
||||||
// mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./b.mp4", outputType:"flac"})
|
// mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./b.mp4", outputType:"flac"})
|
||||||
|
|
||||||
// mapFunctions.get("ipc-handler").function("extraction-video-to-audio", {inputVideoPath:"./a.mp4", outputType:"flac"})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name:"module-handler", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()"
|
|
||||||
async function(module,parameter){
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
if(mapFunctions.get(module) == undefined){
|
|
||||||
reject("requested modules not found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mapFunctions.get(module).function(parameter).then((result) => {
|
|
||||||
resolve(result)
|
|
||||||
}).catch((err) => {
|
|
||||||
reject(err)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// services/pipeline/jobs/transcribeLatest.ts
|
// services/pipeline/jobs/transcribeLatest.ts
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
// @ts-ignore: module has no type declarations or cannot be resolved in current TS config
|
|
||||||
import assembly from '../../modules/transcription/assembly';
|
import assembly from '../../modules/transcription/assembly';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
const transSummarizer = require("../../services/modules/jsonTools/transcriptionSummarizer.js");
|
|
||||||
|
|
||||||
// JSON-Datei laden
|
|
||||||
const inputJson = JSON.parse(fs.readFileSync("./testFile.json", "utf8"));
|
|
||||||
|
|
||||||
// Übergabe an den Summarizer
|
|
||||||
transSummarizer.function({
|
|
||||||
json: inputJson
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user