mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-16 02:11:52 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e4cf93cae | |||
| fe86fa1a2f | |||
| 1e4bde93b1 | |||
| ee31d26116 | |||
| a13fea6734 | |||
| e82cf779da |
Vendored
BIN
Binary file not shown.
@@ -19,7 +19,7 @@
|
|||||||
</label>
|
</label>
|
||||||
|
|
||||||
<nav class="menu1">
|
<nav class="menu1">
|
||||||
<a href="custom_document.html" class="li1">Manage document types</a>
|
<a href="custom_document.html" class="li1">Custom document</a>
|
||||||
<a href="" class="li1">Help</a>
|
<a href="" class="li1">Help</a>
|
||||||
</nav>
|
</nav>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
+15
-19
@@ -3,39 +3,35 @@ const { contextBridge, ipcRenderer, webUtils } = require('electron')
|
|||||||
try {
|
try {
|
||||||
contextBridge.exposeInMainWorld("explorer", {
|
contextBridge.exposeInMainWorld("explorer", {
|
||||||
onFileDrop: (file) => webUtils.getPathForFile(file)
|
onFileDrop: (file) => webUtils.getPathForFile(file)
|
||||||
});
|
})
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("submit", {
|
contextBridge.exposeInMainWorld("submit", {
|
||||||
submit: (meeting_specifications) => ipcRenderer.send("file_submit", meeting_specifications)
|
submit: (meeting_specifications) => {ipcRenderer.send("file_submit", meeting_specifications)}
|
||||||
});
|
})
|
||||||
|
|
||||||
// ALLE electronAPI Funktionen in EINEM Objekt
|
|
||||||
contextBridge.exposeInMainWorld("electronAPI", {
|
contextBridge.exposeInMainWorld("electronAPI", {
|
||||||
getFilePath: (file) => webUtils.getPathForFile(file),
|
getFilePath: (file) => {return webUtils.getPathForFile(file)}
|
||||||
saveSpeakerMapping: (data) => ipcRenderer.send("save-speaker-mapping", data)
|
})
|
||||||
});
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("onStartup", {
|
contextBridge.exposeInMainWorld("onStartup", {
|
||||||
getModuleNames: () => ipcRenderer.invoke('get-module-names')
|
getModuleNames: () => ipcRenderer.invoke('get-module-names')
|
||||||
});
|
})
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electron', {
|
contextBridge.exposeInMainWorld('electron', {
|
||||||
progress: (callback) => ipcRenderer.on('progress', callback)
|
progress: (callback) => ipcRenderer.on('progress', callback)
|
||||||
});
|
})
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('audios', {
|
contextBridge.exposeInMainWorld('audios', {
|
||||||
speakerAudios: (callback) => ipcRenderer.on('speakerAudios', callback)
|
speakerAudios: (callback) => ipcRenderer.on('speakerAudios', callback)
|
||||||
});
|
})
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("submitSpeaker", {
|
contextBridge.exposeInMainWorld("submitSpeaker", {
|
||||||
speaker_submit: (speaker_names) => ipcRenderer.send("speaker_submit", speaker_names)
|
speaker_submit: (speaker_names) => {ipcRenderer.send("speaker_submit", speaker_names)}
|
||||||
});
|
})
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("download", {
|
contextBridge.exposeInMainWorld("download", {
|
||||||
file_download: () => ipcRenderer.send("file_download")
|
file_download: () => {ipcRenderer.send("file_download")}
|
||||||
});
|
})
|
||||||
|
|
||||||
ipcRenderer.on("error", (event, err) => { alert(err) });
|
|
||||||
|
ipcRenderer.on("error", (event, err) => {alert(err)})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in preload.js", error);
|
console.log("Error in preload.js");
|
||||||
}
|
}
|
||||||
+3
-12
@@ -315,20 +315,11 @@ function setSpeakerAudiosValue(valy) {
|
|||||||
|
|
||||||
function rewriteSpeakerName(){
|
function rewriteSpeakerName(){
|
||||||
try {
|
try {
|
||||||
const oldKey = document.getElementById("cur_speaker").value;
|
var tempy = document.getElementById("cur_speaker").value;
|
||||||
const newName = document.getElementById("newSpeaker").value;
|
speakerAudios[tempy].name = document.getElementById("newSpeaker").value;
|
||||||
|
|
||||||
speakerAudios[oldKey].name = newName;
|
|
||||||
loadSpeakerOptions(speakerAudios);
|
loadSpeakerOptions(speakerAudios);
|
||||||
|
|
||||||
// IPC-Aufruf an Electron main process
|
|
||||||
window.electronAPI.saveSpeakerMapping({
|
|
||||||
speakerId: oldKey,
|
|
||||||
speakerName: newName
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log("\n\n\n" + error + "\n\n\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,23 +103,7 @@ electron.ipcMain.handle('get-module-names', async () => {
|
|||||||
return module_array
|
return module_array
|
||||||
});
|
});
|
||||||
|
|
||||||
electron.ipcMain.on("save-speaker-mapping", (event, data) => {
|
|
||||||
|
|
||||||
const filePath = "/Users/mikehughes/PROJ/video2document/storage/speakerMapping/speakerMapping.json";
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
speakerId: data.speakerId,
|
|
||||||
speakerName: data.speakerName,
|
|
||||||
updated: new Date().toISOString()
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
||||||
console.log("Speaker mapping saved!");
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to save speaker mapping", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// electron.ipcMain.on("get_modules", async (event, args) => {
|
// electron.ipcMain.on("get_modules", async (event, args) => {
|
||||||
// let module_array = {
|
// let module_array = {
|
||||||
// "ai_modules":[],
|
// "ai_modules":[],
|
||||||
|
|||||||
Generated
+4
-8
@@ -450,7 +450,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz",
|
||||||
"integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==",
|
"integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.16.0"
|
||||||
}
|
}
|
||||||
@@ -1306,8 +1305,7 @@
|
|||||||
"version": "0.0.1534754",
|
"version": "0.0.1534754",
|
||||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1534754.tgz",
|
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1534754.tgz",
|
||||||
"integrity": "sha512-26T91cV5dbOYnXdJi5qQHoTtUoNEqwkHcAyu/IKtjIAxiEqPMrDiRkDOPWVsGfNZGmlQVHQbZRSjD8sxagWVsQ==",
|
"integrity": "sha512-26T91cV5dbOYnXdJi5qQHoTtUoNEqwkHcAyu/IKtjIAxiEqPMrDiRkDOPWVsGfNZGmlQVHQbZRSjD8sxagWVsQ==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/diff": {
|
"node_modules/diff": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
@@ -3490,10 +3488,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.14.1",
|
"version": "6.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"side-channel": "^1.1.0"
|
"side-channel": "^1.1.0"
|
||||||
},
|
},
|
||||||
@@ -4207,7 +4204,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const module_exports = {
|
|
||||||
name: "replace_speaker",
|
|
||||||
type: "processor",
|
|
||||||
displayname: "Speaker Name Replacer",
|
|
||||||
description: "Replaces speaker placeholder names with actual names based on a mapping in HTML files",
|
|
||||||
|
|
||||||
async function({ inputHtmlPath, speakerMappingPath }) {
|
|
||||||
return await this.replaceNames(inputHtmlPath, speakerMappingPath);
|
|
||||||
},
|
|
||||||
|
|
||||||
replaceNames: async function(inputHtmlPath, speakerMappingPath) {
|
|
||||||
try {
|
|
||||||
const htmlContent = await fs.promises.readFile(inputHtmlPath, "utf-8");
|
|
||||||
const mappingData = await fs.promises.readFile(speakerMappingPath, "utf-8");
|
|
||||||
|
|
||||||
let speakerMap = {};
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(mappingData);
|
|
||||||
if (parsed.speakerId && parsed.speakerName) {
|
|
||||||
speakerMap[parsed.speakerId] = parsed.speakerName;
|
|
||||||
} else {
|
|
||||||
Object.assign(speakerMap, parsed);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
const lines = mappingData.trim().split('\n');
|
|
||||||
lines.forEach(line => {
|
|
||||||
const [placeholder, realName] = line.split(',').map(s => s.trim());
|
|
||||||
if (placeholder && realName) speakerMap[placeholder] = realName;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let outputContent = htmlContent;
|
|
||||||
Object.entries(speakerMap).forEach(([placeholder, realName]) => {
|
|
||||||
const regex = new RegExp(`[\$begin:math:text$\\\\\[\]\?\$\{placeholder\}\[\\$end:math:text$\\]]?`, 'g');
|
|
||||||
outputContent = outputContent.replace(regex, realName);
|
|
||||||
});
|
|
||||||
|
|
||||||
await fs.promises.writeFile(inputHtmlPath, outputContent, "utf-8");
|
|
||||||
|
|
||||||
return inputHtmlPath;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error replacing speaker names:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = module_exports;
|
|
||||||
|
|
||||||
if (require.main === module) {
|
|
||||||
(async () => {
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
if (args.length < 2) process.exit(1);
|
|
||||||
|
|
||||||
const [inputHtmlPath, speakerMappingPath] = args;
|
|
||||||
|
|
||||||
if (!fs.existsSync(inputHtmlPath)) process.exit(1);
|
|
||||||
if (!fs.existsSync(speakerMappingPath)) process.exit(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await module_exports.replaceNames(inputHtmlPath, speakerMappingPath);
|
|
||||||
} catch (err) {
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// -----------------------------------------------------------
|
||||||
|
// Parakeet (Step 3A: spawn Python minimal integration)
|
||||||
|
// -----------------------------------------------------------
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const { spawn } = require("child_process");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "parakeet",
|
||||||
|
type: "transcription",
|
||||||
|
displayname: "NVIDIA Parakeet",
|
||||||
|
|
||||||
|
async function(audioFilePath) {
|
||||||
|
console.log("🦜 [Parakeet] Starting test integration (spawn only)...");
|
||||||
|
console.log("🦜 Input audio:", audioFilePath);
|
||||||
|
|
||||||
|
// Check audio exists
|
||||||
|
if (!fs.existsSync(audioFilePath)) {
|
||||||
|
throw new Error("Audio file does not exist: " + audioFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output path in storage/transcripts
|
||||||
|
const sessionId = path.basename(audioFilePath).replace(/\.[^.]+$/, "");
|
||||||
|
const outputDir = path.join(__dirname, "../../../storage/transcripts");
|
||||||
|
fs.mkdirSync(outputDir, { recursive: true });
|
||||||
|
|
||||||
|
const outputPath = path.join(outputDir, `${sessionId}.json`);
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// SPAWN PYTHON SCRIPT (step 3A — dummy script)
|
||||||
|
// -------------------------------------------------------
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const python310 = "C:\\Users\\smith\\AppData\\Local\\Programs\\Python\\Python310\\python.exe";
|
||||||
|
const py = spawn(python310, [
|
||||||
|
path.join(__dirname, "parakeet_transcribe.py"),
|
||||||
|
audioFilePath,
|
||||||
|
outputPath
|
||||||
|
]);
|
||||||
|
|
||||||
|
py.stdout.on("data", data => console.log("🦜 [Python]", data.toString().trim()));
|
||||||
|
py.stderr.on("data", data => console.error("🦜 [Python ERR]", data.toString().trim()));
|
||||||
|
|
||||||
|
py.on("close", code => {
|
||||||
|
if (code === 0) {
|
||||||
|
console.log("🦜 [Parakeet] Done (spawn test). Output:", outputPath);
|
||||||
|
resolve(outputPath);
|
||||||
|
} else {
|
||||||
|
reject(new Error("Python script failed with exit code " + code));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# -----------------------------------------------------------
|
||||||
|
# Parakeet Real Transcriber (NVIDIA NeMo + PyTorch GPU)
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import soundfile as sf
|
||||||
|
import torch
|
||||||
|
from nemo.collections.asr.models import ASRModel
|
||||||
|
|
||||||
|
# Args:
|
||||||
|
# sys.argv[1] = input audio path
|
||||||
|
# sys.argv[2] = output JSON path
|
||||||
|
|
||||||
|
audio_path = sys.argv[1]
|
||||||
|
output_path = sys.argv[2]
|
||||||
|
|
||||||
|
print("🔥 Starting Parakeet model...")
|
||||||
|
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||||
|
print("🔥 Using device:", device)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
# Load Parakeet model (NVIDIA pretrained ASR)
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
model = ASRModel.from_pretrained(model_name="nvidia/parakeet-ctc-0.6b")
|
||||||
|
model = model.to(device)
|
||||||
|
model.eval()
|
||||||
|
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
# Load audio
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
print("🎧 Loading audio:", audio_path)
|
||||||
|
audio, sr = sf.read(audio_path)
|
||||||
|
|
||||||
|
# model expects mono float32
|
||||||
|
if len(audio.shape) > 1:
|
||||||
|
audio = audio.mean(axis=1)
|
||||||
|
|
||||||
|
audio = audio.astype("float32")
|
||||||
|
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
# Run inference
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
print("🧠 Running inference...")
|
||||||
|
with torch.no_grad():
|
||||||
|
hyp = model.transcribe([audio])[0]
|
||||||
|
|
||||||
|
# Extract only the text
|
||||||
|
if hasattr(hyp, "text"):
|
||||||
|
transcript = hyp.text
|
||||||
|
else:
|
||||||
|
# fallback: convert to string (rare)
|
||||||
|
transcript = str(hyp)
|
||||||
|
|
||||||
|
print("📄 Transcript:", transcript)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
# Save JSON format compatible with V2D pipeline
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
result = {
|
||||||
|
"id": output_path.split("/")[-1].replace(".json", ""),
|
||||||
|
"tool": "nemo_parakeet",
|
||||||
|
"status": "completed",
|
||||||
|
"text": transcript,
|
||||||
|
"words": [] # Parakeet XS doesn’t return word timestamps
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(output_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(result, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
print("✔ JSON saved at:", output_path)
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"speakerId": "speakerB",
|
|
||||||
"speakerName": "Peter",
|
|
||||||
"updated": "2026-01-10T13:54:55.608Z"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user