voiceguard-api / backend.py
EngrAhmedRehan's picture
Prepare architecture for cloud deployment
8a86c9a
Raw
History Blame Contribute Delete
3.65 kB
import os
import json
import re
from fastapi import FastAPI, UploadFile, File
from fastapi.middleware.cors import CORSMiddleware
from groq import Groq
from dotenv import load_dotenv
from presidio_analyzer import AnalyzerEngine, PatternRecognizer, Pattern
from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import OperatorConfig
load_dotenv()
app = FastAPI(title="VoiceGuard Engine")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"])
# Initialize Groq Client & Presidio
client = Groq(api_key=os.getenv("GROQ_API_KEY"))
analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()
# --- ENHANCED SECURITY: Custom Credit Card / Account Number Recognizer ---
# This regex catches variations of numbers separated by hyphens or spaces (e.g., 4-3-3-5 patterns)
card_pattern = Pattern(
name="custom_card_pattern",
regex=r"\b(?:\d[ -]*?){10,19}\b",
score=0.85
)
custom_card_recognizer = PatternRecognizer(
supported_entity="CUSTOM_CARD",
patterns=[card_pattern]
)
# Register the custom firewall rule
analyzer.registry.add_recognizer(custom_card_recognizer)
# -------------------------------------------------------------------------
def scrub_pii(text: str) -> str:
"""Detects and redacts sensitive data (Names, Phones, Cards, APIs)."""
# Added "CUSTOM_CARD" to the target entities list
target_entities = ["PHONE_NUMBER", "EMAIL_ADDRESS", "PERSON", "CREDIT_CARD", "CUSTOM_CARD"]
results = analyzer.analyze(
text=text,
entities=target_entities,
language='en'
)
operators = {
"PERSON": OperatorConfig("replace", {"new_value": "[NAME REDACTED]"}),
"PHONE_NUMBER": OperatorConfig("replace", {"new_value": "[PHONE REDACTED]"}),
"CREDIT_CARD": OperatorConfig("replace", {"new_value": "[CARD REDACTED]"}),
"CUSTOM_CARD": OperatorConfig("replace", {"new_value": "[CARD REDACTED]"}) # Map custom matches to standard redactor tag
}
return anonymizer.anonymize(text=text, analyzer_results=results, operators=operators).text
def extract_analytics(text: str) -> dict:
"""Uses Llama 3 to generate structured business analytics from the safe text."""
prompt = f"""Analyze the following transcript. Output ONLY valid JSON with no markdown formatting.
Format required: {{"sentiment": "Positive/Neutral/Negative", "compliance_flag": true/false, "action_items": ["item1"]}}
Transcript: {text}"""
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role": "user", "content": prompt}],
temperature=0,
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
@app.post("/process-audio")
async def process_audio(file: UploadFile = File(...)):
temp_file_path = f"temp_{file.filename}"
with open(temp_file_path, "wb") as buffer:
buffer.write(await file.read())
try:
with open(temp_file_path, "rb") as audio_file:
transcription = client.audio.transcriptions.create(
file=(temp_file_path, audio_file.read()),
model="whisper-large-v3",
response_format="text"
)
raw_text = transcription
safe_text = scrub_pii(raw_text)
analytics = extract_analytics(safe_text)
return {
"raw_transcript": raw_text,
"safe_transcript": safe_text,
"analytics": analytics
}
finally:
if os.path.exists(temp_file_path):
os.remove(temp_file_path)