Akki0404's picture
v2 - web interface, health endpoint, full app.py
4921871
|
Raw
History Blame
23.4 kB
metadata
title: Voice Authenticity OpenEnv
emoji: πŸŽ™οΈ
colorFrom: blue
colorTo: red
sdk: docker
pinned: false
app_port: 7860
tags:
  - openenv
  - speech
  - fraud-detection
  - audio

πŸŽ™οΈ Voice Authenticity Detection β€” OpenEnv Environment

Voice fraud cost the global economy $25B+ in 2024. Tools like ElevenLabs can clone any voice in 60 seconds. Banks, insurers, and telecom providers face real-time phone scams, identity spoofing, and deepfake audio at unprecedented scale β€” and existing benchmarks can't keep up.

This environment trains agents to actively investigate, gather evidence, and reason about acoustic features under realistic degradation β€” codec compression, adversarial perturbation, streaming noise, and phone call simulation β€” through a genuine multi-step decision process with calibrated, risk-aware grading.

The 5-Action Agent Protocol

Step Action What the Agent Gets Purpose
1 request_temporal_features Jitter, shimmer, HNR (raw + normalized) Vocal cord irregularity markers
2 request_spectral_features 20 MFCC means, 20 MFCC stds, ZCR, spectral centroid Timbre and spectral shape
3 request_comparison Cosine similarity + euclidean distance to real/fake centroids Statistical comparison to known references
4 analyze_evidence Structured synthesis of all gathered evidence with signal tally Evidence integration and confidence calibration
5 final_classify Submits label (0=real, 1=synthetic) + confidence + reasoning Terminal action β€” triggers 6-component grading

The agent starts with zero features visible and must earn its information before classifying. This is sequential decision-making under partial observability β€” not a single-shot classifier.


🚫 Why Existing Benchmarks Fail Here

ASVspoof (Automatic Speaker Verification Spoofing) evaluates countermeasure systems using static datasets with fixed train/test splits. Agents see the full feature set at once, make a single prediction, and receive binary pass/fail scoring. There is no partial observability, no multi-step interaction, no confidence calibration, and no reward shaping. ASVspoof cannot evaluate whether an agent knows how to investigate β€” only whether it gets the right answer.

ADD (Audio Deepfake Detection) benchmarks follow the same static paradigm: models are trained on one distribution and tested on another, with no mechanism for the agent to actively gather information or express calibrated uncertainty. ADD evaluates classifiers, not agents.

This environment is different. It requires agents to:

  • Choose which features to request and in what order (partial observability)
  • Synthesize heterogeneous evidence sources before committing to a classification
  • Express calibrated confidence β€” overconfident wrong answers are penalized more harshly than uncertain wrong answers
  • Operate under real-world degradation β€” codec compression, adversarial perturbation, streaming noise, and phone-call simulation
  • Follow logical investigation trajectories β€” gather β†’ analyze β†’ classify, scored by a 6-component grader

No existing benchmark evaluates these capabilities.


🌍 Real-World Motivation

AI-generated voices are increasingly weaponized for:

  • Phone fraud & social engineering β€” real-time voice cloning during live calls
  • Deepfake audio in misinformation β€” fabricated audio of public figures
  • Identity spoofing β€” bypassing voice biometric authentication systems
  • Financial fraud β€” CEO voice cloning for unauthorized wire transfers
  • Insurance scams β€” fabricated recorded statements

This environment provides a structured benchmark for training agents to detect synthetic speech under conditions that static classifiers and existing benchmarks cannot handle.


πŸ—οΈ Environment Overview

The environment serves 48-dimensional feature vectors extracted from audio samples. Unlike standard classification benchmarks, agents start with NO features visible and must actively query the environment through the 5-action protocol to gather evidence before making a final classification.

This creates genuine sequential decision-making under partial observability, requiring agents to:

  • Choose which information to request and in what order
  • Synthesize heterogeneous evidence sources
  • Express calibrated confidence reflecting genuine uncertainty
  • Follow logical investigation trajectories

πŸ† Tasks (5 Total) β€” Monotonic Difficulty Progression

Task Difficulty Expected Score Description
clean_detection Easy 0.65–0.78 Clean, unmodified audio features β€” clear signal separation
compressed_detection Medium 0.50–0.65 Codec compression flattens MFCC stds, suppresses jitter/shimmer
adversarial_detection Hard 0.40–0.58 Feature distributions overlap β€” no clean threshold separates classes
streaming_detection Medium-Hard 0.38–0.55 Step-dependent noise soft-gating β€” earlier steps noisier, later cleaner
phonecall_detection Extreme 0.25–0.42 Heavy narrowband codec + background noise β€” near detection limit

