AI-powered mental health journal analysis using Google Vertex AI. Transform weekly voice recordings into actionable insights with Speech-to-Text v2 and Gemini 2.0.
FULLY OPERATIONAL - All components tested end-to-end (October 27, 2025)
- ✅ Audio upload (no time limit)
- ✅ Automatic transcription (95-99% accuracy)
- ✅ Emotion & event extraction
- ✅ Weekly report generation (HTML/PDF)
# Upload a session (recommended method)
./scripts/upload_session_simple.sh my_journal.wav 2025-W44 session_001
# Generate weekly report
bash scripts/run_pipeline.sh 2025-W44
# View report
gsutil cp gs://mj-reports-mental-journal-dev/2025-W44/weekly_report.html .
open weekly_report.htmlFor detailed instructions, see User Guide
| Document | Description |
|---|---|
| USER_GUIDE.md | Complete step-by-step usage guide |
| SYSTEM_STATUS.md | Current system status & test results |
| SIGNED_URL_ISSUE.md | Known issue with signed URLs & workaround |
| ARCHITECTURE.md | System architecture details |
| QUICKSTART.md | Fast deployment guide |
-
Region:
europe-west1(Belgium) -
PROJECT_ID:
mental-journal-dev -
GCS buckets :
mj-audio-raw-<PROJECT_ID>(source WAV/MP3/FLAC)mj-audio-processed-<PROJECT_ID>(normalized wav + features)mj-analytics-<PROJECT_ID>(JSON artifacts)mj-reports-<PROJECT_ID>(weekly HTML/PDF)
-
BQ dataset (optionnel Looker Studio) :
journaling -
Service account :
pipeline-sa@<PROJECT_ID>.iam.gserviceaccount.com
Voice Recording (≤ 15 min)
↓ Speech-to-Text v2 → transcript.json (+ word timestamps)
↓ Librosa (Prosody) → prosody_features.json (pitch, energy, pauses)
↓ Gemini (NLU) → events_emotions.json (events, emotions, themes)
↓ Jinja2 + WeasyPrint → weekly_report.json + weekly_report.{html,pdf}
# Authenticate with GCP
gcloud auth login
gcloud config set project mental-journal-dev
# Enable required APIs
gcloud services enable \
run.googleapis.com \
cloudbuild.googleapis.com \
secretmanager.googleapis.com \
aiplatform.googleapis.com \
speech.googleapis.com \
cloudkms.googleapis.com \
workflows.googleapis.com \
logging.googleapis.com \
pubsub.googleapis.com \
bigquery.googleapis.com./scripts/setup.shCrée les buckets GCS, le service account, KMS (CMEK) et active les APIs.
./scripts/deploy.shConstruit l’image Docker et déploie le Cloud Run Job.
# Upload audio (ex. semaine 2025-W42)
gsutil cp audio.wav gs://mj-audio-raw-mental-journal-dev/2025-W42/session_001.wav
# Execute pipeline for that week
gcloud run jobs execute mj-weekly-pipeline --region=europe-west1 --args=2025-W42Vérifier les résultats :
./scripts/check_results.sh 2025-W42vertex/ ├── pipeline/ # Main analysis pipeline │ ├── main.py # Orchestration script │ ├── Dockerfile │ └── requirements.txt ├── api/ # FastAPI REST API │ ├── main.py # API entry point │ ├── routers/ # API routes (health, upload, sessions, reports, orchestration) │ ├── Dockerfile │ └── .env.example ├── templates/ # HTML report templates ├── scripts/ # Bash automation scripts │ ├── deploy.sh # Deploy pipeline (Cloud Run Job) │ ├── deploy_api.sh # Deploy API (Cloud Run Service) │ ├── test_api.sh # Test all API routes │ └── ... └── docs/ # Documentation ├── INDEX.md # Documentation index ├── ACCOMPLISSEMENT.md ├── RESUME_EXECUTIF.md ├── GEMINI_2X_MIGRATION.md ├── PROJECT_ROADMAP.md ├── API_GUIDE.md # API usage guide ├── API_ROUTES.md # API routes reference └── MCP_SETUP.md
-
Cloud : Cloud Run, Cloud Storage (CMEK), Vertex AI, Workflows, Cloud Scheduler
-
AI Models :
- Speech-to-Text v2 (
location=global, support long audios via LRO) - Gemini 2.x (Flash/Pro selon besoins)
- Speech-to-Text v2 (
-
Python :
librosa,scipy,numpy,jinja2,weasyprint -
Container : Docker (Python 3.11 +
ffmpeg+ deps WeasyPrint)
Pour chaque semaine (ex. 2025-W42) :
gs://mj-analytics-mental-journal-dev/2025-W42/
├── session_001/
│ ├── transcript.json # STT transcription
│ ├── prosody_features.json # Vocal features
│ └── events_emotions.json # NLU analysis
└── weekly_report.json # Aggregated report
gs://mj-reports-mental-journal-dev/2025-W42/
├── weekly_report.html
└── weekly_report.pdf
**~ €0.30 / semaine** (≈ €1.20 / mois)
- Speech-to-Text v2 : ~€0.10
- Gemini (Flash/Pro) : ~€0.15
- Storage + Compute : ~€0.05
(Dépend de la durée d’audio, du modèle Gemini et de la fréquence d’exécution.)
PROJECT_ID=mental-journal-dev
REGION=europe-west1
GOOGLE_CLOUD_LOCATION=global
GEMINI_MODEL=gemini-2.0-flash-exp # ou gemini-2.5-pro
BUCKET_RAW=mj-audio-raw-mental-journal-dev
BUCKET_PROC=mj-audio-processed-mental-journal-dev
BUCKET_ANALYTICS=mj-analytics-mental-journal-dev
BUCKET_REPORTS=mj-reports-mental-journal-dev- CMEK activé sur tous les buckets.
- IAM minimal :
pipeline-sapour écrire/lire là où nécessaire, lecteur Looker si export BQ. - Logs d’accès : Cloud Audit Logging (optionnel : sink vers BigQuery).
Exemple de sink :
bq --location=$REGION mk --dataset $PROJECT_ID:logsink
LOG_SINK=access-logs
gcloud logging sinks create $LOG_SINK \
bigquery.googleapis.com/projects/$PROJECT_ID/datasets/logsink \
--log-filter='resource.type="gcs_bucket"'schemas/transcript.schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Transcript",
"type": "object",
"properties": {
"session_id": {"type": "string"},
"audio_uri": {"type": "string"},
"language_code": {"type": "string"},
"created_at": {"type": "string", "format": "date-time"},
"transcript": {"type": "string"},
"words": {
"type": "array",
"items": {
"type": "object",
"properties": {
"start": {"type": "number"},
"end": {"type": "number"},
"word": {"type": "string"},
"confidence": {"type": "number"}
},
"required": ["start", "end", "word"]
}
}
},
"required": ["session_id", "audio_uri", "language_code", "created_at", "transcript"]
}schemas/prosody_features.schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ProsodyFeatures",
"type": "object",
"properties": {
"session_id": {"type": "string"},
"created_at": {"type": "string", "format": "date-time"},
"sr": {"type": "integer"},
"duration_sec": {"type": "number"},
"pitch_mean": {"type": "number"},
"pitch_std": {"type": "number"},
"energy_mean": {"type": "number"},
"energy_std": {"type": "number"},
"pause_count": {"type": "integer"},
"pause_total_sec": {"type": "number"}
},
"required": ["session_id", "created_at", "sr", "duration_sec"]
}schemas/events_emotions.schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EventsEmotions",
"type": "object",
"properties": {
"session_id": {"type": "string"},
"created_at": {"type": "string", "format": "date-time"},
"events": {"type": "array", "items": {"type": "string"}},
"emotions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {"type": "string"},
"confidence": {"type": "number"}
},
"required": ["label"]
}
},
"themes": {"type": "array", "items": {"type": "string"}}
},
"required": ["session_id", "created_at", "events", "emotions"]
}schemas/weekly_report.schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "WeeklyReport",
"type": "object",
"properties": {
"week": {"type": "string"},
"user_tz": {"type": "string"},
"sessions": {"type": "integer"},
"emotion_index": {"type": "number"},
"trend": {"type": "string", "enum": ["up", "down", "flat"]},
"highlights": {"type": "array", "items": {"type": "string"}},
"prosody_summary": {
"type": "object",
"properties": {
"pitch_mean": {"type": "number"},
"energy_mean": {"type": "number"},
"pause_rate": {"type": "number"}
}
}
},
"required": ["week", "sessions", "emotion_index", "trend"]
}# Build image
gcloud builds submit --tag gcr.io/$PROJECT_ID/mj-pipeline:latest pipeline/
# Create Cloud Run Job
gcloud run jobs create mj-weekly-pipeline \
--image gcr.io/$PROJECT_ID/mj-pipeline:latest \
--region=$REGION \
--service-account=pipeline-sa@$PROJECT_ID.iam.gserviceaccount.com \
--set-env-vars=PROJECT_ID=$PROJECT_ID,REGION=$REGION,BUCKET_RAW=mj-audio-raw-$PROJECT_ID,BUCKET_PROC=mj-audio-processed-$PROJECT_ID,BUCKET_ANALYTICS=mj-analytics-$PROJECT_ID,BUCKET_REPORTS=mj-reports-$PROJECT_ID,USER_TZ=Europe/Paris \
--max-retries=1 \
--task-timeout=3600s
# Manual execution for current week
WEEK=$(date +"%G-W%V")
gcloud run jobs execute mj-weekly-pipeline --region=$REGION --args=$WEEKworkflows/trigger_job.yaml
main:
params: [week]
steps:
- callRunJob:
call: http.post
args:
url: https://run.googleapis.com/apis/run.googleapis.com/v1/projects/${sys.get_env("GOOGLE_CLOUD_PROJECT")}/locations/europe-west1/jobs/mj-weekly-pipeline:run
auth:
type: OAuth2
body:
overrides:
containerOverrides:
- args: ["${week}"]
result: r
- returnResult:
return: ${r.body}Déploiement & autorisations :
WORKFLOW=mj-run-job
gcloud workflows deploy $WORKFLOW --source=workflows/trigger_job.yaml --location=$REGION
# Autoriser le SA à invoquer le workflow
gcloud workflows add-iam-policy-binding $WORKFLOW \
--location=$REGION \
--member=serviceAccount:pipeline-sa@$PROJECT_ID.iam.gserviceaccount.com \
--role=roles/workflows.invokerCloud Scheduler (dimanche 23:55 Europe/Paris) :
CRON="55 23 * * SUN"
PAYLOAD=$(jq -n --arg w "$(date +"%G-W%V")" '{argument: {week: $w}}')
gcloud scheduler jobs create http mj-weekly \
--schedule="$CRON" \
--time-zone="Europe/Paris" \
--http-method=POST \
--uri="https://workflowexecutions.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/workflows/$WORKFLOW/executions" \
--oauth-service-account-email=pipeline-sa@$PROJECT_ID.iam.gserviceaccount.com \
--headers="Content-Type=application/json" \
--message-body="$PAYLOAD"Variante Pub/Sub : publier
{week:"YYYY-Www"}et déclencher une petite Cloud Run Service/Workflow. La version HTTP ci-dessus est la plus simple.
# Execute for current week
gcloud run jobs execute mj-weekly-pipeline --args=$(date +'%G-W%V') --region=$REGION
# View logs
gcloud logging read 'resource.type=cloud_run_job' --limit=20
# List outputs
gsutil ls gs://mj-analytics-mental-journal-dev/
# Download report
gsutil cp gs://mj-reports-mental-journal-dev/2025-W42/weekly_report.pdf ./Toute la documentation est dans /docs :
- INDEX.md - Index complet de la documentation
- API_GUIDE.md - Guide d'utilisation de l'API FastAPI
- API_ROUTES.md - Référence des 15 routes avec exemples
- PROJECT_ROADMAP.md - Guide de setup détaillé
- MCP_SETUP.md - Configuration Google Cloud MCP
This project was developed for the GCPU Hackathon 2025 – Mental Health Journal.
GCP Project: mental-journal-dev
Region: europe-west1
Contact: queriauxrobin@gmail.com