mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-15 18:01:52 +02:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1683502aa1 | |||
| 789ecd3a31 | |||
| e72d03efbe | |||
| ec57411992 | |||
| 1e38cc79f4 | |||
| 746fec05d4 | |||
| d647f53790 | |||
| 791dbab739 | |||
| c497fa9532 | |||
| 3ce632bf8d | |||
| 5ea8ec6a1a | |||
| 15e2e35bda | |||
| 53508b175a | |||
| 3dd8485140 | |||
| 68c1f0ed9f | |||
| 3af038d195 | |||
| 6512b50d83 | |||
| faee605f12 | |||
| 037d29e656 | |||
| 8c201db539 | |||
| 882b49a489 | |||
| 25d11d74a3 | |||
| 0d3535128d | |||
| e661aefbe8 | |||
| ed94928953 | |||
| 8adf470f18 | |||
| f858f2edbb | |||
| 425e24853e | |||
| 05c04aaef2 | |||
| 84cc94aa34 | |||
| 16f319f89f | |||
| 9ab98825a2 | |||
| 9a0a349813 | |||
| 9dfc05e987 | |||
| a5a60635fc | |||
| af13907fdc | |||
| 812bca8cfb | |||
| 34d644d7d7 | |||
| e73a2a8203 | |||
| 2f5efee9c7 | |||
| 465fe8bd41 | |||
| 78e5cf0503 | |||
| 718664523c | |||
| eb42a1f377 | |||
| 0e7b42cb4a | |||
| 31ddddab6a | |||
| 9082543652 | |||
| b9657e1c95 | |||
| baeb9efd2b | |||
| 8c4d213ed0 | |||
| 474e587ff2 | |||
| 6531f5f51c | |||
| 05449ad8f2 | |||
| 8046fe53d1 | |||
| c2f22b3525 | |||
| 6257ad05a8 | |||
| bf7438b753 | |||
| 868945fb92 | |||
| 0f689e2846 | |||
| b4f2ed561d | |||
| 925eb33eab | |||
| 911cba14fd | |||
| 6813659443 | |||
| a0ed2ab7bd | |||
| b87bfd444d | |||
| 97b571b7f9 | |||
| 455147a41b | |||
| fde4d584ab | |||
| abd72c9b54 | |||
| 4dc53b9d5f | |||
| 5f14d633e3 | |||
| 7b01c4f022 | |||
| 4f57ec25bf | |||
| f8fb71e146 | |||
| ada231cd28 | |||
| 1e3d830ae2 | |||
| ab0e737f33 | |||
| 9441699561 |
Binary file not shown.
+16
-2
@@ -963,9 +963,23 @@ app.*.symbols
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
!/dev/ci/**/Gemfile.lock
|
||||
|
||||
#Storage files
|
||||
storage/
|
||||
# Storage files
|
||||
storage/documents/*
|
||||
storage/transcriptionSummaries/*
|
||||
storage/transcripts/*
|
||||
storage/video/*
|
||||
# The inverse for the .gitkeep files, to make sure the folders are there but not the local files
|
||||
!storage/documents/.gitkeep
|
||||
!storage/transcriptionSummaries/.gitkeep
|
||||
!storage/transcripts/.gitkeep
|
||||
!storage/video/.gitkeep
|
||||
|
||||
*.mp4
|
||||
*.webm
|
||||
*.mp3
|
||||
*.mov
|
||||
*.wav
|
||||
*.flac
|
||||
|
||||
|
||||
!testvideo.mp4
|
||||
|
||||
+19
-25
@@ -1,33 +1,27 @@
|
||||
workflow:
|
||||
rules:
|
||||
# Run the pipeline for merge requests or when committing to a branch
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
|
||||
image: python:3.14.0
|
||||
image: node:latest
|
||||
|
||||
stages:
|
||||
- setup
|
||||
# - install
|
||||
- test
|
||||
|
||||
setup_environment:
|
||||
stage: setup
|
||||
script:
|
||||
- pip install --upgrade pip
|
||||
- pip install -r requirements.txt
|
||||
- echo "Dependencies installed successfully."
|
||||
# job-install:
|
||||
# stage: install
|
||||
# script:
|
||||
# - npm install
|
||||
# artifacts:
|
||||
# untracked: false
|
||||
# when: on_success
|
||||
# access: all
|
||||
# expire_in: "30 days"
|
||||
# paths:
|
||||
# - node_modules
|
||||
|
||||
only:
|
||||
- main
|
||||
- feature/ci-pipeline-s1-09a-1 # You can add more branches if needed
|
||||
|
||||
test_app:
|
||||
|
||||
job-test:
|
||||
stage: test
|
||||
script:
|
||||
- echo "Running V2D Framework basic test..."
|
||||
- python -m unittest discover || echo "No tests found."
|
||||
|
||||
only:
|
||||
- main
|
||||
- feature/ci-pipeline-s1-09a-1
|
||||
|
||||
- npm install
|
||||
- echo "ASSEMBLYAI_API_KEY=$apikey_assembly" > .env
|
||||
- echo "GOOGLE_API_KEY=$apikey_gemini" >> .env
|
||||
- npm test
|
||||
@@ -9,9 +9,22 @@
|
||||
<body>
|
||||
|
||||
<div class="mitte" id="mitte">
|
||||
<div class="flagsBtns" id="flagsBtns">
|
||||
<div class="labelDiv" id="labelDiv">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
@@ -20,28 +33,32 @@
|
||||
|
||||
<div class="upload-container" id="uploadContainer">
|
||||
<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>
|
||||
|
||||
<button class="custom-btn" id="manualUploadBtn">Search video</button>
|
||||
<div id="thumbnailContainer">
|
||||
<img id="thumbnailImage" style="display:none;">
|
||||
</div>
|
||||
<button class="custom-btn" id="manualUploadBtn">Search video</button>
|
||||
<input type="file" id="videoUpload" accept="video/*">
|
||||
</div>
|
||||
|
||||
<div class="checkbox-group">
|
||||
<label id="checkbox_group" for="checkbox-group">Choose prefered document style:</label>
|
||||
<div class="checkbox-container">
|
||||
<input type="checkbox" name ="docFormat" id="docFormat">
|
||||
<input type="checkbox" name ="docFormat" id="docFormat" value="Meeting report">
|
||||
<label id="label_format" for="docFormat">Meeting report</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-container">
|
||||
<input type="checkbox" name="docFormat" id="docFormatSummary">
|
||||
<input type="checkbox" name="docFormat" id="docFormatSummary" value="Summary with timestamps">
|
||||
<label id="label_summary" for="docFormatSummary">Summary with timestamps</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="submit-btn" id="submitButton" onclick="checkBoxes()">Submit</button>
|
||||
<button class="submit-btn" id="submitButton" onclick="checkBoxes()" disabled>Submit</button>
|
||||
|
||||
<div class="progressbar">
|
||||
<div class="progressbar" id="progressbar">
|
||||
<div class="progress_fill"></div>
|
||||
<span class="progress_text">0%</span>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
var languageOptions = {
|
||||
"eng":{
|
||||
"flagPath": "flags/united-kingdom-flag-png-large.jpg",
|
||||
"labelKI": "Select ki:",
|
||||
"labelTranscription": "Select transcription:",
|
||||
"labelLanguage": "Select language:",
|
||||
"title": "Video to document",
|
||||
"h1": "Video to document",
|
||||
"p1": "Drag and drop video file",
|
||||
@@ -11,6 +15,10 @@ var languageOptions = {
|
||||
"submitButton": "Submit"
|
||||
},
|
||||
"de":{
|
||||
"flagPath": "flags/germany-flag-png-large.jpg",
|
||||
"labelKI": "Waehle KI:",
|
||||
"labelTranscription": "Waehle Transkription:",
|
||||
"labelLanguage": "Waehle Sprache:",
|
||||
"title": "Video zu Dokument",
|
||||
"h1": "Video zu Dokument",
|
||||
"p1": "Video per Drag & Drop ablegen",
|
||||
@@ -22,6 +30,10 @@ var languageOptions = {
|
||||
"submitButton": "Absenden"
|
||||
},
|
||||
"in":{
|
||||
"flagPath": "flags/india-flag-png-large.png",
|
||||
"labelKI": "की का चयन करें:",
|
||||
"labelTranscription": "प्रतिलेखन चुनें:",
|
||||
"labelLanguage": "भाषा चुने:",
|
||||
"title": "दस्तावेज़ के लिए वीडियो",
|
||||
"h1": "दस्तावेज़ के लिए वीडियो",
|
||||
"p1": "वीडियो फ़ाइल खींचें और छोड़ें",
|
||||
|
||||
@@ -4,12 +4,24 @@ try {
|
||||
contextBridge.exposeInMainWorld("explorer", {
|
||||
onFileDrop: (file) => webUtils.getPathForFile(file)
|
||||
})
|
||||
contextBridge.exposeInMainWorld("extractor", {
|
||||
extract: (file) => ipcRenderer.send("extract", file)
|
||||
contextBridge.exposeInMainWorld("submit", {
|
||||
submit: (meeting_specifications) => {ipcRenderer.send("file_submit", meeting_specifications)}
|
||||
})
|
||||
contextBridge.exposeInMainWorld("electronAPI", {
|
||||
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) {
|
||||
console.log("Error in preload.js");
|
||||
}
|
||||
}
|
||||
|
||||
+56
-10
@@ -16,26 +16,72 @@ uploadContainer.addEventListener("drop", (e) => {
|
||||
e.preventDefault()
|
||||
const files = e.dataTransfer.files
|
||||
const filePath = window.explorer.onFileDrop(files[0])
|
||||
var holdy = filePath + "";
|
||||
if(holdy.endsWith(".mp4") || holdy.endsWith(".mov") || holdy.endsWith(".avi") || holdy.endsWith( ".mkv")){
|
||||
console.log(filePath)
|
||||
|
||||
const testEndings = [".mp4", ".mov", ".avi", ".mkv"];
|
||||
var pathToLower = filePath.toLowerCase();
|
||||
if(testEndings.some(e => pathToLower.endsWith(e))){
|
||||
document.getElementById("progressbar").style.visibility = "visible";
|
||||
const files1 = e.dataTransfer.files;
|
||||
handleFiles(files1);
|
||||
}else{
|
||||
alert('The given file is not compatible. These are the available types: [".mp4", ".mov", ".avi", ".mkv"].');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log("Error in renderer.js with the listerner for the drop function");
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('load', async (e) => {
|
||||
try {
|
||||
console.log("test");
|
||||
loadLanguageOptions();
|
||||
const value = await window.onStartup.getModuleNames();
|
||||
loadAiOptions(value.ai_modules);
|
||||
loadTranscriptionOptions(value.transcription_modules);
|
||||
|
||||
window.addEventListener('load', (e) => {
|
||||
console.log("test");
|
||||
loadLanguageOptions();
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
language_option.addEventListener('change', (e)=>{
|
||||
const select = document.getElementById('language_option');
|
||||
console.log(select.value);
|
||||
changeLanguage(select.value);
|
||||
try {
|
||||
const select = document.getElementById('language_option');
|
||||
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);
|
||||
}
|
||||
|
||||
});
|
||||
+117
-33
@@ -1,45 +1,84 @@
|
||||
//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 checkBoxes() {
|
||||
try {
|
||||
const checkboxes = document.querySelectorAll('input[name="docFormat"]');
|
||||
let isChecked = false;
|
||||
|
||||
var checkedCounter = 0;
|
||||
checkboxes.forEach(function(checkbox){
|
||||
if(checkbox.checked){
|
||||
isChecked = true;
|
||||
checkedCounter++;
|
||||
}
|
||||
});
|
||||
|
||||
if(isChecked){
|
||||
if (isChecked) {
|
||||
//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]);
|
||||
if(pathTest.endsWith(".mp4") || holdy.endsWith(".mov") || holdy.endsWith(".avi") || holdy.endsWith( ".mkv")){
|
||||
window.extractor.extract({inputVideoPath: pathTest, outputType:"wav"})
|
||||
var pathToLower = pathTest.toLowerCase();
|
||||
if(testEndings.some(e => pathToLower.endsWith(e))){
|
||||
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 {
|
||||
//language only english at the moment
|
||||
alert('Please select at least one document type.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log("Error in script.js checkBoxes function");
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
// mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./a.mp4", outputType:"wav"})
|
||||
}
|
||||
|
||||
//language changing feature
|
||||
function changeLanguage(language) {
|
||||
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('h1').textContent = languageOptions[language].h1;
|
||||
document.getElementById('p1').textContent = languageOptions[language].p1;
|
||||
@@ -49,46 +88,43 @@ function changeLanguage(language) {
|
||||
document.getElementById('label_format').textContent = languageOptions[language].label_format;
|
||||
document.getElementById('label_summary').textContent = languageOptions[language].label_summary;
|
||||
document.getElementById('submitButton').textContent = languageOptions[language].submitButton;
|
||||
|
||||
} catch (error) {
|
||||
console.log("Error in script.js changeLanguage function");
|
||||
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 handleFiles(files) {
|
||||
try {
|
||||
if (files.length > 0) {
|
||||
const file = files[0];
|
||||
if (file.type.startsWith('video/')) {
|
||||
const filePath = window.explorer.onFileDrop(files[0])
|
||||
videoUpload.files = files;
|
||||
fileName.textContent = `Chosen video: ${file.name}`;
|
||||
generateThumbnail(filePath);
|
||||
activateSubmitBtn(true);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error in script.js handleFiles function");
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//function to regulate the progress on the progressbar
|
||||
function updateProgressBar(bar, value){
|
||||
function updateProgressBar(bar, value) {
|
||||
try {
|
||||
value = Math.round(value);
|
||||
bar.querySelector(".progress_fill").style.width = `${value}%`;
|
||||
bar.querySelector(".progress_text").textContent = `${value}%`;
|
||||
} catch (error) {
|
||||
console.log("Error in scripts.js updateProgressBar function");
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -97,12 +133,13 @@ function updateProgressBar(bar, value){
|
||||
function loadAiOptions(options){
|
||||
try {
|
||||
var menu = document.getElementById('ai_type');
|
||||
var object_holdy;
|
||||
var choice ;
|
||||
object_holdy = options
|
||||
for(i = 0; i < options.length; i++){
|
||||
var opty = options[i];
|
||||
var namey = "option" + i;
|
||||
var choice = document.createElement(namey);
|
||||
choice.textContent = "t";
|
||||
choice.value = i;
|
||||
choice = document.createElement('option');
|
||||
choice.textContent = object_holdy[i].displayname;
|
||||
choice.value = object_holdy[i].name;
|
||||
menu.appendChild(choice);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -111,6 +148,25 @@ 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 loadLanguageOptions(){
|
||||
try {
|
||||
@@ -129,4 +185,32 @@ function loadLanguageOptions(){
|
||||
console.log("Error in script.js loadLanguageOptions function");
|
||||
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;
|
||||
}
|
||||
|
||||
+74
-33
@@ -5,46 +5,71 @@ body {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
background-color: #555;
|
||||
background-color: #f2f3f4;
|
||||
gap: 15px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.upload-container {
|
||||
background: white;
|
||||
padding: 40px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
||||
text-align: center;
|
||||
width: 400px;
|
||||
width: 350px;
|
||||
height: 200px;
|
||||
transition: border 0.3s, background-color 0.3s;
|
||||
border: 2px dashed #ccc;
|
||||
border: 2px dashed #7378c9;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.upload-container.dragover {
|
||||
border-color: #007BFF;
|
||||
background-color: #eaf0ff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.upload-container p {
|
||||
margin: 0 0 15px 0;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.file-name {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
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 {
|
||||
padding: 10px 20px;
|
||||
margin-top: 10px;
|
||||
background-color: #007BFF;
|
||||
color: white;
|
||||
border: none;
|
||||
@@ -52,27 +77,27 @@ body {
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.custom-btn:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
|
||||
.submit-btn:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
|
||||
input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.checkbox-container{
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
|
||||
.checkbox-group {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
@@ -81,9 +106,11 @@ gap: 5px;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
|
||||
.submit-btn {
|
||||
padding: 10px 20px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
background-color: #007BFF;
|
||||
color: white;
|
||||
border: none;
|
||||
@@ -91,24 +118,33 @@ gap: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.submit-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mitte {
|
||||
background-color: #f2f3f4;
|
||||
background-color: #FDFCFA;
|
||||
display: flex;
|
||||
width: 700px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 5% 50px;
|
||||
margin-top: 20px;
|
||||
gap: 10px;
|
||||
border: 1px;
|
||||
border: 0px;
|
||||
border-color: black;
|
||||
border-style: solid;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 4px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
|
||||
h1 {
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
|
||||
.progressbar{
|
||||
position: relative;
|
||||
width: 210px;
|
||||
@@ -116,15 +152,16 @@ h1 {
|
||||
background: rgb(42, 46, 78);
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
.progress_fill{
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
background: green;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.progress_text{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@@ -133,15 +170,19 @@ h1 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.flagsBtns {
|
||||
|
||||
.dropdownMenus {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 1px;
|
||||
gap: 150px;
|
||||
padding: 2px 10px 2px 10px;
|
||||
}
|
||||
|
||||
.de_Btn, .eng_Btn, .in_Btn {
|
||||
padding: 8px 16px;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
#ai_type, #transkript_type, #language_option {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.labelDiv {
|
||||
gap: 200px;
|
||||
}
|
||||
@@ -35,6 +35,8 @@ console.log("-------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------- CLI COMMANDS --------------------------------------------------------- //
|
||||
|
||||
const rl = readline.createInterface({
|
||||
@@ -58,22 +60,196 @@ rl.on("line", data =>{
|
||||
let mainWindow;
|
||||
|
||||
function createWindow() {
|
||||
mainWindow = new electron.BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
preload: `${mainDir}/electron/main/preload.js`
|
||||
}
|
||||
});
|
||||
mainWindow = new electron.BrowserWindow({
|
||||
width: 800,
|
||||
height: 800,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
preload: `${mainDir}/electron/main/preload.js`
|
||||
}
|
||||
});
|
||||
|
||||
mainWindow.loadFile('./electron/main/index.html');
|
||||
mainWindow.loadFile('./electron/main/index.html');
|
||||
}
|
||||
|
||||
electron.app.whenReady().then(createWindow);
|
||||
|
||||
|
||||
electron.ipcMain.on("extract", (event, args) => {
|
||||
mapFunctions.get("extraction-video-to-audio").function(args)
|
||||
})
|
||||
// electron.ipcMain.on("extract", (event, 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: 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)
|
||||
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++) {
|
||||
console.log(`\n\n Running the LLM for Document Style ${i+1}`);
|
||||
|
||||
await mapFunctions.get("module-handler").function(args.document.module, {inputTranscriptPath: transcriptpath, documentTypePath: "./storage/documentType/meetingReport.json", language: "en"}).then(resp => {
|
||||
console.log(resp);
|
||||
transcriptpath = resp
|
||||
curstep++
|
||||
mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
||||
}).catch(err => {
|
||||
mainWindow.webContents.send("error", err)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// TODO actually implement this functionality
|
||||
// Module to get the first few lines for each speaker to send to the frontend
|
||||
// await mapFunctions.get("speaker-getter-idfk").function(transcriptpath).then(resp => {
|
||||
// console.log(resp);
|
||||
// transcriptpath = resp
|
||||
// curstep++
|
||||
// mainWindow.webContents.send("progress", {curstep:curstep, totalsteps:totalsteps})
|
||||
|
||||
// // {
|
||||
// // speakerA: {source: "Pfad zur Audio File"},
|
||||
// // speakerB:.....
|
||||
// // }
|
||||
mainWindow.webContents.send("speakers", {speakerA:"pfad1", speakerB:"pfad2"})
|
||||
// }).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
+1289
-38
File diff suppressed because it is too large
Load Diff
+5
-3
@@ -1,12 +1,14 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@google/genai": "^1.30.0",
|
||||
"@types/axios": "^0.9.36",
|
||||
"cli-progress": "^3.12.0",
|
||||
"axios": "^1.13.2",
|
||||
"dotenv": "^17.2.3",
|
||||
"electron": "^39.1.1",
|
||||
"express": "^5.1.0",
|
||||
"ffmpeg-static": "^5.2.0",
|
||||
"fluent-ffmpeg": "^2.1.3"
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"mocha": "^11.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cli-progress": "^3.11.6",
|
||||
@@ -25,7 +27,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "electron main.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "mocha ./test/unit/test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
fastapi
|
||||
uvicorn
|
||||
pytest
|
||||
+5
-1
@@ -11,8 +11,12 @@ config = require("./config/config")
|
||||
ffmpegPath = require('ffmpeg-static');
|
||||
ffmpeg = require('fluent-ffmpeg');
|
||||
path = require('path');
|
||||
cliProgress = require('cli-progress');
|
||||
// cliProgress = require('cli-progress');
|
||||
|
||||
// { app, BrowserWindow, ipcMain, dialog } = require('electron');
|
||||
|
||||
electron = require('electron');
|
||||
|
||||
axios = require("axios")
|
||||
|
||||
console.log(require('dotenv').config({path: __dirname + '/.env'}));
|
||||
@@ -0,0 +1,47 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
//node show-models.js, remember to set SAIA_API_KEY in your environment before running the script
|
||||
|
||||
const SAIA_API_KEY = process.env.SAIA_API_KEY;
|
||||
const SAIA_MODELS_URL = "https://chat-ai.academiccloud.de/v1/models";
|
||||
|
||||
// Script to list available models
|
||||
(async () => {
|
||||
if (!SAIA_API_KEY) {
|
||||
console.error("ERROR: SAIA_API_KEY environment variable is not set!");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Fetching available models from SAIA...\n");
|
||||
|
||||
try {
|
||||
const response = await fetch(SAIA_MODELS_URL, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${SAIA_API_KEY}`,
|
||||
"Accept": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`SAIA API error (${response.status}): ${text}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
console.log("Available models:");
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
|
||||
if (data.data && Array.isArray(data.data)) {
|
||||
console.log("\n\nModel IDs:");
|
||||
data.data.forEach(model => {
|
||||
console.log(`- ${model.id}`);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error fetching models:", error);
|
||||
}
|
||||
})();
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// Ensure ffmpeg binary is available
|
||||
if (!ffmpegPath) {
|
||||
throw new Error('FFmpeg binary not found!');
|
||||
@@ -25,18 +24,12 @@ module.exports = {
|
||||
outputType: String // Audio file output format
|
||||
}
|
||||
*/
|
||||
let progressBar = new cliProgress.SingleBar({
|
||||
format: 'Processing |{bar}| {percentage}% | {timemark}',
|
||||
barCompleteChar: '\u2588',
|
||||
barIncompleteChar: '\u2591',
|
||||
hideCursor: true
|
||||
});
|
||||
try {
|
||||
// if (meta.url === `file://${process.argv[1]}`) {
|
||||
this.extractAudioFromVideo(parameter.inputVideoPath, progressBar, parameter.outputType)
|
||||
.then(() => console.log('Audio extraction successful.'))
|
||||
.catch((err) => console.error(err));
|
||||
// }
|
||||
return new Promise((resolve, reject) => {
|
||||
this.extractAudioFromVideo(parameter.inputVideoPath, parameter.outputType)
|
||||
.then((resp) => resolve(resp))
|
||||
.catch((err) => {reject(err)});
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(parameter.outputType);
|
||||
|
||||
@@ -53,7 +46,7 @@ module.exports = {
|
||||
* - Shows CLI progress bar
|
||||
* - Handles errors gracefully (without errors)
|
||||
*/
|
||||
extractAudioFromVideo: async function (videoFilePath, progressBar, outputType){
|
||||
extractAudioFromVideo: async function (videoFilePath, outputType){
|
||||
let inputVideoName = path.basename(videoFilePath, path.extname(videoFilePath));
|
||||
let outputAudioPath = path.join(outputDir, `${inputVideoName}.${outputType}`);
|
||||
|
||||
@@ -64,30 +57,18 @@ module.exports = {
|
||||
// .audioCodec('pcm_s16le')
|
||||
.audioChannels(1)
|
||||
.audioFrequency(16000)
|
||||
// .setFfmpegPath("./ffmpeg.exe")
|
||||
.on('progress', (progress) => {
|
||||
if (!progressBar.isActive) progressBar.start(100, 0, { timemark: '00:00:00' });
|
||||
if (progress.percent) {
|
||||
progressBar.update(progress.percent, { timemark: progress.timemark });
|
||||
}
|
||||
})
|
||||
.on('end', () => {
|
||||
progressBar.update(100, { timemark: 'done' });
|
||||
progressBar.stop();
|
||||
console.log(`Extraction completed: ${outputAudioPath}`);
|
||||
resolve();
|
||||
resolve(outputAudioPath);
|
||||
})
|
||||
.on('error', (err) => {
|
||||
progressBar.stop();
|
||||
console.error(`failed_audio_extraction on type ${outputType}: ${err.message}`);
|
||||
// console.error(`failed_audio_extraction on type ${outputType}: ${err.message}`);
|
||||
reject(err);
|
||||
})
|
||||
.save(outputAudioPath);
|
||||
|
||||
} catch (error) {
|
||||
console.log();
|
||||
// console.log(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
|
||||
// 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);
|
||||
reject(e)
|
||||
return
|
||||
}
|
||||
}
|
||||
// JSON parsen
|
||||
if (typeof args === "string") {
|
||||
try {
|
||||
await new Promise((res, rej) => {
|
||||
fs.readFile(args, 'utf8', function (err, data) {
|
||||
if (err){
|
||||
rej(err)
|
||||
return
|
||||
}
|
||||
inputJson = JSON.parse(data);
|
||||
res()
|
||||
});
|
||||
})
|
||||
} catch (e) {
|
||||
// console.log("Invalid JSON in summarize-transcription");
|
||||
// console.log(e)
|
||||
reject(e)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const words = inputJson.words;
|
||||
if (!Array.isArray(words)) {
|
||||
reject("No words Array found")
|
||||
return
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
|
||||
// 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);
|
||||
reject("Could not read JSON from file path.")
|
||||
return
|
||||
}
|
||||
}
|
||||
// JSON parsen
|
||||
if (typeof args === "string") {
|
||||
try {
|
||||
await new Promise((res, rej) => {
|
||||
fs.readFile(args, 'utf8', function (err, data) {
|
||||
if (err){
|
||||
rej(err)
|
||||
return
|
||||
}
|
||||
inputJson = JSON.parse(data);
|
||||
res()
|
||||
});
|
||||
})
|
||||
} catch (e) {
|
||||
// console.log("Invalid JSON in summarize-transcription");
|
||||
// console.log(e)
|
||||
reject(e)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const words = inputJson.words;
|
||||
if (!Array.isArray(words)) {
|
||||
reject("No words Array found")
|
||||
return;
|
||||
}
|
||||
|
||||
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,8 +1,131 @@
|
||||
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()"
|
||||
type:"document", // value used to differentiate each module to order them in the UI
|
||||
displayname:"ChatGPT", // The displayname used within the UI
|
||||
async function(parameter){
|
||||
// TODO add code to actually send the transcript to ChatGPT and get a response back
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const outputDir = path.join(__dirname, "../../../storage/documents"); // path for output directory
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true }); // Create output directory if it doesn't exist
|
||||
}
|
||||
|
||||
// Ensure SAIA API key is set in environment variables: export SAIA_API_KEY="your_api_key_here"
|
||||
const SAIA_API_KEY = process.env.SAIA_API_KEY; // Ensure SAIA API key is set in environment variables
|
||||
|
||||
const SAIA_URL = "https://chat-ai.academiccloud.de/v1/chat/completions"; //URL for the REST call, used model and action
|
||||
|
||||
const module_exports = {
|
||||
name: "llm-saia_openai_gpt",
|
||||
type: "llm",
|
||||
displayname: "GPT 120B",
|
||||
description: "Generates documents using OpenAI GPT OSS 120B via SAIA platform",
|
||||
|
||||
async function(parameter) {
|
||||
try {
|
||||
console.log("SAIA OpenAI GPT module invoked with parameters:", parameter);
|
||||
|
||||
await this.createDocumentFromTranscript( //Call the function to create document with transcript, document type and language
|
||||
parameter.inputTranscriptPath, // Path to input transcript file
|
||||
parameter.documentTypePath, // Path to document type file which is chosen in the front end by the user
|
||||
parameter.language // Language for the document which is chosen in the front end by the user
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in SAIA OpenAI GPT module:", error);
|
||||
}
|
||||
},
|
||||
|
||||
createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") { // default language is English
|
||||
try {
|
||||
const transcript = await fs.promises.readFile(transcriptPath, "utf-8"); //read transcript file from Path
|
||||
const documentType = await fs.promises.readFile(documentTypePath, "utf-8"); //read document type from Path
|
||||
const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`; //combine doc type, language and transcript - Change prompt here if needed
|
||||
|
||||
// --- REST CALL ---
|
||||
const response = await fetch(SAIA_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${SAIA_API_KEY}`,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: "openai-gpt-oss-120b",
|
||||
messages: [
|
||||
{ role: "system", content: "You are a helpful assistant that generates HTML documents from transcripts. Output only valid HTML content without any preamble, explanations, or markdown formatting." },
|
||||
{ role: "user", content: promptText }
|
||||
],
|
||||
temperature: 0
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) { //ok is true when a response was successful
|
||||
const text = await response.text();
|
||||
throw new Error(`SAIA API error (${response.status}): ${text}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Get generated text from response or default to empty string (if null)
|
||||
// SAIA uses OpenAI-compatible structure: data.choices[x].message.content
|
||||
const output = data.choices?.[0]?.message?.content || "";
|
||||
|
||||
let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); // Name for the output file
|
||||
console.log(inputTranscriptName);
|
||||
|
||||
const outPath = path.join(outputDir, `${inputTranscriptName}.html`); // Output file path & name to make naming dynamic. Pulled from input transcript name
|
||||
fs.writeFileSync(outPath, output, "utf8"); // Write output to file
|
||||
|
||||
console.log("Generated document written to:", outPath);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error generating SAIA content:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = module_exports;
|
||||
|
||||
// CLI Mode: Allow direct execution
|
||||
if (require.main === module) {
|
||||
(async () => {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length < 2) {
|
||||
console.error("Usage: node llm-openai-gpt.js <transcriptPath> <documentTypePath> [language]");
|
||||
console.error("Example: node llm-openai-gpt.js ./transcript.json ./docType.txt de");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const [transcriptPath, documentTypePath, language] = args;
|
||||
|
||||
// Check if API key is set
|
||||
if (!SAIA_API_KEY) {
|
||||
console.error("ERROR: SAIA_API_KEY environment variable is not set!");
|
||||
console.error("Please set it with: export SAIA_API_KEY='your_api_key_here'");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if files exist
|
||||
if (!fs.existsSync(transcriptPath)) {
|
||||
console.error(`ERROR: Transcript file not found: ${transcriptPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(documentTypePath)) {
|
||||
console.error(`ERROR: Document type file not found: ${documentTypePath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Starting document generation...");
|
||||
console.log(`Transcript: ${transcriptPath}`);
|
||||
console.log(`Document Type: ${documentTypePath}`);
|
||||
console.log(`Language: ${language || 'en (default)'}`);
|
||||
|
||||
await module_exports.createDocumentFromTranscript(
|
||||
transcriptPath,
|
||||
documentTypePath,
|
||||
language || 'en'
|
||||
);
|
||||
|
||||
console.log("Done!");
|
||||
})();
|
||||
}
|
||||
@@ -1,59 +1,134 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { GoogleGenAI } = require("@google/genai"); // Import Google Gemini AI SDK
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const outputDir = path.join(__dirname, "../../../storage/documents"); // path for output directory
|
||||
const outputDir = path.join(__dirname, "../../../storage/documents"); // path for output directory
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true }); // Create output directory if it doesn't exist
|
||||
}
|
||||
|
||||
const ai = new GoogleGenAI({
|
||||
apiKey: process.env.GOOGLE_API_KEY // Ensure Google API key is set in environment variables: export GOOGLE_API_KEY="your_api_key_here"
|
||||
});
|
||||
// Ensure Google API key is set in environment variables: export GOOGLE_API_KEY="your_api_key_here"
|
||||
const GEMINI_API_KEY = process.env.GOOGLE_API_KEY; // Ensure Google API key is set in environment variables: export GOOGLE_API_KEY="your_api_key_here"
|
||||
const GEMINI_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent"; // URL for the REST call, used model and action
|
||||
|
||||
module.exports = {
|
||||
const module_exports = {
|
||||
name: "llm-gemini",
|
||||
type: "llm",
|
||||
displayname: "Gemini LLM",
|
||||
description: "Generates documents using Google Gemini LLM",
|
||||
|
||||
async function(parameter) {
|
||||
try {
|
||||
console.log("Gemini LLM module invoked with parameters:", parameter);
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
// console.log("Gemini LLM module invoked with parameters:", parameter);
|
||||
|
||||
await this.createDocumentFromTranscript( //Call the function to create document with transcript, document type and language
|
||||
parameter.inputTranscriptPath, // Path to input transcript file
|
||||
parameter.documentTypePath, // Path to document type file which is chosen in the front end by the user
|
||||
parameter.language // Language for the document which is chosen in the front end by the user
|
||||
);
|
||||
resolve(await this.createDocumentFromTranscript( //Call the function to create document with transcript, document type and language
|
||||
parameter.inputTranscriptPath, // Path to input transcript file
|
||||
parameter.documentTypePath, // Path to document type file which is chosen in the front end by the user
|
||||
parameter.language // Language for the document which is chosen in the front end by the user
|
||||
));
|
||||
|
||||
} catch (error) {
|
||||
// console.error("Error in Gemini LLM module:", error);
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in Gemini LLM module:", error);
|
||||
}
|
||||
},
|
||||
|
||||
createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") { // default language is English
|
||||
try {
|
||||
const transcript = await fs.promises.readFile(transcriptPath, "utf-8");
|
||||
const documentType = await fs.promises.readFile(documentTypePath, "utf-8");
|
||||
return new Promise(async(resolve, reject) => {
|
||||
try {
|
||||
const transcript = await fs.promises.readFile(transcriptPath, "utf-8"); //read transcript file from Path
|
||||
const documentType = await fs.promises.readFile(documentTypePath, "utf-8"); //read document type from Path
|
||||
const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`; //combine doc type, language and transcript - Change prompt here if needed
|
||||
|
||||
const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`;
|
||||
// --- REST CALL ---
|
||||
const response = await fetch(`${GEMINI_URL}?key=${GEMINI_API_KEY}`, { //safe model response in variable
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
contents: [
|
||||
{
|
||||
parts: [
|
||||
{ text: promptText } // Input prompt for content generation
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
const response = await ai.models.generateContent({
|
||||
model: "gemini-2.5-flash", // Specify the Gemini model to use
|
||||
contents: promptText // Input prompt for content generation
|
||||
});
|
||||
if (!response.ok) { //ok is true when a responce was successfull
|
||||
const text = await response.text();
|
||||
throw new Error(`Gemini API error (${response.status}): ${text}`);
|
||||
}
|
||||
|
||||
const output = response.text || ""; // Get generated text from response or default to empty string (if null)
|
||||
const data = await response.json();
|
||||
|
||||
const outPath = path.join(outputDir, "test.md"); // Output file path & name TO BE DONE to make dynamic out of input transcript name
|
||||
fs.writeFileSync(outPath, output, "utf8"); // Write output to file
|
||||
// Get generated text from response or default to empty string (if null)
|
||||
const output = data?.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
||||
let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); // Name for the output file
|
||||
// console.log(inputTranscriptName);
|
||||
const outPath = path.join(outputDir, `${inputTranscriptName}.md`); // Output file path & name to make naming dynamic. Pulled from input transcript name
|
||||
fs.writeFileSync(outPath, output, "utf8"); // Write output to file
|
||||
|
||||
console.log("Generated document written to:", outPath);
|
||||
// console.log("Generated document written to:", outPath);
|
||||
resolve(outPath)
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error generating Gemini content:", error);
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error("Error generating Gemini content:", error);
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = module_exports;
|
||||
|
||||
// CLI Mode: Allow direct execution
|
||||
if (require.main === module) {
|
||||
(async () => {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length < 2) {
|
||||
console.error("Usage: node llm-gemini.js <transcriptPath> <documentTypePath> [language]");
|
||||
console.error("Example: node llm-gemini.js ./transcript.json ./docType.txt de");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const [transcriptPath, documentTypePath, language] = args;
|
||||
|
||||
// Check if API key is set
|
||||
if (!GEMINI_API_KEY) {
|
||||
console.error("ERROR: GOOGLE_API_KEY environment variable is not set!");
|
||||
console.error("Please set it with: export GOOGLE_API_KEY='your_api_key_here'");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if files exist
|
||||
if (!fs.existsSync(transcriptPath)) {
|
||||
console.error(`ERROR: Transcript file not found: ${transcriptPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(documentTypePath)) {
|
||||
console.error(`ERROR: Document type file not found: ${documentTypePath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Starting document generation...");
|
||||
console.log(`Transcript: ${transcriptPath}`);
|
||||
console.log(`Document Type: ${documentTypePath}`);
|
||||
console.log(`Language: ${language || 'en (default)'}`);
|
||||
|
||||
await module_exports.createDocumentFromTranscript(
|
||||
transcriptPath,
|
||||
documentTypePath,
|
||||
language || 'en'
|
||||
);
|
||||
|
||||
console.log("Done!");
|
||||
})();
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const outputDir = path.join(__dirname, "../../../storage/documents"); // path for output directory
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true }); // Create output directory if it doesn't exist
|
||||
}
|
||||
|
||||
// Ensure SAIA API key is set in environment variables: export SAIA_API_KEY="your_api_key_here"
|
||||
const SAIA_API_KEY = process.env.SAIA_API_KEY;
|
||||
const SAIA_URL = "https://chat-ai.academiccloud.de/v1/chat/completions"; // URL for the REST call, used model and action
|
||||
|
||||
const module_exports = {
|
||||
name: "qwen3-235b-a22b",
|
||||
type: "llm",
|
||||
displayname: "QWEN 3 235B",
|
||||
description: "Generates documents using QWEN 3 235B via SAIA platform",
|
||||
|
||||
async function(parameter) {
|
||||
try {
|
||||
console.log("SAIA QWEN 3 235B module invoked with parameters:", parameter);
|
||||
|
||||
await this.createDocumentFromTranscript( // Call the function to create document with transcript, document type and language
|
||||
parameter.inputTranscriptPath, // Path to input transcript file
|
||||
parameter.documentTypePath, // Path to document type file which is chosen in the front end by the user
|
||||
parameter.language // Language for the document which is chosen in the front end by the user
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in SAIA QWEN 3 235B module:", error);
|
||||
}
|
||||
},
|
||||
|
||||
createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") { // default language is English
|
||||
try {
|
||||
const transcript = await fs.promises.readFile(transcriptPath, "utf-8"); // read transcript file from Path
|
||||
const documentType = await fs.promises.readFile(documentTypePath, "utf-8"); // read document type from Path
|
||||
const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`; // combine doc type, language and transcript - Change prompt here if needed
|
||||
|
||||
// --- REST CALL ---
|
||||
const response = await fetch(SAIA_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${SAIA_API_KEY}`,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: "qwen3-235b-a22b",
|
||||
messages: [
|
||||
{ role: "system", content: "You are a helpful assistant that generates HTML documents from transcripts. Output only valid HTML content without any preamble, explanations, or markdown formatting." },
|
||||
{ role: "user", content: promptText }
|
||||
],
|
||||
temperature: 0
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) { // ok is true when a response was successful
|
||||
const text = await response.text();
|
||||
throw new Error(`SAIA API error (${response.status}): ${text}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Get generated text from response or default to empty string (if null)
|
||||
// SAIA uses OpenAI-compatible structure: data.choices[x].message.content
|
||||
const output = data.choices?.[0]?.message?.content || "";
|
||||
|
||||
let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); // Name for the output file
|
||||
console.log(inputTranscriptName);
|
||||
|
||||
const outPath = path.join(outputDir, `${inputTranscriptName}.html`); // Output file path & name to make naming dynamic. Pulled from input transcript name
|
||||
fs.writeFileSync(outPath, output, "utf8"); // Write output to file
|
||||
|
||||
console.log("Generated document written to:", outPath);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error generating SAIA content:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = module_exports;
|
||||
|
||||
// CLI Mode: Allow direct execution
|
||||
if (require.main === module) {
|
||||
(async () => {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length < 2) {
|
||||
console.error("Usage: node qwen3.js <transcriptPath> <documentTypePath> [language]");
|
||||
console.error("Example: node qwen3.js ./transcript.json ./docType.txt de");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const [transcriptPath, documentTypePath, language] = args;
|
||||
|
||||
// Check if API key is set
|
||||
if (!SAIA_API_KEY) {
|
||||
console.error("ERROR: SAIA_API_KEY environment variable is not set!");
|
||||
console.error("Please set it with: export SAIA_API_KEY='your_api_key_here'");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if files exist
|
||||
if (!fs.existsSync(transcriptPath)) {
|
||||
console.error(`ERROR: Transcript file not found: ${transcriptPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(documentTypePath)) {
|
||||
console.error(`ERROR: Document type file not found: ${documentTypePath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Starting document generation...");
|
||||
console.log(`Transcript: ${transcriptPath}`);
|
||||
console.log(`Document Type: ${documentTypePath}`);
|
||||
console.log(`Language: ${language || 'en (default)'}`);
|
||||
|
||||
await module_exports.createDocumentFromTranscript(
|
||||
transcriptPath,
|
||||
documentTypePath,
|
||||
language || 'en'
|
||||
);
|
||||
|
||||
console.log("Done!");
|
||||
})();
|
||||
}
|
||||
+1
Submodule services/modules/transcription-local/whisper.cpp added at 999a7e0cbf
@@ -1,8 +1,125 @@
|
||||
module.exports = {
|
||||
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", // value used to differentiate each module to order them in the UI
|
||||
displayname:"Assembly", // The displayname used within the UI
|
||||
async function(parameter){
|
||||
// TODO add code to actually process the audio file
|
||||
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 = {
|
||||
name: 'assembly',
|
||||
type: 'transcription',
|
||||
displayname: 'AssemblyAI',
|
||||
audioformat: "mp3",
|
||||
|
||||
async function(audioFileName) {
|
||||
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);
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
module.exports = {
|
||||
name:"Startup_function",
|
||||
async function(){
|
||||
@@ -6,8 +7,18 @@ module.exports = {
|
||||
// We are now calling the example function from the example folder
|
||||
mapFunctions.get("example").function("Startup")
|
||||
|
||||
// let transcript = await mapFunctions.get("assembly").function('../../storage/audio/IMG_2978.wav');
|
||||
|
||||
// let summary = await mapFunctions.get("summarize-transcription").function({jsonPath:'/Users/santa/Proj25/video2document/storage/transcripts/IMG_2978.json'});
|
||||
|
||||
|
||||
|
||||
|
||||
// mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./a.mp4", outputType:"wav"})
|
||||
// mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./b.mp4", outputType:"wav"})
|
||||
// mapFunctions.get("extraction-video-to-audio").function({inputVideoPath:"./b.mp4", outputType:"flac"})
|
||||
|
||||
// mapFunctions.get("ipc-handler").function("extraction-video-to-audio", {inputVideoPath:"./a.mp4", outputType:"flac"})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
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,6 +1,7 @@
|
||||
// services/pipeline/jobs/transcribeLatest.ts
|
||||
import path from 'path';
|
||||
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';
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"FORMAT": "markdown",
|
||||
"GOAL":"Generate a structured meeting report (Markdown). **Output ONLY:** final .md. No meta.",
|
||||
"STRUCTURE": {
|
||||
"titlepage": ["title","date","start","end","duration","location","host","participants"],
|
||||
"toc": "[section](#anchor) — HH:MM:SS",
|
||||
"section": {
|
||||
"h2": "<topic> — HH:MM:SS",
|
||||
"summary": "1 sentence",
|
||||
"key_points": "<=5 bullets, quotes optional",
|
||||
"decisions": "list: text | owner | due",
|
||||
"actions": "table: id | task | owner | due | status"
|
||||
},
|
||||
"exec_summary": "3 short sentences",
|
||||
"consolidated": ["decisions", "actions"],
|
||||
"appendix": "optional"
|
||||
},
|
||||
|
||||
"STYLE": {
|
||||
"tone": "neutral, concise",
|
||||
"ts_format": "HH:MM:SS",
|
||||
"no_meta": true
|
||||
},
|
||||
|
||||
"PROCESS": {
|
||||
"timestamps": "use if present; else estimate minimal",
|
||||
"speakers": "use labels; else Speaker X",
|
||||
"long_transcripts": "chunk → summarize → merge",
|
||||
"unclear": "UNKLAR:<reason>"
|
||||
},
|
||||
|
||||
"JSON_OUTPUT_OPTIONAL": true,
|
||||
|
||||
"PROMPT_SNIPPET": "Generate meeting report in markdown using STRUCTURE and STYLE. Output only the report."
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
Generate a structured meeting report in HTML using STRUCTURE and STYLE.
|
||||
Output ONLY the final .md document — no meta comments, no explanations.
|
||||
|
||||
Follow exactly the STRUCTURE defined below.
|
||||
Follow exactly the STYLE rules.
|
||||
Use timestamps in HH:MM:SS format.
|
||||
If information is missing, use: Unclear:<reason>.
|
||||
|
||||
==================== STRUCTURE & RULES ====================
|
||||
|
||||
{
|
||||
"FORMAT": "HTML",
|
||||
|
||||
"STRUCTURE": {
|
||||
"titlepage": [
|
||||
"title",
|
||||
"date",
|
||||
"start",
|
||||
"end",
|
||||
"duration",
|
||||
"location",
|
||||
"host",
|
||||
"participants"
|
||||
],
|
||||
|
||||
"toc": "[section](#anchor) — HH:MM:SS",
|
||||
|
||||
"section": {
|
||||
"h2": "<topic> — HH:MM:SS",
|
||||
"summary": "exactly 1 concise sentence",
|
||||
"key_points": "maximum 5 bullet points; quotes optional",
|
||||
"decisions": "list items formatted as: decision text | owner | due date",
|
||||
"actions": "HTML table: id | task | owner | due | status"
|
||||
},
|
||||
|
||||
"exec_summary": "exactly 3 short sentences",
|
||||
|
||||
"consolidated": [
|
||||
"decisions",
|
||||
"actions"
|
||||
],
|
||||
|
||||
"appendix": "optional"
|
||||
},
|
||||
|
||||
"STYLE": {
|
||||
"tone": "neutral, concise, professional",
|
||||
"ts_format": "HH:MM:SS",
|
||||
"no_meta": true
|
||||
},
|
||||
|
||||
"PROCESS": {
|
||||
"timestamps": "use transcript timestamps if present; otherwise estimate minimal",
|
||||
"speakers": "use names if available; else Speaker X",
|
||||
"long_transcripts": "split → summarize → merge",
|
||||
"unclear": "Unclear:<reason>"
|
||||
},
|
||||
|
||||
"PROMPT_SNIPPET": "Generate meeting report in HTML using STRUCTURE and STYLE. Output only the report."
|
||||
}
|
||||
|
||||
============================================================
|
||||
|
||||
Insert all generated content into the following HTML TEMPLATE:
|
||||
|
||||
# {{title}}
|
||||
|
||||
**Date:** {{date}}
|
||||
**Start:** {{start}}
|
||||
**End:** {{end}}
|
||||
**Duration:** {{duration}}
|
||||
**Location:** {{location}}
|
||||
**Host:** {{host}}
|
||||
**Participants:** {{participants}}
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
{{toc}}
|
||||
|
||||
---
|
||||
Generate a structured meeting report in HTML using STRUCTURE and STYLE.
|
||||
Output ONLY the final .md document — no meta comments, no explanations.
|
||||
|
||||
Follow exactly the STRUCTURE defined below.
|
||||
Follow exactly the STYLE rules.
|
||||
Use timestamps in HH:MM:SS format.
|
||||
If information is missing, use: UNKLAR:<reason>.
|
||||
|
||||
==================== STRUCTURE & RULES ====================
|
||||
|
||||
{
|
||||
"FORMAT": "HTML",
|
||||
|
||||
"STRUCTURE": {
|
||||
"titlepage": [
|
||||
"title",
|
||||
"date",
|
||||
"start",
|
||||
"end",
|
||||
"duration",
|
||||
"location",
|
||||
"host",
|
||||
"participants"
|
||||
],
|
||||
|
||||
"toc": "[section](#anchor) — HH:MM:SS",
|
||||
|
||||
"section": {
|
||||
"h2": "<topic> — HH:MM:SS",
|
||||
"summary": "exactly 1 concise sentence",
|
||||
"key_points": "maximum 5 bullet points; quotes optional",
|
||||
"decisions": "list items formatted as: decision text | owner | due date",
|
||||
"actions": "HTML table: id | task | owner | due | status"
|
||||
},
|
||||
|
||||
"exec_summary": "exactly 3 short sentences",
|
||||
|
||||
"consolidated": [
|
||||
"decisions",
|
||||
"actions"
|
||||
],
|
||||
|
||||
"appendix": "optional"
|
||||
},
|
||||
|
||||
"STYLE": {
|
||||
"tone": "neutral, concise, professional",
|
||||
"ts_format": "HH:MM:SS",
|
||||
"no_meta": true
|
||||
},
|
||||
|
||||
"PROCESS": {
|
||||
"timestamps": "use transcript timestamps if present; otherwise estimate minimal",
|
||||
"speakers": "use names if available; else Speaker X",
|
||||
"long_transcripts": "split → summarize → merge",
|
||||
"unclear": "UNKLAR:<reason>"
|
||||
},
|
||||
|
||||
"PROMPT_SNIPPET": "Generate meeting report in HTML using STRUCTURE and STYLE. Output only the report."
|
||||
}
|
||||
|
||||
============================================================
|
||||
|
||||
Insert all generated content into the following HTML TEMPLATE:
|
||||
|
||||
# {{title}}
|
||||
|
||||
**Date:** {{date}}
|
||||
**Start:** {{start}}
|
||||
**End:** {{end}}
|
||||
**Duration:** {{duration}}
|
||||
**Location:** {{location}}
|
||||
**Host:** {{host}}
|
||||
**Participants:** {{participants}}
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
{{toc}}
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
{{exec_summary}}
|
||||
|
||||
---
|
||||
|
||||
## Sections
|
||||
{{sections}}
|
||||
|
||||
---
|
||||
|
||||
## Consolidated Decisions
|
||||
{{consolidated_decisions}}
|
||||
|
||||
---
|
||||
|
||||
## Consolidated Actions
|
||||
{{consolidated_actions}}
|
||||
|
||||
---
|
||||
|
||||
## Appendix
|
||||
{{appendix}}
|
||||
|
||||
============================================================
|
||||
|
||||
Final Requirement:
|
||||
Output ONLY the completed HTML meeting report.
|
||||
## Executive Summary
|
||||
{{exec_summary}}
|
||||
|
||||
---
|
||||
|
||||
## Sections
|
||||
{{sections}}
|
||||
|
||||
---
|
||||
|
||||
## Consolidated Decisions
|
||||
{{consolidated_decisions}}
|
||||
|
||||
---
|
||||
|
||||
## Consolidated Actions
|
||||
{{consolidated_actions}}
|
||||
|
||||
---
|
||||
|
||||
## Appendix
|
||||
{{appendix}}
|
||||
|
||||
============================================================
|
||||
|
||||
Final Requirement:
|
||||
Output ONLY the completed HTML meeting report.
|
||||
@@ -0,0 +1,18 @@
|
||||
require('dotenv').config();
|
||||
const path = require('path');
|
||||
const assemblyModule = require('../../services/modules/transcription-remote/assembly.js');
|
||||
|
||||
// Audio-Datei oder URL aus Kommandozeile, Standard: test.wav
|
||||
const audioPath = process.argv[2] || './storage/audio/IMG_2978.wav';
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const transcript = await assemblyModule.run(audioPath);
|
||||
|
||||
console.log('Transcription succesful');
|
||||
console.log('Transcript ID:', transcript?.id);
|
||||
console.log('Speaker labels:', transcript?.utterances?.length || 0);
|
||||
} catch (error) {
|
||||
console.error('Error in Transcription:', error?.message || error);
|
||||
}
|
||||
})();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
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
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi.testclient import TestClient
|
||||
from app.main import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
def test_health():
|
||||
response = client.get("/health")
|
||||
assert response.status_code == 200
|
||||
@@ -0,0 +1,170 @@
|
||||
// DO NOT TOUCH THIS
|
||||
require("../../requires.js")
|
||||
|
||||
mapFunctions = new Map()
|
||||
// Loading the Function Map
|
||||
var path = `${mainDir}/services/modules`
|
||||
var folders = fs.readdirSync(path).filter(function (file) {
|
||||
return fs.statSync(path+'/'+file).isDirectory();
|
||||
});
|
||||
folders.forEach(element => {
|
||||
var commandFiles = fs.readdirSync(`${path}/${element}`).filter(file => file.endsWith('.js') && !file.startsWith("index"));
|
||||
for (const file of commandFiles) {
|
||||
delete require.cache[require.resolve(`${path}/${element}/${file}`)];
|
||||
const command = require(`${path}/${element}/${file}`);
|
||||
mapFunctions.set(command.name, command);
|
||||
}
|
||||
});
|
||||
// You can touch beyond this point
|
||||
|
||||
let audiopath
|
||||
let transcriptPath
|
||||
let summarizePath
|
||||
let llmpath
|
||||
|
||||
describe("Unit Tests", function() {
|
||||
|
||||
describe('Audio Extraction', function () {
|
||||
this.slow(1000)
|
||||
this.timeout(3000)
|
||||
it('Extract .mp4 to .mp3', function (done) {
|
||||
|
||||
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: __dirname.replaceAll("\\","/")+"/testvideo.mp4", outputType: "mp3"}).then(resp => {
|
||||
audiopath = resp
|
||||
// console.log(resp);
|
||||
done()
|
||||
}).catch(err => {
|
||||
throw err;
|
||||
})
|
||||
})
|
||||
it('Extract .mp4 to .flac', function (done) {
|
||||
|
||||
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: __dirname.replaceAll("\\","/")+"/testvideo.mp4", outputType: "flac"}).then(resp => {
|
||||
// console.log(resp);
|
||||
done()
|
||||
}).catch(err => {
|
||||
throw err;
|
||||
})
|
||||
})
|
||||
it('Extracting to a nonexistant format', function (done) {
|
||||
|
||||
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: __dirname.replaceAll("\\","/")+"/testvideo.mp4", outputType: "qqq"}).then(resp => {
|
||||
// console.log(resp);
|
||||
done("Didnt crash")
|
||||
}).catch(err => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
it('Extracting from nonexistant file', function (done) {
|
||||
|
||||
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: "a", outputType: "mp3"}).then(resp => {
|
||||
// console.log(resp);
|
||||
done("Didnt crash")
|
||||
}).catch(err => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
it('Extracting from nonexistant file to nonexistant format', function (done) {
|
||||
|
||||
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: "a", outputType: "qqq"}).then(resp => {
|
||||
// console.log(resp);
|
||||
done("Didnt crash")
|
||||
}).catch(err => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
describe("Audio Transcription", function() {
|
||||
this.slow(20000)
|
||||
this.timeout(120000)
|
||||
|
||||
it('Assembly', function (done) {
|
||||
mapFunctions.get("assembly").function(audiopath).then(resp => {
|
||||
// console.log(resp);
|
||||
transcriptPath = resp
|
||||
done()
|
||||
}).catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
|
||||
it('Assembly Wrong file', function (done) {
|
||||
mapFunctions.get("assembly").function("a").then(resp => {
|
||||
// console.log(resp);
|
||||
// transcriptPath = resp
|
||||
done("Didnt crash")
|
||||
}).catch(err => {
|
||||
// console.log(err);
|
||||
done()
|
||||
})
|
||||
})
|
||||
// TODO add more Transcription Tool tests here
|
||||
})
|
||||
|
||||
describe("Transcript Summarizer", function() {
|
||||
this.slow(100)
|
||||
this.timeout(1000)
|
||||
|
||||
it("Summarizer 1", function (done){
|
||||
mapFunctions.get("summarize-transcription").function(transcriptPath).then(resp => {
|
||||
done()
|
||||
}).catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
|
||||
it("Summarizer 1 Wrong File", function (done){
|
||||
mapFunctions.get("summarize-transcription").function("a").then(resp => {
|
||||
done("Didnt crash")
|
||||
}).catch(err => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("Summarizer 2 (Main)", function (done){
|
||||
mapFunctions.get("summarize-transcription2").function(transcriptPath).then(resp => {
|
||||
summarizePath = resp
|
||||
done()
|
||||
}).catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
|
||||
it("Summarizer 2 (Main) Wrong File", function (done){
|
||||
mapFunctions.get("summarize-transcription2").function("a").then(resp => {
|
||||
done("Didnt crash")
|
||||
}).catch(err => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("Large Language Model", function() {
|
||||
this.slow(30000)
|
||||
this.timeout(120000)
|
||||
|
||||
// it("ChatGPT", function (done){
|
||||
// mapFunctions.get("chatgpt").function({inputTranscriptPath: summarizePath, documentTypePath: "./storage/documentType/meetingReport.json", language: "en"}).then(resp => {
|
||||
// done()
|
||||
// }).catch(err => {
|
||||
// throw err
|
||||
// })
|
||||
// })
|
||||
|
||||
it("Gemini", function (done){
|
||||
mapFunctions.get("llm-gemini").function({inputTranscriptPath: summarizePath, documentTypePath: "./storage/documentType/meetingReport.json", language: "en"}).then(resp => {
|
||||
llmpath = resp
|
||||
done()
|
||||
}).catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
})
|
||||
after(function() {
|
||||
console.log(`\n\n\n${audiopath} \n${transcriptPath} \n${summarizePath} \n${llmpath}`);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user