Difficulty Progression Design

Harder tasks apply difficulty-aware score scaling in the grader. This models genuine signal degradation: adversarial samples have overlapping feature distributions, phone call codec compression destroys discriminative features, and streaming noise makes early observations unreliable. Even a perfect agent achieves lower scores on harder tasks because the underlying signal quality is genuinely worse.


πŸ… Grading System (6 Components)

Each episode is scored across 6 components with difficulty-weighted contributions:

Component What It Measures Easy Medium Hard Extreme
Correctness Label matches ground truth 0.40 0.30 0.25 0.20
Confidence Calibration Penalizes overconfidence, rewards calibrated uncertainty 0.15 0.20 0.25 0.25
Trajectory Quality Did agent gather β†’ analyze β†’ classify? 0.10 0.15 0.18 0.20
Feature Utilization Did agent request temporal AND spectral features? 0.15 0.15 0.12 0.15
Reasoning Consistency Does reasoning text match chosen label? 0.10 0.10 0.10 0.10
Action Ordering Logical sequence: gather β†’ analyze β†’ classify 0.10 0.10 0.10 0.10

After component scoring, a difficulty scaling factor is applied:

Difficulty Scaling Factor Max Achievable Score
Easy 0.78 ~0.73
Medium 0.66 ~0.61
Hard 0.59 ~0.55
Medium-Hard 0.55 ~0.51
Extreme 0.41 ~0.38

Why This Matters

On easy tasks, correctness dominates. On hard/extreme tasks, confidence calibration and trajectory quality become critical β€” mirroring real-world fraud detection where a confident wrong answer is more dangerous than an uncertain one, and where systematic investigation outperforms snap judgments.


🎁 Step-Level Rewards

The environment provides shaping signals at every step, not just on final classification:

Condition Reward
First action is a feature request +0.05
Requested both temporal AND spectral features +0.05
Used analyze_evidence before final_classify +0.05
Jumped straight to final_classify without gathering -0.10
Repeated the same action consecutively -0.05
Reasoning contradicts chosen label -0.10

Step-level rewards are clamped to [0.02, 0.18] and never produce exactly 0.0 or 1.0. The terminal final_classify step returns the pure grader score.

These intermediate rewards teach agents investigation behavior rather than pure classification.


βš™οΈ Why Feature Vectors Instead of Raw Audio?

  • Fits within 2 vCPU / 8GB RAM constraints
  • Feature extraction is performed offline for fast inference
  • Enables LLM-native reasoning over interpretable acoustic characteristics β€” not possible with raw waveforms under current infrastructure constraints
  • Avoids heavy signal processing during evaluation

πŸ“Š Dataset

  • Real speech: 250 samples from garystafford/deepfake-audio-detection (authentic human recordings)
  • Synthetic speech: 250 samples (ElevenLabs, Hume AI, and other TTS platforms)
  • Total: 500 labeled samples across 5 task variants

The dataset is designed for evaluation structure and reward learning, not scale. The feature pipeline supports arbitrary dataset expansion for production deployment.


πŸ“ Observation Space

Each observation contains:

class VoiceObservation(BaseModel):
    features: List[float]                          # 48-dim (zeroed until revealed)
    task_name: str                                 # current task
    step_number: int                               # current step in episode
    difficulty: str                                # easy|medium|medium_hard|hard|extreme
    sample_id: int                                 # index into dataset
    hint: Optional[str]                            # context and guidance
    visible_features: Dict[str, Any]               # features revealed so far
    evidence_summary: Optional[str]                # from analyze_evidence
    comparison_result: Optional[Dict[str, float]]  # from request_comparison
    available_actions: List[str]                    # valid actions this step
    actions_taken: List[str]                        # action history

48-Dimensional Feature Vector

Index Feature Description
0–19 MFCC means Timbre and spectral shape of the voice
20–39 MFCC std devs Temporal variation in spectral characteristics
40 Zero crossing rate Signal sign changes per frame
41 Spectral centroid Brightness of the sound
42 Jitter Cycle-to-cycle frequency instability
43 Shimmer Amplitude variation between glottal pulses
44 HNR Ratio of harmonic energy to background noise
45–47 Compression artifacts Spectral bandwidth, rolloff, RMS energy

