chore: initial project scaffold and README (CorpTrainer MVP)

This commit is contained in:
2025-09-10 01:27:23 +05:30
commit 4edef4ba5e
16 changed files with 656 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# Byte-compiled / caches
__pycache__/
*.py[cod]
*$py.class
# Virtual env
.venv/
venv/
env/
# OS / Editor
.DS_Store
.vscode/
.idea/
# DB and sessions (audio)
*.db
/db/
/backups/
sessions/*
# Logs
*.log

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

19
.idea/CorpTrainer.iml generated Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/backups" />
<excludeFolder url="file://$MODULE_DIR$/db" />
<excludeFolder url="file://$MODULE_DIR$/venv/include" />
<excludeFolder url="file://$MODULE_DIR$/venv/lib/python3.11/site-packages/_distutils_hack" />
<excludeFolder url="file://$MODULE_DIR$/venv/lib/python3.11/site-packages/pip" />
<excludeFolder url="file://$MODULE_DIR$/venv/lib/python3.11/site-packages/pip-23.2.1.dist-info" />
<excludeFolder url="file://$MODULE_DIR$/venv/lib/python3.11/site-packages/pkg_resources" />
<excludeFolder url="file://$MODULE_DIR$/venv/lib/python3.11/site-packages/setuptools" />
<excludeFolder url="file://$MODULE_DIR$/venv/lib/python3.11/site-packages/setuptools-65.5.0.dist-info" />
</content>
<orderEntry type="jdk" jdkName="Python 3.11 (CorpTrainer)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/CorpTrainer.iml" filepath="$PROJECT_DIR$/.idea/CorpTrainer.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

8
LICENSE Normal file
View File

@@ -0,0 +1,8 @@
MIT License
Copyright (c) YEAR YOUR_NAME
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights...
(Replace YEAR and YOUR_NAME with appropriate values.)

228
README.md Normal file
View File

@@ -0,0 +1,228 @@
# CorpTrainer
**AI-driven Corporate Communication Coach**
CorpTrainer helps professionals **speak with clarity, confidence, and authority** in corporate settings.
Unlike generic public speaking apps, CorpTrainer focuses on **real workplace scenarios** — project updates, client calls, stakeholder meetings, and executive briefings.
The system is designed to be **drillable** (board → phases → categories → subtasks), mirroring how corporate training is rolled out: start lean with an MVP, then add feedback loops, roleplay, analytics, and enterprise integrations.
---
## 🌟 Vision
- **Private practice sandbox** — zero fear of judgment, unlimited reps.
- **Real-time nudges** — filler detection, pacing, assertiveness feedback during sessions.
- **Post-session learning** — regression over time, personalized weak-spot tracking.
- **Enterprise-ready** — team dashboards, SSO, HR/LMS integration.
CorpTrainer turns your communication growth into a structured roadmap:
📋 **Board (CorpTrainer)** → 🎯 **Phases** → 📂 **Categories** → ✅ **Tasks**
---
## 🏗️ Architecture Overview
```text
# Updated Architecture (two use-cases: Practice Mode → Interactive Trainer)
Mic -> Audio Capture -> VAD & Buffer -> Streaming ASR (tiny/small)
│ │
│ ├─> store raw audio (sessions/)
│ └─> partial transcript chunks -> Event Router (Practice Mode)
│
└─> Audio Feature Extractor -> (pause, pitch, energy)
```
Event Router (Practice Mode):
- Rule-based engine (instant nudges on partials) <-- local, sub-200ms
- Fast LLM micro-feedback (triggered; tiny prompt) <-- optional, 200–800ms
- UI (Streamlit/WebSocket) updates in <1s (toasts/popovers)
- Async: persist chunks -> assemble full transcript -> Post-session LLM
- Persist: canonical transcript JSON + metrics + accepted/ignored suggestions
------------------------------------------------------------
```text
Interactive Trainer (conversational roleplay — Phase 2)
(LLM acts as interlocutor; must be low-latency & stateful)
Mic -> Audio Capture -> VAD & Buffer -> Streaming ASR (tiny/small or cloud realtime)
│ │
│ ├─> partial transcript chunks -> Dialogue Manager
│ │
│ └─> store raw audio (sessions/) (persist for replay & training)
│
└─> Audio Feature Extractor -> (pause, pitch, energy) -> Dialogue Manager
```
Dialogue Manager / Event Router (Interactive Trainer):
- Turn-taking controller (who speaks next, interrupts, confirmations)
- Short-window context builder (last N secs / last M turns)
- Fast LLM endpoint for roleplay responses (gpt-4o-mini / local Mistral) with <1s SLA
- Micro-feedback on user's utterances (fast LLM + rule-based) during roleplay
- Policy layer: when to call LLM vs use rule-based response vs local persona script
- UI/WebSocket: stream LLM replies & inline feedback to client instantly
- Async recorder: persist conversation transcript, LLM responses, accept/reject events
Post-session (both modes):
- Assemble canonical transcript JSON (segments, timestamps)
- Run deep LLM regression analysis (larger model) for trendlines, personalized plans
- Update user profile (weak-supervision labels, adapted heuristics)
- Re-run historical transcripts when model/prompt improvements are available
Storage & Dataflow:
- Raw audio (FLAC/WAV) stored in sessions/ (or cloud bucket if opted-in)
- Canonical transcript JSON (session_id, segments, metrics, feedback)
- Feedback logs: {type, suggestion, timestamp, accepted:bool}
- Versioning: model_name, model_version, prompt_template_id, timestamp
- Optionally: embeddings index (vector DB) for semantic search / examples
Privacy & Controls:
- Local-only mode (no cloud LLMs; everything on-device)
- Opt-in cloud mode (encrypted transport, audit logs)
- Data retention & purge policy (user controlled)
- Anonymization toggle for uploads (strip PII before cloud)
Monitoring & Ops:
- Metrics: micro-feedback latency distribution, LLM call rate, accept-rate of suggestions
- Alerting on SLA breaches (>1s median for micro-feedback)
- Model version comparison pipeline: reprocess transcripts & produce diff reports
Notes & heuristics:
- Practice Mode = rule-first (cheap, immediate) + occasional fast-LLM triggers.
- Interactive Trainer = LLM-first for responses + rule-based safety/quick nudges.
- Always persist raw artifacts so post-session reprocessing and model upgrades are possible.
## Design (Use Cases & Phases)
**Two prioritized use-cases (phased rollout)**
1. **Practice Mode (Phase 1)** — *User speaks on a topic.*
- Low friction: user records or speaks, system provides immediate rule-based nudges during or right after the recording.
- Primary realtime mechanism uses streaming ASR partials + local rule-based checks (fillers, pauses, WPM) to deliver instant lightweight nudges.
- Post-session: full batch ASR → transcript JSON saved for deeper analysis and to train models later.
- Goal: minimal infra + high perceived responsiveness; easy to implement first MVP.
2. **Interactive Trainer (Phase 2)** — *User talks to an LLM trainer (roleplay).*
- True conversational experience: the LLM acts as the interlocutor, asks questions, interrupts, and provides coaching in-session.
- Requires low-latency streaming, event routing, and frequent short LLM calls (fast model) for micro-feedback and roleplay responses.
- Must combine streaming ASR, fast LLM (local or cloud), and smart trigger heuristics to keep latency < 1s for most interactions.
- Post-session: richer transcripts + deeper LLM regression analysis and personalized plans.
Design principles (both phases):
- **Hybrid pipeline**: streaming ASR + local rule-based immediate feedback + triggered fast-LLM micro-feedback → async deep LLM post-session.
- **Persist canonical artifacts**: raw audio + canonical transcript JSON (timestamps + segments) + feedback/metrics array.
- **Privacy-first**: local-only mode; opt-in cloud LLMs; explicit user consent for storage/backups.
- **Upgradeable dataset**: always store raw audio and canonical transcripts so new models can reprocess old sessions.
Quick implementation plan (Phase 1 first):
- Implement audio capture & batch ASR pipeline (record -> transcribe -> store JSON).
- Implement lightweight rule-based analyzer that runs on partial transcripts for instant nudges.
- Provide Streamlit UI for recording, playback, and session summary (fillers, WPM, hedges).
- Persist data with versioned schema to allow reprocessing later.
Performance & UX targets (Phase 1):
- Rule-based nudges delivered in <200ms locally after text arrives.
- Streaming ASR chunking at ~0.5–1s for partial transcripts.
- Post-session full transcript available within seconds to minutes depending on model size.
---
## 🚀 Roadmap (Phases)
1. **MVP (Phase 1)**
- Setup environment
- Audio capture & storage
- Whisper ASR transcription
- Rule-based analysis (fillers, pacing, hedges)
- Streamlit UI with live counters
- SQLite storage
2. **Smart Feedback Layer (Phase 2)**
- Fast LLM micro-feedback
- Roleplay with simulated managers/clients
- Privacy toggles
3. **Regression Learning (Phase 3)**
- Track progress over time
- Generate growth areas per session
- Dashboards with trendlines
4. **Portability & Future-Proofing (Phase 4)**
- Export/import transcripts (JSON/Parquet)
- Semantic search over past sessions
- Archival storage with schema versioning
5. **Advanced Extensions (Phase 5)**
- Multi-language support
- Real meeting integration (Zoom/Meet plugins)
- Personalized growth plans
- Team/L&D version
6. **Deployment & Rollout (Phase 6)**
- CI/CD pipeline
- Enterprise integrations (SSO, LMS, compliance)
- Pilot programs
- Pricing & commercialization
---
## 📦 Setup (Phase 1)
### 1. Clone & bootstrap
```bash
git clone https://github.com/yourname/corptrainer.git
cd corptrainer
bash scripts/bootstrap.sh
```
### 2. Create virtual environment
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
### 3. Run environment check
```bash
streamlit run src/ui/check_env.py
```
### 4. Test ASR
Place a short test audio file at `sessions/test.wav` and run:
```bash
python src/asr/test_transcribe.py
```
You should see a time-stamped transcript printed in the terminal.
### 🧩 Tech Stack
• ASR: faster-whisper for lightweight, streaming-friendly transcription.
• UI: Streamlit for rapid prototyping and dashboards.
• DB: SQLite / DuckDB for storing transcripts and metrics.
• Planner: IndexedDB (Dexie) with JSON import/export for drillable planning.
• LLMs (Phase 2+): GPT-4o-mini, Mistral, Claude Haiku (fast feedback); GPT-5 (deep regression).
⸻
### ✅ Status
• Phase 1 roadmap imported into Planner (drillable).
• Environment scaffold defined (requirements, bootstrap).
• Audio capture & transcription working.
• Streamlit MVP UI live.
• Rule-based feedback integrated.
• Post-session regression analysis.
⸻
### 🔮 Next Steps
• Implement Phase 1 → Step 2: Audio Capture with live mic recording.
• Add rule-based analyzers (fillers, WPM, hedges).
• Build a Streamlit dashboard showing filler counters in real time.
• Prepare for Phase 2 fast LLM feedback integration.
⸻
### 🤝 Contributing
#### Currently a private dev project. Contributions will be opened up for:
• New analyzers (e.g., tone, persuasion markers)
• Multi-language support
• Integrations with meeting platforms (Zoom, Meet)
• Enterprise dashboards (HR, L&D)
## 📜 License
Licensed under the MIT License – see the [LICENSE](./LICENSE) file for details.

7
main.py Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env python3
# main.py — small helper to point to the Streamlit app.
import sys
print("CorpTrainer scaffold created.")
print("To run the app (after creating/activating venv and installing deps):")
print(" streamlit run src/ui/app.py")
sys.exit(0)

21
requirements.txt Normal file
View File

@@ -0,0 +1,21 @@
# ASR & audio
faster-whisper>=1.2.0
# Install ffmpeg via brew: `brew install ffmpeg`
ffmpeg-python>=0.2.0 ; extra == "ffmpeg_optional"
sounddevice>=0.4.8
soundfile>=0.12.1
# Web UI
streamlit>=1.20.0
# DB / storage
sqlalchemy>=1.4
pandas>=2.0
duckdb>=0.8.0
pyarrow>=9.0.0
# Utilities
python-dotenv
tqdm
typing_extensions

12
scripts/bootstrap.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
echo "Bootstrapping CorpTrainer environment..."
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip setuptools wheel
if [ -f requirements.txt ]; then
pip install -r requirements.txt
else
echo "requirements.txt not found. Please create it or run pip manually."
fi
echo "Bootstrap complete. Activate the venv with: source .venv/bin/activate"

298
setup_project.sh Executable file
View File

@@ -0,0 +1,298 @@
#!/usr/bin/env bash
# setup_project.sh
# Safe project reset + scaffold for CorpTrainer
# Usage:
# ./setup_project.sh # backup, remove existing pieces, recreate skeleton, create venv
# ./setup_project.sh --install # same as above + pip install -r requirements.txt into .venv
# ./setup_project.sh --force # skip confirmation prompt (still backs up unless --no-backup)
# ./setup_project.sh --no-backup # do not create backup (NOT recommended)
# ./setup_project.sh --no-venv # do not create .venv
set -euo pipefail
# Config
PROJECT_ROOT="$(pwd)"
BACKUP_DIR="${PROJECT_ROOT}/backups"
TIMESTAMP="$(date +%Y%m%dT%H%M%S)"
TO_REMOVE=( "db" "scripts" "sessions" "src" ".venv" ".gitignore" "LICENSE" "README.md" "main.py" "requirements.txt" "requirement.txt" )
CREATE_DIRS=( "db" "scripts" "sessions" "src/analysis" "src/asr" "src/ui" )
VENV_DIR=".venv"
INSTALL_REQS=false
FORCE=false
NO_BACKUP=false
CREATE_VENV=true
function usage() {
cat <<EOF
setup_project.sh — reset existing project structure and create CorpTrainer skeleton
Options:
--install create venv AND pip install -r requirements.txt (default: venv created, no install)
--force skip confirmation prompt (still backups unless --no-backup)
--no-backup do NOT create a backup before deleting
--no-venv do NOT create a .venv
-h|--help show this message
EOF
}
# parse args
while [[ $# -gt 0 ]]; do
case "$1" in
--install) INSTALL_REQS=true; shift ;;
--force) FORCE=true; shift ;;
--no-backup) NO_BACKUP=true; shift ;;
--no-venv) CREATE_VENV=false; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown arg: $1"; usage; exit 1 ;;
esac
done
echo "Project root: $PROJECT_ROOT"
echo "Items that will be removed (if present):"
for f in "${TO_REMOVE[@]}"; do printf " - %s\n" "$f"; done
echo
if ! $FORCE; then
read -r -p "Proceed? This will BACKUP & DELETE the items above if they exist. Type 'yes' to continue: " answer
if [[ "$answer" != "yes" ]]; then
echo "Aborted by user. No changes made."
exit 0
fi
fi
# create backup (unless disabled)
if ! $NO_BACKUP; then
mkdir -p "$BACKUP_DIR"
BACKUP_FILE="${BACKUP_DIR}/corp_backup_${TIMESTAMP}.tar.gz"
# only include existing files
EXISTING=()
for f in "${TO_REMOVE[@]}"; do
if [ -e "$PROJECT_ROOT/$f" ]; then EXISTING+=( "$f" ); fi
done
if [ ${#EXISTING[@]} -gt 0 ]; then
echo "Creating backup: $BACKUP_FILE (contains: ${EXISTING[*]})"
tar -czf "$BACKUP_FILE" "${EXISTING[@]}"
echo "Backup saved to: $BACKUP_FILE"
else
echo "No existing items to backup."
fi
else
echo "Skipping backup as requested (--no-backup)."
fi
# remove listed items
echo "Removing old items (if any)..."
for f in "${TO_REMOVE[@]}"; do
if [ -e "$PROJECT_ROOT/$f" ]; then
rm -rf "$PROJECT_ROOT/$f"
echo " removed: $f"
fi
done
# recreate directories
echo "Creating skeleton directories..."
for d in "${CREATE_DIRS[@]}"; do
mkdir -p "$PROJECT_ROOT/$d"
echo " created: $d"
done
# create placeholder .gitignore
cat > .gitignore <<'EOF'
# Byte-compiled / caches
__pycache__/
*.py[cod]
*$py.class
# Virtual env
.venv/
venv/
env/
# OS / Editor
.DS_Store
.vscode/
.idea/
# DB and sessions (audio)
*.db
/db/
/backups/
sessions/*
# Logs
*.log
EOF
echo "Created .gitignore"
# create LICENSE (MIT) — edit name/year later
cat > LICENSE <<'EOF'
MIT License
Copyright (c) YEAR YOUR_NAME
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights...
(Replace YEAR and YOUR_NAME with appropriate values.)
EOF
echo "Created LICENSE"
# create README.md
cat > README.md <<'EOF'
# CorpTrainer — AI-driven Corporate Communication Coach
This repository contains the scaffold for the CorpTrainer MVP (Practice Mode) and roadmap.
## Quickstart (recommended)
1. Create & activate venv:
\`\`\`bash
python3 -m venv .venv
source .venv/bin/activate
\`\`\`
2. Install dependencies:
\`\`\`bash
pip install -r requirements.txt
\`\`\`
3. Run Streamlit app:
\`\`\`bash
streamlit run src/ui/app.py
\`\`\`
## Project layout
- db/ — persistent small DB files (sqlite)
- sessions/ — stored raw audio sessions (WAV/FLAC)
- src/analysis/ — rule-based analyzers
- src/asr/ — recorder & ASR stream wrappers
- src/ui/ — Streamlit UI
- scripts/ — helper scripts (bootstrap, maintenance)
- requirements.txt — python deps
See `scripts/bootstrap.sh` to bootstrap the environment automatically.
EOF
echo "Created README.md"
# create requirements.txt (conservative set)
cat > requirements.txt <<'EOF'
# ASR & audio
faster-whisper>=1.2.0
# Install ffmpeg via brew: `brew install ffmpeg`
ffmpeg-python>=0.2.0 ; extra == "ffmpeg_optional"
sounddevice>=0.4.8
soundfile>=0.12.1
# Web UI
streamlit>=1.20.0
# DB / storage
sqlalchemy>=1.4
pandas>=2.0
duckdb>=0.8.0
pyarrow>=9.0.0
# Utilities
python-dotenv
tqdm
typing_extensions
EOF
echo "Created requirements.txt"
# create scripts/bootstrap.sh
mkdir -p scripts
cat > scripts/bootstrap.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
echo "Bootstrapping CorpTrainer environment..."
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip setuptools wheel
if [ -f requirements.txt ]; then
pip install -r requirements.txt
else
echo "requirements.txt not found. Please create it or run pip manually."
fi
echo "Bootstrap complete. Activate the venv with: source .venv/bin/activate"
EOF
chmod +x scripts/bootstrap.sh
echo "Created scripts/bootstrap.sh"
# create main.py (entry notes)
cat > main.py <<'EOF'
#!/usr/bin/env python3
# main.py — small helper to point to the Streamlit app.
import sys
print("CorpTrainer scaffold created.")
print("To run the app (after creating/activating venv and installing deps):")
print(" streamlit run src/ui/app.py")
sys.exit(0)
EOF
chmod +x main.py
echo "Created main.py"
# create minimal Streamlit app skeleton
cat > src/ui/app.py <<'EOF'
import streamlit as st
st.set_page_config(page_title="CorpTrainer", layout="centered")
st.title("CorpTrainer — Practice Mode (MVP)")
st.write("This is a skeleton Streamlit app. Replace with app logic in src/ui/")
if st.button("Demo: env check"):
st.write("Environment looks fine — implement recorder, asr, analyzer in src/")
EOF
echo "Created src/ui/app.py"
# create minimal analyzer & recorder & db placeholders
cat > src/analysis/rule_analyzer.py <<'EOF'
import re
FILLERS = ["um","uh","like","you know","so","actually","basically"]
def count_fillers(text):
t = text.lower()
return sum(len(re.findall(r'\\b' + re.escape(f) + r'\\b', t)) for f in FILLERS)
EOF
echo "Created src/analysis/rule_analyzer.py"
cat > src/asr/recorder.py <<'EOF'
# minimal recorder placeholder (use sounddevice in real implementation)
def placeholder_record():
print("Recorder placeholder. Implement using sounddevice. See src/audio/recorder.py in design notes.")
EOF
echo "Created src/asr/recorder.py"
# ensure src/storage exists and move file (if directory absent)
mkdir -p src/storage
cat > src/storage/db.py <<'EOF'
# DB placeholder. Implement sqlite3/sqlalchemy wrapper here.
def init_db(path='db/corptrainer.db'):
print(f"DB init placeholder: {path}")
EOF
echo "Created src/storage/db.py (note: directory src/storage was not pre-created; created file)"
mv -f src/storage/db.py src/storage/db.py || true
# create .venv (unless the user opted out)
if $CREATE_VENV; then
echo "Creating virtual environment at .venv ..."
python3 -m venv "$VENV_DIR"
echo ".venv created."
if $INSTALL_REQS; then
echo "Activating venv and installing requirements..."
# shellcheck disable=SC1091
source "$VENV_DIR/bin/activate"
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
deactivate || true
fi
else
echo "Skipping creation of .venv (--no-venv)."
fi
echo
echo "Setup complete. Created files & dirs:"
ls -1 \
db scripts sessions src .gitignore LICENSE README.md main.py requirements.txt | sed 's/^/ - /'
echo
echo "Next steps:"
echo " 1) Activate venv: source .venv/bin/activate"
echo " 2) Install deps: pip install -r requirements.txt (if you didn't run --install)"
echo " 3) Run Streamlit: streamlit run src/ui/app.py"
echo
echo "Backup location (if created): $BACKUP_FILE"

View File

@@ -0,0 +1,5 @@
import re
FILLERS = ["um","uh","like","you know","so","actually","basically"]
def count_fillers(text):
t = text.lower()
return sum(len(re.findall(r'\\b' + re.escape(f) + r'\\b', t)) for f in FILLERS)

3
src/asr/recorder.py Normal file
View File

@@ -0,0 +1,3 @@
# minimal recorder placeholder (use sounddevice in real implementation)
def placeholder_record():
print("Recorder placeholder. Implement using sounddevice. See src/audio/recorder.py in design notes.")

3
src/storage/db.py Normal file
View File

@@ -0,0 +1,3 @@
# DB placeholder. Implement sqlite3/sqlalchemy wrapper here.
def init_db(path='db/corptrainer.db'):
print(f"DB init placeholder: {path}")

6
src/ui/app.py Normal file
View File

@@ -0,0 +1,6 @@
import streamlit as st
st.set_page_config(page_title="CorpTrainer", layout="centered")
st.title("CorpTrainer — Practice Mode (MVP)")
st.write("This is a skeleton Streamlit app. Replace with app logic in src/ui/")
if st.button("Demo: env check"):
st.write("Environment looks fine — implement recorder, asr, analyzer in src/")