From c1fbcdf6b156ddb64ce7ce539543b747435b3d7e Mon Sep 17 00:00:00 2001 From: balex Date: Sat, 28 Feb 2026 19:44:58 +0100 Subject: [PATCH] initial commit --- .env.example | 2 + .gitignore | 3 + Dockerfile | 7 + README.md | 130 +++++ generate-audio.js | 209 +++++++ package-lock.json | 830 +++++++++++++++++++++++++++ package.json | 16 + src/public/favicon-192.png | Bin 0 -> 13685 bytes src/public/favicon-32.png | Bin 0 -> 1326 bytes src/public/favicon-512.png | Bin 0 -> 46143 bytes src/public/favicon.svg | 34 ++ src/public/index.html | 1112 ++++++++++++++++++++++++++++++++++++ src/server.js | 79 +++ 13 files changed, 2422 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 generate-audio.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/public/favicon-192.png create mode 100644 src/public/favicon-32.png create mode 100644 src/public/favicon-512.png create mode 100644 src/public/favicon.svg create mode 100644 src/public/index.html create mode 100644 src/server.js diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..706674a --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +ANTHROPIC_API_KEY=your-key-here +PORT=8083 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d70f259 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.env +src/public/audio/*.mp3 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f37220a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM node:22-alpine +WORKDIR /app +COPY package*.json ./ +RUN npm ci --production +COPY src/ ./src/ +EXPOSE 8083 +CMD ["node", "src/server.js"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..f184ea9 --- /dev/null +++ b/README.md @@ -0,0 +1,130 @@ +# audio-foreign + +<<<<<<< HEAD +German conversation practice app with speech recognition and AI feedback. + +## Quick start + +```bash +cp .env.example .env +# Add your ANTHROPIC_API_KEY to .env + +npm install +npm start +# → http://localhost:8083 +``` + +## Docker + +```bash +docker build -t audio-foreign . +docker run -p 8083:8083 --env-file .env audio-foreign +``` + +## Features + +- 6 topics × 10 questions each +- Web Speech API — speech synthesis (de-DE) + real-time recognition +- AI feedback via Claude (grammar, style, vocabulary) — response in Russian +- Level selector: A2 / B1 / B2 +- Session history (in-memory) +- Dark theme, mobile-first + +## Stack + +- Node.js 22 + Express (single dependency) +- Vanilla JS SPA (no frameworks) +- Anthropic Claude API (server-side only) +======= + + +## Getting started + +To make it easy for you to get started with GitLab, here's a list of recommended next steps. + +Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! + +## Add your files + +* [Create](https://docs.gitlab.com/user/project/repository/web_editor/#create-a-file) or [upload](https://docs.gitlab.com/user/project/repository/web_editor/#upload-a-file) files +* [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command: + +``` +cd existing_repo +git remote add origin https://gitlab.com/mirage74-group/audio-foreign.git +git branch -M main +git push -uf origin main +``` + +## Integrate with your tools + +* [Set up project integrations](https://gitlab.com/mirage74-group/audio-foreign/-/settings/integrations) + +## Collaborate with your team + +* [Invite team members and collaborators](https://docs.gitlab.com/user/project/members/) +* [Create a new merge request](https://docs.gitlab.com/user/project/merge_requests/creating_merge_requests/) +* [Automatically close issues from merge requests](https://docs.gitlab.com/user/project/issues/managing_issues/#closing-issues-automatically) +* [Enable merge request approvals](https://docs.gitlab.com/user/project/merge_requests/approvals/) +* [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/) + +## Test and Deploy + +Use the built-in continuous integration in GitLab. + +* [Get started with GitLab CI/CD](https://docs.gitlab.com/ci/quick_start/) +* [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/user/application_security/sast/) +* [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/topics/autodevops/requirements/) +* [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/user/clusters/agent/) +* [Set up protected environments](https://docs.gitlab.com/ci/environments/protected_environments/) + +*** + +# Editing this README + +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. + +## Suggestions for a good README + +Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. + +## Name +Choose a self-explaining name for your project. + +## Description +Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. + +## Badges +On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. + +## Visuals +Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. + +## Installation +Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. + +## Usage +Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. + +## Support +Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. + +## Roadmap +If you have ideas for releases in the future, it is a good idea to list them in the README. + +## Contributing +State if you are open to contributions and what your requirements are for accepting them. + +For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. + +You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. + +## Authors and acknowledgment +Show your appreciation to those who have contributed to the project. + +## License +For open source projects, say how it is licensed. + +## Project status +If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +>>>>>>> 46b082d869bd049e04a5c3fdb6e5ca31ffd86f77 diff --git a/generate-audio.js b/generate-audio.js new file mode 100644 index 0000000..ec3de76 --- /dev/null +++ b/generate-audio.js @@ -0,0 +1,209 @@ +#!/usr/bin/env node + +/** + * Generate MP3 audio files for all German questions using ElevenLabs TTS API. + * + * Usage: + * 1. Get your API key from https://elevenlabs.io/app/settings/api-keys + * 2. Run: ELEVENLABS_API_KEY=your-key-here node generate-audio.js + * + * Output: src/public/audio/_.mp3 + * + * Free tier: ~10,000 characters/month — enough for all 60 questions (~2,500 chars total). + */ + +const fs = require("fs"); +const path = require("path"); + +const API_KEY = process.env.ELEVENLABS_API_KEY; +if (!API_KEY) { + console.error("Error: set ELEVENLABS_API_KEY environment variable"); + console.error(" ELEVENLABS_API_KEY=your-key node generate-audio.js"); + process.exit(1); +} + +// Same questions as in index.html +const TOPICS = [ + { + id: "alltag", + questions: [ + "Wie sieht dein typischer Morgen aus?", + "Was machst du normalerweise in deiner Freizeit?", + "Wie oft kochst du zu Hause und was bereitest du gerne zu?", + "Beschreibe deinen Tagesablauf an einem Werktag.", + "Welche Aufgaben im Haushalt magst du und welche nicht?", + "Wie verbringst du deinen Feierabend?", + "Machst du regelmäßig Sport? Was und wie oft?", + "Wie oft triffst du dich mit Freunden oder Familie?", + "Was liest du gerne – Bücher, Zeitungen oder Online-Artikel?", + "Wie entspannst du dich nach einem stressigen Tag?", + ], + }, + { + id: "arbeit", + questions: [ + "Was machst du beruflich und was gefällt dir an deiner Arbeit?", + "Wie sieht dein Arbeitsplatz aus – Büro, Homeoffice oder beides?", + "Was sind die größten Herausforderungen in deinem Job?", + "Wie lange arbeitest du täglich und wie ist die Work-Life-Balance?", + "Hast du nette Kollegen? Wie ist das Arbeitsklima?", + "Welche Fähigkeiten brauchst du für deinen Beruf?", + "Was würdest du beruflich ändern, wenn du könntest?", + "Wie wichtig ist Karriere für dich im Vergleich zu Freizeit?", + "Hast du schon mal den Job gewechselt? Warum?", + "Was sind deine beruflichen Ziele für die Zukunft?", + ], + }, + { + id: "reisen", + questions: [ + "Wohin bist du zuletzt gereist und wie war es?", + "Reist du lieber alleine oder mit anderen? Warum?", + "Was ist dein Traumreiseziel und warum?", + "Bevorzugst du Strand, Berge oder Städtereisen?", + "Wie planst du normalerweise deine Reisen?", + "Was nimmst du immer mit auf Reisen?", + "Hast du schon mal einen Kulturschock erlebt?", + "Welches Essen aus einem anderen Land hat dir besonders gefallen?", + "Wie wichtig ist es für dich, die Landessprache zu kennen?", + "Erzähl von einem unvergesslichen Reiseerlebnis.", + ], + }, + { + id: "schweiz", + questions: [ + "Was magst du am Leben in der Schweiz besonders?", + "Wie unterscheidet sich das Schweizerdeutsch vom Hochdeutsch?", + "Was sind typisch schweizerische Gewohnheiten oder Traditionen?", + "Welche Sehenswürdigkeiten in Bern kennst du?", + "Was ist das Besondere am schweizerischen Bildungssystem?", + "Wie ist das öffentliche Verkehrsnetz in der Schweiz?", + "Was denkst du über die Mehrsprachigkeit in der Schweiz?", + "Welche Schweizer Gerichte kennst du und magst du?", + "Wie erleben Ausländer das Einleben in der Schweiz?", + "Was sind Vor- und Nachteile der direkten Demokratie?", + ], + }, + { + id: "gesundheit", + questions: [ + "Wie wichtig ist dir deine Gesundheit im Alltag?", + "Treibst du Sport für die Gesundheit oder zum Spaß?", + "Wie ernährst du dich – bewusst oder eher spontan?", + "Wie gehst du mit Stress um?", + "Schläfst du gut? Was machst du für besseren Schlaf?", + "Gehst du regelmäßig zum Arzt für Vorsorgeuntersuchungen?", + "Was meinst du – wie viel Einfluss hat man auf die eigene Gesundheit?", + "Wie beeinflusst das Wetter deine Stimmung und Gesundheit?", + "Hast du Allergien oder besondere gesundheitliche Themen?", + "Was ist für dich gesunde Ernährung?", + ], + }, + { + id: "meinungen", + questions: [ + "Was denkst du über soziale Medien – Fluch oder Segen?", + "Glaubst du, dass Homeoffice die Produktivität steigert?", + "Was meinst du: Ist lebenslanges Lernen wichtig?", + "Wie stehst du zu vegetarischer oder veganer Ernährung?", + "Glaubst du, dass KI unsere Arbeitswelt stark verändern wird?", + "Was hältst du von öffentlichem Nahverkehr statt Autofahren?", + "Ist es wichtig, mehrere Sprachen zu sprechen? Warum?", + "Was denkst du über die vier-Tage-Arbeitswoche?", + "Sollten mehr Menschen ehrenamtlich arbeiten?", + "Wie wichtig ist lokales Einkaufen für die Umwelt?", + ], + }, +]; + +// ElevenLabs voice ID — "Daniel" (German male, clear, natural) +// Browse voices at https://elevenlabs.io/voice-library and replace if needed +const VOICE_ID = "onwK4e9ZLuTAKqWW03F9"; +const MODEL_ID = "eleven_multilingual_v2"; + +const OUTPUT_DIR = path.join(__dirname, "src", "public", "audio"); + +async function generateAudio(text, outputPath) { + const response = await fetch( + `https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}`, + { + method: "POST", + headers: { + "xi-api-key": API_KEY, + "Content-Type": "application/json", + Accept: "audio/mpeg", + }, + body: JSON.stringify({ + text, + model_id: MODEL_ID, + language_code: "de", + voice_settings: { + stability: 0.6, + similarity_boost: 0.8, + speed: 0.9, + }, + }), + } + ); + + if (!response.ok) { + const error = await response.text(); + throw new Error(`ElevenLabs API error ${response.status}: ${error}`); + } + + const buffer = Buffer.from(await response.arrayBuffer()); + fs.writeFileSync(outputPath, buffer); +} + +async function main() { + fs.mkdirSync(OUTPUT_DIR, { recursive: true }); + + let total = 0; + let generated = 0; + let skipped = 0; + + for (const topic of TOPICS) { + total += topic.questions.length; + } + + console.log(`Generating ${total} audio files...\n`); + + for (const topic of TOPICS) { + for (let i = 0; i < topic.questions.length; i++) { + const filename = `${topic.id}_${i}.mp3`; + const outputPath = path.join(OUTPUT_DIR, filename); + + // Skip if already exists (resume support) + if (fs.existsSync(outputPath)) { + skipped++; + console.log(` [skip] ${filename} (already exists)`); + continue; + } + + const question = topic.questions[i]; + process.stdout.write( + ` [${generated + skipped + 1}/${total}] ${filename} ... ` + ); + + try { + await generateAudio(question, outputPath); + generated++; + console.log("OK"); + } catch (err) { + console.log(`FAILED: ${err.message}`); + console.log(" Stopping. Re-run to continue from where you left off."); + process.exit(1); + } + + // Delay to respect rate limits + await new Promise((r) => setTimeout(r, 500)); + } + } + + console.log( + `\nDone! Generated: ${generated}, Skipped: ${skipped}, Total: ${total}` + ); + console.log(`Files saved to: ${OUTPUT_DIR}`); +} + +main(); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b636f18 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,830 @@ +{ + "name": "audio-foreign", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "audio-foreign", + "version": "1.0.0", + "dependencies": { + "express": "^4.18.2" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d17afa1 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "audio-foreign", + "version": "1.0.0", + "description": "German conversation practice app", + "main": "src/server.js", + "scripts": { + "start": "node src/server.js", + "dev": "node --env-file=.env --watch src/server.js" + }, + "dependencies": { + "express": "^4.18.2" + }, + "engines": { + "node": ">=22" + } +} diff --git a/src/public/favicon-192.png b/src/public/favicon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..46203cd5ffed15fb9ec10d1ba57d76d3c7835edf GIT binary patch literal 13685 zcmYLw1yozn5^ZoNP`pTx;$B)Dg0&QidvPhHxH|-w0>z=Y6ff@XrL?$9acOY~ngAjE z^u7Q7Us=grS-F|nXJ*blXJ+>Kq@kurg#Q#D000mvy;0CYUHksMaj{XKTB{B?s0+5` zTSW!Hu-+-OV4^=`dd5Vs{AFS$ z_i9~tuRADUZ%(Z2P-k9jUUz;z*DoJuM)x`o*5!E!J2`_vV(=5~rRPO(w0X7ba1EZ_ zZ3tTn5Py925p%oUfrA1G+49uIb5xw=9rJ1TYZ+wo4sjb?j3od5 zO>e)*#r-=smY=lO&vo~3#lMVJ$y02kO(n4v!=~gYPSQgc9=oHccc2ALjF8kY)4qfP z7rsq=%p+GE(E}{3a*dZB2GwdE%J;DbC(T!oM%Ca4xgv0@B``1iH7|mwhV6oMC(;Xd zu{OW0V5d_L*vL3x9$t#S*q+ke;*SSK96s%oIaPUP`FPe7q-C!6+{n<4Br=ZcU!7;sYqZFC zUj$7}NToBqPyX}WPUa>V>tLOT-c^)xT0F?4uG^xyI${SFsC^yL>o07CHBw^Fy5M2C zNsHcE8m9~RpYn+Qv!rW19Bz>$15LhLph3IS|^gm4HPVc+`&&(&o4Uu6C8ydtPvYYeyppHA^e1<)a!;n z(Wk(ko7v39pn*?>G`?$Gh@tZ$jkSipvo}(a9gpe!KdYvMFFB0^kNWO4+{`f9jd%V( z9zA$>hmqy$V_plnD)$zE{@OZNpXOo>J(t?ze}YKEK;{RDX>hbR>)ef$|3GQ8{#if7 zKZAM@G@3*NwRPavJoHgTNhh6URbdr4ANG}%|F|K1+bXbv0$fs=dUuD@E9#>*aTL1V zwcV0e;X1mC|3d%&MMD}!ucGivy7=73+_Un+0w9J_a0azm8GcZIN5pc?fEn}JpKk3Z zt=8Sr51+Z6X^m|S7O-{K#um9>{73s} z!HW6!Cy#XSOxV!N{HF$SoV8EfLL7E`jVX}ZaLw}5^5Bij)~?$q`-h|=$dsyd_PJ?N zE=Qiz|NVJCbOW;YmgY<}sH$Bz%j!oTQ$b;q8o7MyziG#z9{(exWse`~T*!fy*lqx3EZ=J^e_xbCTC#&o{0%p2#HG)e`)%hYv@1LFHHZev;~ zKiWm_dqlk10MH$g3!jlA;SDak3OC03tid1v>Cs>`f=v0~W4pZ*EgX$GNY9TQe_E<> ztF|%(SS9Ftq>RCGh3uYYO2<2ddtKLWwJ4>;9b89?!tQw4myu+XB2+K_dkA3fn;3U z9sp|4@>>y@zeB+Dac+l5W%`Fe-*%k!Q_pS=w9LNTnts~EDPF5fEEV{s3lH;%1%kK6 z^GLPC;j*0bb{sl8(A<9*g9NXJ8&WAD07D|iy#V=tlDQBi>CgLs8rkj>sK-enD)O}6 zW^Upff1Dcl&#+K`As{_y_Br;(WBC1yPLy}9>1mZQ#SX@o-CI5Mdl7aYs93D(J+JsZ z<9c~U>(u*k2}@&v`m3J%5+A61I=V&#_>DLD;D)m+tQDs{2rMcD2^;1`!dGNXC8$}B ziW68RVVAPVYhQ~#AzjfWRtMvJ^I5joBk+^GzrLh1(S&bf2*8-+!CVO0j_J+XTGr-d z34wB}&8VYcm)+0oQ9jV%NHdz4KhClBA9}t%$|T9^HrA&v8!e_=zu zqvZQbS(}|ew&fLP*GDP5bfig68rtlap|tHmpe)yv(E*rn{Zyb((D0|LW+9xmz;i|Vc!SZ|=Q!K-b zr_IJOkyl0#W%XAlq0Xwe&aqX4HsPk*?UU!s_BG#qM4>_ROyowo61VCEGHvLtzv)Pv zM_6q6T6Jh96MxhVod0s8;QZ4w6Lg~%Bf_fZoT@Au;_!YxfG+&OkHChD&)BKKqvmV( ztCG9%=*TsV;F*o7CNmo&RsE43wF9{)LX5TtkCv9LBNNIh`a~!?HZ3-YW0X zjWqB{E8o635r09h&0c(~Uz@Rxek6f7V^_zeCx+t1KDHI*KmK$}=(iehB`Bo|oK>^k z!im=1TAW$`)@GjB&${_s9M6t1CbD=eX*9vK03|rm!#iz@P1yPfP9L!>jDj9RM@kF+g&b$kOXeJS*0OsiD7_}gsJNu7+;j@Xyko7ZZ6PZoMDT`wiQ8M~ZKl6lc)3w|hsH5ysKTps{= zfv?(ba=Ea^&cBcaI5$qMmS;5l+|6R;LKMz2mC*70;Q?6TA%8i>08OnMJmT+#e78i% zzpG5jO()i!;da5ZhCpU5<<*)2NEWuz1IoCRvIvQw zEDsYLG%yg2CZA_xY34m-7p4fR+b8qcsh90>`rc+4ZwYlt&IjkbSFAPFZ?p4t&=~-} z!iy+(fbR$zTvDb~u3M5^dhB;Yvmv&)Od-Q+~Mm;a9lkY|HCs1ss*(iHjF@>)yZrZ50|Y*{`8N z)@YNFjNBRvZ5{RCK}2a*GS+Cz5wruN1*?_9CK>B~I)m@tCQHJNlgDwwCm_)x93RGn+jf(w&vMEJCX316#q=k4+}uF$il|*|r*o)l zoH}~6pz#ERPHmE}d3f7HF?uZk%w4XyE!`H=U|eT9)VAY^S&-k&i=jPfy1}bB0_5eQ zQXWLiJ0Dy%NmVW2^O&E(xtE-7N}eq=?)*~&`Hq?8dtkDXlr**D1(liV-+7uXjp&hx z-U>8nH^(>%g6IAv#0ciP`+_>p)}hVBNT*riwQHqT{~ZZc5Q5*aF$Npl*GS8oKB1W- zwee>DM*H{kYhM5EzPeud=L)grS$>h6Nk4luM4noQ%QJCNA>YlCx2{uL1!$L&;vmC@ z{~5ey_UWe{Gy~YTSNeuL@mh6u75xK^k`GAJEyZ5En%u}s`k;%>XYQq(PY>a}FtDWrcSV<>vndAN0$3sQN5H(};{P=rI_2?-}|hlkMO% z!bapB&2-jC|EdPC}I=!XdVSU1HVmvqkK4iYU=aBN&o?%sulR? z?0Q0fOp*s-Z9LMhI)jhBj+Gz&UY1Stv7a~=+C}N_lEBrF~O{(NmhPa{ z`8Dt8+94lL9Z8#)B#rSm`VvwT`dn*f-sEoYcz#lwN{0`z$0ywO$D|($yCT@=;_fG? z#oOZ-_Bi#OZXUhNZd^pf8zVmqE~df9XVcF-IrE3f_zejO+s`t6-FC&T&}*r^64x~1 zm-92;Wv&%=N3Hda_G`r}YP3W7^NQf3upj7-9@n^!h(XL1*kME+-p=(sGj!X2pdxP- zqLN*{`ig&ZA8)I~QBUuoPC9Bn@Q-I~82zcCLdFn3Q)8NoVZ8B9Xd8`_RAJ7=h1ZEg zyTORCvxXLXq{RH~hSQkwCOXlPes8|{25Gma>$$_dT*xBKI!}>ecla<3S+`$i+Mp$n zzT;~^DcSl?^d!>}f7XVIsVGhB=3ZV_P_E^>WtujwxElUZ>zj8)Sm+Fne+Ixc4AQ>x zP>0E1vjZZhYA(mcr@}eC-`^1Vsprj1XWSy9GogR~oOT5$XfR*OZ2DL%@I39rFQh65iji{~QQa9nq3y>jL)w!*K@AlBT%e8H z08eu4Gv>QJD59+GCe1@y_5pj)Q3l5_c1`*<@+wnzOG693(A}|u(UF$no$i1BH&;&G zOcXp}vY&q!;FO~41*c!Go1dAk$eo%6^-#DhV0OV=d1BuKV+G=pG8s-zqMRQGw$G_X zf#Bj&S#DaSuMqiSuT*2qlTH6#m4?9D`}LXjNF)=MxcW}){N$e~+X1myLTfIuTBFls19ywz zii=7MT}rZADsVK*G~yshY>>Y?kCnJaFuR#b10?p|Ue%$okzomAKviP3MqL_AIj$2| zdD%*LV2@=H7+*>oaK1_6u)&=pHF+CI-s{WuOS`sDmx}f~hMtSsbzjjDZ?e+b6TYlJ zdIz;RpGbK`QH^@Hc8OxtEGn)hudn#>_BxZ z$NPMc7>eQfh>49YljlYyzhQxj;VET<_w@liHf0%oZ&wC%!%BiTlEx)?)5m97&8FBn zC$hd}NU&UXkeLkhK8$@Wn!WC9owPi}Of%$mF?><7dHtY-yzoo0C0omU9_(Yx{@~|f zvee%@uu}2ueR}9KIUbE$`nY0s@NB)nj%A0bq@PMkTn52@2?^57k3` z1#Qb*$47i(ljd^v8N8XcFN3feQ(p-o^d^#A;9>e%J=7r77Pm*SI&RH?z^2{LpO^qc ze(T}mQ`BzG)*7|Xd$WJSKep%6al3^hB_p}C1({sd)_uLu<^T;leeH{J{8#0A17`3A z3KhC@KbtR=jTZ7prQpgDgpss(QTn_u4TMG9G44;p20*44ixWH96plBt>dbZSK}|!c ztc^q)lefQV+wC9S`p$k%1SW?z7ODY1(*MHhWpSoks2st6$T6Imz%XnbvV5E#JK7tc zs$gvN$(-FY)>4AXN23coA?C(fG~SN)qldrR%!^8)ArL2!oXztGzI|P#F72upN8fl5 z`@tfBxQvzv5}b>(T4QWdEl~@?h6IP81>9%bs43B^<4Hn`{}_Q?^3MKL#&vC2ych)f z;`hA~LzJ>&&$9a#GzBFNn>8&3PCbS#&iB3dCn$_2P$36@kTAjUk8v69F{k|#2{K=l z?G`uG-}!+R5wTIUmWw0Qqj!CdAZ-jNd$%ObP~>f5eSvpn7`T6rPT? z(Zw!_D9Bf`X?=T>dNW2V-7)cXLyh_H;VStuN6-AYANUT1Uc4)yr+=&>^8g?eP_CnCP6Kzgc~$NL%(uRJU$1v)iT=&HYEs?P|Hokb2kH5 ztuWK9tJ&-Gh>rf80&=Gj{!3<)yx=3Tp9$eOQJd3yLO7+>s^WhYIq7e*dDYcXvdhNf zj#ZB=Kfgc#T($T9g5Bh(LTOUIu1L8VYtfoNJ@UMX^H{Sntq-_Q%tgOka5pKb#{?Hs zpv3xUWm~R~jq!}DJJkhj^~aB86rbRCq!a#D`!bn8ld_g;7TViuj0X+Ndl2)RS>qFZ zIo$8De9Xox>NoS?l(O=?fB!U$s`YLd9pGNd@!M#a0kO#mNZW)C?NQS#J>&6tR&axp z@nYR%1UyGtp1cTj_U?P)z22pTN_QaV;X%{Raxw}I)SZgzZ9%QA*xZlj*4!?YyCYaz zxiy&S1ARa*v~tX-v`~V{3FGUvhSBZaim{sUHu3IYEWf{hee_RH)rG-qt(`$2i3+16 zIJ4XaWK?Nj5x(upK*1v%Hw;q{nShll52`~%X46JL)9*Bje_wT_$;!ePOo zpz{zRL_sFmoP0?p*(&IxA>O`L{g9A5*4;0W4dVSgrBSH`lL&BV>r9FP_Oj65nBpkp ziwM_9cRC3x89K?Le!K-w zzo6F4$G0=BkU;!mHi<>76x027E1QT^G(fUx)H(v>@!X_VH0_m6C%a^nMN{+pj{tG< z&Y+*D(kX>lhinlkq(qqnpHz1v)5=tQvHDXk*wkkn%zn0{i~n1yEXN}Umk)4@$XGh; z-AhVo@6=pAN$>d}={H04iKL*qU7%A1SwmIj}c9QWz07Xslh)aB7XL4e3IOWHt+m%K88t%VyGC^R9Wf#} z$SU$d@%aJqkC_u;e+XhC7^8IXPO#@!FH`ZQ2X%hnnZg{u@uJupBLM3urVNu;r~jJs z+EOAOxGyiv$&T{OS!gAtC9r7__zFKF`rBCq$UKQX@DocX@nOn**l~*=1W_}K%;Jgx zRj&_jLxCh=fj8YLvtIREF3(HF5^8*nk+BWS*MDDMu%ST@fo$fFn!n03auN^g0bp__ zlmQ^(2y;a%za=vBmAqrx8KbOK^c_dEum2!+J3IICxh($^xadU=9(eOuAl*84E+SPW z7PIE0j)rSU>h->rjB@+d@q;=@0y-!l&-C>Wr+?%3Zf(Rs_%jilCP0KFVHqt`qN}t_ zN6lWYMoST#RIjyCf5TL!ERb{R)K*pSej3b zgLKG7^Md9&v&Zi3n?$JAAD;F=&Nrjb|Dm%919>2T@U1iPG%4N4lzmDMOshg*(fYda zHs<;@@h*LVY+w1Zx!!wu7j6h?=gQ1EdamXX_iA=x1!MH zPy+WtK^_E~5uo$os^VB}dyK1BOSfsKjf=$aGA(XW$P_`CS_nl!4PT5&uUzk*@n%6H zuA+EX+0PZQj)qqc6xA0o3xG3Oaww1w);OIKXw{3NO0H3E;V&0gXyq}xmDsvK5LY=o zt+iOBLq{4KII(`dv4-t9F3wDr({a?-&l9a(k6z4m1UYzF-q;K%B7#Jtrp&wxHN4++ z2G+-)m^8G^?b)2C@ri_HsNvSwEVfqogcdgj;~O2E>GFPIh#(AvSgUX_VJz_oHouc; zYvwc%iP1qvXnZv&sDp-?6qSv)l0!dhz04La0!SSOQc@DzI_hm> z`n=ZwndOrgxLzLJozPWE76Xwg9ejjx8V|2>8$qfYsI+zB3^c~Dvhz@%EQT*5ov-T8 z_N!fcrWM$Bu^H7Q$7Q}dMw&$rf$lx3sCOOB(_h6=(7CF$02{K^x$qzyN`|RWC^y#2 z`X)r`K0MC>l98wIZdtBi5bof2`I+EZ0L%IDb1f)_f$hO~;~CKe5m@H=f#Jn(rA2z` zkuf$CE1OjM6R7<3?AP!p&~cAV2Tros(&ZiL}%;mfoIq z8UT4VBNy1n8?EyM@xkuEFjfLPhPYQKSZ{Y-&5%r=rZ+(g&7=rW;Q_Z;vek^#zXTG7 zVCER<=C8lJc=HX!(*ZQz4{J<@JLTAO34A-zI>;*Ry;*EDkC;b9GB+cV*VC?)O;p(s z>F_em%iCN<_wSog7A3D}Agzj+*iSNv>`mg4*3UUBo^oz5&9o!l_&IYU`#n+3#Fdhn z>ziAwH--`3{+6W@_vw`YADqtkhyMQ6wZdt1FnJDT32q?7=y|CmmYsd0S%yj}8}su5 zqO&OF<$C7>Zk04#@Oxsv?# zvz+bj0DH@30vw<_p}_qu7CM_3m9M%u)|h)wJn>qh#4 z*qC4tbCeu8%GG75fS!gsWhN{X`Fe8stu~;hzDROsrO`m%& zyvwQ5?)XKqwdVD$Oq?6Zn-0eyw4XgxmU2QgILXB}TeQ_s`F)M(nZDZ8iTz{LWBmfI zA|LOFV;p?P<9durb|etXmlA)u{z-YOe`^TP>}O)Ja4bXrJ)^fi>nW6CbKp+xwmh-@ zYN#JrD95CX18y6J`S3e4>^;_Zw>LE0{jqo2LtOwJq%sQNPf{aN>_t&@!paSv3P`2YzmJphgq5%ju) zoaYYOe(rp7JLtgoe0f(=VE-7v-MH+q_+u?)mkiH@6!V}o|JlxQzNoA0+8z`DpkVmN z1>hQ4DstP3$|)o%i2`{DW3%slZmn(qsCR?2Cw0F1D}f9PqPUTb_m$N=MNv5aa+x=; z#;mYnIx{|Gw!8g&(z^3k%6uXFaL?hg_G&LZywg7-Pg3!xUsw4@IFmhxg72pH`+L)0 zlDDoOZr0!FCm5LSmW=|2@L|MrA{A^rjX=M6v*7)@ClFX z@VBvSh5!qj*5dTA>_D2CfkEJDK#NhvzDbyp3z{1^77CfJeXK4V=div%wYeyq_ zai(^vbgBeu&(N@If8ir&w~1rM@%?8XP#o4R;@EmQHTjNumFV!q+s4JtK2(S<>YQaB zed$p&Gl823GF7=_dNtEebfg$q9e+l81rRl|40&aHz$Ke6kir|5cQRBS3eqYhVZrHT zF@n8$?cV8T@wady-UsNHF_r8u#*z)H(AIaz6z%ZQjZB-IY?$h=;$0zG3I=f^ z-*+dEHG~z=jE})p{>|6B>4jbCzhq^h*OU`lbH$%~F?~F3T23eTQL`&Xj0xL|o+REs z9?cDD*sNl`kA9yriY{c(NTvFMC%+1u2gvvuuj)^Sf7|J}XTaY9utwehzYT?p6L%C8+w* zkr+p-gU)qEAcpVFEwhRuIx+)~H}4VU?m8NbB|Kn>kcsb+v>! z7;)~CUh`HO+*RiC;RtEmw%YfLdWSy6aXB~saX$+5`YJp_MQnldc>N4WM6o$Qv7U2v zIusS(4pnnpTq`Jt9D_qU2eC!%-CpDq%zj=lRL$P(y>N+Ntyn(JiVUKgCUs#nx00&L zspY>I=!HcWQ)JYmf#a6&1egCzdwTT{Px2V68oM6cVjpaJc&^NbeDxMp%_LbT9Zm>T zL|9DQVC6(eBttP&a?8_FPj(BfrXMn0g`Q1No0_h)gN6G6mK#<@)VSj?rr4Z2T z-SCXne}%zb79sWrBmImJ!F!y9w&~(o_Sdi-nW#3g5X^}z<0S*;925Qw%+GU-Y1p_%a9ASd9%I3?{53~j|vGqpxu}qef$Y9vnS&YBRBwFa- zar#nG{cc(#zc6_=p)edwf1m1=7SmpV3AeZO+F0{C-&gvTNiO=+Nxr&sT!+Vz#pKa( zkEVyjRxxk+h1XV8Lmmm4srL?X?BK9*U2gv7b{cl$Ob17p{6uPbdb@TJ&=SUwJXiB# zaLV;f8UVb{m#P0~uIK^&;A7ZKX5u8;UIcD7ah(WALwl^}+qw?)3w}X~lA23GrmBz0 z01Oma4@t%pc?^9{&t&{F=b(_EBLDb~KUsw};YPJ>9&?!OMO} zpnm>k-D5@&nkr}8_JB$s7OKl7`~G+UXf4K6DzK*C^7gM%(pUTM1Yc;SA8MRLeU(W{ zPJH(22jS;;((0lueTYP?f;ngyvGUvI@UJ%SzrqEr8tCV+J#rT;=1d>b2y{1pd@;d^ zaP)r*^H-eb$3kdakXho-&pRWIVd>c+V?q*s<8~~bZFwx~qG>cKMb|s1%)>PpFw6ce zXZc`YnO+)k-R$HO2~dnD2z==8kkuj!`{j5;5E4j_#A-Sphu*k9;Nto%u2~%sOp0nc zJZSX;S*4gtHB4Zit#Su;_zk4tvWmgTgS1F~jZ>epV!3c4EP~0H1&_0(y>$heo2|9N zzzHP%zyZ$DMD~_h#cDQXOwQ!#v8{3~0^b96>)kh`(sue}km_>BAP6~s<@*SgrZVb9 z)uePA{*7e33qI|co-Of{MSF$ftmpd~GQPVQGGv>gvpzf54e7dxv^mt>JofE3D>g=L z3UKLrO*cU6PVN{gcJBOY2|JG|1cV#kS}$#FL?nB~E`6h}+cWM;B0%#{Zv5K z&C@8JAf)m=to>tqzi+G*@9QrvSH#N%Sb|G?s~Z-g zlPpdHbdzya%elFf zDUF`$ZL+o|pQSvxeph19JI(EVKX-YsK3)2C|H7Mr#B}M2)Q|F|yFcNe7_Wb$+1kXB z!h)x4u!<#74)URUx(*H32x(2ncM?a_ayj-j_#$gGg!5ZZT{~r&>pZ+NToul@oU34G zQKv^yfxfV9JO5alN}bckb+jetVQ8!Hz~?Wt6?2!S_Ney9qB>55L=>!@`VLhLi}{bY zwzj;BodFOycPx^LN=xy_Jh$|nQ&nAAwN1qtMi|=YDy|(&oklV3eF+coH(pc*pYt7$1MP{$tP8pnmbiyXCA7k08G;Aq{ zpCSZ~|C#YKaWBh#0{%wOl%)V8uenj|cI~?TbH}gS9tl#-c#HxzSu?KJzV9DCcx$Qz z6Qq~NxqF25$k*rPYSmeWm~EvkUM`OBWP5V7y8oe#^8CK{T@T*ZNoYtbw586r^+nxK zT=rZbfT0HYrXM&cj+#?z11M6=9%O46$R5ZpA>M4Q9kxxjcocHJK6onpw&Y3=?5x+s zC>9{MwDZo<(O#1$JNs0}7UctZp`Kq--PVtq=d49U$&um)l5b18#C@LkVQ zQW~iO9||>-;_V`3o}M>|0O3pjQ@Dkq`=px;U<5(G6Zk^bvP1*+xl-IIIfT!W=NP91 zJinzC7%x5SnP_131eze^(6PN{kao#0H^o$DjG5YvT6s%x=Y-{q`Z^*^GzJx zpyiBSvbGMvmtUxR2J^bTcnR{{4AJf%xcR+cBgBh)jDqA{Cz9&=uQr#*GsU#&KMh;l z26)HlD-5Gr4w?Pg>1`q^XP1wQ+PWyRo;7X+2R$ObtK%&k8N_-(`vino3R1Jv4lw_G zFbWr_VVE$h>XeuD5^wF=o%5=`IZ$9PE2@$X~bp3^?EX~p#7 zbduk6HK0?=e!3yx;V@NI;YR|tZ?HU&?5<0be(ho!(hhouc-Yo zVuSlW9#`T9@3NHp@bEd2n2_R5wufx_CwtnH>X;sgi2cQZsmwvdiz)MQ@Z0)(#*k(^ z^87M&En}GQnt2nH!P22E82SX*nj|8_vZ4 zSLm(>^sGZyF*F*O+Ra+7h?*iA1vQ3Z4ry9iE4@u-PkP9_>RbTe3eVlsm- zt_Nlpq_!(7ir}m3gsok(#S4v>4jYbV>p+DAy4X{i`;cVPaXuhxN2X+9iFq*AsAho9rzA@fa&jYmM*K5LU zm+;<8%~nv}i7ti>M>OuiMRtLN{b514#Ph_-e=a>GA*(4N<4=})7A@^MEkoU3hYaUf z+rnq{yJXA4Z+Av*eqi4`feRL_KeqR?L|STXy;cMw))(LIas2B?8TMrYMy7_N{c7F0 zOa~b$yv&zr)p*|SaR$0pq8MrnV8Y*|l`mbTc3#*@qLw|AgO}tL4;`PbB+VzP(oBwG z-wy=A+n~p67WX~%`5ndK5ISvhb-h;0*ois z^2?^WqeSWS{l4jXU(uoH`$ADlvJ&A62U7iz*Qox-LEwW_6l-&BTZODmQMQDMU{K_` z$p^emfW3NARw;vs=!4&I>C%?cgpBaP+(o)XjZ8tSI*Qv>CcPT?Cg2@iD57@24AbOo z%MhW3wlHGy1w3rmqjudNRkhDMq|>i$eA(J6211H>G7%MAZPmCKC_yq+Vg_DjzUYF&PrZa+%%3$sZCTMtxTXbLZ%GSmn7VhgY$Q zAvU{mHHukoaA!pT0qh9AIl#tA-e3rJ!3lJbr2n4=C5u-ml zy?8)zPUmz7tR8P@JgFtIHhY>61-?Rb`Ph}q{ws_W0vOc*yCH9Qw~c<%zt3E)!A$%H z{W6+RPXL~>nse{H9MA_qE)rhS21ku-D&YO&Ex!#S90dOCe!Nji`z@SG`hztRF*zfl z839&pltWM-K~r83?%1!3Jjd_r_MVdjBD%uWbhcpjdeI;&21sgh{`zgJT_>!&PsSA0 zsL%>uH!+Op)j%P&o}(BP=*dDt%+cCl+;;i6W}G2pujZ-;%y=Gz01z4ErBP6ka7j?Q zC$}Oq!+m7m-)(VCo`2l+8L-giUNP$rn=t7~L%^v~CAQ{*s*G7u4o5PIWovnm&jc+> zy&LEaGNdP(`ISir%agD()BRZ%yQSdzpAkK(gn)d!wrzWIb@_WaHCqD&UBLs*gDzij z|53S1g0TC8vFVE)k96FdLa5TP-Eky-?)`b(G91BM8_^J^2f(k)$5gZ4q)h$b0 z>I@-K{HD95K3hcsp5TC^-TuhU*Mr&2dOo`%Rq_scbwavpSHRvy)?R`-SAY;5+|-wx z5)|@TU^kJY0t9!SmHTRvpOx?k$^SsYeR|P5PlXpXT5RjpSJhjTA#TY5Wo8H2VR7~jwNpV6~9*<I8?`Q){5v=f#hgH^L4&T2ke#2 zV{FwD*NNoB&i=tLQ(i4klnA+*BSJ;kuLL1{qz%R4-+)--LI>hSnT}P2Z>B@mr?Ubd z@Bcvg(YJwT=Qym=qx!2^o@n<~!_W8@$i zD;*`uPfPFkU6^1_ov#3G#-)HJvK*o&W|$Ky#v?5PcmsjX^(8!5eM!ysLrb=-wNJv- zIkxDPHOX#%j|8Jm<=}aqctjlX{WvFZK1|k9en$|jFOBRiE(v11<@3+)e_HS|+sRr6 zb#?}`qf?fF%v#dP0I{y5Z=gm~kG`4qPbiu@Q8Krz9><(p2q$B;a)qA9R{5w6>R5#E z8fi!n2|d?r1^F6BJa^IwhgEjp!uwGD-b)yl2f1v;?jy#gZaS@*eF;7492G$6m6}40 IoO$T~0pjFTkN^Mx literal 0 HcmV?d00001 diff --git a/src/public/favicon-32.png b/src/public/favicon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..edc36daf4951e00e4e09a599d77625a9d1d50d7f GIT binary patch literal 1326 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 O0XmlqG)pho-upjZlvpVM literal 0 HcmV?d00001 diff --git a/src/public/favicon.svg b/src/public/favicon.svg new file mode 100644 index 0000000..fd9a18a --- /dev/null +++ b/src/public/favicon.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + de + diff --git a/src/public/index.html b/src/public/index.html new file mode 100644 index 0000000..701e114 --- /dev/null +++ b/src/public/index.html @@ -0,0 +1,1112 @@ + + + + + + Deutsch üben + + + + + + + + +
+ + +
+

