#!/usr/bin/env python3 """ Complete Safe Conversational Startup Journey Advisor - All testing and validation features restored - CSP-safe implementation - Async model loading to prevent startup blocking - Full conversation intelligence with proper error handling """ import os import json import secrets import asyncio import threading from typing import Dict, List, Any, Optional from datetime import datetime import torch from transformers import AutoTokenizer, AutoModelForCausalLM from passlib.context import CryptContext from dotenv import load_dotenv # FastAPI imports from fastapi import FastAPI, Request, HTTPException, Depends, BackgroundTasks from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse load_dotenv() print("=" * 60) print("🚀 COMPLETE SAFE CONVERSATIONAL STARTUP ADVISOR") print("=" * 60) # Configuration SUPABASE_URL = os.getenv("SUPABASE_URL") SUPABASE_SERVICE_KEY = os.getenv("SUPABASE_SERVICE_KEY") HF_TOKEN = os.getenv("HF_TOKEN") print(f"🔧 Supabase: {'✅ Configured' if SUPABASE_URL and SUPABASE_SERVICE_KEY else '❌ Missing'}") print(f"🔧 HF Token: {'✅ Set' if HF_TOKEN else '❌ Missing'}") # Initialize Supabase SUPABASE_CONNECTED = False supabase = None if SUPABASE_URL and SUPABASE_SERVICE_KEY: try: from supabase import create_client, Client supabase: Client = create_client(SUPABASE_URL, SUPABASE_SERVICE_KEY) test_result = supabase.table("companies").select("count", count="exact").limit(1).execute() SUPABASE_CONNECTED = True print("✅ Supabase connected and tested") except Exception as e: print(f"⚠️ Supabase connection failed: {e}") SUPABASE_CONNECTED = False else: print("⚠️ Supabase not configured - using fallback mode") # Model loading (async to prevent blocking) MODEL_NAME = "NousResearch/Hermes-2-Pro-Mistral-7B" device = "cuda" if torch.cuda.is_available() else "cpu" MODEL_LOADED = False MODEL_LOADING = False model = None tokenizer = None def load_model_async(): """Load model in background thread""" global MODEL_LOADED, MODEL_LOADING, model, tokenizer if MODEL_LOADING or MODEL_LOADED: return MODEL_LOADING = True print(f"🤖 Starting async model loading: {MODEL_NAME} on {device}...") try: tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, token=HF_TOKEN, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained( MODEL_NAME, token=HF_TOKEN, torch_dtype=torch.float16 if device == "cuda" else torch.float32, device_map="auto" if device == "cuda" else None, trust_remote_code=True, load_in_8bit=True if device == "cuda" else False ) if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token model.eval() MODEL_LOADED = True print("✅ Model loaded successfully in background!") except Exception as e: print(f"❌ Model loading failed: {e}") MODEL_LOADED = False finally: MODEL_LOADING = False # Start model loading in background immediately model_thread = threading.Thread(target=load_model_async, daemon=True) model_thread.start() # ===================================================================== # STARTUP EVENT HANDLERS # ===================================================================== @app.on_event("startup") async def startup_event(): """Startup event handler""" print("🚀 Application startup complete") print("📡 Server is ready to accept requests") print("🤖 Model loading in background...") @app.on_event("shutdown") async def shutdown_event(): """Shutdown event handler""" print("🛑 Application shutting down...") print("💾 Cleaning up resources...") # ===================================================================== # COMPLETE CONVERSATION INTELLIGENCE SYSTEM # ===================================================================== class ConversationIntelligence: """Complete conversation tracking with validation and testing""" def __init__(self): self.topics_discussed = set() self.questions_asked = [] self.conversation_quality_scores = [] self.response_validation_logs = [] def analyze_conversation_depth(self, conversation_history: List[Dict]) -> Dict[str, Any]: """Deep conversation analysis with full validation""" if not conversation_history: return { "has_history": False, "user_level": "unknown", "main_concern": "unknown", "conversation_stage": "beginning", "topics_covered": [], "last_real_need": None, "avoid_repeating": [], "context_summary": "This is our first interaction.", "quality_score": 1.0, "validation_status": "no_history" } # Comprehensive analysis user_responses = [ex.get('user_query', '') for ex in conversation_history] ai_responses = [ex.get('model_response', '') for ex in conversation_history] combined_user_text = ' '.join(user_responses).lower() combined_ai_text = ' '.join(ai_responses).lower() # User level detection with validation user_level = self.detect_user_level_validated(combined_user_text) # Main concern extraction with confidence scoring main_concern, concern_confidence = self.extract_real_concern_scored(conversation_history) # Topic tracking with validation topics_covered = self.extract_and_validate_topics(conversation_history) # Advice repetition detection advice_given = self.extract_advice_given_comprehensive(ai_responses) # Conversation quality assessment quality_score = self.assess_conversation_quality(conversation_history) # Context summary generation context_summary = self.create_intelligent_summary_validated(conversation_history) # Last question tracking last_ai_question = self.extract_last_question_validated(conversation_history) return { "has_history": True, "user_level": user_level, "main_concern": main_concern, "concern_confidence": concern_confidence, "conversation_stage": self.identify_conversation_stage_detailed(conversation_history), "topics_covered": topics_covered, "last_real_need": self.extract_last_need_validated(conversation_history), "avoid_repeating": advice_given, "context_summary": context_summary, "last_ai_question": last_ai_question, "quality_score": quality_score, "validation_status": "analyzed", "conversation_flow": self.analyze_flow_detailed(conversation_history), "continuity_score": self.calculate_continuity_score(conversation_history) } def detect_user_level_validated(self, combined_text: str) -> str: """Enhanced user level detection with validation""" level_indicators = { "complete_beginner": ['just have an idea', 'where do i start', 'how do i even', 'never done this', 'don\'t know'], "early_stage": ['have a prototype', 'built something', 'some customers', 'testing', 'mvp'], "growth_stage": ['scaling', 'growing', 'hiring', 'series', 'funding round'], "experienced": ['raised', 'previous startup', 'sold', 'exit', 'portfolio'] } scores = {} for level, indicators in level_indicators.items(): score = sum(1 for indicator in indicators if indicator in combined_text) if score > 0: scores[level] = score if not scores: return "unclear" return max(scores, key=scores.get) def extract_real_concern_scored(self, conversation_history: List[Dict]) -> tuple[str, float]: """Extract concern with confidence score""" if not conversation_history: return "unknown", 0.0 last_exchange = conversation_history[-1] last_user_query = last_exchange.get('user_query', '').lower() concern_patterns = { "communication_anxiety": (['how do i talk', 'how to talk', 'scared', 'nervous', 'don\'t know what to say'], 0.9), "customer_discovery_mechanics": (['find customers', 'find people', 'who to talk to', 'where to find'], 0.8), "overwhelmed_by_process": (['where do i start', 'too much', 'overwhelmed', 'don\'t know'], 0.7), "validation_process": (['validate', 'test idea', 'prove', 'market research'], 0.8), "funding_concerns": (['money', 'funding', 'investor', 'capital', 'raise'], 0.8) } for concern, (patterns, base_confidence) in concern_patterns.items(): matches = sum(1 for pattern in patterns if pattern in last_user_query) if matches > 0: confidence = min(base_confidence * matches, 1.0) return concern, confidence return "general_guidance", 0.5 def extract_and_validate_topics(self, conversation_history: List[Dict]) -> List[str]: """Extract topics with validation""" topics = set() for exchange in conversation_history: text = (exchange.get('user_query', '') + ' ' + exchange.get('model_response', '')).lower() if any(word in text for word in ['customer', 'user', 'interview', 'feedback']): topics.add('customer_development') if any(word in text for word in ['funding', 'investor', 'money', 'raise', 'capital']): topics.add('fundraising') if any(word in text for word in ['product', 'feature', 'build', 'develop', 'mvp']): topics.add('product_development') if any(word in text for word in ['marketing', 'growth', 'acquisition', 'launch']): topics.add('marketing') if any(word in text for word in ['team', 'hire', 'hiring', 'employee']): topics.add('team_building') return list(topics) def extract_advice_given_comprehensive(self, ai_responses: List[str]) -> List[str]: """Comprehensive advice tracking""" advice_given = [] combined_text = ' '.join(ai_responses).lower() advice_patterns = { 'market_research': ['market research', 'research the market', 'analyze the market'], 'business_plan': ['business plan', 'create a plan', 'planning'], 'social_media': ['social media', 'linkedin', 'twitter', 'facebook'], 'landing_page': ['landing page', 'website', 'web page'], 'customer_interviews': ['customer interviews', 'talk to customers', 'interview'], 'networking': ['networking', 'events', 'meetups', 'conferences'], 'mvp': ['mvp', 'minimum viable product', 'prototype'] } for advice_type, patterns in advice_patterns.items(): if any(pattern in combined_text for pattern in patterns): advice_given.append(advice_type) return advice_given def assess_conversation_quality(self, conversation_history: List[Dict]) -> float: """Assess overall conversation quality""" if not conversation_history: return 1.0 quality_factors = [] # Check for topic continuity topics_per_exchange = [] for i, exchange in enumerate(conversation_history): topics = self.extract_and_validate_topics([exchange]) topics_per_exchange.append(len(topics)) # Penalize topic jumping topic_consistency = 1.0 if len(topics_per_exchange) > 1: topic_jumps = sum(1 for i in range(1, len(topics_per_exchange)) if topics_per_exchange[i] != topics_per_exchange[i-1]) topic_consistency = max(0.5, 1.0 - (topic_jumps * 0.2)) quality_factors.append(topic_consistency) # Check response relevance (simple heuristic) relevance_score = 1.0 for i in range(1, len(conversation_history)): prev_query = conversation_history[i-1].get('user_query', '').lower() curr_response = conversation_history[i-1].get('model_response', '').lower() # Simple relevance check if len(prev_query) > 10 and len(curr_response) > 10: common_words = set(prev_query.split()) & set(curr_response.split()) if len(common_words) < 2: # Very basic relevance check relevance_score -= 0.1 quality_factors.append(max(0.0, relevance_score)) return sum(quality_factors) / len(quality_factors) if quality_factors else 1.0 def calculate_continuity_score(self, conversation_history: List[Dict]) -> float: """Calculate conversation continuity score""" if len(conversation_history) < 2: return 1.0 continuity_score = 1.0 for i in range(1, len(conversation_history)): prev_response = conversation_history[i-1].get('model_response', '').lower() curr_query = conversation_history[i].get('user_query', '').lower() # Check if current query relates to previous response if '?' in prev_response: # AI asked a question # Simple check if user is answering if any(word in curr_query for word in ['yes', 'no', 'yeah', 'nope']): continuity_score += 0.1 # Bonus for answering questions # Check for topic continuity prev_topics = self.extract_and_validate_topics([conversation_history[i-1]]) curr_topics = self.extract_and_validate_topics([conversation_history[i]]) if prev_topics and curr_topics: topic_overlap = len(set(prev_topics) & set(curr_topics)) if topic_overlap == 0: continuity_score -= 0.2 # Penalty for topic jumping return max(0.0, min(1.0, continuity_score)) def extract_last_question_validated(self, conversation_history: List[Dict]) -> Optional[str]: """Extract and validate last AI question""" if not conversation_history: return None last_exchange = conversation_history[-1] last_ai_response = last_exchange.get('model_response', '') # Extract questions more reliably sentences = last_ai_response.split('?') if len(sentences) > 1: # Get the sentence with the question for sentence in reversed(sentences[:-1]): # Exclude empty last part question = sentence.strip() if len(question) > 10: # Valid question length # Get the last sentence before the ? question_parts = question.split('.') if question_parts: return question_parts[-1].strip() + '?' return None def create_intelligent_summary_validated(self, conversation_history: List[Dict]) -> str: """Create validated intelligent summary""" if not conversation_history: return "Starting fresh conversation" analysis = self.analyze_conversation_depth(conversation_history) summary_parts = [] # User level context summary_parts.append(f"User is {analysis['user_level']}") # Main concern if analysis['main_concern'] != 'unknown': summary_parts.append(f"struggling with {analysis['main_concern']}") # Topics covered if analysis['topics_covered']: summary_parts.append(f"discussed {', '.join(analysis['topics_covered'])}") # Advice given if analysis['avoid_repeating']: summary_parts.append(f"already covered {', '.join(analysis['avoid_repeating'])}") # Quality indicator if analysis['quality_score'] < 0.7: summary_parts.append("conversation needs refocusing") return ". ".join(summary_parts).capitalize() + "." def identify_conversation_stage_detailed(self, conversation_history: List[Dict]) -> str: """Detailed conversation stage identification""" num_exchanges = len(conversation_history) if num_exchanges == 0: return "initial_contact" elif num_exchanges == 1: return "understanding_needs" elif num_exchanges <= 3: return "clarifying_and_advising" elif num_exchanges <= 6: return "deep_guidance" else: return "ongoing_mentorship" def extract_last_need_validated(self, conversation_history: List[Dict]) -> Optional[str]: """Extract and validate user's most recent need""" if not conversation_history: return None last_query = conversation_history[-1].get('user_query', '').lower() need_patterns = { "wants_conversation_scripts": ['how do i talk', 'what do i say', 'conversation'], "wants_specific_tactics": ['how to find', 'where to find', 'specific ways'], "admits_no_progress": ['haven\'t yet', 'not really', 'haven\'t done'], "seeks_validation": ['is this right', 'am i doing', 'should i'], "needs_encouragement": ['struggling', 'hard', 'difficult', 'stuck'] } for need, patterns in need_patterns.items(): if any(pattern in last_query for pattern in patterns): return need return None def analyze_flow_detailed(self, conversation_history: List[Dict]) -> str: """Detailed conversation flow analysis""" if not conversation_history: return "starting" last_exchange = conversation_history[-1] user_query = last_exchange.get('user_query', '').lower() flow_indicators = { "answering_question": ['yes', 'no', 'yeah', 'nope', 'sure', 'definitely'], "asking_clarification": ['what do you mean', 'can you explain', 'how do i'], "expressing_frustration": ['but', 'however', 'struggling', 'difficult'], "showing_agreement": ['exactly', 'right', 'that makes sense', 'i see'], "changing_topic": ['also', 'another thing', 'what about'], "seeking_specifics": ['specific', 'example', 'exactly how'] } for flow_type, indicators in flow_indicators.items(): if any(indicator in user_query for indicator in indicators): return flow_type return "continuing" # Initialize conversation intelligence conv_intel = ConversationIntelligence() # ===================================================================== # ENHANCED RESPONSE GENERATION WITH VALIDATION # ===================================================================== def create_validated_prompt(user_query: str, company_context: Dict[str, Any], conversation_history: List[Dict] = None) -> str: """Create prompts with full validation and testing""" # Get comprehensive analysis analysis = conv_intel.analyze_conversation_depth(conversation_history or []) stage = company_context.get('stage', 'startup') industry = company_context.get('industry', 'tech') # Log analysis for debugging print(f"🧠 ANALYSIS: Level={analysis['user_level']}, Concern={analysis['main_concern']}, Quality={analysis['quality_score']:.2f}") # Create context-aware prompts based on detailed analysis if not analysis["has_history"]: # First interaction - establish rapport system_prompt = f"""You are a startup advisor meeting a {stage} {industry} founder for the first time. INSTRUCTIONS: - Give specific, helpful advice about their question - Be professional but warm and approachable - Keep response to 2-3 sentences + one relevant follow-up question - Establish rapport and show expertise USER QUESTION: {user_query}""" else: # Ongoing conversation - use full intelligence concern = analysis['main_concern'] user_level = analysis['user_level'] last_question = analysis.get('last_ai_question') conversation_flow = analysis['conversation_flow'] if conversation_flow == "answering_question" and last_question: # User is responding to our question system_prompt = f"""CRITICAL: You are continuing a conversation. You asked: "{last_question}" CONTEXT: They just answered your question. Their response: "{user_query}" INSTRUCTIONS: - ACKNOWLEDGE their specific answer to your question - BUILD directly on what they just told you - Give advice that relates to their answer - Ask a natural follow-up about the SAME topic - Show you're listening and building on the conversation AVOID repeating: {', '.join(analysis['avoid_repeating'])}""" elif user_level == "complete_beginner" and concern == "communication_anxiety": # Beginner who's scared to talk to people system_prompt = f"""You are a supportive startup mentor. User is a complete beginner with anxiety about customer conversations. CONTEXT: {analysis['context_summary']} CURRENT QUESTION: "{user_query}" INSTRUCTIONS: - Be encouraging and reduce their anxiety - Give ONE simple, concrete step - Make it feel less scary and more achievable - Focus on emotional support + practical guidance AVOID repeating: {', '.join(analysis['avoid_repeating'])}""" elif concern == "overwhelmed_by_process": # User feels overwhelmed system_prompt = f"""You are a calming startup mentor. User feels overwhelmed by startup advice. CONTEXT: {analysis['context_summary']} CURRENT QUESTION: "{user_query}" INSTRUCTIONS: - Acknowledge there's too much conflicting advice - Give them ONE single next step (not a list) - Make it feel manageable and specific - Reduce overwhelm, don't add to it AVOID repeating: {', '.join(analysis['avoid_repeating'])}""" else: # General ongoing conversation system_prompt = f"""You are an experienced startup advisor in an ongoing conversation. CONTEXT: {analysis['context_summary']} CURRENT QUESTION: "{user_query}" CONVERSATION QUALITY: {analysis['quality_score']:.2f}/1.0 INSTRUCTIONS: - Continue the conversation naturally - Reference previous context when relevant - Give practical, actionable advice - Ask thoughtful follow-up questions - Maintain conversation flow and continuity AVOID repeating: {', '.join(analysis['avoid_repeating'])}""" return f"""<|im_start|>system {system_prompt} <|im_end|> <|im_start|>assistant""" def validate_response_quality(response: str, analysis: Dict[str, Any], user_query: str) -> tuple[bool, str]: """Comprehensive response quality validation""" validation_issues = [] # Basic quality checks if len(response) < 20: validation_issues.append("Response too short") if len(response) > 500: validation_issues.append("Response too long") # Check for repetition of avoided topics response_lower = response.lower() for avoided_topic in analysis.get('avoid_repeating', []): topic_words = avoided_topic.replace('_', ' ').split() if all(word in response_lower for word in topic_words): validation_issues.append(f"Repeated avoided topic: {avoided_topic}") # Check for conversation continuity if analysis.get('has_history') and analysis.get('last_ai_question'): last_question = analysis['last_ai_question'].lower() if 'angel' in last_question and 'angel' not in response_lower and 'investor' not in response_lower: validation_issues.append("Lost topic continuity") # Check for generic responses generic_phrases = ['market research', 'business plan', 'social media strategy'] if analysis.get('user_level') == 'complete_beginner': for phrase in generic_phrases: if phrase in response_lower and phrase.replace(' ', '_') in analysis.get('avoid_repeating', []): validation_issues.append(f"Generic advice: {phrase}") is_valid = len(validation_issues) == 0 validation_summary = "; ".join(validation_issues) if validation_issues else "Response validated successfully" # Log validation results conv_intel.response_validation_logs.append({ "timestamp": datetime.now().isoformat(), "is_valid": is_valid, "issues": validation_issues, "response_length": len(response), "user_level": analysis.get('user_level'), "main_concern": analysis.get('main_concern') }) return is_valid, validation_summary def generate_enhanced_fallback(user_query: str, company_context: Dict[str, Any], analysis: Dict[str, Any]) -> str: """Enhanced fallback with comprehensive conversation awareness""" user_level = analysis.get('user_level', 'unknown') concern = analysis.get('main_concern', 'unknown') conversation_flow = analysis.get('conversation_flow', 'continuing') last_question = analysis.get('last_ai_question') print(f"🔄 FALLBACK: Level={user_level}, Concern={concern}, Flow={conversation_flow}") # Handle different scenarios with full context awareness if conversation_flow == "answering_question" and last_question: # User answered our question if 'no' in user_query.lower() or 'haven\'t' in user_query.lower(): return f"""No problem at all - many founders haven't explored that yet. Since you mentioned that about {concern.replace('_', ' ')}, let me suggest a simple first step that won't feel overwhelming. What feels like the biggest barrier right now - time, knowing where to start, or something else?""" elif 'yes' in user_query.lower(): return f"""Great! Since you have some experience with that, let's build on it. Based on what you just shared about {concern.replace('_', ' ')}, what specific challenge are you facing?""" else: return f"""Thanks for that context. Based on what you're telling me, I think the key is to start simple and build momentum. What feels most urgent to tackle first?""" elif user_level == "complete_beginner": if concern == "communication_anxiety": return """I totally understand - talking to strangers about your idea feels scary! Here's the secret: don't pitch your idea at all. Just ask people about their problems. Try this: "Hey, what's your biggest frustration with [relevant area]?" Then just listen. No pressure to sell anything. What kind of people do you think struggle with the problem you want to solve?""" elif concern == "overwhelmed_by_process": return """I know there's a million pieces of startup advice out there - ignore most of it for now. Here's your only focus this week: have conversations with 5 people about the problem you think you're solving. That's it. Not your solution, just the problem. Who's the first person you could talk to about this?""" elif concern == "customer_discovery_mechanics": return """Since you're just starting out, here's the simplest approach: start with people you already know. Friends, family, coworkers - anyone who might face the problem you're solving. Ask: "Can I get your opinion on something? I'm trying to understand if [problem] is actually frustrating for people." Who in your network might deal with this issue?""" # Default enhanced fallback topic_context = f" about {analysis.get('topics_covered', ['startup strategy'])[0]}" if analysis.get('topics_covered') else "" return f"""Starting with an idea is exactly where you should be! The key is validation through conversations before building anything{topic_context}. What feels like the biggest challenge right now - finding the right people to talk to or knowing what questions to ask them?""" # ===================================================================== # CORE FUNCTIONS WITH FULL VALIDATION # ===================================================================== pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") def create_company(company_data: Dict[str, Any]) -> Dict[str, Any]: """Create company with validation""" required_fields = ["name", "stage", "industry"] # Validate input for field in required_fields: if field not in company_data: return {"success": False, "error": f"Missing required field: {field}"} # Sanitize input company_data["name"] = company_data["name"].strip()[:100] # Limit length if not SUPABASE_CONNECTED: api_key = f"demo-{secrets.token_urlsafe(16)}" return { "success": True, "api_key": api_key, "company": { "id": f"demo-{secrets.token_urlsafe(8)}", **company_data }, "message": "Demo mode - using fallback storage" } try: api_key = secrets.token_urlsafe(32) company_record = { "name": company_data["name"], "stage": company_data["stage"], "industry": company_data["industry"], "description": company_data.get("description", "")[:500], # Limit length "team_size": min(max(company_data.get("team_size", 1), 1), 10000), # Validate range "founded_year": company_data.get("founded_year"), "api_key_hash": pwd_context.hash(api_key), "created_at": datetime.utcnow().isoformat(), "conversation_count": 0 } result = supabase.table("companies").insert(company_record).execute() if result.data: return { "success": True, "api_key": api_key, "company": result.data[0] } else: return {"success": False, "error": "Failed to create company record"} except Exception as e: print(f"❌ Company creation error: {e}") return {"success": False, "error": f"Database error: {str(e)}"} def get_company_by_api_key(api_key: str) -> Optional[Dict[str, Any]]: """Get company with validation""" if not api_key or len(api_key) < 10: return None if not SUPABASE_CONNECTED: return { "id": "demo-company", "name": "Demo Company", "stage": "idea", "industry": "tech", "team_size": 1 } try: companies = supabase.table("companies").select("*").execute() for company in companies.data: if pwd_context.verify(api_key, company["api_key_hash"]): return company return None except Exception as e: print(f"❌ API key validation error: {e}") return None def get_conversation_history_validated(company_id: str, limit: int = 10) -> List[Dict]: """Get conversation history with validation""" if not company_id: return [] if not SUPABASE_CONNECTED: return [] try: interactions = supabase.table("company_interactions")\ .select("user_query, model_response, created_at")\ .eq("company_id", company_id)\ .order("created_at", desc=True)\ .limit(min(max(limit, 1), 20))\ .execute() if interactions.data: # Validate and clean data cleaned_data = [] for interaction in interactions.data: if interaction.get('user_query') and interaction.get('model_response'): cleaned_data.append(interaction) return list(reversed(cleaned_data)) return [] except Exception as e: print(f"❌ Conversation history error: {e}") return [] async def track_interaction_async(company_id: str, interaction_data: Dict[str, Any]): """Async interaction tracking with validation""" if not SUPABASE_CONNECTED or not company_id: return try: # Validate and sanitize interaction data validated_data = { "company_id": company_id, "interaction_type": interaction_data.get("interaction_type", "chat")[:50], "user_query": interaction_data.get("user_query", "")[:1000], "model_response": interaction_data.get("model_response", "")[:2000], "processing_time_ms": min(max(interaction_data.get("processing_time_ms", 0), 0), 30000), "created_at": datetime.utcnow().isoformat(), "quality_score": interaction_data.get("quality_score", 1.0), "validation_status": interaction_data.get("validation_status", "unknown") } supabase.table("company_interactions").insert(validated_data).execute() except Exception as e: print(f"❌ Interaction tracking error: {e}") def generate_ai_response_validated(user_query: str, company_context: Dict[str, Any], conversation_history: List[Dict] = None) -> tuple[str, Dict[str, Any]]: """Generate AI response with full validation and testing""" start_time = datetime.now() # Sanitize input user_query = user_query.strip()[:500] # Limit input length # Get comprehensive conversation analysis analysis = conv_intel.analyze_conversation_depth(conversation_history or []) # Generate response response = "" validation_result = {"is_valid": False, "validation_summary": "Not generated"} if MODEL_LOADED and model and tokenizer: try: # Create validated prompt prompt = create_validated_prompt(user_query, company_context, conversation_history) print(f"🎯 PROMPT: {prompt[:200]}...") inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1000) if device == "cuda": inputs = {k: v.to(device) for k, v in inputs.items()} with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=120, do_sample=True, temperature=0.7, top_p=0.9, repetition_penalty=1.1, pad_token_id=tokenizer.eos_token_id, eos_token_id=tokenizer.eos_token_id ) response = tokenizer.decode(outputs[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True).strip() print(f"🤖 MODEL RESPONSE: {response}") # Validate response quality is_valid, validation_summary = validate_response_quality(response, analysis, user_query) validation_result = {"is_valid": is_valid, "validation_summary": validation_summary} print(f"✅ VALIDATION: {validation_summary}") if not is_valid: print("⚠️ Response failed validation, using enhanced fallback") response = generate_enhanced_fallback(user_query, company_context, analysis) validation_result = {"is_valid": True, "validation_summary": "Enhanced fallback used"} except Exception as e: print(f"❌ Model generation error: {e}") response = generate_enhanced_fallback(user_query, company_context, analysis) validation_result = {"is_valid": True, "validation_summary": f"Fallback due to model error: {str(e)}"} else: # Model not loaded, use enhanced fallback response = generate_enhanced_fallback(user_query, company_context, analysis) validation_result = {"is_valid": True, "validation_summary": "Enhanced fallback (model not loaded)"} processing_time = (datetime.now() - start_time).total_seconds() * 1000 # Add processing metadata response_metadata = { "analysis": analysis, "validation": validation_result, "processing_time_ms": int(processing_time), "model_used": MODEL_LOADED, "timestamp": datetime.now().isoformat() } return response, response_metadata # ===================================================================== # CSP-SAFE HTML TEMPLATE WITH ALL FEATURES # ===================================================================== HTML_TEMPLATE = """
Full conversation intelligence with comprehensive testing and validation
Don't have one? Create a company profile first.