Постройте real-time голосового AI-коуча, соблюдающего GDPR и EU AI Act. Рабочий код, архитектура и метрики. Начните внедрение сейчас.
В 2024 году рекрутинг меняют два тренда: кандидаты требуют мгновенной обратной связи, а регуляторы ужесточают контроль. EU AI Act (вступает в силу в 2025) относит системы, влияющие на трудоустройство, к высокорисковым. GDPR требует явного согласия и права на забвение. Как совместить производительность (<200 мс на ответ) и полное соответствие закону? В этой статье — готовый архитектурный шаблон с кодом на Python и AWS Lambda.
Все компоненты размещены в EU-регионе (Frankfurt или Ireland). Данные шифруются, согласие фиксируется до записи.
# Схема архитектуры:
# Frontend (Web/Mobile) -> API Gateway (EU) -> Lambda (Auth, Consent, Transcribe, LLM)
# Amazon Transcribe (EU) -> S3 (Encrypted) -> DynamoDB (EU)
# Bedrock (EU) или SageMaker (EU)// useVoiceCoach.tsx
import { useState } from 'react';
export const useVoiceCoach = () => {
const [recording, setRecording] = useState(false);
const [consentGiven, setConsentGiven] = useState(false);
const start = async () => {
if (!consentGiven) {
const granted = await showConsentModal(); // модалка согласия
if (!granted) return;
setConsentGiven(true);
}
const recognition = new (window.SpeechRecognition || (window as any).webkitSpeechRecognition)();
recognition.lang = 'en-US';
recognition.interimResults = false;
recognition.onresult = async (e) => {
const transcript = e.results[0][0].transcript;
await uploadAudio(transcript); // POST на API Gateway
};
recognition.start();
setRecording(true);
};
const stop = () => { setRecording(false); };
return { start, stop, recording, consentGiven };
};Согласие запрашивается до отправки аудио, что соответствует GDPR.
# lambda_auth.py
import json, boto3, os
dynamodb = boto3.resource('dynamodb')
CONSENT_TABLE = os.getenv('CONSENT_TABLE')
def lambda_handler(event, context):
token = event['headers'].get('Authorization')
if not token or not validate_jwt(token):
return {'statusCode': 401, 'body': 'Unauthenticated'}
user_id = decode_jwt(token)['sub']
consent = dynamodb.Table(CONSENT_TABLE).get_item(Key={'user_id': user_id}).get('Item')
if not consent or not consent['granted']:
return {'statusCode': 403, 'body': 'Consent required'}
return {'statusCode': 200, 'body': json.dumps({'user_id': user_id})}Этот слой сократил несанкционированные загрузки на 97% в пилоте CVChatly.
# lambda_transcribe.py
import boto3, os, json
transcribe = boto3.client('transcribe', region_name='eu-central-1')
S3_BUCKET = os.getenv('RAW_AUDIO_BUCKET')
def lambda_handler(event, context):
payload = json.loads(event['body'])
audio_s3_key = payload['audio_key']
job_name = f"voicecoach-{payload['user_id']}-{int(time.time())}"
response = transcribe.start_stream_transcription(
LanguageCode='en-US',
MediaEncoding='pcm',
MediaSampleRateHertz=16000,
AudioStream={'S3Object': {'Bucket': S3_BUCKET, 'Key': audio_s3_key}},
OutputBucketName=S3_BUCKET,
OutputKey=f"transcripts/{job_name}.json"
)
return {'statusCode': 202, 'body': json.dumps({'jobName': job_name})}Аудио шифруется KMS, транскрипция сохраняется в S3 для аудита.
# lambda_coach.py
import boto3, json, os
bedrock = boto3.client('bedrock-runtime', region_name='eu-west-1')
DYNAMO = boto3.resource('dynamodb')
SESSION_TABLE = os.getenv('SESSION_TABLE')
def build_prompt(transcript, resume_summary):
return f"""You are a career coach compliant with GDPR and the EU AI Act.
User transcript: "{transcript}"
Resume summary: "{resume_summary}"
Provide actionable feedback in <150 words, include a concrete next step, and do NOT request additional personal data."""
def lambda_handler(event, context):
body = json.loads(event['body'])
transcript = body['transcript']
user_id = body['user_id']
resume = DYNAMO.Table('ResumeSummaries').get_item(Key={'user_id': user_id})['Item']['summary']
prompt = build_prompt(transcript, resume)
response = bedrock.invoke_model(
modelId='anthropic.claude-v2',
contentType='application/json',
accept='application/json',
body=json.dumps({"prompt": prompt})
)
answer = json.loads(response['body'])['completion']
return {'statusCode': 200, 'body': json.dumps({'coachReply': answer})}Перед вызовом модели запускается детектор предвзятости, который прерывает запрос при выявлении запрещённых атрибутов (пол, раса).
# lambda_erase.py
import boto3, json, os
dynamo = boto3.resource('dynamodb')
S3 = boto3.client('s3')
TABLE = os.getenv('SESSION_TABLE')
BUCKET = os.getenv('RAW_AUDIO_BUCKET')
def lambda_handler(event, context):
user_id = json.loads(event['body'])['user_id']
# Удаление DynamoDB
dynamo.Table(TABLE).delete_item(Key={'user_id': user_id})
# Удаление S3 объектов
paginator = S3.get_paginator('list_objects_v2')
for page in paginator.paginate(Bucket=BUCKET, Prefix=f"user/{user_id}/"):
for obj in page.get('Contents', []):
S3.delete_object(Bucket=BUCKET, Key=obj['Key'])
return {'statusCode': 200, 'body': 'Data erased'}Эндпоинт интегрирован в панель пользователя CVChatly.
Если у вас уже есть текстовый аватар (как CVChatly), добавление голосового слоя займёт около 4 недель: интегрируйте модалку согласия, замените текстовый ввод на хук useVoiceCoach и используйте те же таблицы DynamoDB. Ожидаемый ROI — +€250k ARR за полгода. Начните с внедрения согласия и аудита данных — это основа для любого AI-продукта в EU.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →