rairo commited on
Commit
97cdc57
·
verified ·
1 Parent(s): 45f8ce2

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +152 -213
main.py CHANGED
@@ -968,7 +968,7 @@ KNOWN_VOICE_IDS = {
968
  class ConversationalAIHandler:
969
  def __init__(self):
970
  self.client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
971
- self.base_url = "https://api.elevenlabs.io/v1"
972
  self.headers = {
973
  "xi-api-key": os.getenv("ELEVENLABS_API_KEY"),
974
  "Content-Type": "application/json"
@@ -984,10 +984,9 @@ class ConversationalAIHandler:
984
  return KNOWN_VOICE_IDS["Daniel"]
985
 
986
  # Fallback: Try to get voices from API (if above fails)
987
- # Note: Using the correct method based on current SDK
988
  try:
989
  logger.info(f"[VOICE] Fallback: Fetching voices from API")
990
- response = self.client.voices.get_all() # Try get_all method
991
  voices = response.voices if hasattr(response, 'voices') else response
992
  logger.info(f"[VOICE] Retrieved {len(voices)} voices from API")
993
 
@@ -1005,13 +1004,13 @@ class ConversationalAIHandler:
1005
  logger.info(f"[VOICE] Using fallback voice: {voices[0].name} - {voices[0].voice_id}")
1006
  return voices[0].voice_id
1007
 
1008
- except AttributeError as ae:
1009
  logger.warning(f"[VOICE] SDK method failed, trying alternative: {str(ae)}")
1010
 
1011
  # Alternative: Try direct API call
1012
  try:
1013
  response = requests.get(
1014
- f"{self.base_url}/voices",
1015
  headers={"xi-api-key": os.getenv("ELEVENLABS_API_KEY")}
1016
  )
1017
  if response.status_code == 200:
@@ -1067,26 +1066,38 @@ class ConversationalAIHandler:
1067
  Ask clarifying questions when needed and share relevant tips from your experience.
1068
  """
1069
 
 
1070
  agent_data = {
1071
  "name": f"DIY Expert - {project_data.get('projectTitle', project_data.get('title', 'Project'))}",
1072
- "prompt": diy_expert_prompt,
1073
- "voice_id": voice_id,
1074
- "language": "en",
1075
  "conversation_config": {
1076
- "turn_detection": {
1077
- "type": "server_vad",
1078
- "threshold": 0.5,
1079
- "prefix_padding_ms": 300,
1080
- "silence_duration_ms": 800
 
 
 
 
 
 
 
 
 
 
 
 
1081
  }
1082
  },
1083
- "webhook_url": f"{request.host_url}api/webhook/agent/{project_id}",
1084
- "max_duration_seconds": 1800 # 30 minutes max
 
1085
  }
1086
 
1087
  logger.info(f"[AGENT] Agent data prepared, checking for existing agent")
1088
 
1089
  # Check if agent already exists for this project
 
1090
  existing_agent_id = db_ref.child(f'projects/{project_id}/agent_id').get()
1091
 
1092
  if existing_agent_id:
@@ -1107,17 +1118,23 @@ class ConversationalAIHandler:
1107
 
1108
  # Create new agent
1109
  logger.info(f"[AGENT] Creating new agent")
 
 
 
 
1110
  response = requests.post(
1111
  f"{self.base_url}/agents",
1112
  headers=self.headers,
1113
- json=agent_data
 
1114
  )
1115
 
1116
  logger.info(f"[AGENT] Agent creation response status: {response.status_code}")
 
1117
 
1118
  if response.status_code == 201:
1119
  agent_info = response.json()
1120
- agent_id = agent_info["id"]
1121
  logger.info(f"[AGENT] New agent created successfully: {agent_id}")
1122
 
1123
  # Store agent ID in database
@@ -1133,51 +1150,82 @@ class ConversationalAIHandler:
1133
  return agent_id
1134
  else:
1135
  logger.error(f"[AGENT] Failed to create agent: Status {response.status_code}")
1136
- logger.error(f"[AGENT] Response: {response.text}")
1137
- raise Exception(f"Failed to create agent: {response.text}")
 
 
 
 
 
 
 
 
1138
 
1139
  except Exception as e:
1140
  logger.error(f"[AGENT] Error creating/getting agent: {str(e)}")
1141
  logger.error(f"[AGENT] Exception type: {type(e).__name__}")
1142
  raise
1143
 
1144
- def simulate_conversation(self, agent_id, user_message):
1145
- """Simulate a conversation with the agent"""
1146
  try:
1147
- logger.info(f"[SIMULATION] Starting conversation simulation with agent: {agent_id}")
1148
- logger.info(f"[SIMULATION] User message: {user_message[:100]}{'...' if len(user_message) > 100 else ''}")
1149
 
1150
- simulation_data = {
1151
- "simulation_specification": {
1152
- "user_message": user_message,
1153
- "max_turns": 10,
1154
- "evaluation_criteria": ["helpfulness", "accuracy", "clarity"]
1155
- }
1156
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1157
 
1158
- logger.info(f"[SIMULATION] Sending simulation request")
1159
  response = requests.post(
1160
- f"{self.base_url}/agents/{agent_id}/simulate-conversation",
1161
  headers=self.headers,
1162
- json=simulation_data,
1163
- timeout=30 # Add timeout
 
 
 
1164
  )
1165
 
1166
- logger.info(f"[SIMULATION] Simulation response status: {response.status_code}")
1167
 
1168
  if response.status_code == 200:
1169
- result = response.json()
1170
- logger.info(f"[SIMULATION] Simulation completed successfully")
1171
- logger.info(f"[SIMULATION] Response keys: {list(result.keys()) if isinstance(result, dict) else 'Not a dict'}")
1172
- return result
1173
  else:
1174
- logger.error(f"[SIMULATION] Simulation failed: Status {response.status_code}")
1175
- logger.error(f"[SIMULATION] Response: {response.text}")
1176
- raise Exception(f"Simulation failed: {response.text}")
1177
 
1178
  except Exception as e:
1179
- logger.error(f"[SIMULATION] Error simulating conversation: {str(e)}")
1180
- logger.error(f"[SIMULATION] Exception type: {type(e).__name__}")
1181
  raise
1182
 
1183
  def calculate_cost(duration_seconds):
@@ -1185,6 +1233,7 @@ def calculate_cost(duration_seconds):
1185
  minutes = (duration_seconds + 59) // 60
1186
  return minutes * CREDITS_PER_MIN
1187
 
 
1188
  @app.route('/api/projects/<project_id>/start-conversation', methods=['POST'])
1189
  def start_conversation(project_id):
1190
  """Start a conversational AI session for a project"""
@@ -1192,202 +1241,92 @@ def start_conversation(project_id):
1192
  logger.info(f"[CONVERSATION] Starting conversation process for project: {project_id}")
1193
 
1194
  try:
1195
- # Authorization timing
1196
- auth_start = time.time()
1197
- logger.info(f"[CONVERSATION] Starting authorization check for project: {project_id}")
1198
  uid = verify_token(request.headers.get('Authorization'))
1199
  if not uid:
1200
  logger.error(f"[CONVERSATION] ERROR: Unauthorized access attempt for project: {project_id}")
1201
  return jsonify({'error': 'Unauthorized'}), 401
1202
- auth_time = time.time() - auth_start
1203
- logger.info(f"[CONVERSATION] Authorization completed in {auth_time:.3f}s for user: {uid}")
1204
 
1205
- # User data fetch timing
1206
- user_fetch_start = time.time()
1207
- logger.info(f"[CONVERSATION] Fetching user data for uid: {uid}")
1208
  user_ref = db_ref.child(f'users/{uid}')
1209
  user = user_ref.get()
1210
  if not user:
1211
  logger.error(f"[CONVERSATION] ERROR: User not found for uid: {uid}")
1212
  return jsonify({'error': 'User not found'}), 404
1213
- user_fetch_time = time.time() - user_fetch_start
1214
- logger.info(f"[CONVERSATION] User data fetch completed in {user_fetch_time:.3f}s, credits: {user.get('credits', 0)}")
1215
 
1216
- # Project data fetch timing
1217
- project_fetch_start = time.time()
1218
- logger.info(f"[CONVERSATION] Fetching project data for project_id: {project_id}")
1219
  project = db_ref.child(f'projects/{project_id}').get()
1220
- if not project:
1221
- logger.error(f"[CONVERSATION] ERROR: Project not found for project_id: {project_id}")
1222
- return jsonify({'error': 'Project not found'}), 404
1223
- if project.get('uid') != uid:
1224
- logger.error(f"[CONVERSATION] ERROR: Project access denied - project_id: {project_id}, project_uid: {project.get('uid')}, requesting_uid: {uid}")
1225
  return jsonify({'error': 'Project not found'}), 404
1226
- project_fetch_time = time.time() - project_fetch_start
1227
- logger.info(f"[CONVERSATION] Project data fetch completed in {project_fetch_time:.3f}s for project: {project.get('projectTitle', 'Unknown')}")
1228
 
1229
- # Request data parsing timing
1230
- data_parse_start = time.time()
1231
- logger.info(f"[CONVERSATION] Parsing request data")
1232
- try:
1233
- data = request.get_json()
1234
- if data is None:
1235
- logger.error(f"[CONVERSATION] ERROR: No JSON data received in request")
1236
- return jsonify({'error': 'No JSON data provided'}), 400
1237
- initial_message = data.get('message', 'Hello, I need help with my DIY project.')
1238
- logger.info(f"[CONVERSATION] Initial message: {initial_message[:100]}{'...' if len(initial_message) > 100 else ''}")
1239
- except Exception as e:
1240
- logger.error(f"[CONVERSATION] ERROR: Failed to parse request JSON: {str(e)}")
1241
- return jsonify({'error': 'Invalid JSON data'}), 400
1242
- data_parse_time = time.time() - data_parse_start
1243
- logger.info(f"[CONVERSATION] Request data parsing completed in {data_parse_time:.3f}s")
1244
-
1245
- # AI Handler initialization timing
1246
- ai_init_start = time.time()
1247
- logger.info(f"[CONVERSATION] Initializing ConversationalAIHandler")
1248
- try:
1249
- ai_handler = ConversationalAIHandler()
1250
- logger.info(f"[CONVERSATION] ConversationalAIHandler initialized successfully")
1251
- except Exception as e:
1252
- logger.error(f"[CONVERSATION] ERROR: Failed to initialize ConversationalAIHandler: {str(e)}")
1253
- return jsonify({'error': 'Failed to initialize AI handler'}), 500
1254
- ai_init_time = time.time() - ai_init_start
1255
- logger.info(f"[CONVERSATION] AI handler initialization completed in {ai_init_time:.3f}s")
1256
 
1257
- # Agent creation/retrieval timing
1258
- agent_start = time.time()
1259
- logger.info(f"[CONVERSATION] Creating or getting agent for project: {project_id}")
1260
- try:
1261
- agent_id = ai_handler.create_or_get_agent(project_id, project)
1262
- logger.info(f"[CONVERSATION] Agent created/retrieved successfully: {agent_id}")
1263
- except Exception as e:
1264
- logger.error(f"[CONVERSATION] ERROR: Failed to create/get agent: {str(e)}")
1265
- return jsonify({'error': 'Failed to create AI agent'}), 500
1266
- agent_time = time.time() - agent_start
1267
- logger.info(f"[CONVERSATION] Agent creation/retrieval completed in {agent_time:.3f}s")
1268
 
1269
- # Conversation simulation timing
1270
- simulation_start = time.time()
1271
- logger.info(f"[CONVERSATION] Starting conversation simulation with agent: {agent_id}")
1272
- try:
1273
- conversation_result = ai_handler.simulate_conversation(agent_id, initial_message)
1274
- logger.info(f"[CONVERSATION] Conversation simulation completed successfully")
1275
- logger.info(f"[CONVERSATION] Simulation result type: {type(conversation_result)}")
1276
- if isinstance(conversation_result, dict):
1277
- logger.info(f"[CONVERSATION] Simulation result keys: {list(conversation_result.keys())}")
1278
- except Exception as e:
1279
- logger.error(f"[CONVERSATION] ERROR: Failed to simulate conversation: {str(e)}")
1280
- return jsonify({'error': 'Failed to simulate conversation'}), 500
1281
- simulation_time = time.time() - simulation_start
1282
- logger.info(f"[CONVERSATION] Conversation simulation completed in {simulation_time:.3f}s")
1283
 
1284
- # Duration and cost calculation timing
1285
- calc_start = time.time()
 
 
 
 
 
 
 
1286
  duration = time.time() - start_time
1287
- logger.info(f"[CONVERSATION] Total duration so far: {duration:.3f}s")
1288
- try:
1289
- cost = calculate_cost(duration)
1290
- logger.info(f"[CONVERSATION] Calculated cost: {cost} credits")
1291
- except Exception as e:
1292
- logger.error(f"[CONVERSATION] ERROR: Failed to calculate cost: {str(e)}")
1293
- return jsonify({'error': 'Failed to calculate cost'}), 500
1294
- calc_time = time.time() - calc_start
1295
- logger.info(f"[CONVERSATION] Cost calculation completed in {calc_time:.3f}s")
1296
-
1297
- # Credit check timing
1298
- credit_check_start = time.time()
1299
  user_credits = user.get('credits', 0)
1300
- logger.info(f"[CONVERSATION] Checking credits - User has: {user_credits}, Cost: {cost}")
1301
  if user_credits < cost:
1302
- logger.error(f"[CONVERSATION] ERROR: Insufficient credits - User: {user_credits}, Needed: {cost}")
1303
  return jsonify({'error': 'Insufficient credits', 'needed': cost}), 402
1304
- credit_check_time = time.time() - credit_check_start
1305
- logger.info(f"[CONVERSATION] Credit check completed in {credit_check_time:.3f}s")
1306
-
1307
- # Credit deduction timing
1308
- deduction_start = time.time()
1309
  new_credits = user_credits - cost
1310
- logger.info(f"[CONVERSATION] Deducting {cost} credits, new balance: {new_credits}")
1311
- try:
1312
- user_ref.update({'credits': new_credits})
1313
- logger.info(f"[CONVERSATION] Credits updated successfully in database")
1314
- except Exception as e:
1315
- logger.error(f"[CONVERSATION] ERROR: Failed to update user credits: {str(e)}")
1316
- return jsonify({'error': 'Failed to update credits'}), 500
1317
- deduction_time = time.time() - deduction_start
1318
- logger.info(f"[CONVERSATION] Credit deduction completed in {deduction_time:.3f}s")
1319
-
1320
- # Conversation logging timing
1321
- logging_start = time.time()
1322
- conversation_id = f"{project_id}_{int(start_time)}"
1323
- logger.info(f"[CONVERSATION] Logging conversation with ID: {conversation_id}")
1324
- try:
1325
- conversation_data = {
1326
- 'project_id': project_id,
1327
- 'uid': uid,
1328
- 'agent_id': agent_id,
1329
- 'initial_message': initial_message,
1330
- 'result': conversation_result,
1331
- 'duration_seconds': duration,
1332
- 'credits_used': cost,
1333
- 'created_at': int(start_time)
1334
- }
1335
- db_ref.child(f'conversations/{conversation_id}').set(conversation_data)
1336
- logger.info(f"[CONVERSATION] Conversation logged successfully to database")
1337
- except Exception as e:
1338
- logger.error(f"[CONVERSATION] ERROR: Failed to log conversation: {str(e)}")
1339
- return jsonify({'error': 'Failed to log conversation'}), 500
1340
- logging_time = time.time() - logging_start
1341
- logger.info(f"[CONVERSATION] Conversation logging completed in {logging_time:.3f}s")
1342
-
1343
- # Response preparation timing
1344
- response_start = time.time()
1345
- total_duration = time.time() - start_time
1346
- logger.info(f"[CONVERSATION] Preparing response, total duration: {total_duration:.3f}s")
1347
- try:
1348
- response_data = {
1349
- 'conversation_id': conversation_id,
1350
- 'agent_id': agent_id,
1351
- 'simulation_result': conversation_result,
1352
- 'durationSeconds': round(total_duration, 1),
1353
- 'creditsDeducted': cost,
1354
- 'remainingCredits': new_credits
1355
- }
1356
- logger.info(f"[CONVERSATION] Response prepared successfully")
1357
- except Exception as e:
1358
- logger.error(f"[CONVERSATION] ERROR: Failed to prepare response: {str(e)}")
1359
- return jsonify({'error': 'Failed to prepare response'}), 500
1360
- response_time = time.time() - response_start
1361
- logger.info(f"[CONVERSATION] Response preparation completed in {response_time:.3f}s")
1362
-
1363
- # Final success logging
1364
- logger.info(f"[CONVERSATION] SUCCESS: User {uid} started conversation for project {project_id}, "
1365
- f"duration {total_duration:.1f}s, cost {cost} credits.")
1366
 
1367
- # Performance summary
1368
- logger.info(f"[CONVERSATION] PERFORMANCE BREAKDOWN:")
1369
- logger.info(f"[CONVERSATION] - Authorization: {auth_time:.3f}s")
1370
- logger.info(f"[CONVERSATION] - User fetch: {user_fetch_time:.3f}s")
1371
- logger.info(f"[CONVERSATION] - Project fetch: {project_fetch_time:.3f}s")
1372
- logger.info(f"[CONVERSATION] - Data parsing: {data_parse_time:.3f}s")
1373
- logger.info(f"[CONVERSATION] - AI init: {ai_init_time:.3f}s")
1374
- logger.info(f"[CONVERSATION] - Agent creation: {agent_time:.3f}s")
1375
- logger.info(f"[CONVERSATION] - Simulation: {simulation_time:.3f}s")
1376
- logger.info(f"[CONVERSATION] - Cost calc: {calc_time:.3f}s")
1377
- logger.info(f"[CONVERSATION] - Credit check: {credit_check_time:.3f}s")
1378
- logger.info(f"[CONVERSATION] - Credit deduction: {deduction_time:.3f}s")
1379
- logger.info(f"[CONVERSATION] - Conversation logging: {logging_time:.3f}s")
1380
- logger.info(f"[CONVERSATION] - Response prep: {response_time:.3f}s")
1381
- logger.info(f"[CONVERSATION] - TOTAL: {total_duration:.3f}s")
1382
-
1383
- return jsonify(response_data), 200
 
 
 
 
 
 
 
 
1384
 
1385
  except Exception as e:
1386
  total_duration = time.time() - start_time
1387
- logger.error(f"[CONVERSATION] CRITICAL ERROR: Unhandled exception after {total_duration:.3f}s")
1388
  logger.error(f"[CONVERSATION] Exception type: {type(e).__name__}")
1389
- logger.error(f"[CONVERSATION] Exception message: {str(e)}")
1390
- logger.error(f"[CONVERSATION] Exception traceback:", exc_info=True)
1391
  return jsonify({'error': 'Failed to start conversation'}), 500
1392
 
1393
  @app.route('/api/projects/<project_id>/continue-conversation', methods=['POST'])
 
968
  class ConversationalAIHandler:
969
  def __init__(self):
970
  self.client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
971
+ self.base_url = "https://api.elevenlabs.io/v1/convai" # Fixed: Use convai endpoint
972
  self.headers = {
973
  "xi-api-key": os.getenv("ELEVENLABS_API_KEY"),
974
  "Content-Type": "application/json"
 
984
  return KNOWN_VOICE_IDS["Daniel"]
985
 
986
  # Fallback: Try to get voices from API (if above fails)
 
987
  try:
988
  logger.info(f"[VOICE] Fallback: Fetching voices from API")
989
+ response = self.client.voices.get_all()
990
  voices = response.voices if hasattr(response, 'voices') else response
991
  logger.info(f"[VOICE] Retrieved {len(voices)} voices from API")
992
 
 
1004
  logger.info(f"[VOICE] Using fallback voice: {voices[0].name} - {voices[0].voice_id}")
1005
  return voices[0].voice_id
1006
 
1007
+ except Exception as ae:
1008
  logger.warning(f"[VOICE] SDK method failed, trying alternative: {str(ae)}")
1009
 
1010
  # Alternative: Try direct API call
1011
  try:
1012
  response = requests.get(
1013
+ "https://api.elevenlabs.io/v1/voices",
1014
  headers={"xi-api-key": os.getenv("ELEVENLABS_API_KEY")}
1015
  )
1016
  if response.status_code == 200:
 
1066
  Ask clarifying questions when needed and share relevant tips from your experience.
1067
  """
1068
 
1069
+ # Fixed: Correct ElevenLabs Conversational AI agent structure
1070
  agent_data = {
1071
  "name": f"DIY Expert - {project_data.get('projectTitle', project_data.get('title', 'Project'))}",
 
 
 
1072
  "conversation_config": {
1073
+ "agent": {
1074
+ "prompt": {
1075
+ "prompt": diy_expert_prompt
1076
+ },
1077
+ "first_message": "Hello! I'm your DIY expert assistant. I'm here to help you with your project. What would you like to work on today?",
1078
+ "language": "en"
1079
+ },
1080
+ "asr": {
1081
+ "provider": "deepgram",
1082
+ "user_input_audio_format": "pcm_16000"
1083
+ },
1084
+ "tts": {
1085
+ "voice_id": voice_id
1086
+ },
1087
+ "llm": {
1088
+ "provider": "openai",
1089
+ "model": "gpt-4"
1090
  }
1091
  },
1092
+ "platform_settings": {
1093
+ "webhook_url": f"{os.getenv('BASE_URL', 'https://yourapp.com')}/api/webhook/agent/{project_id}"
1094
+ }
1095
  }
1096
 
1097
  logger.info(f"[AGENT] Agent data prepared, checking for existing agent")
1098
 
1099
  # Check if agent already exists for this project
1100
+ from your_database import db_ref # Import your database reference
1101
  existing_agent_id = db_ref.child(f'projects/{project_id}/agent_id').get()
1102
 
1103
  if existing_agent_id:
 
1118
 
1119
  # Create new agent
1120
  logger.info(f"[AGENT] Creating new agent")
1121
+ logger.info(f"[AGENT] Request URL: {self.base_url}/agents")
1122
+ logger.info(f"[AGENT] Request headers: {self.headers}")
1123
+ logger.info(f"[AGENT] Request payload keys: {list(agent_data.keys())}")
1124
+
1125
  response = requests.post(
1126
  f"{self.base_url}/agents",
1127
  headers=self.headers,
1128
+ json=agent_data,
1129
+ timeout=30
1130
  )
1131
 
1132
  logger.info(f"[AGENT] Agent creation response status: {response.status_code}")
1133
+ logger.info(f"[AGENT] Agent creation response headers: {dict(response.headers)}")
1134
 
1135
  if response.status_code == 201:
1136
  agent_info = response.json()
1137
+ agent_id = agent_info.get("agent_id")
1138
  logger.info(f"[AGENT] New agent created successfully: {agent_id}")
1139
 
1140
  # Store agent ID in database
 
1150
  return agent_id
1151
  else:
1152
  logger.error(f"[AGENT] Failed to create agent: Status {response.status_code}")
1153
+ logger.error(f"[AGENT] Response text: {response.text}")
1154
+
1155
+ # Try to parse error response
1156
+ try:
1157
+ error_data = response.json()
1158
+ logger.error(f"[AGENT] Error details: {error_data}")
1159
+ except:
1160
+ logger.error(f"[AGENT] Could not parse error response as JSON")
1161
+
1162
+ raise Exception(f"Failed to create agent: HTTP {response.status_code} - {response.text}")
1163
 
1164
  except Exception as e:
1165
  logger.error(f"[AGENT] Error creating/getting agent: {str(e)}")
1166
  logger.error(f"[AGENT] Exception type: {type(e).__name__}")
1167
  raise
1168
 
1169
+ def start_conversation(self, agent_id):
1170
+ """Start a conversation with the agent"""
1171
  try:
1172
+ logger.info(f"[CONVERSATION] Starting conversation with agent: {agent_id}")
 
1173
 
1174
+ # Start conversation
1175
+ response = requests.post(
1176
+ f"{self.base_url}/agents/{agent_id}/conversations",
1177
+ headers=self.headers,
1178
+ json={},
1179
+ timeout=30
1180
+ )
1181
+
1182
+ logger.info(f"[CONVERSATION] Start conversation response status: {response.status_code}")
1183
+
1184
+ if response.status_code == 201:
1185
+ conversation_info = response.json()
1186
+ conversation_id = conversation_info.get("conversation_id")
1187
+ logger.info(f"[CONVERSATION] Conversation started successfully: {conversation_id}")
1188
+ return conversation_id
1189
+ else:
1190
+ logger.error(f"[CONVERSATION] Failed to start conversation: Status {response.status_code}")
1191
+ logger.error(f"[CONVERSATION] Response: {response.text}")
1192
+ raise Exception(f"Failed to start conversation: {response.text}")
1193
+
1194
+ except Exception as e:
1195
+ logger.error(f"[CONVERSATION] Error starting conversation: {str(e)}")
1196
+ logger.error(f"[CONVERSATION] Exception type: {type(e).__name__}")
1197
+ raise
1198
+
1199
+ def send_message(self, agent_id, conversation_id, message):
1200
+ """Send a message to the conversation"""
1201
+ try:
1202
+ logger.info(f"[MESSAGE] Sending message to agent: {agent_id}, conversation: {conversation_id}")
1203
+ logger.info(f"[MESSAGE] Message: {message[:100]}{'...' if len(message) > 100 else ''}")
1204
 
 
1205
  response = requests.post(
1206
+ f"{self.base_url}/agents/{agent_id}/conversations/{conversation_id}/messages",
1207
  headers=self.headers,
1208
+ json={
1209
+ "message": message,
1210
+ "message_type": "text"
1211
+ },
1212
+ timeout=30
1213
  )
1214
 
1215
+ logger.info(f"[MESSAGE] Send message response status: {response.status_code}")
1216
 
1217
  if response.status_code == 200:
1218
+ message_response = response.json()
1219
+ logger.info(f"[MESSAGE] Message sent successfully")
1220
+ return message_response
 
1221
  else:
1222
+ logger.error(f"[MESSAGE] Failed to send message: Status {response.status_code}")
1223
+ logger.error(f"[MESSAGE] Response: {response.text}")
1224
+ raise Exception(f"Failed to send message: {response.text}")
1225
 
1226
  except Exception as e:
1227
+ logger.error(f"[MESSAGE] Error sending message: {str(e)}")
1228
+ logger.error(f"[MESSAGE] Exception type: {type(e).__name__}")
1229
  raise
1230
 
1231
  def calculate_cost(duration_seconds):
 
1233
  minutes = (duration_seconds + 59) // 60
1234
  return minutes * CREDITS_PER_MIN
1235
 
1236
+ # Updated Flask route
1237
  @app.route('/api/projects/<project_id>/start-conversation', methods=['POST'])
1238
  def start_conversation(project_id):
1239
  """Start a conversational AI session for a project"""
 
1241
  logger.info(f"[CONVERSATION] Starting conversation process for project: {project_id}")
1242
 
1243
  try:
1244
+ # Authorization
 
 
1245
  uid = verify_token(request.headers.get('Authorization'))
1246
  if not uid:
1247
  logger.error(f"[CONVERSATION] ERROR: Unauthorized access attempt for project: {project_id}")
1248
  return jsonify({'error': 'Unauthorized'}), 401
 
 
1249
 
1250
+ # Get user data
 
 
1251
  user_ref = db_ref.child(f'users/{uid}')
1252
  user = user_ref.get()
1253
  if not user:
1254
  logger.error(f"[CONVERSATION] ERROR: User not found for uid: {uid}")
1255
  return jsonify({'error': 'User not found'}), 404
 
 
1256
 
1257
+ # Get project data
 
 
1258
  project = db_ref.child(f'projects/{project_id}').get()
1259
+ if not project or project.get('uid') != uid:
1260
+ logger.error(f"[CONVERSATION] ERROR: Project not found or access denied")
 
 
 
1261
  return jsonify({'error': 'Project not found'}), 404
 
 
1262
 
1263
+ # Parse request data
1264
+ data = request.get_json()
1265
+ if data is None:
1266
+ logger.error(f"[CONVERSATION] ERROR: No JSON data received")
1267
+ return jsonify({'error': 'No JSON data provided'}), 400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1268
 
1269
+ initial_message = data.get('message', 'Hello, I need help with my DIY project.')
1270
+ logger.info(f"[CONVERSATION] Initial message: {initial_message[:100]}{'...' if len(initial_message) > 100 else ''}")
1271
+
1272
+ # Initialize AI Handler
1273
+ ai_handler = ConversationalAIHandler()
 
 
 
 
 
 
1274
 
1275
+ # Create or get agent
1276
+ agent_id = ai_handler.create_or_get_agent(project_id, project)
1277
+ logger.info(f"[CONVERSATION] Agent ready: {agent_id}")
 
 
 
 
 
 
 
 
 
 
 
1278
 
1279
+ # Start conversation
1280
+ conversation_id = ai_handler.start_conversation(agent_id)
1281
+ logger.info(f"[CONVERSATION] Conversation started: {conversation_id}")
1282
+
1283
+ # Send initial message
1284
+ response_data = ai_handler.send_message(agent_id, conversation_id, initial_message)
1285
+ logger.info(f"[CONVERSATION] Message sent successfully")
1286
+
1287
+ # Calculate cost and duration
1288
  duration = time.time() - start_time
1289
+ cost = calculate_cost(duration)
1290
+
1291
+ # Check and deduct credits
 
 
 
 
 
 
 
 
 
1292
  user_credits = user.get('credits', 0)
 
1293
  if user_credits < cost:
1294
+ logger.error(f"[CONVERSATION] ERROR: Insufficient credits")
1295
  return jsonify({'error': 'Insufficient credits', 'needed': cost}), 402
1296
+
 
 
 
 
1297
  new_credits = user_credits - cost
1298
+ user_ref.update({'credits': new_credits})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1299
 
1300
+ # Log conversation
1301
+ conversation_log_id = f"{project_id}_{int(start_time)}"
1302
+ conversation_data = {
1303
+ 'project_id': project_id,
1304
+ 'uid': uid,
1305
+ 'agent_id': agent_id,
1306
+ 'conversation_id': conversation_id,
1307
+ 'initial_message': initial_message,
1308
+ 'response': response_data,
1309
+ 'duration_seconds': duration,
1310
+ 'credits_used': cost,
1311
+ 'created_at': int(start_time)
1312
+ }
1313
+ db_ref.child(f'conversations/{conversation_log_id}').set(conversation_data)
1314
+
1315
+ # Return success response
1316
+ return jsonify({
1317
+ 'conversation_log_id': conversation_log_id,
1318
+ 'agent_id': agent_id,
1319
+ 'conversation_id': conversation_id,
1320
+ 'response': response_data,
1321
+ 'durationSeconds': round(duration, 1),
1322
+ 'creditsDeducted': cost,
1323
+ 'remainingCredits': new_credits
1324
+ }), 200
1325
 
1326
  except Exception as e:
1327
  total_duration = time.time() - start_time
1328
+ logger.error(f"[CONVERSATION] CRITICAL ERROR: {str(e)}")
1329
  logger.error(f"[CONVERSATION] Exception type: {type(e).__name__}")
 
 
1330
  return jsonify({'error': 'Failed to start conversation'}), 500
1331
 
1332
  @app.route('/api/projects/<project_id>/continue-conversation', methods=['POST'])