File size: 8,136 Bytes
32c5a96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import logging
import json
import os
from typing import Optional, Dict, Any
import datetime
import re

def convert_numpy_floats(obj):
    if isinstance(obj, dict):
        return {k: convert_numpy_floats(v) for k, v in obj.items()}
    elif isinstance(obj, list):
        return [convert_numpy_floats(elem) for elem in obj]
    elif isinstance(obj, float):
        return obj
    return obj

SUPABASE_PREDICTION_TABLE_NAME = os.getenv("SUPABASE_PREDICTION_TABLE_NAME")

def extract_simplified_contextual_outcome(analysis_response_text: str) -> Optional[str]:
    if not analysis_response_text:
        logging.warning("No analysis response text provided.")
        return None

    start = analysis_response_text.find("### EXECUTIVE_SUMMARY_START")
    end   = analysis_response_text.find("### EXECUTIVE_SUMMARY_END")
    if start != -1 and end != -1 and end > start:
        summary = analysis_response_text[start + len("### EXECUTIVE_SUMMARY_START"):end].strip()
    else:
        logging.info("No standard summary block found, using entire text.")
        summary = analysis_response_text

    extracted_value_from_source = None
    logging_source_info = ""

    for line in summary.splitlines():
        if "DUAL RECOMMENDATION" in line:
            m = re.search(r"\bOR\s+([^@|]+?)(?=\s*(?:@|\|))", line, re.IGNORECASE)
            if m:
                extracted_value_from_source = m.group(1).strip()
                logging_source_info = "DUAL RECOMMENDATION"
                break 
    
    if not extracted_value_from_source:
        for line in summary.splitlines():
            if "Preferred Outcome: Contextual" in line:
                m = re.search(r"Contextual\s*\(([^)]+)\)", line)
                if m:
                    raw_fallback_text = m.group(1).strip()
                    extracted_value_from_source = raw_fallback_text.split(" due to ")[0].split(" (")[0].strip()
                    logging_source_info = "Preferred Outcome: Contextual"
                    break 
    
    if not extracted_value_from_source:
        logging.warning("Could not extract any contextual outcome candidate.")
        return None

    # Normalize the extracted string for comparison (handles case and internal spaces)
    normalized_for_comparison = ' '.join(extracted_value_from_source.lower().split())

    if normalized_for_comparison == "home win":
        final_outcome = "Home"
        logging.info(f"Extracted and simplified contextual outcome from {logging_source_info}: '{final_outcome}' (original: '{extracted_value_from_source}')")
        return final_outcome
    elif normalized_for_comparison == "away win":
        final_outcome = "Away"
        logging.info(f"Extracted and simplified contextual outcome from {logging_source_info}: '{final_outcome}' (original: '{extracted_value_from_source}')")
        return final_outcome
    else:
        # No simplification for "Home Win" / "Away Win" applies. Return the extracted value as is.
        logging.info(f"Extracted contextual outcome from {logging_source_info}: '{extracted_value_from_source}' (no 'Win' rule simplification)")
        return extracted_value_from_source

def log_new_prediction_session(
    supabase_client,
    user_message_predict: str,
    prediction_context: Dict[str, Any],
    full_bot_response_predict: str
) -> Optional[str]:
    logging.info("Attempting to create new prediction session entry in Supabase...")

    if supabase_client is None:
        logging.warning("Supabase client not provided or initialized. Cannot create prediction session.")
        return None
    if not prediction_context or not prediction_context.get('odds') or not prediction_context.get('prediction') or 'probabilities' not in prediction_context:
         logging.error("Prediction context is incomplete or missing probabilities for saving.")
         return None

    try:
        odds = prediction_context['odds']
        teams = prediction_context.get('teams')
        pred_code = prediction_context['prediction']
        probabilities_data = prediction_context.get('probabilities', {})
        statistical_pred_str = {"W": "Home", "D": "Draw", "L": "Away"}.get(pred_code, pred_code)

        data_to_save = {
            "user_message_predict": user_message_predict,
            "match_teams": f"{teams[0]} - {teams[1]}" if teams and isinstance(teams, (list, tuple)) and len(teams) == 2 else None,
            "home_odds": odds.get('W'),
            "draw_odds": odds.get('D'),
            "away_odds": odds.get('L'),
            "statistical_prediction": statistical_pred_str,
            "statistical_probabilities": json.dumps(probabilities_data),
            "full_bot_response_predict": full_bot_response_predict,
            "contextual_prediction": None,
            "user_message_analyze": None,
            "full_bot_response_analyze": None,
            "updated_at": None
        }

        response = supabase_client.table(SUPABASE_PREDICTION_TABLE_NAME).insert([data_to_save]).execute()

        if response and hasattr(response, 'data') and response.data:
             new_id = response.data[0].get('id')
             logging.info(f"Successfully created prediction session entry. Record ID: {new_id}")
             return str(new_id)
        elif response and hasattr(response, 'error') and response.error:
             logging.error(f"Supabase insert failed for new session: {response.error.message if hasattr(response.error, 'message') else response.error}")
             return None
        else:
             logging.warning(f"Supabase insert for new session executed, but unexpected response format: {response}")
             return None

    except Exception as e:
        logging.exception(f"An unexpected error occurred during Supabase new session logging:")
        return None

def update_prediction_session_analysis(
    supabase_client,
    session_id: str,
    user_message_analyze: str,
    full_bot_response_analyze: str,
    prediction_context: Dict[str, Any]
) -> bool:
    logging.info(f"Attempting to update prediction session entry ID {session_id} with analysis...")

    if supabase_client is None:
        logging.warning("Supabase client not provided or initialized. Cannot update prediction session.")
        return False
    if not session_id:
        logging.error("No session_id provided for update.")
        return False

    try:
        contextual_outcome = extract_simplified_contextual_outcome(full_bot_response_analyze)
        
        if contextual_outcome is None:
            logging.warning("Could not extract a contextual outcome from the analysis. "
                           "Setting contextual_prediction to null in the database.")

        update_data = {
            "user_message_analyze": user_message_analyze,
            "contextual_prediction": contextual_outcome,
            "full_bot_response_analyze": full_bot_response_analyze,
            "updated_at": datetime.datetime.now(datetime.timezone.utc).isoformat()
        }

        response = supabase_client.table(SUPABASE_PREDICTION_TABLE_NAME).update(update_data).eq('id', session_id).execute()

        if response and hasattr(response, 'data') and response.data:
             logging.info(f"Successfully updated prediction session entry ID {session_id} with analysis.")
             return True
        elif response and hasattr(response, 'error') and response.error:
             logging.error(f"Supabase update failed for session ID {session_id}: {response.error.message if hasattr(response.error, 'message') else response.error}")
             return False
        elif response and hasattr(response, 'count') and response.count > 0:
             logging.info(f"Successfully updated prediction session entry ID {session_id} (Count: {response.count}).")
             return True
        else:
             logging.warning(f"Supabase update for session ID {session_id} executed, but unexpected response format or no rows updated: {response}")
             return False

    except Exception as e:
        logging.exception(f"An unexpected error occurred during Supabase session update for ID {session_id}:")
        return False