Merge branch 'develop' into feature/30-backend-export-funktion-des-dokuments-in-verschiedene-datei-formate-s4-05

This commit is contained in:
MikeHughes-BIN
2025-12-15 14:41:28 +01:00
24 changed files with 955 additions and 693 deletions
+15 -1
View File
@@ -964,8 +964,22 @@ app.*.symbols
!/dev/ci/**/Gemfile.lock !/dev/ci/**/Gemfile.lock
# Storage files # Storage files
storage/ 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 *.mp4
*.webm
*.mp3
*.mov
*.wav *.wav
*.flac *.flac
!testvideo.mp4
+19 -25
View File
@@ -1,33 +1,27 @@
workflow: image: node:latest
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
stages: stages:
- setup # - install
- test - test
setup_environment: # job-install:
stage: setup # stage: install
script: # script:
- pip install --upgrade pip # - npm install
- pip install -r requirements.txt # artifacts:
- echo "Dependencies installed successfully." # 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 stage: test
script: script:
- echo "Running V2D Framework basic test..." - npm install
- python -m unittest discover || echo "No tests found." - echo "ASSEMBLYAI_API_KEY=$apikey_assembly" > .env
- echo "GOOGLE_API_KEY=$apikey_gemini" >> .env
only: - npm test
- main
- feature/ci-pipeline-s1-09a-1
+1 -1
View File
@@ -185,7 +185,7 @@ electron.ipcMain.on("file_submit", async (event, args) => {
for (let i = 0; i < args.document.styles.length; i++) { for (let i = 0; i < args.document.styles.length; i++) {
console.log(`\n\n Running the LLM for Document Style ${i+1}`); console.log(`\n\n Running the LLM for Document Style ${i+1}`);
await mapFunctions.get("module-handler").function(args.document.module, {inputTranscriptPath: transcriptpath, documentTypePath: "/Users/mikehughes/PROJ/video2document/storage/documentType/meetingReport.json", language: "en"}).then(resp => { await mapFunctions.get("module-handler").function(args.document.module, {inputTranscriptPath: transcriptpath, documentTypePath: "./storage/documentType/meetingReport.json", language: "en"}).then(resp => {
console.log(resp); console.log(resp);
transcriptpath = resp transcriptpath = resp
curstep++ curstep++
+332 -526
View File
File diff suppressed because it is too large Load Diff
+2 -8
View File
@@ -3,18 +3,12 @@
"@google/genai": "^1.30.0", "@google/genai": "^1.30.0",
"@types/axios": "^0.9.36", "@types/axios": "^0.9.36",
"axios": "^1.13.2", "axios": "^1.13.2",
"cli-progress": "^3.12.0",
"docx": "^9.5.1",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"electron": "^39.1.1", "electron": "^39.1.1",
"express": "^5.1.0", "express": "^5.1.0",
"ffmpeg-static": "^5.2.0", "ffmpeg-static": "^5.2.0",
"fluent-ffmpeg": "^2.1.3", "fluent-ffmpeg": "^2.1.3",
"html-to-docx": "^1.8.0", "mocha": "^11.7.5"
"marked": "^17.0.1",
"open": "^11.0.0",
"pdfkit": "^0.17.2",
"puppeteer": "^24.33.0"
}, },
"devDependencies": { "devDependencies": {
"@types/cli-progress": "^3.11.6", "@types/cli-progress": "^3.11.6",
@@ -33,7 +27,7 @@
}, },
"scripts": { "scripts": {
"start": "electron main.js", "start": "electron main.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "mocha ./test/unit/test.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
-3
View File
@@ -1,3 +0,0 @@
fastapi
uvicorn
pytest
+1 -2
View File
@@ -11,12 +11,11 @@ config = require("./config/config")
ffmpegPath = require('ffmpeg-static'); ffmpegPath = require('ffmpeg-static');
ffmpeg = require('fluent-ffmpeg'); ffmpeg = require('fluent-ffmpeg');
path = require('path'); path = require('path');
cliProgress = require('cli-progress'); // 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") axios = require("axios")
+47
View File
@@ -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);
}
})();
+5 -22
View File
@@ -24,17 +24,11 @@ module.exports = {
outputType: String // Audio file output format outputType: String // Audio file output format
} }
*/ */
let progressBar = new cliProgress.SingleBar({
format: 'Processing |{bar}| {percentage}% | {timemark}',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true
});
try { try {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.extractAudioFromVideo(parameter.inputVideoPath, progressBar, parameter.outputType) this.extractAudioFromVideo(parameter.inputVideoPath, parameter.outputType)
.then((resp) => resolve(resp)) .then((resp) => resolve(resp))
.catch((err) => console.error(err)); .catch((err) => {reject(err)});
}) })
} catch (error) { } catch (error) {
console.log(parameter.outputType); console.log(parameter.outputType);
@@ -52,7 +46,7 @@ module.exports = {
* - Shows CLI progress bar * - Shows CLI progress bar
* - Handles errors gracefully (without errors) * - 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 inputVideoName = path.basename(videoFilePath, path.extname(videoFilePath));
let outputAudioPath = path.join(outputDir, `${inputVideoName}.${outputType}`); let outputAudioPath = path.join(outputDir, `${inputVideoName}.${outputType}`);
@@ -63,28 +57,17 @@ module.exports = {
// .audioCodec('pcm_s16le') // .audioCodec('pcm_s16le')
.audioChannels(1) .audioChannels(1)
.audioFrequency(16000) .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', () => { .on('end', () => {
progressBar.update(100, { timemark: 'done' });
progressBar.stop();
console.log(`Extraction completed: ${outputAudioPath}`);
resolve(outputAudioPath); resolve(outputAudioPath);
}) })
.on('error', (err) => { .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); reject(err);
}) })
.save(outputAudioPath); .save(outputAudioPath);
} catch (error) { } catch (error) {
console.log(); // console.log(error);
} }
}); });
} }
@@ -21,30 +21,36 @@ module.exports = {
const raw = fs.readFileSync(args.jsonPath, "utf-8"); const raw = fs.readFileSync(args.jsonPath, "utf-8");
inputJson = JSON.parse(raw); inputJson = JSON.parse(raw);
} catch (e) { } catch (e) {
console.error("Failed to load JSON from file:", e); // console.error("Failed to load JSON from file:", e);
return { error: "Could not read JSON from file path." }; reject(e)
return
} }
} }
// JSON parsen // JSON parsen
if (typeof args === "string") { if (typeof args === "string") {
try { try {
await new Promise((res) => { await new Promise((res, rej) => {
fs.readFile(args, 'utf8', function (err, data) { fs.readFile(args, 'utf8', function (err, data) {
if (err) throw err; if (err){
rej(err)
return
}
inputJson = JSON.parse(data); inputJson = JSON.parse(data);
res() res()
}); });
}) })
} catch (e) { } catch (e) {
console.log("Invalid JSON in summarize-transcription"); // console.log("Invalid JSON in summarize-transcription");
console.log(e) // console.log(e)
return { error: "Invalid JSON" }; reject(e)
return
} }
} }
const words = inputJson.words; const words = inputJson.words;
if (!Array.isArray(words)) { if (!Array.isArray(words)) {
return { error: "No words Array found" }; reject("No words Array found")
return
} }
const ENDINGS = [".", "!", "?"]; // '...' auch als Satzende ? const ENDINGS = [".", "!", "?"]; // '...' auch als Satzende ?
@@ -136,11 +142,11 @@ module.exports = {
const txtPath = path.join(outputDir, "transcription_result.txt"); const txtPath = path.join(outputDir, "transcription_result.txt");
fs.writeFileSync(txtPath, output.join("\n"), "utf-8"); fs.writeFileSync(txtPath, output.join("\n"), "utf-8");
console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`); // console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`);
resolve(jsonPath); resolve(jsonPath);
} catch (err) { } catch (err) {
console.error("Error saving Summary:", err); // console.error("Error saving Summary:", err);
reject(err); reject(err);
} }
}) })
@@ -32,29 +32,35 @@ module.exports = {
inputJson = JSON.parse(raw); inputJson = JSON.parse(raw);
} catch (e) { } catch (e) {
console.error("Failed to load JSON from file:", e); console.error("Failed to load JSON from file:", e);
return { error: "Could not read JSON from file path." }; reject("Could not read JSON from file path.")
return
} }
} }
// JSON parsen // JSON parsen
if (typeof args === "string") { if (typeof args === "string") {
try { try {
await new Promise((res) => { await new Promise((res, rej) => {
fs.readFile(args, 'utf8', function (err, data) { fs.readFile(args, 'utf8', function (err, data) {
if (err) throw err; if (err){
rej(err)
return
}
inputJson = JSON.parse(data); inputJson = JSON.parse(data);
res() res()
}); });
}) })
} catch (e) { } catch (e) {
console.log("Invalid JSON in summarize-transcription"); // console.log("Invalid JSON in summarize-transcription");
console.log(e) // console.log(e)
return { error: "Invalid JSON" }; reject(e)
return
} }
} }
const words = inputJson.words; const words = inputJson.words;
if (!Array.isArray(words)) { if (!Array.isArray(words)) {
return { error: "No words Array found" }; reject("No words Array found")
return;
} }
const ENDINGS = [".", "!", "?"]; // '...' auch als Satzende ? const ENDINGS = [".", "!", "?"]; // '...' auch als Satzende ?
@@ -132,10 +138,10 @@ module.exports = {
const txtPath = path.join(outputDir, `${filename}-${new Date().getTime()}.txt`); const txtPath = path.join(outputDir, `${filename}-${new Date().getTime()}.txt`);
fs.writeFileSync(txtPath, output.join("\n"), "utf-8"); fs.writeFileSync(txtPath, output.join("\n"), "utf-8");
console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`); // console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`);
resolve(jsonPath); resolve(jsonPath);
} catch (err) { } catch (err) {
console.error("Error saving Summary:", err); // console.error("Error saving Summary:", err);
reject(err); reject(err);
} }
}) })
+128 -5
View File
@@ -1,8 +1,131 @@
module.exports = { const fs = require('fs');
name:"chatgpt", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()" const path = require('path');
type:"llm", // value used to differentiate each module to order them in the UI
displayname:"ChatGPT", // The displayname used within the UI 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) { async function(parameter) {
// TODO add code to actually send the transcript to ChatGPT and get a response back 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 documents from transcripts." },
{ 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}.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);
} 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.json 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!");
})();
}
+15 -7
View File
@@ -16,21 +16,26 @@ module.exports = {
description: "Generates documents using Google Gemini LLM", description: "Generates documents using Google Gemini LLM",
async function(parameter) { async function(parameter) {
return new Promise(async (resolve, reject) => {
try { try {
console.log("Gemini LLM module invoked with parameters:", parameter); // console.log("Gemini LLM module invoked with parameters:", parameter);
await this.createDocumentFromTranscript( //Call the function to create document with transcript, document type and language resolve(await this.createDocumentFromTranscript( //Call the function to create document with transcript, document type and language
parameter.inputTranscriptPath, // Path to input transcript file 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.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 parameter.language // Language for the document which is chosen in the front end by the user
); ));
} catch (error) { } catch (error) {
console.error("Error in Gemini LLM module:", error); // console.error("Error in Gemini LLM module:", error);
reject(error)
} }
})
}, },
createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") { // default language is English createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") { // default language is English
return new Promise(async(resolve, reject) => {
try { try {
const transcript = await fs.promises.readFile(transcriptPath, "utf-8"); //read transcript file from Path 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 documentType = await fs.promises.readFile(documentTypePath, "utf-8"); //read document type from Path
@@ -63,14 +68,17 @@ module.exports = {
// Get generated text from response or default to empty string (if null) // Get generated text from response or default to empty string (if null)
const output = data?.candidates?.[0]?.content?.parts?.[0]?.text || ""; const output = data?.candidates?.[0]?.content?.parts?.[0]?.text || "";
let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); // Name for the output file let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); // Name for the output file
console.log(inputTranscriptName); // console.log(inputTranscriptName);
const outPath = path.join(outputDir, `${inputTranscriptName}.md`); // Output file path & name to make naming dynamic. Pulled from input transcript name 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 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) { } catch (error) {
console.error("Error generating Gemini content:", error); // console.error("Error generating Gemini content:", error);
reject(error)
} }
})
} }
}; };
+123
View File
@@ -0,0 +1,123 @@
const fs = require('fs');
const path = require('path');
const outputDir = path.join(__dirname, "../../../storage/documents");
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const SAIA_API_KEY = process.env.SAIA_API_KEY;
const SAIA_URL = "https://chat-ai.academiccloud.de/v1/chat/completions";
const module_exports = {
name: "llm-saia_llama_3.3",
type: "llm",
displayname: "LLAMA",
description: "Generates documents using Llama 3.3 70B Instruct via SAIA platform",
async function(parameter) {
try {
console.log("SAIA Llama 3.3 70B module invoked with parameters:", parameter);
await this.createDocumentFromTranscript(
parameter.inputTranscriptPath,
parameter.documentTypePath,
parameter.language
);
} catch (error) {
console.error("Error in SAIA Llama 3.3 70B module:", error);
}
},
createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") {
try {
const transcript = await fs.promises.readFile(transcriptPath, "utf-8");
const documentType = await fs.promises.readFile(documentTypePath, "utf-8");
const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`;
// --- 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: "llama-3.3-70b-instruct", // Korrekter Modellname!
messages: [
{ role: "system", content: "You are a helpful assistant that generates documents from transcripts." },
{ role: "user", content: promptText }
],
temperature: 0
})
});
if (!response.ok) {
const text = await response.text();
throw new Error(`SAIA API error (${response.status}): ${text}`);
}
const data = await response.json();
const output = data.choices?.[0]?.message?.content || "";
let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath));
console.log(inputTranscriptName);
const outPath = path.join(outputDir, `${inputTranscriptName}.md`);
fs.writeFileSync(outPath, output, "utf8");
console.log("Generated document written to:", outPath);
} catch (error) {
console.error("Error generating SAIA content:", error);
}
}
};
module.exports = module_exports;
if (require.main === module) {
(async () => {
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("Usage: node llm-llama-3.3.js <transcriptPath> <documentTypePath> [language]");
console.error("Example: node llm-llama-3.3.js ./transcript.json ./docType.json de");
process.exit(1);
}
const [transcriptPath, documentTypePath, language] = args;
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);
}
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!");
})();
}
Submodule services/modules/transcription-local/whisper.cpp added at 999a7e0cbf
@@ -78,7 +78,7 @@ function saveTranscript(transcript, sessionId) {
const outputPath = path.join(outputDir, `${sessionId}.json`); const outputPath = path.join(outputDir, `${sessionId}.json`);
fs.writeFileSync(outputPath, JSON.stringify(transcript, null, 2)); fs.writeFileSync(outputPath, JSON.stringify(transcript, null, 2));
console.log(`Transcript saved: ${outputPath}`); // console.log(`Transcript saved: ${outputPath}`);
return outputPath; return outputPath;
} }
@@ -116,8 +116,9 @@ module.exports = {
resolve(saveTranscript(transcript, sessionId)); resolve(saveTranscript(transcript, sessionId));
} catch (error) { } catch (error) {
console.error('Transcription error:', error.message); // console.error('Transcription error:', error.message);
reject(error); reject(error);
return
} }
}) })
} }
+1
View File
@@ -1,3 +1,4 @@
module.exports = { module.exports = {
name:"Startup_function", name:"Startup_function",
async function(){ async function(){
+4 -7
View File
@@ -1,7 +1,6 @@
{ {
"SPEAKERS":"First Identify each speaker in the transcript and give the first time snippet where they speak for the first time. Use labels like Speaker 1, Speaker 2, etc. If no speakers are identified, use 'Speaker X'.", "FORMAT": "markdown",
"FORMAT": "HTML", "GOAL":"Generate a structured meeting report (Markdown). **Output ONLY:** final .md. No meta.",
"GOAL":"Generate a structured meeting report (HTML). **Output ONLY:** final .html. No meta.",
"STRUCTURE": { "STRUCTURE": {
"titlepage": ["title","date","start","end","duration","location","host","participants"], "titlepage": ["title","date","start","end","duration","location","host","participants"],
"toc": "[section](#anchor) — HH:MM:SS", "toc": "[section](#anchor) — HH:MM:SS",
@@ -16,21 +15,19 @@
"consolidated": ["decisions", "actions"], "consolidated": ["decisions", "actions"],
"appendix": "optional" "appendix": "optional"
}, },
"STYLE": { "STYLE": {
"tone": "neutral, concise", "tone": "neutral, concise",
"ts_format": "HH:MM:SS", "ts_format": "HH:MM:SS",
"no_meta": true "no_meta": true
}, },
"PROCESS": { "PROCESS": {
"timestamps": "use if present; else estimate minimal", "timestamps": "use if present; else estimate minimal",
"speakers": "use labels; else Speaker X", "speakers": "use labels; else Speaker X",
"long_transcripts": "chunk → summarize → merge", "long_transcripts": "chunk → summarize → merge",
"unclear": "UNKNOWN:<reason>" "unclear": "UNKLAR:<reason>"
}, },
"JSON_OUTPUT_OPTIONAL": true, "JSON_OUTPUT_OPTIONAL": true,
"PROMPT_SNIPPET": "Generate meeting report in HTML using STRUCTURE and STYLE. Output only the report." "PROMPT_SNIPPET": "Generate meeting report in markdown using STRUCTURE and STYLE. Output only the report."
} }
-8
View File
@@ -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
+170
View File
@@ -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.