Spaces:
Sleeping
Sleeping
File size: 5,396 Bytes
5621acf af51678 5621acf b39b3a3 af51678 b39b3a3 5621acf b39b3a3 70c561e 5621acf b39b3a3 af51678 5621acf af51678 b39b3a3 624426e cc1e332 4b20561 cc1e332 624426e 01a0663 624426e b39b3a3 624426e cc1e332 9111a92 624426e b39b3a3 624426e b39b3a3 624426e 9111a92 df37c18 af51678 df37c18 af51678 b39b3a3 af51678 df37c18 af51678 b39b3a3 af51678 b39b3a3 af51678 e310b5f af51678 df37c18 af51678 e310b5f df37c18 b39b3a3 e310b5f af51678 e310b5f df37c18 e310b5f af51678 e310b5f df37c18 305af1d 05ceeaa af51678 05ceeaa af51678 05ceeaa 305af1d 05ceeaa 305af1d 05ceeaa | 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 | import os
import requests
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
app = FastAPI()
# ---- Allow frontend access ----
app.add_middleware(
CORSMiddleware,
allow_origins=["https://voice-call-agent.vercel.app/"], # β
Restrict in production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ---- Environment variables ----
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
AIRTABLE_API_KEY = os.getenv("AIRTABLE_API_KEY")
AIRTABLE_BASE_ID = os.getenv("AIRTABLE_BASE_ID")
AIRTABLE_TABLE = "Appointments"
# ---- Ephemeral Key Endpoint ----
@app.get("/get-ephemeral-key")
def get_ephemeral_key():
"""Generate an ephemeral client secret for OpenAI Realtime API"""
url = "https://api.openai.com/v1/realtime/client_secrets"
headers = {
"Authorization": f"Bearer {OPENAI_API_KEY}",
"Content-Type": "application/json",
}
body = {
"session": {
"type": "realtime",
"model": "gpt-4o-mini-realtime-preview",
"audio": {
"output": {"voice": "verse"}
},
}
}
res = requests.post(url, headers=headers, json=body)
print("π Ephemeral key request status:", res.status_code)
data = res.json()
print("π Ephemeral key response:", data)
return data
# ---- Add Appointment ----
class Appointment(BaseModel):
name: str
phone: str
date: str
time: str
service: str
@app.post("/add")
def add_appointment(appo: Appointment):
"""Add a new appointment to Airtable (auto-increment ID handled by Airtable)"""
url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE}"
headers = {
"Authorization": f"Bearer {AIRTABLE_API_KEY}",
"Content-Type": "application/json",
}
data = {
"fields": {
"Name": appo.name,
"Phone": appo.phone,
"Date": appo.date,
"Time": appo.time,
"Service": appo.service,
}
}
r = requests.post(url, headers=headers, json=data)
print("πΉ Airtable Add Response:", r.status_code, r.text)
return r.json()
# ---- Update Appointment ----
class UpdateAppointment(BaseModel):
appointment_id: str
name: str | None = None
phone: str | None = None
date: str | None = None
time: str | None = None
service: str | None = None
@app.post("/update")
def update_appointment(update: UpdateAppointment):
"""Update an existing appointment in Airtable using custom Appointment ID"""
headers = {
"Authorization": f"Bearer {AIRTABLE_API_KEY}",
"Content-Type": "application/json",
}
# Step 1: Find record by Appointment ID field
filter_formula = f"{{Appointment ID}} = '{update.appointment_id}'"
search_url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE}?filterByFormula={filter_formula}"
search_res = requests.get(search_url, headers=headers).json()
if not search_res.get("records"):
print("β No record found for Appointment ID:", update.appointment_id)
return {"status": "error", "message": "Appointment not found"}
record_id = search_res["records"][0]["id"]
# Step 2: Prepare updated fields
fields = {}
if update.name:
fields["Name"] = update.name
if update.phone:
fields["Phone"] = update.phone
if update.date:
fields["Date"] = update.date
if update.time:
fields["Time"] = update.time
if update.service:
fields["Service"] = update.service
# Step 3: Patch record by record ID
update_url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE}/{record_id}"
patch_res = requests.patch(update_url, headers=headers, json={"fields": fields})
print("πΈ Airtable Update Response:", patch_res.status_code, patch_res.text)
if patch_res.status_code == 200:
return {"status": "updated"}
else:
return {"status": "error", "message": "Update failed"}
class CancelAppointment(BaseModel):
appointment_id: str
@app.post("/cancel")
def cancel_appointment(cancel: CancelAppointment):
"""Cancel appointment by custom Appointment ID field"""
# Step 1: Search record by Appointment ID field
filter_formula = f"{{Appointment ID}} = '{cancel.appointment_id}'"
search_url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE}?filterByFormula={filter_formula}"
headers = {"Authorization": f"Bearer {AIRTABLE_API_KEY}"}
search_res = requests.get(search_url, headers=headers).json()
if not search_res.get("records"):
print("β No record found for Appointment ID:", cancel.appointment_id)
return {"status": "error", "message": "Appointment not found"}
record_id = search_res["records"][0]["id"]
print(f"β
Found Record ID: {record_id} for Appointment ID: {cancel.appointment_id}")
# Step 2: Delete record by Record ID
delete_url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE}/{record_id}"
delete_res = requests.delete(delete_url, headers=headers)
print("ποΈ Airtable Delete Response:", delete_res.status_code, delete_res.text)
if delete_res.status_code == 200:
return {"status": "deleted"}
else:
return {"status": "error", "message": "Delete failed"} |