Deutsch üben

+
+ + + +
+
+ + +
+
+

Wähle ein Thema und übe dein gesprochenes Deutsch

+
+
+
+ + +
+
+ + +
+ +
+
+
+
+ +
+ +
+
Frage
+
+ +
+ +
+ +
Tippen zum Aufnehmen
+
+ +
+ +
+ + + +
+ + + + + + +
+
Verlauf dieser Sitzung
+
+
+
+ + +
+
+
🎉
+

Gut gemacht!

+

Du hast alle Fragen in dieser Einheit beantwortet.

+
+
+
0
+
Antworten
+
+
+
B1
+
Niveau
+
+
+ +
+
+ +
+ + + + diff --git a/src/server.js b/src/server.js new file mode 100644 index 0000000..3df78a5 --- /dev/null +++ b/src/server.js @@ -0,0 +1,79 @@ +const express = require("express"); +const path = require("path"); + +const app = express(); +const PORT = process.env.PORT || 8083; +const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY; + +app.use(express.json()); +app.use(express.static(path.join(__dirname, "public"))); + +const LEVEL_DESCRIPTIONS = { + A2: "базовый (A2): будь снисходителен к ошибкам, хвали за попытку, указывай только грубые ошибки", + B1: "средний (B1): указывай основные грамматические ошибки и предлагай улучшения", + B2: "выше среднего (B2): анализируй детально — грамматику, стиль, лексику, естественность речи", +}; + +app.post("/api/check", async (req, res) => { + const { question, answer, level } = req.body; + + if (!question || !answer) { + return res.status(400).json({ error: "question and answer are required" }); + } + + if (!ANTHROPIC_API_KEY) { + return res.status(500).json({ error: "API key not configured" }); + } + + const levelDesc = LEVEL_DESCRIPTIONS[level] || LEVEL_DESCRIPTIONS["B1"]; + + const systemPrompt = `Ты помощник для практики разговорного немецкого языка. Уровень пользователя: ${levelDesc}. + +ВАЖНО: ответ пользователя получен через автоматическое распознавание речи (speech-to-text), поэтому в нём могут быть неправильные заглавные буквы, отсутствовать знаки препинания или быть опечатки — это артефакты распознавания, НЕ ошибки пользователя. Никогда не упоминай и не исправляй заглавные буквы, пунктуацию и орфографию. + +Тебе дают вопрос на немецком и ответ пользователя на немецком. Твоя задача: + +1. **Оценка** — кратко оцени ответ (1-2 предложения) +2. **Ошибки** — перечисли грамматические/лексические ошибки с исправлениями (если есть) +3. **Улучшенная версия** — предложи более естественную/правильную формулировку ответа +4. **Полезные слова и фразы** — 2-4 слова или выражения по теме с переводом + +Отвечай на русском языке. Будь конструктивным. Используй markdown для форматирования.`; + + const userMessage = `Вопрос: ${question}\n\nОтвет пользователя: ${answer}`; + + try { + const response = await fetch("https://api.anthropic.com/v1/messages", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-api-key": ANTHROPIC_API_KEY, + "anthropic-version": "2023-06-01", + }, + body: JSON.stringify({ + model: "claude-haiku-4-5-20251001", + max_tokens: 1024, + system: systemPrompt, + messages: [{ role: "user", content: userMessage }], + }), + }); + + if (!response.ok) { + const error = await response.text(); + console.error("Anthropic API error:", response.status, error); + return res.status(502).json({ error: "AI service error" }); + } + + const data = await response.json(); + const feedback = data.content?.[0]?.text || ""; + + res.json({ feedback }); + } catch (err) { + console.error("Request failed:", err); + res.status(500).json({ error: "Internal server error" }); + } +}); + +app.listen(PORT, () => { + console.log(`Server running on http://localhost:${PORT}`); +});