Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -1087,72 +1087,206 @@ def calculate_cost(duration_seconds):
|
|
| 1087 |
@app.route('/api/projects/<project_id>/start-conversation', methods=['POST'])
|
| 1088 |
def start_conversation(project_id):
|
| 1089 |
"""Start a conversational AI session for a project"""
|
| 1090 |
-
|
|
|
|
| 1091 |
|
| 1092 |
try:
|
|
|
|
|
|
|
|
|
|
| 1093 |
uid = verify_token(request.headers.get('Authorization'))
|
| 1094 |
if not uid:
|
|
|
|
| 1095 |
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
|
|
|
| 1096 |
|
|
|
|
|
|
|
|
|
|
| 1097 |
user_ref = db_ref.child(f'users/{uid}')
|
| 1098 |
user = user_ref.get()
|
| 1099 |
if not user:
|
|
|
|
| 1100 |
return jsonify({'error': 'User not found'}), 404
|
|
|
|
|
|
|
| 1101 |
|
|
|
|
|
|
|
|
|
|
| 1102 |
project = db_ref.child(f'projects/{project_id}').get()
|
| 1103 |
-
if not project
|
|
|
|
| 1104 |
return jsonify({'error': 'Project not found'}), 404
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1105 |
|
| 1106 |
-
data
|
| 1107 |
-
|
| 1108 |
-
|
| 1109 |
-
|
| 1110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1111 |
|
| 1112 |
-
#
|
| 1113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1114 |
|
| 1115 |
-
#
|
| 1116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1117 |
|
| 1118 |
-
|
| 1119 |
-
|
| 1120 |
-
|
| 1121 |
-
|
| 1122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1123 |
return jsonify({'error': 'Insufficient credits', 'needed': cost}), 402
|
|
|
|
|
|
|
| 1124 |
|
| 1125 |
-
#
|
| 1126 |
-
|
| 1127 |
-
|
| 1128 |
-
|
| 1129 |
-
|
| 1130 |
-
|
| 1131 |
-
|
| 1132 |
-
|
| 1133 |
-
|
| 1134 |
-
'
|
| 1135 |
-
|
| 1136 |
-
|
| 1137 |
-
|
| 1138 |
-
|
| 1139 |
-
|
| 1140 |
-
})
|
| 1141 |
-
|
| 1142 |
-
|
| 1143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1144 |
|
| 1145 |
-
return jsonify(
|
| 1146 |
-
'conversation_id': conversation_id,
|
| 1147 |
-
'agent_id': agent_id,
|
| 1148 |
-
'simulation_result': conversation_result,
|
| 1149 |
-
'durationSeconds': round(duration, 1),
|
| 1150 |
-
'creditsDeducted': cost,
|
| 1151 |
-
'remainingCredits': new_credits
|
| 1152 |
-
}), 200
|
| 1153 |
|
| 1154 |
except Exception as e:
|
| 1155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1156 |
return jsonify({'error': 'Failed to start conversation'}), 500
|
| 1157 |
|
| 1158 |
@app.route('/api/projects/<project_id>/continue-conversation', methods=['POST'])
|
|
|
|
| 1087 |
@app.route('/api/projects/<project_id>/start-conversation', methods=['POST'])
|
| 1088 |
def start_conversation(project_id):
|
| 1089 |
"""Start a conversational AI session for a project"""
|
| 1090 |
+
start_time = time.time()
|
| 1091 |
+
logger.info(f"[CONVERSATION] Starting conversation process for project: {project_id}")
|
| 1092 |
|
| 1093 |
try:
|
| 1094 |
+
# Authorization timing
|
| 1095 |
+
auth_start = time.time()
|
| 1096 |
+
logger.info(f"[CONVERSATION] Starting authorization check for project: {project_id}")
|
| 1097 |
uid = verify_token(request.headers.get('Authorization'))
|
| 1098 |
if not uid:
|
| 1099 |
+
logger.error(f"[CONVERSATION] ERROR: Unauthorized access attempt for project: {project_id}")
|
| 1100 |
return jsonify({'error': 'Unauthorized'}), 401
|
| 1101 |
+
auth_time = time.time() - auth_start
|
| 1102 |
+
logger.info(f"[CONVERSATION] Authorization completed in {auth_time:.3f}s for user: {uid}")
|
| 1103 |
|
| 1104 |
+
# User data fetch timing
|
| 1105 |
+
user_fetch_start = time.time()
|
| 1106 |
+
logger.info(f"[CONVERSATION] Fetching user data for uid: {uid}")
|
| 1107 |
user_ref = db_ref.child(f'users/{uid}')
|
| 1108 |
user = user_ref.get()
|
| 1109 |
if not user:
|
| 1110 |
+
logger.error(f"[CONVERSATION] ERROR: User not found for uid: {uid}")
|
| 1111 |
return jsonify({'error': 'User not found'}), 404
|
| 1112 |
+
user_fetch_time = time.time() - user_fetch_start
|
| 1113 |
+
logger.info(f"[CONVERSATION] User data fetch completed in {user_fetch_time:.3f}s, credits: {user.get('credits', 0)}")
|
| 1114 |
|
| 1115 |
+
# Project data fetch timing
|
| 1116 |
+
project_fetch_start = time.time()
|
| 1117 |
+
logger.info(f"[CONVERSATION] Fetching project data for project_id: {project_id}")
|
| 1118 |
project = db_ref.child(f'projects/{project_id}').get()
|
| 1119 |
+
if not project:
|
| 1120 |
+
logger.error(f"[CONVERSATION] ERROR: Project not found for project_id: {project_id}")
|
| 1121 |
return jsonify({'error': 'Project not found'}), 404
|
| 1122 |
+
if project.get('uid') != uid:
|
| 1123 |
+
logger.error(f"[CONVERSATION] ERROR: Project access denied - project_id: {project_id}, project_uid: {project.get('uid')}, requesting_uid: {uid}")
|
| 1124 |
+
return jsonify({'error': 'Project not found'}), 404
|
| 1125 |
+
project_fetch_time = time.time() - project_fetch_start
|
| 1126 |
+
logger.info(f"[CONVERSATION] Project data fetch completed in {project_fetch_time:.3f}s for project: {project.get('projectTitle', 'Unknown')}")
|
| 1127 |
|
| 1128 |
+
# Request data parsing timing
|
| 1129 |
+
data_parse_start = time.time()
|
| 1130 |
+
logger.info(f"[CONVERSATION] Parsing request data")
|
| 1131 |
+
try:
|
| 1132 |
+
data = request.get_json()
|
| 1133 |
+
if data is None:
|
| 1134 |
+
logger.error(f"[CONVERSATION] ERROR: No JSON data received in request")
|
| 1135 |
+
return jsonify({'error': 'No JSON data provided'}), 400
|
| 1136 |
+
initial_message = data.get('message', 'Hello, I need help with my DIY project.')
|
| 1137 |
+
logger.info(f"[CONVERSATION] Initial message: {initial_message[:100]}{'...' if len(initial_message) > 100 else ''}")
|
| 1138 |
+
except Exception as e:
|
| 1139 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to parse request JSON: {str(e)}")
|
| 1140 |
+
return jsonify({'error': 'Invalid JSON data'}), 400
|
| 1141 |
+
data_parse_time = time.time() - data_parse_start
|
| 1142 |
+
logger.info(f"[CONVERSATION] Request data parsing completed in {data_parse_time:.3f}s")
|
| 1143 |
+
|
| 1144 |
+
# AI Handler initialization timing
|
| 1145 |
+
ai_init_start = time.time()
|
| 1146 |
+
logger.info(f"[CONVERSATION] Initializing ConversationalAIHandler")
|
| 1147 |
+
try:
|
| 1148 |
+
ai_handler = ConversationalAIHandler()
|
| 1149 |
+
logger.info(f"[CONVERSATION] ConversationalAIHandler initialized successfully")
|
| 1150 |
+
except Exception as e:
|
| 1151 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to initialize ConversationalAIHandler: {str(e)}")
|
| 1152 |
+
return jsonify({'error': 'Failed to initialize AI handler'}), 500
|
| 1153 |
+
ai_init_time = time.time() - ai_init_start
|
| 1154 |
+
logger.info(f"[CONVERSATION] AI handler initialization completed in {ai_init_time:.3f}s")
|
| 1155 |
|
| 1156 |
+
# Agent creation/retrieval timing
|
| 1157 |
+
agent_start = time.time()
|
| 1158 |
+
logger.info(f"[CONVERSATION] Creating or getting agent for project: {project_id}")
|
| 1159 |
+
try:
|
| 1160 |
+
agent_id = ai_handler.create_or_get_agent(project_id, project)
|
| 1161 |
+
logger.info(f"[CONVERSATION] Agent created/retrieved successfully: {agent_id}")
|
| 1162 |
+
except Exception as e:
|
| 1163 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to create/get agent: {str(e)}")
|
| 1164 |
+
return jsonify({'error': 'Failed to create AI agent'}), 500
|
| 1165 |
+
agent_time = time.time() - agent_start
|
| 1166 |
+
logger.info(f"[CONVERSATION] Agent creation/retrieval completed in {agent_time:.3f}s")
|
| 1167 |
|
| 1168 |
+
# Conversation simulation timing
|
| 1169 |
+
simulation_start = time.time()
|
| 1170 |
+
logger.info(f"[CONVERSATION] Starting conversation simulation with agent: {agent_id}")
|
| 1171 |
+
try:
|
| 1172 |
+
conversation_result = ai_handler.simulate_conversation(agent_id, initial_message)
|
| 1173 |
+
logger.info(f"[CONVERSATION] Conversation simulation completed successfully")
|
| 1174 |
+
logger.info(f"[CONVERSATION] Simulation result type: {type(conversation_result)}")
|
| 1175 |
+
if isinstance(conversation_result, dict):
|
| 1176 |
+
logger.info(f"[CONVERSATION] Simulation result keys: {list(conversation_result.keys())}")
|
| 1177 |
+
except Exception as e:
|
| 1178 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to simulate conversation: {str(e)}")
|
| 1179 |
+
return jsonify({'error': 'Failed to simulate conversation'}), 500
|
| 1180 |
+
simulation_time = time.time() - simulation_start
|
| 1181 |
+
logger.info(f"[CONVERSATION] Conversation simulation completed in {simulation_time:.3f}s")
|
| 1182 |
|
| 1183 |
+
# Duration and cost calculation timing
|
| 1184 |
+
calc_start = time.time()
|
| 1185 |
+
duration = time.time() - start_time
|
| 1186 |
+
logger.info(f"[CONVERSATION] Total duration so far: {duration:.3f}s")
|
| 1187 |
+
try:
|
| 1188 |
+
cost = calculate_cost(duration)
|
| 1189 |
+
logger.info(f"[CONVERSATION] Calculated cost: {cost} credits")
|
| 1190 |
+
except Exception as e:
|
| 1191 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to calculate cost: {str(e)}")
|
| 1192 |
+
return jsonify({'error': 'Failed to calculate cost'}), 500
|
| 1193 |
+
calc_time = time.time() - calc_start
|
| 1194 |
+
logger.info(f"[CONVERSATION] Cost calculation completed in {calc_time:.3f}s")
|
| 1195 |
+
|
| 1196 |
+
# Credit check timing
|
| 1197 |
+
credit_check_start = time.time()
|
| 1198 |
+
user_credits = user.get('credits', 0)
|
| 1199 |
+
logger.info(f"[CONVERSATION] Checking credits - User has: {user_credits}, Cost: {cost}")
|
| 1200 |
+
if user_credits < cost:
|
| 1201 |
+
logger.error(f"[CONVERSATION] ERROR: Insufficient credits - User: {user_credits}, Needed: {cost}")
|
| 1202 |
return jsonify({'error': 'Insufficient credits', 'needed': cost}), 402
|
| 1203 |
+
credit_check_time = time.time() - credit_check_start
|
| 1204 |
+
logger.info(f"[CONVERSATION] Credit check completed in {credit_check_time:.3f}s")
|
| 1205 |
|
| 1206 |
+
# Credit deduction timing
|
| 1207 |
+
deduction_start = time.time()
|
| 1208 |
+
new_credits = user_credits - cost
|
| 1209 |
+
logger.info(f"[CONVERSATION] Deducting {cost} credits, new balance: {new_credits}")
|
| 1210 |
+
try:
|
| 1211 |
+
user_ref.update({'credits': new_credits})
|
| 1212 |
+
logger.info(f"[CONVERSATION] Credits updated successfully in database")
|
| 1213 |
+
except Exception as e:
|
| 1214 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to update user credits: {str(e)}")
|
| 1215 |
+
return jsonify({'error': 'Failed to update credits'}), 500
|
| 1216 |
+
deduction_time = time.time() - deduction_start
|
| 1217 |
+
logger.info(f"[CONVERSATION] Credit deduction completed in {deduction_time:.3f}s")
|
| 1218 |
+
|
| 1219 |
+
# Conversation logging timing
|
| 1220 |
+
logging_start = time.time()
|
| 1221 |
+
conversation_id = f"{project_id}_{int(start_time)}"
|
| 1222 |
+
logger.info(f"[CONVERSATION] Logging conversation with ID: {conversation_id}")
|
| 1223 |
+
try:
|
| 1224 |
+
conversation_data = {
|
| 1225 |
+
'project_id': project_id,
|
| 1226 |
+
'uid': uid,
|
| 1227 |
+
'agent_id': agent_id,
|
| 1228 |
+
'initial_message': initial_message,
|
| 1229 |
+
'result': conversation_result,
|
| 1230 |
+
'duration_seconds': duration,
|
| 1231 |
+
'credits_used': cost,
|
| 1232 |
+
'created_at': int(start_time)
|
| 1233 |
+
}
|
| 1234 |
+
db_ref.child(f'conversations/{conversation_id}').set(conversation_data)
|
| 1235 |
+
logger.info(f"[CONVERSATION] Conversation logged successfully to database")
|
| 1236 |
+
except Exception as e:
|
| 1237 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to log conversation: {str(e)}")
|
| 1238 |
+
return jsonify({'error': 'Failed to log conversation'}), 500
|
| 1239 |
+
logging_time = time.time() - logging_start
|
| 1240 |
+
logger.info(f"[CONVERSATION] Conversation logging completed in {logging_time:.3f}s")
|
| 1241 |
+
|
| 1242 |
+
# Response preparation timing
|
| 1243 |
+
response_start = time.time()
|
| 1244 |
+
total_duration = time.time() - start_time
|
| 1245 |
+
logger.info(f"[CONVERSATION] Preparing response, total duration: {total_duration:.3f}s")
|
| 1246 |
+
try:
|
| 1247 |
+
response_data = {
|
| 1248 |
+
'conversation_id': conversation_id,
|
| 1249 |
+
'agent_id': agent_id,
|
| 1250 |
+
'simulation_result': conversation_result,
|
| 1251 |
+
'durationSeconds': round(total_duration, 1),
|
| 1252 |
+
'creditsDeducted': cost,
|
| 1253 |
+
'remainingCredits': new_credits
|
| 1254 |
+
}
|
| 1255 |
+
logger.info(f"[CONVERSATION] Response prepared successfully")
|
| 1256 |
+
except Exception as e:
|
| 1257 |
+
logger.error(f"[CONVERSATION] ERROR: Failed to prepare response: {str(e)}")
|
| 1258 |
+
return jsonify({'error': 'Failed to prepare response'}), 500
|
| 1259 |
+
response_time = time.time() - response_start
|
| 1260 |
+
logger.info(f"[CONVERSATION] Response preparation completed in {response_time:.3f}s")
|
| 1261 |
+
|
| 1262 |
+
# Final success logging
|
| 1263 |
+
logger.info(f"[CONVERSATION] SUCCESS: User {uid} started conversation for project {project_id}, "
|
| 1264 |
+
f"duration {total_duration:.1f}s, cost {cost} credits.")
|
| 1265 |
+
|
| 1266 |
+
# Performance summary
|
| 1267 |
+
logger.info(f"[CONVERSATION] PERFORMANCE BREAKDOWN:")
|
| 1268 |
+
logger.info(f"[CONVERSATION] - Authorization: {auth_time:.3f}s")
|
| 1269 |
+
logger.info(f"[CONVERSATION] - User fetch: {user_fetch_time:.3f}s")
|
| 1270 |
+
logger.info(f"[CONVERSATION] - Project fetch: {project_fetch_time:.3f}s")
|
| 1271 |
+
logger.info(f"[CONVERSATION] - Data parsing: {data_parse_time:.3f}s")
|
| 1272 |
+
logger.info(f"[CONVERSATION] - AI init: {ai_init_time:.3f}s")
|
| 1273 |
+
logger.info(f"[CONVERSATION] - Agent creation: {agent_time:.3f}s")
|
| 1274 |
+
logger.info(f"[CONVERSATION] - Simulation: {simulation_time:.3f}s")
|
| 1275 |
+
logger.info(f"[CONVERSATION] - Cost calc: {calc_time:.3f}s")
|
| 1276 |
+
logger.info(f"[CONVERSATION] - Credit check: {credit_check_time:.3f}s")
|
| 1277 |
+
logger.info(f"[CONVERSATION] - Credit deduction: {deduction_time:.3f}s")
|
| 1278 |
+
logger.info(f"[CONVERSATION] - Conversation logging: {logging_time:.3f}s")
|
| 1279 |
+
logger.info(f"[CONVERSATION] - Response prep: {response_time:.3f}s")
|
| 1280 |
+
logger.info(f"[CONVERSATION] - TOTAL: {total_duration:.3f}s")
|
| 1281 |
|
| 1282 |
+
return jsonify(response_data), 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1283 |
|
| 1284 |
except Exception as e:
|
| 1285 |
+
total_duration = time.time() - start_time
|
| 1286 |
+
logger.error(f"[CONVERSATION] CRITICAL ERROR: Unhandled exception after {total_duration:.3f}s")
|
| 1287 |
+
logger.error(f"[CONVERSATION] Exception type: {type(e).__name__}")
|
| 1288 |
+
logger.error(f"[CONVERSATION] Exception message: {str(e)}")
|
| 1289 |
+
logger.error(f"[CONVERSATION] Exception traceback:", exc_info=True)
|
| 1290 |
return jsonify({'error': 'Failed to start conversation'}), 500
|
| 1291 |
|
| 1292 |
@app.route('/api/projects/<project_id>/continue-conversation', methods=['POST'])
|