import re import requests API_URL = "/analyze" MAX_FILES = 5 def parse_score_value(raw_score): match = re.search(r"\d+(?:\.\d+)?", str(raw_score)) return float(match.group()) if match else None def clean_text(value, fallback="Not available yet."): text = str(value).strip() if value is not None else "" return text if text else fallback def clean_list(value): if isinstance(value, list): return [str(item).strip() for item in value if str(item).strip()] if value is None: return [] text = str(value).strip() return [text] if text else [] def count_files(uploaded_files): return len(uploaded_files) if uploaded_files else 0 def normalize_files(uploaded_files): if not uploaded_files: return [] return list(uploaded_files[:MAX_FILES]) def interest_to_percent(value): text = str(value or "").lower() mapping = { "very high": 92, "high": 82, "medium": 58, "mixed": 46, "low": 28, "very low": 14, } for key, score in mapping.items(): if key in text: return score return 50 def get_emotional_signal(score_value): if score_value is None: return "AI signal", "The emotional pattern is still forming." if score_value >= 80: return "Deep resonance", "The connection reads warm, mutual, and emotionally available." if score_value >= 60: return "Promising energy", "There is meaningful interest here, but clarity still matters." if score_value >= 40: return "Mixed signals", "The attraction may be real, but the emotional consistency is uneven." return "Guarded connection", "Protect your energy and look for stronger reciprocity before investing more." def analyze_payload(chat, feelings, uploaded_files, user_perspective="", emotional_goal="", conversation_consistency=""): selected_files = normalize_files(uploaded_files) files = [("files", (file.name, file, file.type)) for file in selected_files] response = requests.post( API_URL, data={ "chat": chat, "feelings": feelings, "user_perspective": user_perspective, "emotional_goal": emotional_goal, "conversation_consistency": conversation_consistency }, files=files, timeout=180, ) response.raise_for_status() return response.json() def detect_perspective_payload(chat, feelings, uploaded_files): selected_files = normalize_files(uploaded_files) files = [("files", (file.name, file, file.type)) for file in selected_files] url = API_URL.replace("/analyze", "/detect_perspective") response = requests.post( url, data={"chat": chat, "feelings": feelings}, files=files, timeout=180, ) response.raise_for_status() return response.json() def build_people_cards(analysis, feelings): analyst = analysis.get("analyst", {}) psychology = analysis.get("psychology", {}) interest_level = clean_text(analyst.get("interest_level"), "Unclear") emotional_tone = clean_text(analyst.get("emotional_tone"), "Unreadable") partner_intent = clean_text(psychology.get("partner_intent"), "Unclear intent") user_intent = clean_text(psychology.get("user_intent"), "Clarifying feelings") feelings_text = f"{feelings} {user_intent}".lower() partner_text = f"{interest_level} {emotional_tone} {partner_intent}".lower() if any(word in feelings_text for word in ["break up", "breakup", "leave", "dont love", "don't love", "end it", "distance"]): you = { "label": "You", "emoji": "\U0001F494", "title": "Ready to step back", "description": "Your side reads emotionally detached and focused on ending this respectfully.", "percent": 90, "meter_label": "Clarity", } elif any(word in feelings_text for word in ["confused", "unsure", "mixed", "idk"]): you = { "label": "You", "emoji": "\U0001FAE7", "title": "Still sorting feelings", "description": "You sound uncertain and are looking for emotional clarity before acting.", "percent": 58, "meter_label": "Certainty", } else: you = { "label": "You", "emoji": "\U0001FA77", "title": clean_text(user_intent, "Emotionally engaged"), "description": "Your side still sounds invested in understanding what this connection means.", "percent": 72, "meter_label": "Investment", } if any(word in partner_text for word in ["cold", "dry", "avoidant", "disinterest", "ignoring", "distance", "very low", "low"]): partner = { "label": "Them", "emoji": "\U0001F9CA", "title": "Emotionally cold", "description": "Their side reads short, guarded, and low-effort rather than warm or reassuring.", "percent": 24, "meter_label": "Warmth", } elif any(word in partner_text for word in ["mixed", "unclear"]): partner = { "label": "Them", "emoji": "\U0001F90D", "title": "Mixed energy", "description": "They are giving some signal, but not enough consistency to feel fully safe or clear.", "percent": 48, "meter_label": "Warmth", } else: partner = { "label": "Them", "emoji": "\U0001F60D", "title": clean_text(interest_level, "Interested"), "description": "Their tone and effort look more emotionally open and invested.", "percent": interest_to_percent(interest_level), "meter_label": "Warmth", } return [you, partner] def build_story_cards(analysis): analyst = analysis.get("analyst", {}) psychology = analysis.get("psychology", {}) strategy = analysis.get("strategy", {}) cards = [ { "emoji": "\U0001F50E", "title": "Truth", "body": clean_text(strategy.get("truth")), "tone": "pink", }, { "emoji": "\u26A0\uFE0F", "title": "Risk", "body": clean_text(strategy.get("warning")), "tone": "amber", }, { "emoji": "\U0001F9ED", "title": "Best next move", "body": clean_text(strategy.get("action_advice")), "tone": "violet", }, { "emoji": "\U0001FAE0", "title": "Hidden meaning", "body": clean_text(analyst.get("hidden_meaning")), "tone": "rose", }, { "emoji": "\U0001F9E0", "title": "Psych dynamic", "body": clean_text(psychology.get("psychological_dynamic")), "tone": "indigo", }, ] if strategy.get("detachment_path"): cards.append({ "emoji": "\U0001F6E1\uFE0F", "title": "Healthy Detachment", "body": clean_text(strategy.get("detachment_path")), "tone": "slate", }) if strategy.get("reconnection_path"): cards.append({ "emoji": "\U0001F504", "title": "Reconnection Path", "body": clean_text(strategy.get("reconnection_path")), "tone": "rose", }) for reply in clean_list(strategy.get("suggested_replies"))[:3]: cards.append( { "emoji": "\U0001F4AC", "title": "Suggested reply", "body": reply, "tone": "slate", } ) return cards def build_key_insight_cards(analysis): analyst = analysis.get("analyst", {}) strategy = analysis.get("strategy", {}) return [ { "emoji": "\u26A0\uFE0F", "title": "Risk", "body": clean_text(strategy.get("warning")), "tone": "amber", }, { "emoji": "\U0001FAE0", "title": "Hidden meaning", "body": clean_text(analyst.get("hidden_meaning")), "tone": "rose", }, { "emoji": "\U0001F9ED", "title": "Best next step", "body": clean_text(strategy.get("action_advice")), "tone": "violet", }, ] def default_swipe_profiles(): return [ { "name": "Aarav", "age": 26, "bio": "Warm texter, quick replies, values direct communication and emotional consistency.", "compatibility": 72, "emotional_availability": "Open but cautious", "red_flags": "Can pull back if conversations become unclear.", "communication_style": "Clear, affectionate, reassurance-seeking", "theme": "rose", "emoji": "\U0001F60A", }, { "name": "Maya", "age": 24, "bio": "Playful energy, strong chemistry, but can be inconsistent when overwhelmed.", "compatibility": 64, "emotional_availability": "Mixed signals", "red_flags": "Hot-cold rhythm and unclear follow-through.", "communication_style": "Flirty, reactive, emotionally uneven", "theme": "violet", "emoji": "\U0001F970", }, { "name": "Rehan", "age": 28, "bio": "Slow-burn type, thoughtful in person, not always expressive over text.", "compatibility": 58, "emotional_availability": "Steady but reserved", "red_flags": "Can feel distant if you need frequent reassurance.", "communication_style": "Measured, calm, low-drama", "theme": "amber", "emoji": "\U0001F60C", }, { "name": "Kiara", "age": 25, "bio": "High chemistry, sharp intuition, but protects herself with emotional distance.", "compatibility": 49, "emotional_availability": "Guarded", "red_flags": "Avoids clarity when things get serious.", "communication_style": "Stylish, witty, emotionally hard to read", "theme": "indigo", "emoji": "\U0001F9CA", }, ]