| 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", | |
| }, | |
| ] | |