Key Discriminating Features

  • Jitter: measures cycle-to-cycle frequency instability β€” real voices show natural irregularity, synthetic voices are too stable
  • Shimmer: tracks amplitude variation between consecutive glottal pulses β€” real speech has organic variation
  • HNR: quantifies harmonic-to-noise ratio β€” synthetic voices are typically "too clean"

🎯 Action Space

class VoiceAction(BaseModel):
    action_type: str   # one of the 5 actions
    label: int         # 0=real, 1=synthetic (for final_classify)
    confidence: float  # [0.05, 0.95] (for final_classify)
    reasoning: str     # explanation (for final_classify)

πŸ“Š Baseline Scores

Agent: Qwen/Qwen2.5-72B-Instruct via HuggingFace router Protocol: 5-action (temporal β†’ spectral β†’ comparison β†’ analyze β†’ classify) Runs: 1 episode per task, seed=7

Task Difficulty Score Success Notes
clean_detection Easy 0.74 Yes Clean features β€” strong baseline
compressed_detection Medium 0.62 Yes Codec compression degrades acoustic signal
adversarial_detection Hard 0.55 No Overlapping distributions challenge classification
streaming_detection Medium-Hard 0.30 No Streaming noise fooled the LLM at step 1
phonecall_detection Extreme 0.22 No Phone-call degradation pushed detection below chance

Scores decrease monotonically with difficulty β€” harder tasks have genuinely noisier signals and overlapping feature distributions. The difficulty scaling is applied in the grader, meaning even a perfect agent scores lower on harder tasks. On streaming and phone-call tasks, the LLM was additionally fooled by degraded features, creating sharper score drops.


πŸ”Œ OpenEnv API

from environment.env import VoiceAuthenticityEnv

env = VoiceAuthenticityEnv(task_name="clean_detection")

# Reset β€” no features visible yet
obs = env.reset(seed=42)
# obs.features           β†’ [0.05, 0.05, ..., 0.05] (zeroed)
# obs.available_actions  β†’ ["request_temporal_features", ...]

# Step 1 β€” request temporal features
action = {"action_type": "request_temporal_features"}
obs, reward, done, info = env.step(action)
# obs.visible_features["temporal"]["jitter"] β†’ 0.032451
# reward β†’ 0.10 (shaping: first action is gathering)

# Step 2 β€” request spectral features
action = {"action_type": "request_spectral_features"}
obs, reward, done, info = env.step(action)
# obs.visible_features["spectral"]["mfcc_means"] β†’ [20 values]
# reward β†’ 0.10 (shaping: multi-feature-type bonus)

# Step 3 β€” compare to reference centroids
action = {"action_type": "request_comparison"}
obs, reward, done, info = env.step(action)
# obs.comparison_result["cosine_similarity_to_real"] β†’ 0.8742
# obs.comparison_result["closer_to"] β†’ "real"

# Step 4 β€” analyze all evidence
action = {"action_type": "analyze_evidence"}
obs, reward, done, info = env.step(action)
# obs.evidence_summary β†’ "Evidence analysis (3 sources): ..."

# Step 5 β€” final classification
action = {
    "action_type": "final_classify",
    "label": 0,
    "confidence": 0.78,
    "reasoning": "High jitter and shimmer indicate natural vocal cord variation..."
}
obs, reward, done, info = env.step(action)
# reward β†’ 0.73 (6-component graded score with difficulty scaling)
# done β†’ True
# info["grader_breakdown"] β†’ {correctness: 0.95, calibration: 0.84, ...}

state = env.state()

πŸ“‹ Expected stdout Format

[START] task=clean_detection env=voice-authenticity model=Qwen/Qwen2.5-72B-Instruct
[STEP] step=1 action=request_temporal_features reward=0.10 done=false error=null
[STEP] step=2 action=request_spectral_features reward=0.10 done=false error=null
[STEP] step=3 action=request_comparison reward=0.05 done=false error=null
[STEP] step=4 action=analyze_evidence reward=0.05 done=false error=null
[STEP] step=5 action=final_classify label=0 confidence=0.75 reward=0.74 done=true error=null
[END] success=true steps=5 score=0.74 rewards=0.10,0.10,0.05,0.05,0.74 grader_breakdown={"correctness":0.95,"calibration":0.90,"trajectory":0.95,"utilization":0.95,"reasoning":0.95,"ordering":0.95}

