mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-15 18:01:52 +02:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 55df227599 | |||
| 5c7b1ac5e9 | |||
| c202d3960b | |||
| ec64564a51 | |||
| c1efe77ec1 | |||
| f706dcaf79 | |||
| dacfa2094c | |||
| 49e2724ad3 | |||
| c43ec93894 | |||
| 5ab29e8423 | |||
| 36c0fde0b1 | |||
| 4ca0d46aa9 | |||
| e88e0c45c0 | |||
| 8341861ae2 | |||
| b6276b005e | |||
| 8f2024df14 | |||
| 0f548b3012 | |||
| 17479be27a | |||
| 7fbf0c59d1 | |||
| ef20a08d9f | |||
| 9a3f84efc8 | |||
| 6813b45c80 | |||
| 773e8b471c | |||
| 013c9b5f2c | |||
| 18e791d56e | |||
| 1ed386fcf4 | |||
| c98d7761b2 |
+116
-7
@@ -4,7 +4,9 @@
|
|||||||
1. [How to run the Software](#how-to-run-the-software)
|
1. [How to run the Software](#how-to-run-the-software)
|
||||||
2. [How it works](#how-it-works)
|
2. [How it works](#how-it-works)
|
||||||
3. [Modules](#modules)
|
3. [Modules](#modules)
|
||||||
3. [IPC](#ipc)
|
4. [IPC](#ipc)
|
||||||
|
5. [Authentication](#authentication)
|
||||||
|
6. [UI](#ui)
|
||||||
|
|
||||||
## How to run the Software
|
## How to run the Software
|
||||||
If you read the readme file, you will see the basic setup command in order to run the program.
|
If you read the readme file, you will see the basic setup command in order to run the program.
|
||||||
@@ -17,13 +19,9 @@ Next up you need to set up the .env file.
|
|||||||
The file must contain your keys for the modules you want to use.
|
The file must contain your keys for the modules you want to use.
|
||||||
The .env file looks like this:
|
The .env file looks like this:
|
||||||
```
|
```
|
||||||
ASSEMBLYAI_API_KEY=wefhjhjakeghjkahejkghjkaegh
|
auth_username=wefhjhjakeghjkahejkghjkaegh
|
||||||
GOOGLE_API_KEY=wefhjhjakeghjkahejkghjkaegh
|
auth_password=wefhjhjakeghjkahejkghjkaegh
|
||||||
SAIA_API_KEY=wefhjhjakeghjkahejkghjkaegh
|
|
||||||
```
|
```
|
||||||
Note that if you write your module in the same format we did, then you will only need to supply the api keys to the individual services you will actually use.
|
|
||||||
If you dont want to use Assembly AI, you can for example just leave this row out of your .env, and the program will just work fine.
|
|
||||||
Only issue will be that it will throw an error if you do run the Assembly AI module anyways.
|
|
||||||
Once that is done, you can run the command `npm start` to actually start the program.
|
Once that is done, you can run the command `npm start` to actually start the program.
|
||||||
Alternatively you can double click the start.bat if you are on Windows for example.
|
Alternatively you can double click the start.bat if you are on Windows for example.
|
||||||
|
|
||||||
@@ -114,3 +112,114 @@ The module names are each the name field specified in the module itself.
|
|||||||
As for the rest of the fields, they are pretty self explanatory except `document.type`, that is a predefined report type.
|
As for the rest of the fields, they are pretty self explanatory except `document.type`, that is a predefined report type.
|
||||||
This is the minimum required setup for the currently implemented pipeline to work.
|
This is the minimum required setup for the currently implemented pipeline to work.
|
||||||
You can always add fields to it, but dont remove the ones from above.
|
You can always add fields to it, but dont remove the ones from above.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
Our Software uses a custom API key management System.
|
||||||
|
This system itself is proprietary, and will as such not be delivered with the software.
|
||||||
|
The way it works is simply via a HTTP request.
|
||||||
|
In the current version, the main reads the username and password for authentication from the .env file, and then uses these in the header for the HTTP request.
|
||||||
|
```
|
||||||
|
hostname: "keyserver.dommymommy.xyz", // The URL to the key server
|
||||||
|
port: 443, // The Port of the
|
||||||
|
path: "/v1/auth", // The API Endpoint
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json", // The content type should be JSON
|
||||||
|
"username": un, // the Username used to authenticate
|
||||||
|
"password": pw // The password used to authenticate
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### The Important bit of this whole setup
|
||||||
|
Once the HTTP request is made, it will return a JSON object with the API keys as fields.
|
||||||
|
One such output could look like this:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ASSEMBLYAI_API_KEY": "eajgjkhgahghahegoikh",
|
||||||
|
"GOOGLE_API_KEY": "eajgjkhgahghahegoikh",
|
||||||
|
"SAIA_API_KEY": "eajgjkhgahghahegoikh"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The key for each entry is being used to store the key in memory.
|
||||||
|
Specifically under `process.env`
|
||||||
|
So, if everything in this request worked out, we will have:
|
||||||
|
```js
|
||||||
|
process.env.ASSEMBLYAI_API_KEY
|
||||||
|
process.env.GOOGLE_API_KEY
|
||||||
|
process.env.SAIA_API_KEY
|
||||||
|
```
|
||||||
|
These variables are accessible anywhere in the code and contain the API Keys, so make sure you dont add some untrusted modules that could steal these API Keys.
|
||||||
|
|
||||||
|
|
||||||
|
## UI
|
||||||
|
The UI has a simple, self-explanatory design, in white and blue.
|
||||||
|
For easy handling and understanding, the UI is using 6 steps to guide the user through the process and offers a help page
|
||||||
|
with more defined explanations regarding the steps of the GUI. All parts used in the GUI are stored in the directory `./electron/main`.
|
||||||
|
|
||||||
|
Files used for the UI:
|
||||||
|
- index.html
|
||||||
|
- help_page.html
|
||||||
|
- style.css
|
||||||
|
- script.js
|
||||||
|
- renderer.js
|
||||||
|
- preload.js
|
||||||
|
- languages.js
|
||||||
|
- package-lock.json
|
||||||
|
- package.json
|
||||||
|
|
||||||
|
Folders used for the UI:
|
||||||
|
- /flags
|
||||||
|
- /icons
|
||||||
|
- /node_modules
|
||||||
|
|
||||||
|
**index.html:**
|
||||||
|
This file is the basic framework of our software. Comments in the code define the different UI sections.
|
||||||
|
The comments are the headlines of the code below them.
|
||||||
|
|
||||||
|
**help_page.html:**
|
||||||
|
This is the html to the help page that is accessible though the burger menu in the software.
|
||||||
|
Currently only available in german. It describes the different parts of the program in more depth.
|
||||||
|
|
||||||
|
**style.css:**
|
||||||
|
Contains all the css code of the software used in the UI.
|
||||||
|
|
||||||
|
**script.js:**
|
||||||
|
Stores all functions used in the UI.
|
||||||
|
The code is separated by comments in their matching UI section.
|
||||||
|
|
||||||
|
**renderer.js:**
|
||||||
|
Mainly contains every listener function used in the UI, which listens to any events occuring in the UI,
|
||||||
|
to handle these events as intended.
|
||||||
|
The code is separated by comments in their matching UI section.
|
||||||
|
|
||||||
|
**preload.js:**
|
||||||
|
Contains IPC functions to allow communication between the UI and the main process.
|
||||||
|
|
||||||
|
**languages.js:**
|
||||||
|
Holds one JSON, which is used to store the different language variables. These are used
|
||||||
|
in the script.js for the change of the displayed language of the UI. Add languages here, if
|
||||||
|
you want to add more options in the language selection.
|
||||||
|
|
||||||
|
How to add more languages:
|
||||||
|
1. Add another language block, like an existing one in the file. (Note: Use every key, which is also used in the other sections,
|
||||||
|
beside the first key like "eng". This first key should be always unique from the others)
|
||||||
|
2. Assign the desired values to the keys in the new language section.
|
||||||
|
|
||||||
|
How to add more text which changes languages:
|
||||||
|
1. Create the element in the html file with an unique id.
|
||||||
|
2. Add this id to every language section and assign them a matching value.
|
||||||
|
3. Add inside the `script.js` file, inside the `changeLanguage()` function a document call like the others. Except with our id.
|
||||||
|
|
||||||
|
**package-log.json:**
|
||||||
|
It's an electron module file. No changes needed.
|
||||||
|
|
||||||
|
**package.json:**
|
||||||
|
This is an electron base file. No changes needed.
|
||||||
|
|
||||||
|
**/flags:**
|
||||||
|
This directory contains the flags used for the language selection dropdown menu.
|
||||||
|
|
||||||
|
**/icons:**
|
||||||
|
Pictures for the document preview are stored here.
|
||||||
|
|
||||||
|
**/node_modules:**
|
||||||
|
Contains nodes used by electron.
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="de">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Custom Document</title>
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<h1>Manage document types</h1>
|
|
||||||
|
|
||||||
<label for="existingDocs">Vorhandene Dokumententypen auswählen (optional):</label>
|
|
||||||
<!--Drop Down-->
|
|
||||||
<select name="existingDocs" id="existingDocs">
|
|
||||||
<option value="newDoc">-- Neuen Dokumententyp erstellen --</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div id="docNameWrapper">
|
|
||||||
<label for="docName">Name des Dokumententyps:</label>
|
|
||||||
<input type="text" id="docName" placeholder="Gib hier den Namen für den Dokumententyp ein">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label for="prompt">Dein Prompt:</label>
|
|
||||||
<textarea id="prompt" placeholder="Schreibe hier den Prompt für dein Dokumententyp..."></textarea>
|
|
||||||
|
|
||||||
<div class="buttons">
|
|
||||||
<a href="index.html">
|
|
||||||
<button id="goBackBtn">Abbrechen</button>
|
|
||||||
</a>
|
|
||||||
<button id="deleteBtn">Dokumententyp löschen</button>
|
|
||||||
<button id="generateBtn">Dokumententyp speichern</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="result"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="languages.js"></script>
|
|
||||||
<script>
|
|
||||||
const goBackBtn = document.getElementById("goBackBtn");
|
|
||||||
const generateBtn = document.getElementById("generateBtn");
|
|
||||||
const deleteBtn = document.getElementById("deleteBtn");
|
|
||||||
const existingDocs = document.getElementById("existingDocs");
|
|
||||||
const docNameInput = document.getElementById("docName");
|
|
||||||
const promptInput = document.getElementById("prompt");
|
|
||||||
const resultDiv = document.getElementById("result");
|
|
||||||
const exampleText = "";
|
|
||||||
|
|
||||||
// dokumente speichern
|
|
||||||
generateBtn.addEventListener("click", () => {
|
|
||||||
const name = docNameInput.value.trim();
|
|
||||||
const content = promptInput.value.trim();
|
|
||||||
if (!name || !content) {
|
|
||||||
resultDiv.textContent = "Bitte Name des Dokumententyps und Prompt ausfüllen.";
|
|
||||||
setTimeout(() => {
|
|
||||||
resultDiv.textContent = "";
|
|
||||||
}, 3000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.api.saveTxtFile(name, content).then();
|
|
||||||
resultDiv.textContent = "Dokumententyp erfolgreich gespeichert!";
|
|
||||||
setTimeout(() => {
|
|
||||||
resultDiv.textContent = "";
|
|
||||||
}, 3000);
|
|
||||||
reloadDocuments();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// dokumente löschen
|
|
||||||
deleteBtn.addEventListener("click", () => {
|
|
||||||
const name = docNameInput.value.trim();
|
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
resultDiv.textContent = "Bitte Name des Dokumententyps angeben.";
|
|
||||||
setTimeout(() => {
|
|
||||||
resultDiv.textContent = "";
|
|
||||||
}, 3000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmDelete = confirm(
|
|
||||||
`Möchtest du den Dokumententyp "${name}" wirklich löschen?`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!confirmDelete) return;
|
|
||||||
|
|
||||||
window.api.deleteTxtFile(name).then((success) => {
|
|
||||||
if (success) {
|
|
||||||
resultDiv.textContent = "Dokumententyp erfolgreich gelöscht!";
|
|
||||||
reloadDocuments();
|
|
||||||
existingDocs.value = "newDoc";
|
|
||||||
existingDocs.dispatchEvent(new Event("change"));
|
|
||||||
} else {
|
|
||||||
resultDiv.textContent = "Dokumententyp konnte nicht gelöscht werden.";
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
resultDiv.textContent = "";
|
|
||||||
}, 3000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
//function to load existingDoc options to the drop down list
|
|
||||||
const select = document.getElementById('existingDocs');
|
|
||||||
|
|
||||||
window.api.getTxtFiles().then(files => {
|
|
||||||
reloadDocuments();
|
|
||||||
});
|
|
||||||
|
|
||||||
//content anzeigen
|
|
||||||
const docNameWrapper = document.getElementById("docNameWrapper");
|
|
||||||
|
|
||||||
existingDocs.addEventListener("change", async () => {
|
|
||||||
const selected = existingDocs.value;
|
|
||||||
|
|
||||||
if (selected === "newDoc") {
|
|
||||||
docNameWrapper.classList.remove("hidden");
|
|
||||||
docNameInput.value = "";
|
|
||||||
promptInput.value = exampleText;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
docNameWrapper.classList.add("hidden");
|
|
||||||
|
|
||||||
const content = await window.api.readTxtFile(selected);
|
|
||||||
promptInput.value = content;
|
|
||||||
docNameInput.value = selected.replace(".txt", "");
|
|
||||||
});
|
|
||||||
|
|
||||||
//reload drop down
|
|
||||||
function reloadDocuments() {
|
|
||||||
[...existingDocs.querySelectorAll('option:not([value="newDoc"])')]
|
|
||||||
.forEach(o => o.remove());
|
|
||||||
|
|
||||||
window.api.getTxtFiles().then(files => {
|
|
||||||
files.forEach(file => {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = file;
|
|
||||||
option.textContent = file
|
|
||||||
.replace('.txt', '') // Endung entfernen
|
|
||||||
.replace(/_/g, ' ') // Leerzeichen ersetzen
|
|
||||||
.replace(/\b\w/g, c => c.toUpperCase()) // ersten Buchstaben groß
|
|
||||||
existingDocs.appendChild(option);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
+328
-222
@@ -1,234 +1,340 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="de">
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title id="title">Video to document</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/lc-select@1.3.0/themes/light.css"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="UTF-8">
|
<div id="h1-wrapper">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<section class="p-menu1">
|
||||||
<title id="title">Video to document</title>
|
<nav id="navbar" class="navigation" role="navigation">
|
||||||
<link rel="stylesheet" href="style.css">
|
<input id="toggle1" type="checkbox" />
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lc-select@1.3.0/themes/light.css">
|
<label class="hamburger1" for="toggle1">
|
||||||
</head>
|
<div class="top"></div>
|
||||||
|
<div class="meat"></div>
|
||||||
|
<div class="bottom"></div>
|
||||||
|
</label>
|
||||||
|
|
||||||
<body>
|
<nav class="menu1">
|
||||||
|
<button id="customDocBtn" onclick="showCD()">
|
||||||
<div id="h1-wrapper">
|
Manage document types
|
||||||
<section class="p-menu1">
|
</button>
|
||||||
<nav id="navbar" class="navigation" role="navigation">
|
<a href="help_page.html" class="li1">Help</a>
|
||||||
<input id="toggle1" type="checkbox" />
|
</nav>
|
||||||
<label class="hamburger1" for="toggle1">
|
|
||||||
<div class="top"></div>
|
|
||||||
<div class="meat"></div>
|
|
||||||
<div class="bottom"></div>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<nav class="menu1">
|
|
||||||
<button id="customDocBtn" onclick="showCD()">Manage document types</button>
|
|
||||||
<a href="help_page.html" class="li1">Help</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
</nav>
|
</section>
|
||||||
</section>
|
|
||||||
|
|
||||||
<h1 id="h1">Video to document</h1>
|
<h1 id="h1">Video to document</h1>
|
||||||
|
|
||||||
<div class="gui-language">
|
<div class="gui-language">
|
||||||
<select name="language_option" id="language_option"></select>
|
<select name="language_option" id="language_option"></select>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="step-nav">
|
|
||||||
<div class="step-item active" data-step="1" id="step_nav1">1. Step</div>
|
|
||||||
<div class="step-item" data-step="2" id="step_nav2">2. Step</div>
|
|
||||||
<div class="step-item" data-step="3" id="step_nav3">3. Step</div>
|
|
||||||
<div class="step-item" data-step="4" id="step_nav4">4. Step</div>
|
|
||||||
<div class="step-item" data-step="5" id="step_nav5">5. Step</div>
|
|
||||||
<div class="step-item" data-step="6" id="step_nav6">6. Step</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="middleContainerWrapper" class="middle-container-wrapper">
|
|
||||||
<button id="prevBtn" class="navBtn" disabled>←</button>
|
|
||||||
|
|
||||||
<!-- Visible middle part-->
|
|
||||||
<div class="mitte" id="mitte">
|
|
||||||
|
|
||||||
<!--Costum document section-->
|
|
||||||
<div class="container" id="cdContainer" style="display:none;">
|
|
||||||
<h1 id="cd_h1">Manage document types</h1>
|
|
||||||
|
|
||||||
<label for="existingDocs" id="cd_existingDocs">Select existing documents (optional):</label>
|
|
||||||
<!--Drop Down-->
|
|
||||||
<select name="existingDocs" id="existingDocs">
|
|
||||||
<option value="newDoc" id="newDoc">-- Create new document --</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div id="docNameWrapper">
|
|
||||||
<label for="docName" id="cd_docName">Document name:</label>
|
|
||||||
<input type="text" id="docName" placeholder="Enter the document name here">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label for="prompt" id="cd_promt">Your prompt:</label>
|
|
||||||
<textarea id="prompt" placeholder="Type the prompt for your document here..."></textarea>
|
|
||||||
|
|
||||||
<div class="buttons">
|
|
||||||
<button id="goBackBtn">Return</button>
|
|
||||||
<button id="deleteBtn">Delete document</button>
|
|
||||||
<button id="generateBtn">Save document</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="result"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Here starts code from step 1-->
|
|
||||||
<div class="step" id="step1">
|
|
||||||
<h2 class="h2">Upload your video here:</h2>
|
|
||||||
<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 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>
|
|
||||||
|
|
||||||
<!-- Here starts code from step 2-->
|
|
||||||
<div class="step" id="step2" style="display:none;">
|
|
||||||
<h2 class="h2">Choose your preferences:</h2>
|
|
||||||
<div class="KI-wrapper">
|
|
||||||
<label id="labelKI">Select ki:</label>
|
|
||||||
<select name="ai_type" id="ai_type"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="transcript-wrap">
|
|
||||||
<label id="labelTranscription">Select transcription:</label>
|
|
||||||
<select name="transkript_type" id="transkript_type"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="type-wrapper">
|
|
||||||
<label id="labelType">Select type:</label>
|
|
||||||
<select name="output_type" id="output_type">
|
|
||||||
<option value="pdf">.pdf</option>
|
|
||||||
<option value="word">.docx</option>
|
|
||||||
<option value="txt">.txt</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="language-wrapper">
|
|
||||||
<label id="labelLanguage">Select language:</label>
|
|
||||||
|
|
||||||
<select name="document_language_option" id="document_language_option">
|
|
||||||
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Here starts code from step 3-->
|
|
||||||
|
|
||||||
<!-- Hover Effekt für Dokumentenvorschau, Fragezeichen hinter Text, drüber hoven zeigt Beispieldokument -->
|
|
||||||
<div class="step" id="step3" style="display:none;">
|
|
||||||
<div class="checkbox-group">
|
|
||||||
<h2 class="h2">Choose prefered document style:</h2>
|
|
||||||
<div class="checkbox-container">
|
|
||||||
<input type="checkbox" name="docFormat" id="docFormat" value="followup-report">
|
|
||||||
<label id="label_format" for="docFormat">Follow-up Report</label>
|
|
||||||
<div class="figure1">
|
|
||||||
<img class="img-icon" src="icons/question-mark-button-icon--free-clip-art-30.png">
|
|
||||||
<img class="img-hover1" src="flags/germany-flag-png-large.jpg">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox-container">
|
|
||||||
<input type="checkbox" name="docFormat" id="docFormatSummary1" value="agenda">
|
|
||||||
<label id="label_summary" for="docFormatSummary">Agenda</label>
|
|
||||||
<div class="figure2">
|
|
||||||
<img class="img-icon" src="icons/question-mark-button-icon--free-clip-art-30.png">
|
|
||||||
<img class="img-hover2" src="flags/india-flag-png-large.png">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox-container">
|
|
||||||
<input type="checkbox" name="docFormat" id="docFormatSummary2" value="result-protocol">
|
|
||||||
<label id="label_summary" for="docFormatSummary">Resultprotocol</label>
|
|
||||||
<div class="figure3">
|
|
||||||
<img class="img-icon" src="icons/question-mark-button-icon--free-clip-art-30.png">
|
|
||||||
<img class="img-hover3" src="flags/united-kingdom-flag-png-large.jpg">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox-container">
|
|
||||||
<input type="checkbox" name="docFormat" id="docFormatSummary3" value="sprint-planning">
|
|
||||||
<label id="label_summary" for="docFormatSummary">Sprint Planning Note</label>
|
|
||||||
<div class="figure4">
|
|
||||||
<img class="img-icon" src="icons/question-mark-button-icon--free-clip-art-30.png">
|
|
||||||
<img class="img-hover4" src="flags/germany-flag-png-large.jpg">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox-container">
|
|
||||||
<input type="checkbox" name="docFormat" id="docFormatCustom" value="custom">
|
|
||||||
<select name="customDocumentTypes" id="customDocumentTypes">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Here starts code from step 4-->
|
|
||||||
<div class="step" id="step4" style="display:none;">
|
|
||||||
<h2 class="h2">Click to submit:</h2>
|
|
||||||
<button class="submit-btn" id="submitButton" onclick="checkBoxes()" disabled>Submit</button>
|
|
||||||
|
|
||||||
<div class="testy" id="testy">
|
|
||||||
<div class="box2" id="box1">
|
|
||||||
</div>
|
|
||||||
<p id="box1_p1">---Starting---</p>
|
|
||||||
<div class="box2" id="box2">
|
|
||||||
</div>
|
|
||||||
<p id="box2_p2">---Transkribing---</p>
|
|
||||||
<div class="box2" id="box3">
|
|
||||||
</div>
|
|
||||||
<p id="box3_p3">---Document creation---</p>
|
|
||||||
<div class="box2" id="box4">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Here starts code from step 5-->
|
|
||||||
<div class="step" id="step5" style="display:none;">
|
|
||||||
<h2 class="h2">Change names of the speakers:</h2>
|
|
||||||
<div class="speakerView" id="speakerView">
|
|
||||||
<label id="labelSpeaker">Select Speaker:</label>
|
|
||||||
<select name="cur_speaker" id="cur_speaker">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="speakerAudio" id="speakerAutio">
|
|
||||||
<label id="labelSpeakerAudio">Selected Speaker:</label>
|
|
||||||
<audio controls id="speakerAudioViewer">
|
|
||||||
Currently there is no audio file here.
|
|
||||||
</audio>
|
|
||||||
</div>
|
|
||||||
<div class="speakerWrite" id="speakerWrite">
|
|
||||||
<label id="labelSpeakerWriter">Write name:</label>
|
|
||||||
<input type="text" id="newSpeaker">
|
|
||||||
</div>
|
|
||||||
<div class="speakerButton-group">
|
|
||||||
<button id="speakerLocker" onclick="rewriteSpeakerName()">Rename Speaker</button>
|
|
||||||
<button id="speakerResender" onclick="sendSpeakerPackages()">Rewrite document</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Here starts code from step 6-->
|
|
||||||
<div class="step" id="step6" style="display:none;">
|
|
||||||
<h2 class="h2">Klick to download your document:</h2>
|
|
||||||
<button class="download-btn" id="downloadButton" onclick="fileDownload()">Download</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="nextBtn" class="navBtn">→</button>
|
<div class="step-nav">
|
||||||
|
<div class="step-item active" data-step="1" id="step_nav1">1. Step</div>
|
||||||
|
<div class="step-item" data-step="2" id="step_nav2">2. Step</div>
|
||||||
|
<div class="step-item" data-step="3" id="step_nav3">3. Step</div>
|
||||||
|
<div class="step-item" data-step="4" id="step_nav4">4. Step</div>
|
||||||
|
<div class="step-item" data-step="5" id="step_nav5">5. Step</div>
|
||||||
|
<div class="step-item" data-step="6" id="step_nav6">6. Step</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<div id="middleContainerWrapper" class="middle-container-wrapper">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/lc-select@1.3.0/lc_select.min.js"></script>
|
<button id="prevBtn" class="navBtn" disabled>←</button>
|
||||||
<script src="languages.js"></script>
|
|
||||||
<script src="script.js"></script>
|
|
||||||
<script src="./renderer.js"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
|
<!-- Visible middle part-->
|
||||||
|
<div class="mitte" id="mitte">
|
||||||
|
<!--Costum document section-->
|
||||||
|
<div class="container" id="cdContainer" style="display: none">
|
||||||
|
<h1 id="cd_h1">Manage document types</h1>
|
||||||
|
|
||||||
|
<label for="existingDocs" id="cd_existingDocs"
|
||||||
|
>Select existing documents (optional):</label
|
||||||
|
>
|
||||||
|
<!--Drop Down-->
|
||||||
|
<select name="existingDocs" id="existingDocs">
|
||||||
|
<option value="newDoc" id="newDoc">
|
||||||
|
-- Create new document --
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div id="docNameWrapper">
|
||||||
|
<label for="docName" id="cd_docName">Document name:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="docName"
|
||||||
|
placeholder="Enter the document name here"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="prompt" id="cd_promt">Your prompt:</label>
|
||||||
|
<textarea
|
||||||
|
id="prompt"
|
||||||
|
placeholder="Type the prompt for your document here..."
|
||||||
|
></textarea>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<button id="goBackBtn">Return</button>
|
||||||
|
<button id="deleteBtn">Delete document</button>
|
||||||
|
<button id="generateBtn">Save document</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="result"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Here starts code from step 1-->
|
||||||
|
<div class="step" id="step1">
|
||||||
|
<h2 class="h2" id="step1_h2">Upload your video here:</h2>
|
||||||
|
<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 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>
|
||||||
|
|
||||||
|
<!-- Here starts code from step 2-->
|
||||||
|
<div class="step" id="step2" style="display: none">
|
||||||
|
<h2 class="h2" id="step2_h2">Choose your preferences:</h2>
|
||||||
|
<div class="step2-form">
|
||||||
|
<div class="KI-wrapper">
|
||||||
|
<label id="labelKI">Select ki:</label>
|
||||||
|
<select name="ai_type" id="ai_type"></select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="transcript-wrap">
|
||||||
|
<label id="labelTranscription">Select transcription:</label>
|
||||||
|
<select name="transkript_type" id="transkript_type"></select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="type-wrapper">
|
||||||
|
<label id="labelType">Select type:</label>
|
||||||
|
<select name="output_type" id="output_type">
|
||||||
|
<option value="pdf">.pdf</option>
|
||||||
|
<option value="docx">.docx</option>
|
||||||
|
<option value="txt">.txt</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="language-wrapper">
|
||||||
|
<label id="labelLanguage">Select language:</label>
|
||||||
|
|
||||||
|
<select
|
||||||
|
name="document_language_option"
|
||||||
|
id="document_language_option"
|
||||||
|
></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Here starts code from step 3-->
|
||||||
|
|
||||||
|
<!-- Hover Effekt für Dokumentenvorschau, Fragezeichen hinter Text, drüber hoven zeigt Beispieldokument -->
|
||||||
|
<div class="step" id="step3" style="display: none">
|
||||||
|
<div class="checkbox-group">
|
||||||
|
<h2 class="h2" id="step3_h2">Choose prefered document style:</h2>
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="docFormat"
|
||||||
|
id="docFormat"
|
||||||
|
value="followup-report"
|
||||||
|
/>
|
||||||
|
<label id="label_format" for="docFormat">Follow-up Report</label>
|
||||||
|
<div class="figure1">
|
||||||
|
<img
|
||||||
|
class="img-icon"
|
||||||
|
src="icons/question-mark-button-icon--free-clip-art-30.png"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
class="img-hover1"
|
||||||
|
src="flags/germany-flag-png-large.jpg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="docFormat"
|
||||||
|
id="docFormatSummary1"
|
||||||
|
value="agenda"
|
||||||
|
/>
|
||||||
|
<label id="label_summary" for="docFormatSummary">Agenda</label>
|
||||||
|
<div class="figure2">
|
||||||
|
<img
|
||||||
|
class="img-icon"
|
||||||
|
src="icons/question-mark-button-icon--free-clip-art-30.png"
|
||||||
|
/>
|
||||||
|
<img class="img-hover2" src="flags/india-flag-png-large.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="docFormat"
|
||||||
|
id="docFormatSummary2"
|
||||||
|
value="result-protocol"
|
||||||
|
/>
|
||||||
|
<label id="label_summary" for="docFormatSummary"
|
||||||
|
>Resultprotocol</label
|
||||||
|
>
|
||||||
|
<div class="figure3">
|
||||||
|
<img
|
||||||
|
class="img-icon"
|
||||||
|
src="icons/question-mark-button-icon--free-clip-art-30.png"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
class="img-hover3"
|
||||||
|
src="flags/united-kingdom-flag-png-large.jpg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="docFormat"
|
||||||
|
id="docFormatSummary3"
|
||||||
|
value="sprint-planning"
|
||||||
|
/>
|
||||||
|
<label id="label_summary" for="docFormatSummary"
|
||||||
|
>Sprint Planning Note</label
|
||||||
|
>
|
||||||
|
<div class="figure4">
|
||||||
|
<img
|
||||||
|
class="img-icon"
|
||||||
|
src="icons/question-mark-button-icon--free-clip-art-30.png"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
class="img-hover4"
|
||||||
|
src="flags/germany-flag-png-large.jpg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="docFormat"
|
||||||
|
id="docFormatCustom"
|
||||||
|
value="custom"
|
||||||
|
/>
|
||||||
|
<select
|
||||||
|
name="customDocumentTypes"
|
||||||
|
id="customDocumentTypes"
|
||||||
|
></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Here starts code from step 4-->
|
||||||
|
<div class="step" id="step4" style="display: none">
|
||||||
|
<h2 class="h2" id="step4_h2">Click to submit:</h2>
|
||||||
|
<button
|
||||||
|
class="submit-btn"
|
||||||
|
id="submitButton"
|
||||||
|
onclick="checkBoxes()"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="testy" id="testy">
|
||||||
|
<div class="box2" id="box1"></div>
|
||||||
|
<p id="box1_p1">---Starting---</p>
|
||||||
|
<div class="box2" id="box2"></div>
|
||||||
|
<p id="box2_p2">---Transkribing---</p>
|
||||||
|
<div class="box2" id="box3"></div>
|
||||||
|
<p id="box3_p3">---Document creation---</p>
|
||||||
|
<div class="box2" id="box4"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Here starts code from step 5-->
|
||||||
|
<div class="step" id="step5" style="display: none">
|
||||||
|
<h2 class="h2" id="step5_h2">Change names of the speakers:</h2>
|
||||||
|
|
||||||
|
<div class="speaker-container">
|
||||||
|
<table class="speaker-table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="label-cell">
|
||||||
|
<label id="labelSpeaker" for="cur_speaker"
|
||||||
|
>Select Speaker:</label
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td class="input-cell">
|
||||||
|
<select name="cur_speaker" id="cur_speaker"></select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label-cell">
|
||||||
|
<label id="labelSpeakerAudio">Speaker Audio:</label>
|
||||||
|
</td>
|
||||||
|
<td class="input-cell">
|
||||||
|
<audio controls id="speakerAudioViewer">
|
||||||
|
Currently there is no audio file here.
|
||||||
|
</audio>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label-cell">
|
||||||
|
<label id="labelSpeakerWriter" for="newSpeaker"
|
||||||
|
>New Name:</label
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td class="input-cell">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="newSpeaker"
|
||||||
|
placeholder="Enter new speaker name"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="speaker-button-group">
|
||||||
|
<button id="speakerLocker" onclick="rewriteSpeakerName()">
|
||||||
|
Rename Speaker
|
||||||
|
</button>
|
||||||
|
<button id="speakerResender" onclick="sendSpeakerPackages()">
|
||||||
|
Rewrite Document
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Here starts code from step 6-->
|
||||||
|
<div class="step" id="step6" style="display: none">
|
||||||
|
<h2 class="h2" id="step6_h2">Click to download your document:</h2>
|
||||||
|
<button
|
||||||
|
class="download-btn"
|
||||||
|
id="downloadButton"
|
||||||
|
onclick="fileDownload()"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="nextBtn" class="navBtn">→</button>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/lc-select@1.3.0/lc_select.min.js"></script>
|
||||||
|
<script src="languages.js"></script>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
<script src="./renderer.js"></script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+45
-24
@@ -1,7 +1,7 @@
|
|||||||
var languageOptions = {
|
var languageOptions = {
|
||||||
"eng":{
|
"eng":{
|
||||||
"flagPath": "flags/united-kingdom-flag-png-large.jpg",
|
"flagPath": "flags/united-kingdom-flag-png-large.jpg",
|
||||||
"labelKI": "Select ki:",
|
"labelKI": "Select AI:",
|
||||||
"labelTranscription": "Select transcription:",
|
"labelTranscription": "Select transcription:",
|
||||||
"labelLanguage": "Select language:",
|
"labelLanguage": "Select language:",
|
||||||
"title": "Video to document",
|
"title": "Video to document",
|
||||||
@@ -9,7 +9,7 @@ var languageOptions = {
|
|||||||
"p1": "Drag and drop video file",
|
"p1": "Drag and drop video file",
|
||||||
"fileName": "No video chosen",
|
"fileName": "No video chosen",
|
||||||
"manualUploadBtn": "Search video",
|
"manualUploadBtn": "Search video",
|
||||||
"checkbox_group": "Choose prefered document style:",
|
"checkbox_group": "Choose preferred document style:",
|
||||||
"label_format": "Meeting report",
|
"label_format": "Meeting report",
|
||||||
"label_summary": "Summary with timestamps",
|
"label_summary": "Summary with timestamps",
|
||||||
"submitButton": "Submit",
|
"submitButton": "Submit",
|
||||||
@@ -27,7 +27,7 @@ var languageOptions = {
|
|||||||
"speakerResender": "Rewrite document",
|
"speakerResender": "Rewrite document",
|
||||||
"downloadButton": "Download",
|
"downloadButton": "Download",
|
||||||
"box1_p1": "---Starting---",
|
"box1_p1": "---Starting---",
|
||||||
"box2_p2": "---Transkribing---",
|
"box2_p2": "---Transcribing---",
|
||||||
"box3_p3": "---Document creation---",
|
"box3_p3": "---Document creation---",
|
||||||
"labelType": "Select document type:",
|
"labelType": "Select document type:",
|
||||||
|
|
||||||
@@ -41,18 +41,25 @@ var languageOptions = {
|
|||||||
"goBackBtn": "Return",
|
"goBackBtn": "Return",
|
||||||
"deleteBtn": "Delete document",
|
"deleteBtn": "Delete document",
|
||||||
"generateBtn": "Save document",
|
"generateBtn": "Save document",
|
||||||
"newDoc": "-- Create new document --"
|
"newDoc": "-- Create new document --",
|
||||||
|
|
||||||
|
"step1_h2" : "Upload your video here:",
|
||||||
|
"step2_h2" : "Choose your preferences:",
|
||||||
|
"step3_h2" : "Choose prefered document style:",
|
||||||
|
"step4_h2" : "Click to submit:",
|
||||||
|
"step5_h2" : "Change names of the speakers:",
|
||||||
|
"step6_h2" : "Click to download your document:"
|
||||||
|
|
||||||
},
|
},
|
||||||
"de":{
|
"de":{
|
||||||
"flagPath": "flags/germany-flag-png-large.jpg",
|
"flagPath": "flags/germany-flag-png-large.jpg",
|
||||||
"labelKI": "Waehle KI:",
|
"labelKI": "Wähle KI:",
|
||||||
"labelTranscription": "Waehle Transkription:",
|
"labelTranscription": "Wähle Transkription:",
|
||||||
"labelLanguage": "Waehle Sprache:",
|
"labelLanguage": "Wähle Sprache:",
|
||||||
"title": "Video zu Dokument",
|
"title": "Video zu Dokument",
|
||||||
"h1": "Video zu Dokument",
|
"h1": "Video zu Dokument",
|
||||||
"p1": "Video per Drag & Drop ablegen",
|
"p1": "Video per Drag & Drop ablegen",
|
||||||
"fileName": "Kein Video ausgewaehlt",
|
"fileName": "Kein Video ausgewählt",
|
||||||
"manualUploadBtn": "Video suchen",
|
"manualUploadBtn": "Video suchen",
|
||||||
"checkbox_group": "Bevorzugte Dokumentvarianten:",
|
"checkbox_group": "Bevorzugte Dokumentvarianten:",
|
||||||
"label_format": "Meeting Bericht",
|
"label_format": "Meeting Bericht",
|
||||||
@@ -64,7 +71,7 @@ var languageOptions = {
|
|||||||
"step_nav4": "Schritt 4",
|
"step_nav4": "Schritt 4",
|
||||||
"step_nav5": "Schritt 5",
|
"step_nav5": "Schritt 5",
|
||||||
"step_nav6": "Schritt 6",
|
"step_nav6": "Schritt 6",
|
||||||
"h2": "Uploade dein Video hier:",
|
"h2": "Lade dein Video hier hoch:",
|
||||||
"labelSpeaker": "Wähle Sprecher:",
|
"labelSpeaker": "Wähle Sprecher:",
|
||||||
"labelSpeakerAudio": "Ausgewählter Sprecher:",
|
"labelSpeakerAudio": "Ausgewählter Sprecher:",
|
||||||
"labelSpeakerWriter": "Schreib Namen:",
|
"labelSpeakerWriter": "Schreib Namen:",
|
||||||
@@ -72,27 +79,34 @@ var languageOptions = {
|
|||||||
"speakerResender": "Überschreibe Dokument",
|
"speakerResender": "Überschreibe Dokument",
|
||||||
"downloadButton": "Download",
|
"downloadButton": "Download",
|
||||||
"box1_p1": "---Startet---",
|
"box1_p1": "---Startet---",
|
||||||
"box2_p2": "---Transkribing---",
|
"box2_p2": "---Transkribierung---",
|
||||||
"box3_p3": "---Dokument kreieren---",
|
"box3_p3": "---Dokument erstellen---",
|
||||||
"labelType": "Wähle Dokumenttype:",
|
"labelType": "Wähle Dokumenttyp:",
|
||||||
|
|
||||||
"customDocBtn": "Dokumenttypen verwalten",
|
"customDocBtn": "Dokumenttypen verwalten",
|
||||||
"cd_h1": "Dokumenttypen verwalten",
|
"cd_h1": "Dokumenttypen verwalten",
|
||||||
"cd_existingDocs": "Vorhandene Dokumente auswählen (optional):",
|
"cd_existingDocs": "Vorhandene Dokumente auswählen (optional):",
|
||||||
"cd_docName": "Dokument Name",
|
"cd_docName": "Dokumentname",
|
||||||
"docName": "Geben Sie hier den Dokumentnamen ein",
|
"docName": "Geben Sie hier den Dokumentnamen ein",
|
||||||
"cd_promt": "Ihr Prompt:",
|
"cd_promt": "Ihr Prompt:",
|
||||||
"prompt": "Geben Sie hier die Eingabeaufforderung für Ihr Dokument ein...",
|
"prompt": "Geben Sie hier die Eingabeaufforderung für Ihr Dokument ein...",
|
||||||
"goBackBtn": "Zurück",
|
"goBackBtn": "Zurück",
|
||||||
"deleteBtn": "Lösche Dokument",
|
"deleteBtn": "Lösche Dokument",
|
||||||
"generateBtn": "Speicher Dokument",
|
"generateBtn": "Speichere Dokument",
|
||||||
"newDoc": "-- Neues Dokument erstellen --"
|
"newDoc": "-- Neues Dokument erstellen --",
|
||||||
|
|
||||||
|
"step1_h2" : "Laden Sie Ihr Video hier hoch:",
|
||||||
|
"step2_h2" : "Wählen Sie Ihre Präferenzen:",
|
||||||
|
"step3_h2" : "Wählen Sie den gewünschten Dokumentstil:",
|
||||||
|
"step4_h2" : "Zum Absenden klicken:",
|
||||||
|
"step5_h2" : "Ändern Sie die Namen der Sprecher:",
|
||||||
|
"step6_h2" : "Klicken Sie hier, um Ihr Dokument herunterzuladen:"
|
||||||
},
|
},
|
||||||
"in":{
|
"in":{
|
||||||
"flagPath": "flags/india-flag-png-large.png",
|
"flagPath": "flags/india-flag-png-large.png",
|
||||||
"labelKI": "की का चयन करें:",
|
"labelKI": "KI का चयन करें:",
|
||||||
"labelTranscription": "प्रतिलेखन चुनें:",
|
"labelTranscription": "प्रतिलेखन चुनें:",
|
||||||
"labelLanguage": "भाषा चुने:",
|
"labelLanguage": "भाषा चुनें:",
|
||||||
"title": "दस्तावेज़ के लिए वीडियो",
|
"title": "दस्तावेज़ के लिए वीडियो",
|
||||||
"h1": "दस्तावेज़ के लिए वीडियो",
|
"h1": "दस्तावेज़ के लिए वीडियो",
|
||||||
"p1": "वीडियो फ़ाइल खींचें और छोड़ें",
|
"p1": "वीडियो फ़ाइल खींचें और छोड़ें",
|
||||||
@@ -101,7 +115,7 @@ var languageOptions = {
|
|||||||
"checkbox_group": "पसंदीदा दस्तावेज़ शैली चुनें:",
|
"checkbox_group": "पसंदीदा दस्तावेज़ शैली चुनें:",
|
||||||
"label_format": "बैठक रिपोर्ट",
|
"label_format": "बैठक रिपोर्ट",
|
||||||
"label_summary": "टाइमस्टैम्प के साथ सारांश",
|
"label_summary": "टाइमस्टैम्प के साथ सारांश",
|
||||||
"submitButton": "जमा करना",
|
"submitButton": "जमा करें",
|
||||||
"step_nav1": "स्टेप 1",
|
"step_nav1": "स्टेप 1",
|
||||||
"step_nav2": "स्टेप 2",
|
"step_nav2": "स्टेप 2",
|
||||||
"step_nav3": "स्टेप 3",
|
"step_nav3": "स्टेप 3",
|
||||||
@@ -110,11 +124,11 @@ var languageOptions = {
|
|||||||
"step_nav6": "स्टेप 6",
|
"step_nav6": "स्टेप 6",
|
||||||
"h2": "अपना वीडियो यहां अपलोड करें:",
|
"h2": "अपना वीडियो यहां अपलोड करें:",
|
||||||
"labelSpeaker": "स्पीकर चुनें:",
|
"labelSpeaker": "स्पीकर चुनें:",
|
||||||
"labelSpeakerAudio": "चयनित वक्ता:",
|
"labelSpeakerAudio": "चयनित स्पीकर:",
|
||||||
"labelSpeakerWriter": "नाम लिखें:",
|
"labelSpeakerWriter": "नाम लिखें:",
|
||||||
"speakerLocker": "स्पीकर का नाम बदलें",
|
"speakerLocker": "स्पीकर का नाम बदलें",
|
||||||
"speakerResender": "दस्तावेज़ पुनः लिखें",
|
"speakerResender": "दस्तावेज़ फिर से लिखें",
|
||||||
"downloadButton": "डाउनलोड करना",
|
"downloadButton": "डाउनलोड करें",
|
||||||
"box1_p1": "---प्रारंभ---",
|
"box1_p1": "---प्रारंभ---",
|
||||||
"box2_p2": "---प्रतिलेखन---",
|
"box2_p2": "---प्रतिलेखन---",
|
||||||
"box3_p3": "---दस्तावेज़ निर्माण---",
|
"box3_p3": "---दस्तावेज़ निर्माण---",
|
||||||
@@ -127,10 +141,17 @@ var languageOptions = {
|
|||||||
"docName": "यहां दस्तावेज़ का नाम दर्ज करें",
|
"docName": "यहां दस्तावेज़ का नाम दर्ज करें",
|
||||||
"cd_promt": "आपका संकेत:",
|
"cd_promt": "आपका संकेत:",
|
||||||
"prompt": "अपने दस्तावेज़ के लिए प्रॉम्प्ट यहां टाइप करें...",
|
"prompt": "अपने दस्तावेज़ के लिए प्रॉम्प्ट यहां टाइप करें...",
|
||||||
"goBackBtn": "वापस करना",
|
"goBackBtn": "वापस जाएं",
|
||||||
"deleteBtn": "दस्तावेज़ हटाएँ",
|
"deleteBtn": "दस्तावेज़ हटाएं",
|
||||||
"generateBtn": "दस्तावेज़ सहेजें",
|
"generateBtn": "दस्तावेज़ सहेजें",
|
||||||
"newDoc": "-- नया दस्तावेज़ बनाएँ --"
|
"newDoc": "-- नया दस्तावेज़ बनाएं --",
|
||||||
|
|
||||||
|
"step1_h2" : "अपना वीडियो यहां अपलोड करें:",
|
||||||
|
"step2_h2" : "अपनी प्राथमिकताएँ चुनें:",
|
||||||
|
"step3_h2" : "पसंदीदा दस्तावेज़ शैली चुनें:",
|
||||||
|
"step4_h2" : "सबमिट करने के लिए क्लिक करें:",
|
||||||
|
"step5_h2" : "वक्ताओं के नाम बदलें:",
|
||||||
|
"step6_h2" : "अपना दस्तावेज़ डाउनलोड करने के लिए यहां क्लिक करें:"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import { app, BrowserWindow, ipcMain, dialog } from 'electron';
|
|
||||||
import { exec } from 'child_process';
|
|
||||||
import path from 'path';
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
|
|
||||||
let mainWindow;
|
|
||||||
|
|
||||||
function createWindow() {
|
|
||||||
mainWindow = new BrowserWindow({
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: false,
|
|
||||||
contextIsolation: true,
|
|
||||||
preload: path.join(__dirname, 'preload.js')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mainWindow.loadFile('main/index.html');
|
|
||||||
}
|
|
||||||
|
|
||||||
app.whenReady().then(createWindow);
|
|
||||||
|
|
||||||
// Kommunikation vom Renderer (Frontend)
|
|
||||||
ipcMain.handle('convert-video', async (event, filePath) => {
|
|
||||||
const output = path.join(path.dirname(filePath), 'converted.mp4');
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
exec(`ffmpeg -i "${filePath}" -vcodec libx264 "${output}"`, (error, stdout, stderr) => {
|
|
||||||
if (error) {
|
|
||||||
console.error('Fehler beim Konvertieren:', error);
|
|
||||||
reject(error);
|
|
||||||
} else {
|
|
||||||
console.log('Konvertierung abgeschlossen:', output);
|
|
||||||
resolve(output);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
+46
-58
@@ -133,22 +133,7 @@ Listeners for Step 3
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
window.api.getTxtFiles().then(files => {
|
|
||||||
var menu = document.getElementById('customDocumentTypes');
|
|
||||||
var l = document.getElementById('customDocumentTypes').options.length - 1;
|
|
||||||
for (i = l; i >= 0; i--) {
|
|
||||||
menu.remove(i);
|
|
||||||
}
|
|
||||||
files.forEach(file => {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = file;
|
|
||||||
option.textContent = file
|
|
||||||
.replace('.txt', '') // Endung entfernen
|
|
||||||
.replace(/_/g, ' ') // Leerzeichen ersetzen
|
|
||||||
.replace(/\b\w/g, c => c.toUpperCase()) // ersten Buchstaben groß
|
|
||||||
menu.appendChild(option);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
//Checkboxlistener so that only one can be selected at a time
|
//Checkboxlistener so that only one can be selected at a time
|
||||||
docFormat.addEventListener("change", (e) => {
|
docFormat.addEventListener("change", (e) => {
|
||||||
@@ -315,7 +300,6 @@ generateBtn.addEventListener("click", () => {
|
|||||||
const content = document.getElementById("prompt").value.trim();
|
const content = document.getElementById("prompt").value.trim();
|
||||||
if (!name || !content) {
|
if (!name || !content) {
|
||||||
result.textContent = "Bitte Dokumentname und Prompt ausfüllen.";
|
result.textContent = "Bitte Dokumentname und Prompt ausfüllen.";
|
||||||
console.log(name + " " + content);
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
result.textContent = "";
|
result.textContent = "";
|
||||||
}, 3000);
|
}, 3000);
|
||||||
@@ -332,60 +316,64 @@ generateBtn.addEventListener("click", () => {
|
|||||||
|
|
||||||
// dokumente löschen
|
// dokumente löschen
|
||||||
deleteBtn.addEventListener("click", () => {
|
deleteBtn.addEventListener("click", () => {
|
||||||
const name = docName.value.trim();
|
try {
|
||||||
|
const name = docName.value.trim();
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
result.textContent = "Bitte Dokumentname angeben.";
|
result.textContent = "Bitte Dokumentname angeben.";
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
result.textContent = "";
|
result.textContent = "";
|
||||||
}, 3000);
|
}, 3000);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const confirmDelete = confirm(
|
|
||||||
`Möchtest du das Dokument "${name}" wirklich löschen?`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!confirmDelete) return;
|
|
||||||
|
|
||||||
window.api.deleteTxtFile(name).then((success) => {
|
|
||||||
if (success) {
|
|
||||||
result.textContent = "Dokument erfolgreich gelöscht!";
|
|
||||||
reloadDocuments();
|
|
||||||
existingDocs.value = "newDoc";
|
|
||||||
existingDocs.dispatchEvent(new Event("change"));
|
|
||||||
} else {
|
|
||||||
result.textContent = "Dokument konnte nicht gelöscht werden.";
|
|
||||||
}
|
}
|
||||||
|
var success = true;
|
||||||
setTimeout(() => {
|
window.api.deleteTxtFile(name).then((success) => {
|
||||||
result.textContent = "";
|
if (success) {
|
||||||
}, 3000);
|
result.textContent = "Dokument erfolgreich gelöscht!";
|
||||||
});
|
reloadDocuments();
|
||||||
|
existingDocs.dispatchEvent(new Event("change"));
|
||||||
|
} else {
|
||||||
|
result.textContent = "Dokument konnte nicht gelöscht werden.";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
//function to load existingDoc options to the drop down list
|
//function to load existingDoc options to the drop down list
|
||||||
|
|
||||||
window.api.getTxtFiles().then(files => {
|
window.api.getTxtFiles().then(files => {
|
||||||
reloadDocuments();
|
try {
|
||||||
|
reloadDocuments();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//content anzeigen
|
//content anzeigen
|
||||||
existingDocs.addEventListener("change", async () => {
|
existingDocs.addEventListener("change", async () => {
|
||||||
const existingDocsed = existingDocs.value;
|
try {
|
||||||
const exampleText = "";
|
const existingDocsed = existingDocs.value;
|
||||||
|
const exampleText = "";
|
||||||
|
if (existingDocsed === "newDoc") {
|
||||||
|
docNameWrapper.classList.remove("hidden");
|
||||||
|
docName.value = "";
|
||||||
|
document.getElementById("prompt").value = exampleText;
|
||||||
|
document.getElementById("prompt").textContent = exampleText;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
docNameWrapper.classList.add("hidden");
|
||||||
|
document.getElementById("prompt").textContent = "";
|
||||||
|
document.getElementById("prompt").value = "";
|
||||||
|
|
||||||
if (existingDocsed === "newDoc") {
|
const content = await window.api.readTxtFile(existingDocsed);
|
||||||
docNameWrapper.classList.remove("hidden");
|
document.getElementById("prompt").value = content;
|
||||||
docName.value = "";
|
document.getElementById("prompt").textContent = content;
|
||||||
prompt.value = exampleText;
|
docName.value = existingDocsed.replace(".txt", "");
|
||||||
return;
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
}
|
}
|
||||||
docNameWrapper.classList.add("hidden");
|
|
||||||
|
|
||||||
const content = await window.api.readTxtFile(existingDocsed);
|
|
||||||
prompt.value = content;
|
|
||||||
docName.value = existingDocsed.replace(".txt", "");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+73
-31
@@ -27,12 +27,11 @@ function showCD() {
|
|||||||
//language changing feature => changes the language of every displayed text
|
//language changing feature => changes the language of every displayed text
|
||||||
function changeLanguage(language) {
|
function changeLanguage(language) {
|
||||||
try {
|
try {
|
||||||
//document.getElementById('labelLanguageFlag').src = languageOptions[language].flagPath;
|
|
||||||
document.getElementById('labelKI').textContent = languageOptions[language].labelKI;
|
document.getElementById('labelKI').textContent = languageOptions[language].labelKI;
|
||||||
document.getElementById('labelTranscription').textContent = languageOptions[language].labelTranscription;
|
document.getElementById('labelTranscription').textContent = languageOptions[language].labelTranscription;
|
||||||
document.getElementById('labelLanguage').textContent = languageOptions[language].labelLanguage;
|
document.getElementById('labelLanguage').textContent = languageOptions[language].labelLanguage;
|
||||||
document.getElementById('title').textContent = languageOptions[language].title;
|
document.getElementById('title').textContent = languageOptions[language].title;
|
||||||
//document.getElementById('h1').textContent = languageOptions[language].h1;
|
document.getElementById('h1').textContent = languageOptions[language].h1;
|
||||||
document.getElementById('p1').textContent = languageOptions[language].p1;
|
document.getElementById('p1').textContent = languageOptions[language].p1;
|
||||||
document.getElementById('fileName').textContent = languageOptions[language].fileName;
|
document.getElementById('fileName').textContent = languageOptions[language].fileName;
|
||||||
document.getElementById('manualUploadBtn').textContent = languageOptions[language].manualUploadBtn;
|
document.getElementById('manualUploadBtn').textContent = languageOptions[language].manualUploadBtn;
|
||||||
@@ -45,7 +44,6 @@ function changeLanguage(language) {
|
|||||||
document.getElementById('step_nav4').textContent = languageOptions[language].step_nav4;
|
document.getElementById('step_nav4').textContent = languageOptions[language].step_nav4;
|
||||||
document.getElementById('step_nav5').textContent = languageOptions[language].step_nav5;
|
document.getElementById('step_nav5').textContent = languageOptions[language].step_nav5;
|
||||||
document.getElementById('step_nav6').textContent = languageOptions[language].step_nav6;
|
document.getElementById('step_nav6').textContent = languageOptions[language].step_nav6;
|
||||||
//document.getElementById('h2').textContent = languageOptions[language].h2;
|
|
||||||
document.getElementById('labelSpeaker').textContent = languageOptions[language].labelSpeaker;
|
document.getElementById('labelSpeaker').textContent = languageOptions[language].labelSpeaker;
|
||||||
document.getElementById('labelSpeakerAudio').textContent = languageOptions[language].labelSpeakerAudio;
|
document.getElementById('labelSpeakerAudio').textContent = languageOptions[language].labelSpeakerAudio;
|
||||||
document.getElementById('labelSpeakerWriter').textContent = languageOptions[language].labelSpeakerWriter;
|
document.getElementById('labelSpeakerWriter').textContent = languageOptions[language].labelSpeakerWriter;
|
||||||
@@ -69,6 +67,13 @@ function changeLanguage(language) {
|
|||||||
document.getElementById('generateBtn').textContent = languageOptions[language].generateBtn;
|
document.getElementById('generateBtn').textContent = languageOptions[language].generateBtn;
|
||||||
document.getElementById('newDoc').textContent = languageOptions[language].newDoc;
|
document.getElementById('newDoc').textContent = languageOptions[language].newDoc;
|
||||||
|
|
||||||
|
document.getElementById("step1_h2").textContent = languageOptions[language].step1_h2;
|
||||||
|
document.getElementById("step2_h2").textContent = languageOptions[language].step2_h2;
|
||||||
|
document.getElementById("step3_h2").textContent = languageOptions[language].step3_h2;
|
||||||
|
document.getElementById("step4_h2").textContent = languageOptions[language].step4_h2;
|
||||||
|
document.getElementById("step5_h2").textContent = languageOptions[language].step5_h2;
|
||||||
|
document.getElementById("step6_h2").textContent = languageOptions[language].step6_h2;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in script.js changeLanguage function");
|
console.log("Error in script.js changeLanguage function");
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@@ -89,6 +94,10 @@ let currentStep = 1;
|
|||||||
const totalSteps = steps.length;
|
const totalSteps = steps.length;
|
||||||
|
|
||||||
function showStep(stepNumber) {
|
function showStep(stepNumber) {
|
||||||
|
if(showCDValue == 1){
|
||||||
|
showCDValue = 0;
|
||||||
|
document.getElementById('cdContainer').style.display = "none";
|
||||||
|
}
|
||||||
if (stepNumber < 1 || stepNumber > totalSteps) {
|
if (stepNumber < 1 || stepNumber > totalSteps) {
|
||||||
console.error("StepNumber out of Bounds", stepNumber);
|
console.error("StepNumber out of Bounds", stepNumber);
|
||||||
return;
|
return;
|
||||||
@@ -432,19 +441,30 @@ function setSpeakerAudiosValue(valy) {
|
|||||||
//Function to rewrite the speaker name in the json
|
//Function to rewrite the speaker name in the json
|
||||||
function rewriteSpeakerName() {
|
function rewriteSpeakerName() {
|
||||||
try {
|
try {
|
||||||
var tempy = document.getElementById("cur_speaker").value;
|
const select = document.getElementById("cur_speaker");
|
||||||
speakerAudios[tempy].name = document.getElementById("newSpeaker").value;
|
const newName = document.getElementById("newSpeaker").value.trim();
|
||||||
loadSpeakerOptions(speakerAudios);
|
|
||||||
|
if (!newName) {
|
||||||
|
alert("Please enter a new speaker name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedIndex = select.selectedIndex;
|
||||||
|
const selectedValue = select.value;
|
||||||
|
|
||||||
|
// Update speakerAudios data
|
||||||
|
speakerAudios[selectedValue].name = newName;
|
||||||
|
|
||||||
|
// Update the specific option text and keep value
|
||||||
|
select.options[selectedIndex].text = newName;
|
||||||
|
select.options[selectedIndex].value = selectedValue;
|
||||||
|
|
||||||
|
// Keep it selected
|
||||||
|
select.selectedIndex = selectedIndex;
|
||||||
|
|
||||||
|
console.log("Speaker renamed:", newName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("\n\n\n" + error + "\n\n\n")
|
console.log("Error renaming speaker:", error);
|
||||||
}
|
|
||||||
}
|
|
||||||
//Function to send the json with the given names back to the program to rewrite the document file
|
|
||||||
function sendSpeakerPackages() {
|
|
||||||
try {
|
|
||||||
window.submitSpeaker.speaker_submit(speakerAudios);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,10 +482,6 @@ function fileDownload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Functions for the custom document section
|
Functions for the custom document section
|
||||||
@@ -474,18 +490,44 @@ Functions for the custom document section
|
|||||||
|
|
||||||
//reload drop down
|
//reload drop down
|
||||||
function reloadDocuments() {
|
function reloadDocuments() {
|
||||||
[...existingDocs.querySelectorAll('option:not([value="newDoc"])')]
|
try{
|
||||||
.forEach(o => o.remove());
|
[...existingDocs.querySelectorAll('option:not([value="newDoc"])')]
|
||||||
|
.forEach(o => o.remove());
|
||||||
|
[...customDocumentTypes.querySelectorAll('option:not([value="newDoc"])')]
|
||||||
|
.forEach(o => o.remove());
|
||||||
|
|
||||||
window.api.getTxtFiles().then(files => {
|
window.api.getTxtFiles().then(files => {
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const option = document.createElement('option');
|
var option = document.createElement('option');
|
||||||
option.value = file;
|
option.value = file;
|
||||||
option.textContent = file
|
option.textContent = file
|
||||||
.replace('.txt', '') // Endung entfernen
|
.replace('.txt', '') // Endung entfernen
|
||||||
.replace(/_/g, ' ') // Leerzeichen ersetzen
|
.replace(/_/g, ' ') // Leerzeichen ersetzen
|
||||||
.replace(/\b\w/g, c => c.toUpperCase()) // ersten Buchstaben groß
|
.replace(/\b\w/g, c => c.toUpperCase()); // ersten Buchstaben groß
|
||||||
existingDocs.appendChild(option);
|
existingDocs.appendChild(option);
|
||||||
|
var option2 = document.createElement('option');
|
||||||
|
option2.value = file;
|
||||||
|
option2.name = file;
|
||||||
|
option2.textContent = file
|
||||||
|
.replace('.txt', '') // Endung entfernen
|
||||||
|
.replace(/_/g, ' ') // Leerzeichen ersetzen
|
||||||
|
.replace(/\b\w/g, c => c.toUpperCase()); // ersten Buchstaben groß
|
||||||
|
customDocumentTypes.appendChild(option2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
catch(error){
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendSpeakerPackages() {
|
||||||
|
try {
|
||||||
|
window.submitSpeaker.speaker_submit(speakerAudios);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.sendSpeakerPackages = sendSpeakerPackages;
|
||||||
+127
-23
@@ -11,12 +11,12 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#h1 {
|
#h1 {
|
||||||
position: absolute;
|
position: static;
|
||||||
left: 50%;
|
transform: none;
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#h1-wrapper {
|
#h1-wrapper {
|
||||||
@@ -30,6 +30,26 @@ body {
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gui-language {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
z-index: 100;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#language_option {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-container {
|
.upload-container {
|
||||||
@@ -85,7 +105,6 @@ body {
|
|||||||
#previewThumbnail {
|
#previewThumbnail {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
/*border: 1px dashed black;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-btn {
|
.custom-btn {
|
||||||
@@ -108,8 +127,9 @@ body {
|
|||||||
background-color: #0056b3;
|
background-color: #0056b3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#step2 {
|
.step h2 {
|
||||||
gap: 25px;
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.KI-wrapper {
|
.KI-wrapper {
|
||||||
@@ -356,7 +376,10 @@ input[type="file"] {
|
|||||||
#ai_type,
|
#ai_type,
|
||||||
#transkript_type,
|
#transkript_type,
|
||||||
#language_option {
|
#language_option {
|
||||||
padding: 3px;
|
padding: 8px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.labelDiv {
|
.labelDiv {
|
||||||
@@ -404,7 +427,6 @@ input[type="file"] {
|
|||||||
.step {
|
.step {
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 425px;
|
min-height: 425px;
|
||||||
@@ -473,7 +495,6 @@ li {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.p-menu1 {
|
.p-menu1 {
|
||||||
margin-left: 20px;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,7 +600,27 @@ li {
|
|||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
#step2,
|
|
||||||
|
|
||||||
|
#step2 {
|
||||||
|
font-size: larger;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step2-form {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 420px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px; /* DAS ist dein Spacing */
|
||||||
|
}
|
||||||
|
|
||||||
|
.step2-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
#step3,
|
#step3,
|
||||||
#step5 {
|
#step5 {
|
||||||
font-size: larger;
|
font-size: larger;
|
||||||
@@ -590,7 +631,7 @@ li {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#step5 {
|
#step5 {
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.button-group {
|
||||||
@@ -614,27 +655,84 @@ li {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h2 {
|
||||||
|
font-size: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.speaker-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 700px;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speaker-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speaker-table tbody tr {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-cell {
|
||||||
|
flex: 0 0 150px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-cell label {
|
||||||
|
font-weight: 400;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-cell {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cur_speaker,
|
||||||
|
#newSpeaker {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 14px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#speakerAudioViewer {
|
||||||
|
width: 100%;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speaker-button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
#speakerLocker,
|
#speakerLocker,
|
||||||
#speakerResender {
|
#speakerResender {
|
||||||
padding: 10px 20px;
|
padding: 12px 25px;
|
||||||
margin: 20px auto;
|
|
||||||
background-color: #007BFF;
|
background-color: #007BFF;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h2 {
|
#speakerLocker:hover,
|
||||||
font-size: 25px;
|
#speakerResender:hover {
|
||||||
}
|
background-color: #0056b3;
|
||||||
|
|
||||||
.speakerView,
|
|
||||||
.speakerAudio,
|
|
||||||
.speakerWrite {
|
|
||||||
margin-top: auto;
|
|
||||||
margin-bottom: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@@ -703,3 +801,9 @@ button:hover {
|
|||||||
color: #333;
|
color: #333;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container input,
|
||||||
|
.container textarea,
|
||||||
|
.container select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@@ -168,9 +168,39 @@ electron.ipcMain.on("file_submit", async (event, args) => {
|
|||||||
throw new Error("Unknown document type: " + args.document.type);
|
throw new Error("Unknown document type: " + args.document.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(args);
|
electron.ipcMain.on("file_download", async (event) => {
|
||||||
let audiopath = "";
|
try {
|
||||||
let transcriptpath = "";
|
if (!globalFinalHtmlPath) {
|
||||||
|
throw new Error("No document generated yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
const format = String(globalArgs?.document?.outputType || "")
|
||||||
|
.replace('.', '')
|
||||||
|
.toLowerCase();
|
||||||
|
|
||||||
|
if (!format) {
|
||||||
|
throw new Error("No output format selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputPath = await mapFunctions
|
||||||
|
.get("htmlDocumentConverter")
|
||||||
|
.convert({
|
||||||
|
inputPath: globalFinalHtmlPath,
|
||||||
|
format,
|
||||||
|
showDialog: true
|
||||||
|
});
|
||||||
|
|
||||||
|
event.sender.send("download_success", {
|
||||||
|
path: outputPath,
|
||||||
|
format
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("file_download failed:", err);
|
||||||
|
|
||||||
|
event.sender.send("error", err.message || String(err));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
console.log("\n\n Running the Video to Audio Extractor");
|
console.log("\n\n Running the Video to Audio Extractor");
|
||||||
// This code handles the Video to Audio extraction module call
|
// This code handles the Video to Audio extraction module call
|
||||||
@@ -286,16 +316,6 @@ electron.ipcMain.on("file_submit", async (event, args) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
electron.ipcMain.on("file_download", async () => {
|
|
||||||
await mapFunctions
|
|
||||||
.get("htmlDocumentConverter")
|
|
||||||
.convert({
|
|
||||||
inputPath: globalFinalHtmlPath,
|
|
||||||
format: globalArgs.document.outputType,
|
|
||||||
showDialog: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
electron.ipcMain.on("speaker_submit", async (event, args) => {
|
electron.ipcMain.on("speaker_submit", async (event, args) => {
|
||||||
console.log("\n\n\nJa also hier kam was an \n\n\n");
|
console.log("\n\n\nJa also hier kam was an \n\n\n");
|
||||||
console.log(args);
|
console.log(args);
|
||||||
|
|||||||
+192
-153
@@ -1,35 +1,37 @@
|
|||||||
const fs = require('fs');
|
const fs = require("fs");
|
||||||
const path = require('path');
|
const path = require("path");
|
||||||
const puppeteer = require('puppeteer');
|
const puppeteer = require("puppeteer");
|
||||||
const htmlToDocx = require('html-to-docx');
|
const htmlToDocx = require("html-to-docx");
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = require("child_process");
|
||||||
const os = require('os');
|
const os = require("os");
|
||||||
|
|
||||||
const outputDir = path.join(__dirname, "../../../storage/documents");
|
const outputDir = path.join(__dirname, "../../../storage/documents");
|
||||||
|
|
||||||
if (!fs.existsSync(outputDir)) {
|
if (!fs.existsSync(outputDir)) {
|
||||||
fs.mkdirSync(outputDir, { recursive: true });
|
fs.mkdirSync(outputDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showSaveDialog(defaultName, format) {
|
async function showSaveDialog(defaultName, format) {
|
||||||
const platform = os.platform();
|
const platform = os.platform();
|
||||||
|
|
||||||
if (platform === 'darwin') {
|
if (platform === "darwin") {
|
||||||
// macOS
|
// macOS
|
||||||
const applescript = `
|
const applescript = `
|
||||||
set defaultName to "${defaultName}.${format}"
|
set defaultName to "${defaultName}.${format}"
|
||||||
set theFile to choose file name with prompt "Dokument speichern als:" default name defaultName
|
set theFile to choose file name with prompt "Dokument speichern als:" default name defaultName
|
||||||
POSIX path of theFile
|
POSIX path of theFile
|
||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = execSync(`osascript -e '${applescript}'`, { encoding: 'utf8' });
|
const result = execSync(`osascript -e '${applescript}'`, {
|
||||||
return result.trim();
|
encoding: "utf8",
|
||||||
} catch (err) {
|
});
|
||||||
if (err.status === 1) return null; // User canceled
|
return result.trim();
|
||||||
throw err;
|
} catch (err) {
|
||||||
}
|
if (err.status === 1) return null; // User canceled
|
||||||
} else if (platform === 'win32') {
|
throw err;
|
||||||
|
}
|
||||||
|
} else if (platform === "win32") {
|
||||||
const safeName = decodeURIComponent(defaultName);
|
const safeName = decodeURIComponent(defaultName);
|
||||||
|
|
||||||
const powershell = `
|
const powershell = `
|
||||||
@@ -43,155 +45,192 @@ async function showSaveDialog(defaultName, format) {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = execSync(
|
const result = execSync(
|
||||||
`powershell -NoProfile -Command "${powershell.replace(/\r?\n/g, ' ')}"`,
|
`powershell -NoProfile -Command "${powershell.replace(/\r?\n/g, " ")}"`,
|
||||||
{ encoding: 'utf8' }
|
{ encoding: "utf8" },
|
||||||
);
|
);
|
||||||
return result.trim() || null;
|
return result.trim() || null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.status === 1) return null; // User cancelled
|
if (err.status === 1) return null; // User cancelled
|
||||||
throw new Error("Save dialog failed: " + err.message);
|
throw new Error("Save dialog failed: " + err.message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Linux - zenity oder kdialog
|
// Linux - zenity oder kdialog
|
||||||
try {
|
try {
|
||||||
const result = execSync(
|
const result = execSync(
|
||||||
`zenity --file-selection --save --confirm-overwrite --filename="${defaultName}.${format}"`,
|
`zenity --file-selection --save --confirm-overwrite --filename="${defaultName}.${format}"`,
|
||||||
{ encoding: 'utf8' }
|
{ encoding: "utf8" },
|
||||||
);
|
);
|
||||||
return result.trim();
|
return result.trim();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
try {
|
try {
|
||||||
const result = execSync(
|
const result = execSync(
|
||||||
`kdialog --getsavefilename . "${defaultName}.${format}"`,
|
`kdialog --getsavefilename . "${defaultName}.${format}"`,
|
||||||
{ encoding: 'utf8' }
|
{ encoding: "utf8" },
|
||||||
);
|
);
|
||||||
return result.trim();
|
return result.trim();
|
||||||
} catch (err2) {
|
} catch (err2) {
|
||||||
// Fallback
|
// Fallback
|
||||||
return path.join(os.homedir(), 'Downloads', `${defaultName}.${format}`);
|
return path.join(os.homedir(), "Downloads", `${defaultName}.${format}`);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const module_exports = {
|
const module_exports = {
|
||||||
name: "htmlDocumentConverter",
|
name: "htmlDocumentConverter",
|
||||||
type: "converter",
|
type: "converter",
|
||||||
displayname: "HTML Document Converter",
|
displayname: "HTML Document Converter",
|
||||||
description: "Converts LLM-generated HTML to PDF, DOCX, TXT, or HTML",
|
description: "Converts LLM-generated HTML to PDF, DOCX, TXT, or HTML",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main conversion function
|
* Main conversion function
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @param {string} options.inputPath - Path to the HTML input
|
* @param {string} options.inputPath - Path to the HTML input
|
||||||
* @param {string} options.format - 'pdf' | 'docx' | 'html' | 'txt'
|
* @param {string} options.format - 'pdf' | 'docx' | 'html' | 'txt'
|
||||||
* @param {string} [options.outputName] - Optional output filename (without extension)
|
* @param {string} [options.outputName] - Optional output filename (without extension)
|
||||||
* @param {boolean} [options.showDialog] - Show save dialog (default: false in module mode, true in CLI mode)
|
* @param {boolean} [options.showDialog] - Show save dialog (default: false in module mode, true in CLI mode)
|
||||||
*/
|
*/
|
||||||
async convert({ inputPath, format = 'pdf', outputName, showDialog = false }) {
|
async convert({ inputPath, format = "pdf", outputName, showDialog = false }) {
|
||||||
if (!fs.existsSync(inputPath)) {
|
format = format.toLowerCase().replace(".", ""); // <-- FIX
|
||||||
throw new Error(`Input file not found: ${inputPath}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ext = path.extname(inputPath).toLowerCase();
|
if (!["pdf", "docx", "html", "txt"].includes(format)) {
|
||||||
const baseName = outputName || path.basename(inputPath, ext);
|
throw new Error(`Unsupported format: ${format}`);
|
||||||
|
|
||||||
let outputFile;
|
|
||||||
|
|
||||||
if (showDialog) {
|
|
||||||
// Zeige nativen Dialog
|
|
||||||
outputFile = await showSaveDialog(baseName, format);
|
|
||||||
if (!outputFile) {
|
|
||||||
console.log('Speichervorgang abgebrochen.');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Nutze Standard-Ausgabeverzeichnis
|
|
||||||
outputFile = path.join(outputDir, `${baseName}.${format.toLowerCase()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let htmlContent = fs.readFileSync(inputPath, 'utf8');
|
|
||||||
|
|
||||||
// Remove <think> tags if present
|
|
||||||
htmlContent = htmlContent.replace(/<think>[\s\S]*?<\/think>/gi, '');
|
|
||||||
|
|
||||||
switch (format.toLowerCase()) {
|
|
||||||
case 'html':
|
|
||||||
fs.writeFileSync(outputFile, htmlContent, 'utf8');
|
|
||||||
break;
|
|
||||||
case 'pdf':
|
|
||||||
await this.htmlToPDF(htmlContent, outputFile);
|
|
||||||
break;
|
|
||||||
case 'docx':
|
|
||||||
await this.htmlToDOCX(htmlContent, outputFile);
|
|
||||||
break;
|
|
||||||
case 'txt':
|
|
||||||
fs.writeFileSync(outputFile, this.htmlToTXT(htmlContent), 'utf8');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(`Unsupported format: ${format}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Erfolgreich gespeichert: ${outputFile}`);
|
|
||||||
return outputFile;
|
|
||||||
},
|
|
||||||
|
|
||||||
// HTML → PDF
|
|
||||||
async htmlToPDF(html, outputPath) {
|
|
||||||
const browser = await puppeteer.launch({
|
|
||||||
headless: true,
|
|
||||||
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
|
||||||
});
|
|
||||||
const page = await browser.newPage();
|
|
||||||
await page.setContent(html, { waitUntil: 'networkidle0' });
|
|
||||||
await page.pdf({
|
|
||||||
path: outputPath,
|
|
||||||
format: 'A4',
|
|
||||||
printBackground: true,
|
|
||||||
margin: { top: '20mm', right: '20mm', bottom: '20mm', left: '20mm' }
|
|
||||||
});
|
|
||||||
await browser.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
// HTML → DOCX
|
|
||||||
async htmlToDOCX(html, outputPath) {
|
|
||||||
const buffer = await htmlToDocx(html);
|
|
||||||
fs.writeFileSync(outputPath, buffer);
|
|
||||||
},
|
|
||||||
|
|
||||||
// HTML → TXT (rudimentär)
|
|
||||||
htmlToTXT(html) {
|
|
||||||
return html.replace(/<[^>]*>/g, '').replace(/\s+\n/g, '\n').trim();
|
|
||||||
}
|
}
|
||||||
|
if (!fs.existsSync(inputPath)) {
|
||||||
|
throw new Error(`Input file not found: ${inputPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ext = path.extname(inputPath).toLowerCase();
|
||||||
|
const baseName = outputName || path.basename(inputPath, ext);
|
||||||
|
|
||||||
|
let outputFile;
|
||||||
|
|
||||||
|
if (showDialog) {
|
||||||
|
// Zeige nativen Dialog
|
||||||
|
outputFile = await showSaveDialog(baseName, format);
|
||||||
|
if (!outputFile) {
|
||||||
|
console.log("Speichervorgang abgebrochen.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Nutze Standard-Ausgabeverzeichnis
|
||||||
|
outputFile = path.join(outputDir, `${baseName}.${format.toLowerCase()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlContent = fs.readFileSync(inputPath, "utf8");
|
||||||
|
|
||||||
|
// Remove <think> tags if present
|
||||||
|
htmlContent = htmlContent.replace(/<think>[\s\S]*?<\/think>/gi, "");
|
||||||
|
|
||||||
|
switch (format.toLowerCase()) {
|
||||||
|
case "html":
|
||||||
|
fs.writeFileSync(outputFile, htmlContent, "utf8");
|
||||||
|
break;
|
||||||
|
case "pdf":
|
||||||
|
await this.htmlToPDF(htmlContent, outputFile);
|
||||||
|
break;
|
||||||
|
case "docx":
|
||||||
|
await this.htmlToDOCX(htmlContent, outputFile);
|
||||||
|
break;
|
||||||
|
case "txt":
|
||||||
|
fs.writeFileSync(outputFile, this.htmlToTXT(htmlContent), "utf8");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported format: ${format}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Erfolgreich gespeichert: ${outputFile}`);
|
||||||
|
return outputFile;
|
||||||
|
},
|
||||||
|
|
||||||
|
// HTML → PDF
|
||||||
|
async htmlToPDF(html, outputPath) {
|
||||||
|
let browser;
|
||||||
|
try {
|
||||||
|
browser = await puppeteer.launch({
|
||||||
|
headless: true,
|
||||||
|
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.setContent(html, { waitUntil: "networkidle0" });
|
||||||
|
await page.pdf({
|
||||||
|
path: outputPath,
|
||||||
|
format: "A4",
|
||||||
|
printBackground: true,
|
||||||
|
margin: {
|
||||||
|
top: "20mm",
|
||||||
|
right: "20mm",
|
||||||
|
bottom: "20mm",
|
||||||
|
left: "20mm",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
if (browser) {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// HTML → DOCX
|
||||||
|
async htmlToDOCX(html, outputPath) {
|
||||||
|
try {
|
||||||
|
// html‑to‑docx library converts HTML string into a Word .docx buffer
|
||||||
|
// Usage from html‑to‑docx docs:
|
||||||
|
// await HTMLtoDOCX(htmlString, headerHTMLString, documentOptions, footerHTMLString) [oai_citation:0‡GitHub](https://github.com/privateOmega/html-to-docx?utm_source=chatgpt.com)
|
||||||
|
const buffer = await htmlToDocx(html, null, {
|
||||||
|
table: { row: { cantSplit: true } },
|
||||||
|
});
|
||||||
|
fs.writeFileSync(outputPath, buffer);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`DOCX conversion failed: ${err.message}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// HTML → TXT
|
||||||
|
htmlToTXT(html) {
|
||||||
|
// A decent plain text conversion: strip tags and collapse whitespace
|
||||||
|
// If you want more advanced extraction consider using a library like `html-to-text` or `strip-html` [oai_citation:1‡GitHub](https://github.com/html-to-text/node-html-to-text?utm_source=chatgpt.com)
|
||||||
|
return (
|
||||||
|
html
|
||||||
|
// Remove all tags
|
||||||
|
.replace(/<[^>]+>/g, "")
|
||||||
|
// Convert multiple whitespace into single spaces
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim()
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = module_exports;
|
module.exports = module_exports;
|
||||||
|
|
||||||
// CLI usage mit Dialog
|
// CLI usage mit Dialog
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
(async () => {
|
(async () => {
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
console.log('Usage: node htmlDocumentConverter.js <input.html> [format]');
|
console.log("Usage: node htmlDocumentConverter.js <input.html> [format]");
|
||||||
console.log('Formats: pdf (default), docx, html, txt');
|
console.log("Formats: pdf (default), docx, html, txt");
|
||||||
console.log('');
|
console.log("");
|
||||||
console.log('Ein nativer "Speichern unter" Dialog wird automatisch geöffnet.');
|
console.log(
|
||||||
process.exit(1);
|
'Ein nativer "Speichern unter" Dialog wird automatisch geöffnet.',
|
||||||
}
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
const inputPath = args[0];
|
const inputPath = args[0];
|
||||||
const format = args[1] || 'pdf';
|
const format = args[1] || "pdf";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await module_exports.convert({
|
await module_exports.convert({
|
||||||
inputPath,
|
inputPath,
|
||||||
format,
|
format,
|
||||||
showDialog: true
|
showDialog: true,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Konvertierung fehlgeschlagen:', err.message);
|
console.error("Konvertierung fehlgeschlagen:", err.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
// -----------------------------------------------------------
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
# -----------------------------------------------------------
|
|
||||||
# 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)
|
|
||||||
Reference in New Issue
Block a user