Spaces:
Runtime error
Runtime error
| 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) | |
| 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) |