⚠️ Known Limitations and Failure Cases

  • Synthetic voices with injected background noise may evade temporal feature detection
  • Real voices under heavy studio compression can mimic synthetic spectral profiles
  • Borderline acoustic feature overlap exists between real and adversarially crafted samples β€” no clean threshold separates them
  • Phone call simulation pushes detection to near-chance performance, reflecting genuine real-world difficulty
  • Streaming task noise is step-dependent β€” agents that don't re-request features may work from degraded data
  • Dataset of 500 samples is designed for evaluation structure and reward design, not production scale
  • Results may vary across accents, languages, and recording conditions not represented in the data

This environment is designed to be extended with real enterprise datasets. The evaluation structure, 6-component grader, and feature pipeline are production-ready; the dataset is a research prototype.


πŸš€ Setup and Usage

Requirements

Python 3.10+
Docker
HuggingFace account

Local Setup

git clone https://huggingface.co/spaces/AksharaSharma/voice-authenticity-openenv
cd voice-authenticity-openenv

pip install -r requirements.txt

python scripts/download_data.py
python scripts/extract_features.py

cp .env.example .env
# Edit .env with your HF_TOKEN

# Terminal 1 β€” start the environment server
python app.py

# Terminal 2 β€” run baseline inference (5-action protocol, all 5 tasks)
python inference.py

Validation Sequence

docker build -t voice-authenticity .
docker run --env-file .env voice-authenticity &
sleep 10
curl http://localhost:7860/health
curl -X POST http://localhost:7860/reset
python inference.py

Running Tests

# Run all tests
pytest test_env.py -v

# Run individual tests
pytest test_env.py::test_reset_returns_observation -v
pytest test_env.py::test_five_actions_complete_episode -v

Environment Variables

Variable Description Default
API_BASE_URL LLM API endpoint https://router.huggingface.co/v1
MODEL_NAME Model identifier Qwen/Qwen2.5-72B-Instruct
HF_TOKEN HuggingFace API token required
VOICE_TASK Task to run clean_detection
ENV_SERVER_URL Environment server URL http://localhost:7860

Docker

docker build -t voice-authenticity .
docker run --env-file .env voice-authenticity

πŸ“ Project Structure

voice-authenticity-openenv/
β”œβ”€β”€ environment/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ env.py              # 5-action step/reset/state with partial observability
β”‚   β”œβ”€β”€ models.py           # Pydantic Observation/Action/Reward models
β”‚   β”œβ”€β”€ graders.py          # 6-component scoring with difficulty weights + scaling
β”‚   └── data/
β”‚       β”œβ”€β”€ features.npy            # clean features (500 Γ— 48)
β”‚       β”œβ”€β”€ features_compressed.npy # codec-degraded features
β”‚       β”œβ”€β”€ features_adversarial.npy# adversarially perturbed features
β”‚       β”œβ”€β”€ features_streaming.npy  # streaming degraded features
β”‚       β”œβ”€β”€ features_phonecall.npy  # phone call degraded features
β”‚       β”œβ”€β”€ features_raw.npy        # unnormalized values
β”‚       β”œβ”€β”€ labels.npy              # ground truth labels
β”‚       β”œβ”€β”€ labels_compressed.npy
β”‚       β”œβ”€β”€ labels_adversarial.npy
β”‚       β”œβ”€β”€ labels_streaming.npy
β”‚       └── labels_phonecall.npy
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ download_data.py    # fetch dataset from HuggingFace
β”‚   └── extract_features.py # audio β†’ feature vectors (5 tasks)
β”œβ”€β”€ server/
β”‚   └── app.py              # OpenEnv HTTP server entry point
β”œβ”€β”€ Dashboard.html          # interactive web dashboard (served at / and /web)
β”œβ”€β”€ app.py                  # FastAPI server (serves Dashboard.html + API)
β”œβ”€β”€ inference.py            # baseline LLM agent (5-action protocol)
β”œβ”€β”€ test_env.py             # environment unit tests (5 tests)
β”œβ”€β”€ openenv.yaml            # OpenEnv spec (5 tasks)
β”œβ”€β”€ pyproject.toml          # package config
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ requirements.txt
└── README.md

πŸ–₯️ Web Dashboard

