From aef53eb953484f409ca4508ca2c23e2c3a6739ae Mon Sep 17 00:00:00 2001 From: Madava Date: Mon, 24 Nov 2025 00:30:36 +0100 Subject: [PATCH] first commit --- README.md | 920 ++++++++++++++++++++++++++++ docs/architecture.md | 613 ++++++++++++++++++ docs/docker.md | 28 + docs/git.md | 105 ++++ img/favicon.png | Bin 0 -> 818703 bytes img/logo.png | Bin 0 -> 1008098 bytes infra/.env | 24 + infra/.gitea/workflows/cd.yml | 118 ++++ infra/.gitea/workflows/ci.yml | 90 +++ infra/Caddyfile | 99 +++ infra/docker-compose.yml | 102 +++ infra/gitea-data/gitea/conf/app.ini | 103 ++++ 12 files changed, 2202 insertions(+) create mode 100644 README.md create mode 100644 docs/architecture.md create mode 100644 docs/docker.md create mode 100644 docs/git.md create mode 100644 img/favicon.png create mode 100644 img/logo.png create mode 100644 infra/.env create mode 100644 infra/.gitea/workflows/cd.yml create mode 100644 infra/.gitea/workflows/ci.yml create mode 100644 infra/Caddyfile create mode 100644 infra/docker-compose.yml create mode 100644 infra/gitea-data/gitea/conf/app.ini diff --git a/README.md b/README.md new file mode 100644 index 0000000..7b953a6 --- /dev/null +++ b/README.md @@ -0,0 +1,920 @@ +# Product Description + +avaaz.ai + +

+avaaz.ai is a mobile and web application featuring a motivating conversational AI tutor powered by advanced agentic capabilities. It teaches oral language skills through structured, interactive lessons that adapt to each student’s pace and performance. The core goal is to help students speak new languages confidently to pass the B2 oral proficiency exam. +

