Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -956,17 +956,17 @@ import math
|
|
| 956 |
|
| 957 |
|
| 958 |
# Fixed server code
|
|
|
|
| 959 |
AGENT_ID = os.getenv("AGENT_ID", "agent_01jy1vv1hqe2b9x0yyp6ayrdxj")
|
| 960 |
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
|
| 961 |
|
| 962 |
@app.route('/api/projects/<project_id>/initiate-call', methods=['POST'])
|
| 963 |
def initiate_call(project_id):
|
| 964 |
"""
|
| 965 |
-
|
| 966 |
"""
|
| 967 |
logger.info(f"[INITIATE] Received request for project: {project_id}")
|
| 968 |
|
| 969 |
-
# Your real authentication logic should be active
|
| 970 |
uid = verify_token(request.headers.get('Authorization'))
|
| 971 |
if not uid:
|
| 972 |
return jsonify({'error': 'Unauthorized'}), 401
|
|
@@ -975,87 +975,94 @@ def initiate_call(project_id):
|
|
| 975 |
logger.error("[INITIATE] ELEVENLABS_API_KEY is not set on the server.")
|
| 976 |
return jsonify({'error': 'Server configuration error.'}), 500
|
| 977 |
|
| 978 |
-
# ✅
|
| 979 |
-
|
| 980 |
-
|
| 981 |
-
|
| 982 |
-
|
|
|
|
| 983 |
|
| 984 |
try:
|
| 985 |
-
|
| 986 |
-
|
| 987 |
-
|
| 988 |
-
|
| 989 |
-
|
| 990 |
-
|
| 991 |
-
if
|
| 992 |
-
|
| 993 |
-
|
| 994 |
-
|
| 995 |
-
|
| 996 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 997 |
|
| 998 |
except requests.exceptions.RequestException as e:
|
| 999 |
logger.error(f"[INITIATE] Error calling ElevenLabs API: {e}")
|
| 1000 |
-
|
| 1001 |
-
|
| 1002 |
-
# Alternative for public agents (simpler but less secure):
|
| 1003 |
-
@app.route('/api/projects/<project_id>/initiate-call-simple', methods=['POST'])
|
| 1004 |
-
def initiate_call_simple(project_id):
|
| 1005 |
-
"""
|
| 1006 |
-
For public agents, you can also return the agent ID directly.
|
| 1007 |
-
Less secure but simpler for testing.
|
| 1008 |
-
"""
|
| 1009 |
-
logger.info(f"[INITIATE-SIMPLE] Received request for project: {project_id}")
|
| 1010 |
-
|
| 1011 |
-
uid = verify_token(request.headers.get('Authorization'))
|
| 1012 |
-
if not uid:
|
| 1013 |
-
return jsonify({'error': 'Unauthorized'}), 401
|
| 1014 |
|
| 1015 |
-
# For public agents, you can return the agent ID directly
|
| 1016 |
-
return jsonify({"agent_id": AGENT_ID}), 200
|
| 1017 |
-
|
| 1018 |
-
# Debug endpoint to test your setup
|
| 1019 |
@app.route('/api/debug/test-agent', methods=['GET'])
|
| 1020 |
def test_agent():
|
| 1021 |
-
"""
|
| 1022 |
if not ELEVENLABS_API_KEY:
|
| 1023 |
return jsonify({'error': 'API key not set'}), 500
|
| 1024 |
|
| 1025 |
-
|
| 1026 |
-
|
| 1027 |
-
|
|
|
|
| 1028 |
|
| 1029 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1030 |
agent_response = requests.get(agent_url, headers=headers, timeout=10)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1031 |
|
| 1032 |
-
# Test 2: Try
|
| 1033 |
-
|
| 1034 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1035 |
|
| 1036 |
-
|
| 1037 |
-
|
| 1038 |
-
|
| 1039 |
-
|
| 1040 |
-
|
| 1041 |
-
|
| 1042 |
-
'
|
| 1043 |
-
'
|
| 1044 |
-
'
|
|
|
|
| 1045 |
}
|
| 1046 |
-
|
|
|
|
|
|
|
| 1047 |
except Exception as e:
|
| 1048 |
return jsonify({'error': str(e), 'agent_id': AGENT_ID})
|
| 1049 |
|
| 1050 |
@app.route('/api/projects/<project_id>/log-call-usage', methods=['POST'])
|
| 1051 |
def log_call_usage(project_id):
|
| 1052 |
"""
|
| 1053 |
-
|
| 1054 |
-
after a call is completed. This is the production-ready version.
|
| 1055 |
"""
|
| 1056 |
logger.info(f"[LOGGING] Received usage log for project: {project_id}")
|
| 1057 |
|
| 1058 |
-
# Step 1: Authenticate the user and get their unique ID
|
| 1059 |
uid = verify_token(request.headers.get('Authorization'))
|
| 1060 |
if not uid:
|
| 1061 |
return jsonify({'error': 'Unauthorized'}), 401
|
|
@@ -1066,14 +1073,12 @@ def log_call_usage(project_id):
|
|
| 1066 |
if duration_seconds is None or not isinstance(duration_seconds, (int, float)):
|
| 1067 |
return jsonify({'error': 'Invalid duration provided.'}), 400
|
| 1068 |
|
| 1069 |
-
# Step 2: Calculate credit cost (3 credits per minute, always rounded up)
|
| 1070 |
minutes = math.ceil(duration_seconds / 60)
|
| 1071 |
cost = minutes * 3
|
| 1072 |
|
| 1073 |
logger.info(f"[LOGGING] User '{uid}' call duration: {duration_seconds:.2f}s, rounded to {minutes} minute(s). Cost: {cost} credits.")
|
| 1074 |
|
| 1075 |
try:
|
| 1076 |
-
# Step 3: Perform the database transaction
|
| 1077 |
user_ref = db_ref.child(f'users/{uid}')
|
| 1078 |
user_data = user_ref.get()
|
| 1079 |
|
|
@@ -1082,16 +1087,12 @@ def log_call_usage(project_id):
|
|
| 1082 |
return jsonify({'error': 'User not found.'}), 404
|
| 1083 |
|
| 1084 |
current_credits = user_data.get('credits', 0)
|
| 1085 |
-
|
| 1086 |
-
# Calculate the new balance, ensuring it doesn't go below zero.
|
| 1087 |
new_credits = max(0, current_credits - cost)
|
| 1088 |
|
| 1089 |
-
# Update the user's credit balance in Firebase
|
| 1090 |
user_ref.update({'credits': new_credits})
|
| 1091 |
|
| 1092 |
logger.info(f"[LOGGING] Successfully updated credits for user '{uid}'. Old: {current_credits}, New: {new_credits}")
|
| 1093 |
|
| 1094 |
-
# Step 4: Return the successful response with the actual new balance
|
| 1095 |
return jsonify({
|
| 1096 |
"status": "success",
|
| 1097 |
"creditsDeducted": cost,
|
|
|
|
| 956 |
|
| 957 |
|
| 958 |
# Fixed server code
|
| 959 |
+
|
| 960 |
AGENT_ID = os.getenv("AGENT_ID", "agent_01jy1vv1hqe2b9x0yyp6ayrdxj")
|
| 961 |
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
|
| 962 |
|
| 963 |
@app.route('/api/projects/<project_id>/initiate-call', methods=['POST'])
|
| 964 |
def initiate_call(project_id):
|
| 965 |
"""
|
| 966 |
+
Fixed version - handles the API endpoint issues shown in your debug
|
| 967 |
"""
|
| 968 |
logger.info(f"[INITIATE] Received request for project: {project_id}")
|
| 969 |
|
|
|
|
| 970 |
uid = verify_token(request.headers.get('Authorization'))
|
| 971 |
if not uid:
|
| 972 |
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
| 975 |
logger.error("[INITIATE] ELEVENLABS_API_KEY is not set on the server.")
|
| 976 |
return jsonify({'error': 'Server configuration error.'}), 500
|
| 977 |
|
| 978 |
+
# ✅ FIX: Use the correct API endpoint structure
|
| 979 |
+
# The debug shows your agent exists, but the signed URL endpoint is different
|
| 980 |
+
headers = {
|
| 981 |
+
"xi-api-key": ELEVENLABS_API_KEY,
|
| 982 |
+
"Content-Type": "application/json"
|
| 983 |
+
}
|
| 984 |
|
| 985 |
try:
|
| 986 |
+
# Method 1: Try the newer endpoint format
|
| 987 |
+
url = "https://api.elevenlabs.io/v1/convai/conversation"
|
| 988 |
+
payload = {"agent_id": AGENT_ID}
|
| 989 |
+
|
| 990 |
+
response = requests.post(url, headers=headers, json=payload, timeout=15)
|
| 991 |
+
|
| 992 |
+
if response.status_code == 200:
|
| 993 |
+
data = response.json()
|
| 994 |
+
conversation_id = data.get("conversation_id")
|
| 995 |
+
if conversation_id:
|
| 996 |
+
# Return the WebSocket URL format
|
| 997 |
+
ws_url = f"wss://api.elevenlabs.io/v1/convai/conversation/{conversation_id}"
|
| 998 |
+
logger.info("[INITIATE] Successfully created conversation session.")
|
| 999 |
+
return jsonify({"signed_url": ws_url}), 200
|
| 1000 |
+
|
| 1001 |
+
# Method 2: Try direct agent connection (fallback)
|
| 1002 |
+
logger.info("[INITIATE] Conversation creation failed, trying direct agent approach")
|
| 1003 |
+
|
| 1004 |
+
# For public agents, return agent ID directly - SDK will handle it
|
| 1005 |
+
return jsonify({"agent_id": AGENT_ID}), 200
|
| 1006 |
|
| 1007 |
except requests.exceptions.RequestException as e:
|
| 1008 |
logger.error(f"[INITIATE] Error calling ElevenLabs API: {e}")
|
| 1009 |
+
# Return agent ID as fallback
|
| 1010 |
+
return jsonify({"agent_id": AGENT_ID}), 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1011 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1012 |
@app.route('/api/debug/test-agent', methods=['GET'])
|
| 1013 |
def test_agent():
|
| 1014 |
+
"""Fixed debug endpoint"""
|
| 1015 |
if not ELEVENLABS_API_KEY:
|
| 1016 |
return jsonify({'error': 'API key not set'}), 500
|
| 1017 |
|
| 1018 |
+
headers = {
|
| 1019 |
+
"xi-api-key": ELEVENLABS_API_KEY,
|
| 1020 |
+
"Content-Type": "application/json"
|
| 1021 |
+
}
|
| 1022 |
|
| 1023 |
try:
|
| 1024 |
+
results = {'agent_id': AGENT_ID, 'tests': {}}
|
| 1025 |
+
|
| 1026 |
+
# Test 1: Check agent exists (this works per your debug)
|
| 1027 |
+
agent_url = f"https://api.elevenlabs.io/v1/convai/agents/{AGENT_ID}"
|
| 1028 |
agent_response = requests.get(agent_url, headers=headers, timeout=10)
|
| 1029 |
+
results['tests']['agent_check'] = {
|
| 1030 |
+
'status': agent_response.status_code,
|
| 1031 |
+
'exists': agent_response.status_code == 200
|
| 1032 |
+
}
|
| 1033 |
|
| 1034 |
+
# Test 2: Try conversation creation
|
| 1035 |
+
conv_url = "https://api.elevenlabs.io/v1/convai/conversation"
|
| 1036 |
+
conv_response = requests.post(conv_url, headers=headers, json={"agent_id": AGENT_ID}, timeout=10)
|
| 1037 |
+
results['tests']['conversation_create'] = {
|
| 1038 |
+
'status': conv_response.status_code,
|
| 1039 |
+
'response': conv_response.json() if conv_response.status_code == 200 else conv_response.text[:200]
|
| 1040 |
+
}
|
| 1041 |
|
| 1042 |
+
# Test 3: List available agents to confirm access
|
| 1043 |
+
list_url = "https://api.elevenlabs.io/v1/convai/agents"
|
| 1044 |
+
list_response = requests.get(list_url, headers=headers, timeout=10)
|
| 1045 |
+
if list_response.status_code == 200:
|
| 1046 |
+
agents = list_response.json().get('agents', [])
|
| 1047 |
+
agent_ids = [a.get('agent_id') for a in agents]
|
| 1048 |
+
results['tests']['agent_list'] = {
|
| 1049 |
+
'total_agents': len(agents),
|
| 1050 |
+
'your_agent_found': AGENT_ID in agent_ids,
|
| 1051 |
+
'first_few_agents': agent_ids[:3]
|
| 1052 |
}
|
| 1053 |
+
|
| 1054 |
+
return jsonify(results)
|
| 1055 |
+
|
| 1056 |
except Exception as e:
|
| 1057 |
return jsonify({'error': str(e), 'agent_id': AGENT_ID})
|
| 1058 |
|
| 1059 |
@app.route('/api/projects/<project_id>/log-call-usage', methods=['POST'])
|
| 1060 |
def log_call_usage(project_id):
|
| 1061 |
"""
|
| 1062 |
+
No changes needed here - your original was fine
|
|
|
|
| 1063 |
"""
|
| 1064 |
logger.info(f"[LOGGING] Received usage log for project: {project_id}")
|
| 1065 |
|
|
|
|
| 1066 |
uid = verify_token(request.headers.get('Authorization'))
|
| 1067 |
if not uid:
|
| 1068 |
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
| 1073 |
if duration_seconds is None or not isinstance(duration_seconds, (int, float)):
|
| 1074 |
return jsonify({'error': 'Invalid duration provided.'}), 400
|
| 1075 |
|
|
|
|
| 1076 |
minutes = math.ceil(duration_seconds / 60)
|
| 1077 |
cost = minutes * 3
|
| 1078 |
|
| 1079 |
logger.info(f"[LOGGING] User '{uid}' call duration: {duration_seconds:.2f}s, rounded to {minutes} minute(s). Cost: {cost} credits.")
|
| 1080 |
|
| 1081 |
try:
|
|
|
|
| 1082 |
user_ref = db_ref.child(f'users/{uid}')
|
| 1083 |
user_data = user_ref.get()
|
| 1084 |
|
|
|
|
| 1087 |
return jsonify({'error': 'User not found.'}), 404
|
| 1088 |
|
| 1089 |
current_credits = user_data.get('credits', 0)
|
|
|
|
|
|
|
| 1090 |
new_credits = max(0, current_credits - cost)
|
| 1091 |
|
|
|
|
| 1092 |
user_ref.update({'credits': new_credits})
|
| 1093 |
|
| 1094 |
logger.info(f"[LOGGING] Successfully updated credits for user '{uid}'. Old: {current_credits}, New: {new_credits}")
|
| 1095 |
|
|
|
|
| 1096 |
return jsonify({
|
| 1097 |
"status": "success",
|
| 1098 |
"creditsDeducted": cost,
|