Dashboard.html is a self-contained, interactive web interface served at both / and /web when the server is running. It provides:

  • Real-time investigation simulation β€” press a button to watch the 5-step agent protocol animate live, with terminal-style log output
  • Task difficulty breakdown β€” all 5 tasks with difficulty badges, score bars, and detailed descriptions
  • 6-component score explorer β€” click any task to see its grader breakdown across correctness, confidence calibration, trajectory quality, feature utilization, reasoning consistency, and action ordering
  • Step-by-step protocol visualization β€” the full 5-action investigation protocol with reward annotations and animated step progression

The dashboard uses no external frameworks β€” pure HTML, CSS, and vanilla JavaScript.


πŸ§ͺ Test Suite

test_env.py β€” Environment Unit Tests

Five targeted tests validating core environment behavior:

Test What It Validates
test_reset_returns_observation reset() returns a valid VoiceObservation with step 0, correct task name, and hint
test_step_returns_reward_in_range Rewards from step() are always in [0.05, 0.95] β€” never exactly 0.0 or 1.0
test_five_actions_complete_episode The full 5-action protocol (temporal β†’ spectral β†’ comparison β†’ analyze β†’ classify) completes an episode with done=True
test_reward_never_zero_or_one Explicit check that no step returns a boundary reward of exactly 0.0 or 1.0
test_all_five_tasks_load All 5 task variants (clean, compressed, adversarial, streaming, phonecall) load successfully and return valid observations

Run: pytest test_env.py -v


πŸ”¬ Technical Pipeline

Feature Extraction

flowchart TD
    A["🎀 Raw Audio\n(.wav / .flac)"] --> B["librosa"]
    A --> C["parselmouth / Praat"]

    B --> D["MFCC Means (20)\nMFCC Stds (20)\nZCR Β· Spectral Centroid\nBandwidth Β· Rolloff Β· RMS"]
    C --> E["Jitter Β· Shimmer Β· HNR"]

    D --> F["Concatenate β†’ 48-dim raw vector"]
    E --> F

    F --> G["Z-Score Normalization\n(per-feature mean/std)"]

    G --> H["float32 feature vector (48-dim)"]

    H --> I["Clean\nfeatures.npy"]
    H --> J["Compressed\nfeatures_compressed.npy"]
    H --> K["Adversarial\nfeatures_adversarial.npy"]
    H --> L["Streaming\nfeatures_streaming.npy"]
    H --> M["Phone Call\nfeatures_phonecall.npy"]

    style A fill:#1a1a2e,stroke:#e94560,color:#fff
    style B fill:#0f3460,stroke:#e94560,color:#fff
    style C fill:#0f3460,stroke:#e94560,color:#fff
    style D fill:#16213e,stroke:#0f3460,color:#e0e0e0
    style E fill:#16213e,stroke:#0f3460,color:#e0e0e0
    style F fill:#1a1a2e,stroke:#e94560,color:#fff
    style G fill:#1a1a2e,stroke:#e94560,color:#fff
    style H fill:#e94560,stroke:#e94560,color:#fff
    style I fill:#0d2d1e,stroke:#14b8a6,color:#ccfbf1
    style J fill:#1a1a00,stroke:#fbbf24,color:#fef3c7
    style K fill:#1a0000,stroke:#f87171,color:#fecaca
    style L fill:#0d1a2d,stroke:#fb923c,color:#fed7aa
    style M fill:#1a0010,stroke:#d946ef,color:#f5d0fe

Compression Simulation (Task 2)

Codec compression is simulated by degrading MFCC standard deviations, reducing jitter and shimmer values, and adding spectral artifact signals β€” replicating the acoustic degradation introduced by MP3/codec pipelines.

Adversarial Simulation (Task 3)

Adversarial perturbation shifts synthetic sample features into the real speech distribution range, and real sample features toward the synthetic range. Controlled label noise (8%) simulates real-world annotation ambiguity. No clean threshold separates the classes.

Streaming Simulation (Task 4)

Features undergo two layers of degradation: a static perturbation (partial MFCC decode, mild temporal noise) baked into the data files, and a dynamic soft-gated noise applied at runtime that reduces as the agent takes more steps. Early requests return noisier data; later requests return cleaner data β€” rewarding intelligent sequencing without forcing a fixed order.

Phone Call Simulation (Task 5)

The most aggressive degradation: narrowband codec compression zeros out high-order MFCCs, flattens MFCC temporal variation, injects broadband Gaussian noise, severely degrades HNR, and adds RMS energy fluctuation simulating packet loss. Designed to be near the limit of what's detectable.


πŸ“œ License

MIT