+ +## 1. Features + +1. **Voice-First Conversational Engine** — Students engage in ultra-low-latency speech-to-speech interaction with the AI Tutor, enabling natural dialogue and instant corrective feedback using speech, text, and visuals. +2. **CEFR-B2 Aligned Curriculum with Real-Time AI Practice** — A full CEFR-based speaking progression up to B2, seamlessly integrated with adaptive AI conversation to bridge passive knowledge and active speaking skills. +3. **Immigrant-Focused Real-Life Scenarios** — Lessons target real-world contexts relevant to immigrants, such as workplace, healthcare, school, or daily interactions, enhancing integration and confidence in practical use. +4. **Mock Oral Exam Mode** — Simulates B2 oral exams and citizenship interviews with timed prompts, rubrics, and examiner-style feedback to build test readiness. +5. **Multilingual Scaffolding and Integrated Translation** — Learners receive UI support, bilingual explanations, and on-demand translations in their native language, helping low-confidence speakers stay engaged. +6. **Comprehensive Speaking Feedback** — Beyond pronunciation and grammar, learners get targeted insights on fluency, phrasing, coherence, and vocabulary range, aligned with B2 standards. +7. **Accent and Cultural Adaptation** — Lessons reflect local dialects and cultural etiquette relevant to the learner’s destination country, supporting realistic and socially appropriate speech. +8. **Immersive Role-Plays with Visual Cues** — Speaking simulations are enhanced with contextual images (e.g. menus, documents, locations) to deepen realism and task-based practice. +9. **Gamified Progress and Motivation** — Daily speaking challenges, streak rewards, and level badges reinforce habit formation and learning consistency. +10. **Post-Session Performance Summaries** — After each session, learners receive a concise report of strengths, errors, and suggested improvements to reinforce progress. +11. **Customizable AI Tutor Voices** — Learners can choose from various voice options with different genders or regional accents to diversify listening practice and personalize interaction. +12. **Cross-Device Learning Continuity** — Seamless synchronization ensures progress tracking and learning state remain consistent across mobile and web platforms. + +## 2. Student & AI Tutor Interactions (English → Norwegian Bokmål) + +### 2.1 Real-Time Conversational Flow + +**Scenario:** A beginner is learning everyday greetings. + +**AI Tutor (in Norwegian):** “Hei! Hvordan går det?” +**Student:** “Uh… I think that means, ‘How are you?’” +**AI Tutor:** “Exactly! You can answer: *Jeg har det bra* — that means ‘I’m doing well.’ Try it: *Jeg har det bra.*” +**Student:** “Jeg har det bra.” +**AI Tutor:** “Flott! Literally, it means ‘I have it good.’ Norwegians use that to say they’re fine.” + +**Benefit:** The AI provides instant translation and cultural context, helping English speakers grasp meaning and tone through natural conversation. + +### 2.2 Adaptive Pronunciation, Fluency, and Grammar Support + +**Scenario:** The learner practices sentence structure and pronunciation. + +**AI Tutor:** “Let’s say: *Jeg bor i Oslo* — ‘I live in Oslo.’” +**Student:** “Jeg bor på Oslo.” +**AI Tutor:** “Almost right! We say *i Oslo*, not *på Oslo*. *I* means ‘in,’ while *på* means ‘on.’ Try again: *Jeg bor i Oslo.*” +**Student:** “Jeg bor i Oslo.” +**AI Tutor:** “Perfekt! Now, about pronunciation — it’s *Oslo*, not *Osh-lo.* The *s* is soft. Listen: *Oslo.*” +**Student:** “Oslo.” +**AI Tutor:** “Bra! That sounded natural.” + +**Benefit:** The AI corrects grammar and pronunciation simultaneously, giving immediate, native-level feedback tailored to English-speaking learners. + +### 2.3 Scenario-Based Oral Practice + +**Scenario:** The learner prepares for a B2-level job interview. + +**AI Tutor:** “Du er på et jobbintervju. Spørsmålet er: *Hvorfor vil du jobbe her?* — ‘Why do you want to work here?’” +**Student:** “Fordi jeg liker din selskap.” +**AI Tutor:** “Good start! In Norwegian, we say *firmaet ditt* instead of *din selskap*. Try: *Fordi jeg liker firmaet ditt og arbeidsmiljøet her.* — ‘Because I like your company and the work environment here.’” +**Student:** “Fordi jeg liker firmaet ditt og arbeidsmiljøet her.” +**AI Tutor:** “Veldig bra! That sounded confident and natural.” + +**Benefit:** The learner rehearses authentic B2-level oral exam tasks and professional interactions with context-sensitive correction and adaptive feedback. + +## 3. Pricing Plans + +| **Plan** | **Hours** | **NOK** | **Purpose** | +| --------------------------------- | :-------: | ------------: | ------------------------------------------------------------------- | +| **First Light** | 1 | **Gratis** | A taste of the experience - no pressure, no card required. | +| **Spark** | 5 | **kr 999** | A short, flexible plan to get started or focus on specific skills. | +| **Glow** | 15 | **kr 1 999** | Great for consistent improvement and practicing real conversations. | +| **⭐ Shine** *(Recommended)* | 50 | **kr 5 999** | The sweet spot for building natural fluency and confidence. | +| **Radiance** | 200 | **kr 17 999** | Designed for dedicated learners seeking transformation. | + +## 4. Configuration + +### 4.1 Configure the VPS + +#### 4.1.1 Configure the firewal at the VPS host + +| Public IP | +| :------------: | +| 217.154.51.242 | + +| Action | Allowed IP | Protocol | Port(s) | Description | +| :-----: | :--------: | :------: | ----------: | :------------ | +| Allow | Any | TCP | 80 | HTTP | +| Allow | Any | TCP | 443 | HTTPS | +| Allow | Any | TCP | 2222 | Git SSH | +| Allow | Any | TCP | 2885 | VPS SSH | +| Allow | Any | UDP | 3478 | STUN/TURN | +| Allow | Any | TCP | 5349 | TURN/TLS | +| Allow | Any | TCP | 7881 | LiveKit TCP | +| Allow | Any | UDP | 50000-60000 | LiveKit Media | + +#### 4.1.2 Configure the DNS settings at domain registrar + +| Host (avaaz.ai) | Type | Value | +| :-------------: | :---: | :------------: | +| @ | A | 217.154.51.242 | +| www | CNAME | avaaz.ai | +| app | A | 217.154.51.242 | +| api | A | 217.154.51.242 | +| rtc | A | 217.154.51.242 | +| git | A | 217.154.51.242 | + +#### 4.1.3 Change the SSH port from 22 to 2885 + +1. Connect to the server. + + ```bash + ssh username@avaaz.ai + ``` + +2. Edit the SSH configuration file. + + ```bash + sudo nano /etc/ssh/sshd_config + ``` + +3. Add port 2885 to the file and comment out port 22. + + ```text + #Port 22 + Port 2885 + ``` + +4. Save the file and exit the editor. + + - Press `Ctrl+O`, then `Enter` to save, and `Ctrl+X` to exit. + +5. Restart the SSH service. + + ```bash + sudo systemctl daemon-reload && sudo systemctl restart ssh.socket && sudo systemctl restart ssh.service + ``` + +6. **Before closing the current session**, open a new terminal window and connect to the server to verify the changes work correctly. + + ```bash + ssh username@avaaz.ai # ssh: connect to host avaaz.ai port 22: Connection timed out + ssh username@avaaz.ai -p 2885 + ``` + +7. Once the connection is successful, close the original session safely. + +#### 4.1.4 Build and deploy the infrastructure + +1. Check with `dig git.avaaz.ai +short` wether the DNS settings have been propagated. + +2. SSH into the VPS to install Docker & docker compose. + + ```bash + ssh username@avaaz.ai -p 2885 + ``` + +3. Update system packages. + + ```bash + sudo apt update && sudo apt upgrade -y + ``` + +4. Install dependencies for Docker’s official repo + + ```bash + sudo apt install -y \ + ca-certificates \ + curl \ + gnupg \ + lsb-release + ``` + +5. Add Docker’s official APT repo. + + ```bash + sudo install -m 0755 -d /etc/apt/keyrings + + curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ + sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg + + echo \ + "deb [arch=$(dpkg --print-architecture) \ + signed-by=/etc/apt/keyrings/docker.gpg] \ + https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + + sudo apt update + ``` + +6. Install Docker Engine + compose plugin. + + ```bash + sudo apt install -y \ + docker-ce \ + docker-ce-cli \ + containerd.io \ + docker-buildx-plugin \ + docker-compose-plugin + ``` + +7. Verify the installation. + + ```bash + sudo docker --version + sudo docker compose version + ``` + +8. Create the `/etc/docker/daemon.json` file to avoid issues with overusing disk for log data. + + ```bash + sudo nano /etc/docker/daemon.json + ``` + +9. Paste the following. + + ```json + { + "log-driver": "local", + "log-opts": { + "max-size": "10m", + "max-file": "3" + } + } + ``` + +10. Save the file and exit the editor. + + - Press `Ctrl+O`, then `Enter` to save, and `Ctrl+X` to exit. + +11. Restart the docker service to apply changes. + + ```bash + sudo systemctl daemon-reload + sudo systemctl restart docker + ``` + +12. Create directory for infra stack in `/srv/infra`. + + ```bash + sudo mkdir -p /srv/infra + sudo chown -R $USER:$USER /srv/infra + cd /srv/infra + ``` + +13. Create directories for Gitea (repos, config, etc.) and Runner persistent data. Gitea runs as UID/GID 1000 by default. + + ```bash + mkdir -p gitea-data gitea-runner-data + ``` + +14. Create the `/srv/infra/docker-compose.yml` (Caddy + Gitea + Runner) file. + + ```bash + nano docker-compose.yml + ``` + +15. Paste the following. + + ```yaml + services: + caddy: + # Use the latest official Caddy image + image: caddy:latest + # Docker Compose automatically generates container names: __ + container_name: caddy # Fixed name used by Docker engine + # Automatically restart unless manually stopped + restart: unless-stopped + ports: + # Expose HTTP (ACME + redirect) + - "80:80" + # Expose HTTPS/WSS (frontend, backend, LiveKit) + - "443:443" + volumes: + # Mount the Caddy config file read-only + - ./Caddyfile:/etc/caddy/Caddyfile:ro + # Caddy TLS certs (persistent Docker volume) + - caddy_data:/data + # Internal Caddy state/config + - caddy_config:/config + networks: + # Attach to the shared "proxy" network + - proxy + + gitea: + # Official Gitea image with built-in Actions + image: gitea/gitea:latest + container_name: gitea # Fixed name used by Docker engine + # Auto-restart service + restart: unless-stopped + environment: + # Run Gitea as host user 1000 (prevents permission issues) + - USER_UID=1000 + # Same for group + - USER_GID=1000 + # Use SQLite (stored inside /data) + - GITEA__database__DB_TYPE=sqlite3 + # Location of the SQLite DB + - GITEA__database__PATH=/data/gitea/gitea.db + # Custom config directory + - GITEA_CUSTOM=/data/gitea + volumes: + # Bind mount instead of Docker volume because: + # - We want repos, configs, SSH keys, and SQLite DB **visible and editable** on host + # - Easy backups (just copy `./gitea-data`) + # - Easy migration + # - Avoids losing data if Docker volumes are pruned + - ./gitea-data:/data + networks: + - proxy + ports: + # SSH for Git operations mapped to host 2222 + - "2222:22" + + gitea-runner: + # Official Gitea Actions Runner + image: gitea/act_runner:latest + container_name: gitea-runner # Fixed name used by Docker engine + restart: unless-stopped + depends_on: + # Runner requires Gitea to be available + - gitea + volumes: + # Runner uses host Docker daemon to spin up job containers (Docker-out-of-Docker) + - /var/run/docker.sock:/var/run/docker.sock + # Bind mount instead of volume because: + # - Runner identity is stored in /data/.runner + # - Must persist across container recreations + # - Prevents duplicated runner registrations in Gitea + # - Easy to inspect/reset via `./gitea-runner-data/.runner` + - ./gitea-runner-data:/data + environment: + # Base URL of your Gitea instance + - GITEA_INSTANCE_URL=${GITEA_INSTANCE_URL} + # One-time registration token + - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN} + # Human-readable name for the runner + - GITEA_RUNNER_NAME=${GITEA_RUNNER_NAME} + # Runner labels (e.g., ubuntu-latest) + - GITEA_RUNNER_LABELS=${GITEA_RUNNER_LABELS} + # Set container timezone to UTC for consistent logs + - TZ=Etc/UTC + networks: + - proxy + # Start runner using persisted config + command: ["act_runner", "daemon", "--config", "/data/.runner"] + + networks: + proxy: + # Shared network for Caddy + Gitea (+ later app stack) + name: proxy + # Default Docker bridge network + driver: bridge + + volumes: + # Docker volume for Caddy TLS data (safe to keep inside Docker) + caddy_data: + name: caddy_data + # Docker volume for internal Caddy configs/state + caddy_config: + name: caddy_config + ``` + +16. Save the file and exit the editor. + + - Press `Ctrl+O`, then `Enter` to save, and `Ctrl+X` to exit. + +17. Create the `/srv/infra/.env` file with environment variables. + + ```bash + nano .env + ``` + +18. Paste the following: + + ```env + # Base URL of your Gitea instance (used by the runner to register itself + # and to send/receive workflow job information). + GITEA_INSTANCE_URL=https://git.avaaz.ai + + # One-time registration token generated in: + # Gitea → Site Administration → Actions → Runners → "Generate Token" + # This MUST be filled in once, so the runner can register. + # After registration, the runner stores its identity inside ./gitea-runner-data/.runner + # and this value is no longer needed (can be left blank). + GITEA_RUNNER_REGISTRATION_TOKEN= + + # Human-readable name for this runner. + # This is shown in the Gitea UI so you can distinguish multiple runners: + # Example: "vps-runner", "staging-runner", "gpu-runner" + GITEA_RUNNER_NAME=gitea-runner + + # Runner labels allow workflows to choose specific runners. + # The label format is: label[:schema[:args]] + # - "ubuntu-latest" is the