Spaces:
Paused
Paused
feat: add automatic local/production backend URL routing and ignore zip files
Browse files- .gitignore +1 -0
- src/main.ts +17 -13
- static/app.js +17 -13
.gitignore
CHANGED
|
@@ -58,3 +58,4 @@ reference_voices/
|
|
| 58 |
!.env.example
|
| 59 |
*.pem
|
| 60 |
*.key
|
|
|
|
|
|
| 58 |
!.env.example
|
| 59 |
*.pem
|
| 60 |
*.key
|
| 61 |
+
*.zip
|
src/main.ts
CHANGED
|
@@ -77,6 +77,12 @@ const infoProduct = $<HTMLSpanElement>('info-product');
|
|
| 77 |
const infoDelivery = $<HTMLSpanElement>('info-delivery');
|
| 78 |
const btnStartCall = $<HTMLButtonElement>('btn-start-call');
|
| 79 |
const btnEndCall = $<HTMLButtonElement>('btn-end-call');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
const btnWhatsappFallback = $<HTMLButtonElement>('btn-whatsapp-fallback');
|
| 81 |
const callStatusBadge = $<HTMLDivElement>('call-status-badge');
|
| 82 |
const callStatusText = $<HTMLSpanElement>('call-status-text');
|
|
@@ -155,7 +161,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
| 155 |
|
| 156 |
async function checkServerStatus() {
|
| 157 |
try {
|
| 158 |
-
const res = await fetch(
|
| 159 |
const data = await res.json();
|
| 160 |
if (data.ready) {
|
| 161 |
serverStatus.className = 'status-dot online';
|
|
@@ -172,7 +178,7 @@ async function checkServerStatus() {
|
|
| 172 |
|
| 173 |
async function loadOrders() {
|
| 174 |
try {
|
| 175 |
-
const res = await fetch(
|
| 176 |
state.orders = await res.json();
|
| 177 |
renderOrders();
|
| 178 |
} catch (e) {
|
|
@@ -276,8 +282,7 @@ async function startCall() {
|
|
| 276 |
document.querySelectorAll<HTMLDivElement>('.order-card').forEach(c => c.style.pointerEvents = 'none');
|
| 277 |
document.querySelectorAll<HTMLButtonElement>('.agent-tab').forEach(t => t.style.pointerEvents = 'none');
|
| 278 |
|
| 279 |
-
|
| 280 |
-
state.ws = new WebSocket(`${protocol}//${location.host}/ws/call`);
|
| 281 |
|
| 282 |
state.ws.onopen = () => {
|
| 283 |
callStatusText.textContent = 'In Call';
|
|
@@ -506,8 +511,8 @@ function addSystemMessage(text: string) {
|
|
| 506 |
async function loadFeedback() {
|
| 507 |
try {
|
| 508 |
const [feedbackRes, callsRes] = await Promise.all([
|
| 509 |
-
fetch(
|
| 510 |
-
fetch(
|
| 511 |
]);
|
| 512 |
const feedback: Feedback[] = await feedbackRes.json();
|
| 513 |
const calls: CallRecord[] = await callsRes.json();
|
|
@@ -596,9 +601,9 @@ async function triggerWhatsappFallback() {
|
|
| 596 |
btnWhatsappFallback.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Sending...';
|
| 597 |
|
| 598 |
try {
|
| 599 |
-
let url = `/api/calls/whatsapp-fallback?order_id=${state.selectedOrderId}`;
|
| 600 |
if (state.sessionId) {
|
| 601 |
-
url = `/api/calls/whatsapp-fallback?call_id=${state.sessionId}`;
|
| 602 |
}
|
| 603 |
|
| 604 |
const res = await fetch(url, { method: 'POST' });
|
|
@@ -633,7 +638,7 @@ async function handleCheckoutSubmit(e: Event) {
|
|
| 633 |
btnSubmit.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Processing...';
|
| 634 |
|
| 635 |
try {
|
| 636 |
-
const res = await fetch(
|
| 637 |
method: 'POST',
|
| 638 |
headers: { 'Content-Type': 'application/json' },
|
| 639 |
body: JSON.stringify({
|
|
@@ -707,7 +712,7 @@ async function handleNoAnswerFallback() {
|
|
| 707 |
addSystemMessage(`⚠️ Call missed. Progressing sequence...`);
|
| 708 |
|
| 709 |
try {
|
| 710 |
-
await fetch(`/api/calls/whatsapp-fallback?order_id=${state.ringingOrderId}`, { method: 'POST' });
|
| 711 |
} catch (err) {
|
| 712 |
console.error(err);
|
| 713 |
}
|
|
@@ -715,7 +720,7 @@ async function handleNoAnswerFallback() {
|
|
| 715 |
|
| 716 |
async function loadAnalytics() {
|
| 717 |
try {
|
| 718 |
-
const res = await fetch(
|
| 719 |
const data = await res.json();
|
| 720 |
|
| 721 |
$('stat-total-calls-val').textContent = String(data.overview.total_calls);
|
|
@@ -875,8 +880,7 @@ function renderCharts(data: any) {
|
|
| 875 |
|
| 876 |
|
| 877 |
function connectDashboardWs() {
|
| 878 |
-
const
|
| 879 |
-
const wsUrl = `${protocol}//${location.host}/ws/dashboard`;
|
| 880 |
const ws = new WebSocket(wsUrl);
|
| 881 |
|
| 882 |
ws.onmessage = (event) => {
|
|
|
|
| 77 |
const infoDelivery = $<HTMLSpanElement>('info-delivery');
|
| 78 |
const btnStartCall = $<HTMLButtonElement>('btn-start-call');
|
| 79 |
const btnEndCall = $<HTMLButtonElement>('btn-end-call');
|
| 80 |
+
const BACKEND_URL = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
|
| 81 |
+
? window.location.origin
|
| 82 |
+
: 'https://jashp2323-call-voice-agent.hf.space';
|
| 83 |
+
const BACKEND_HOST = BACKEND_URL.replace(/^https?:\/\//, '');
|
| 84 |
+
const WS_PROTOCOL = BACKEND_URL.startsWith('https:') ? 'wss:' : 'ws:';
|
| 85 |
+
|
| 86 |
const btnWhatsappFallback = $<HTMLButtonElement>('btn-whatsapp-fallback');
|
| 87 |
const callStatusBadge = $<HTMLDivElement>('call-status-badge');
|
| 88 |
const callStatusText = $<HTMLSpanElement>('call-status-text');
|
|
|
|
| 161 |
|
| 162 |
async function checkServerStatus() {
|
| 163 |
try {
|
| 164 |
+
const res = await fetch(`${BACKEND_URL}/api/status`);
|
| 165 |
const data = await res.json();
|
| 166 |
if (data.ready) {
|
| 167 |
serverStatus.className = 'status-dot online';
|
|
|
|
| 178 |
|
| 179 |
async function loadOrders() {
|
| 180 |
try {
|
| 181 |
+
const res = await fetch(`${BACKEND_URL}/api/orders`);
|
| 182 |
state.orders = await res.json();
|
| 183 |
renderOrders();
|
| 184 |
} catch (e) {
|
|
|
|
| 282 |
document.querySelectorAll<HTMLDivElement>('.order-card').forEach(c => c.style.pointerEvents = 'none');
|
| 283 |
document.querySelectorAll<HTMLButtonElement>('.agent-tab').forEach(t => t.style.pointerEvents = 'none');
|
| 284 |
|
| 285 |
+
state.ws = new WebSocket(`${WS_PROTOCOL}//${BACKEND_HOST}/ws/call`);
|
|
|
|
| 286 |
|
| 287 |
state.ws.onopen = () => {
|
| 288 |
callStatusText.textContent = 'In Call';
|
|
|
|
| 511 |
async function loadFeedback() {
|
| 512 |
try {
|
| 513 |
const [feedbackRes, callsRes] = await Promise.all([
|
| 514 |
+
fetch(`${BACKEND_URL}/api/feedback`),
|
| 515 |
+
fetch(`${BACKEND_URL}/api/calls`),
|
| 516 |
]);
|
| 517 |
const feedback: Feedback[] = await feedbackRes.json();
|
| 518 |
const calls: CallRecord[] = await callsRes.json();
|
|
|
|
| 601 |
btnWhatsappFallback.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Sending...';
|
| 602 |
|
| 603 |
try {
|
| 604 |
+
let url = `${BACKEND_URL}/api/calls/whatsapp-fallback?order_id=${state.selectedOrderId}`;
|
| 605 |
if (state.sessionId) {
|
| 606 |
+
url = `${BACKEND_URL}/api/calls/whatsapp-fallback?call_id=${state.sessionId}`;
|
| 607 |
}
|
| 608 |
|
| 609 |
const res = await fetch(url, { method: 'POST' });
|
|
|
|
| 638 |
btnSubmit.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Processing...';
|
| 639 |
|
| 640 |
try {
|
| 641 |
+
const res = await fetch(`${BACKEND_URL}/api/orders`, {
|
| 642 |
method: 'POST',
|
| 643 |
headers: { 'Content-Type': 'application/json' },
|
| 644 |
body: JSON.stringify({
|
|
|
|
| 712 |
addSystemMessage(`⚠️ Call missed. Progressing sequence...`);
|
| 713 |
|
| 714 |
try {
|
| 715 |
+
await fetch(`${BACKEND_URL}/api/calls/whatsapp-fallback?order_id=${state.ringingOrderId}`, { method: 'POST' });
|
| 716 |
} catch (err) {
|
| 717 |
console.error(err);
|
| 718 |
}
|
|
|
|
| 720 |
|
| 721 |
async function loadAnalytics() {
|
| 722 |
try {
|
| 723 |
+
const res = await fetch(`${BACKEND_URL}/api/analytics`);
|
| 724 |
const data = await res.json();
|
| 725 |
|
| 726 |
$('stat-total-calls-val').textContent = String(data.overview.total_calls);
|
|
|
|
| 880 |
|
| 881 |
|
| 882 |
function connectDashboardWs() {
|
| 883 |
+
const wsUrl = `${WS_PROTOCOL}//${BACKEND_HOST}/ws/dashboard`;
|
|
|
|
| 884 |
const ws = new WebSocket(wsUrl);
|
| 885 |
|
| 886 |
ws.onmessage = (event) => {
|
static/app.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
const state = {
|
| 2 |
orders: [],
|
| 3 |
selectedOrderId: null,
|
|
@@ -102,7 +108,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
| 102 |
|
| 103 |
async function checkServerStatus() {
|
| 104 |
try {
|
| 105 |
-
const res = await fetch(
|
| 106 |
const data = await res.json();
|
| 107 |
if (data.ready) {
|
| 108 |
serverStatus.className = 'status-dot online';
|
|
@@ -119,7 +125,7 @@ async function checkServerStatus() {
|
|
| 119 |
|
| 120 |
async function loadOrders() {
|
| 121 |
try {
|
| 122 |
-
const res = await fetch(
|
| 123 |
state.orders = await res.json();
|
| 124 |
renderOrders();
|
| 125 |
} catch (e) {
|
|
@@ -220,8 +226,7 @@ async function startCall() {
|
|
| 220 |
document.querySelectorAll('.order-card').forEach(c => c.style.pointerEvents = 'none');
|
| 221 |
document.querySelectorAll('.agent-tab').forEach(t => t.style.pointerEvents = 'none');
|
| 222 |
|
| 223 |
-
|
| 224 |
-
state.ws = new WebSocket(`${protocol}//${location.host}/ws/call`);
|
| 225 |
|
| 226 |
state.ws.onopen = () => {
|
| 227 |
callStatusText.textContent = 'In Call';
|
|
@@ -450,8 +455,8 @@ function addSystemMessage(text) {
|
|
| 450 |
async function loadFeedback() {
|
| 451 |
try {
|
| 452 |
const [feedbackRes, callsRes] = await Promise.all([
|
| 453 |
-
fetch(
|
| 454 |
-
fetch(
|
| 455 |
]);
|
| 456 |
const feedback = await feedbackRes.json();
|
| 457 |
const calls = await callsRes.json();
|
|
@@ -540,9 +545,9 @@ async function triggerWhatsappFallback() {
|
|
| 540 |
btnWhatsappFallback.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Sending...';
|
| 541 |
|
| 542 |
try {
|
| 543 |
-
let url = `/api/calls/whatsapp-fallback?order_id=${state.selectedOrderId}`;
|
| 544 |
if (state.sessionId) {
|
| 545 |
-
url = `/api/calls/whatsapp-fallback?call_id=${state.sessionId}`;
|
| 546 |
}
|
| 547 |
|
| 548 |
const res = await fetch(url, { method: 'POST' });
|
|
@@ -577,7 +582,7 @@ async function handleCheckoutSubmit(e) {
|
|
| 577 |
btnSubmit.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Processing...';
|
| 578 |
|
| 579 |
try {
|
| 580 |
-
const res = await fetch(
|
| 581 |
method: 'POST',
|
| 582 |
headers: { 'Content-Type': 'application/json' },
|
| 583 |
body: JSON.stringify({
|
|
@@ -651,7 +656,7 @@ async function handleNoAnswerFallback() {
|
|
| 651 |
addSystemMessage(`⚠️ Call missed. Progressing sequence...`);
|
| 652 |
|
| 653 |
try {
|
| 654 |
-
await fetch(`/api/calls/whatsapp-fallback?order_id=${state.ringingOrderId}`, { method: 'POST' });
|
| 655 |
} catch (err) {
|
| 656 |
console.error(err);
|
| 657 |
}
|
|
@@ -659,7 +664,7 @@ async function handleNoAnswerFallback() {
|
|
| 659 |
|
| 660 |
async function loadAnalytics() {
|
| 661 |
try {
|
| 662 |
-
const res = await fetch(
|
| 663 |
const data = await res.json();
|
| 664 |
|
| 665 |
// Update raw overview values
|
|
@@ -809,8 +814,7 @@ function renderCharts(data) {
|
|
| 809 |
|
| 810 |
|
| 811 |
function connectDashboardWs() {
|
| 812 |
-
const
|
| 813 |
-
const wsUrl = `${protocol}//${location.host}/ws/dashboard`;
|
| 814 |
const ws = new WebSocket(wsUrl);
|
| 815 |
|
| 816 |
ws.onmessage = (event) => {
|
|
|
|
| 1 |
+
const BACKEND_URL = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
|
| 2 |
+
? window.location.origin
|
| 3 |
+
: 'https://jashp2323-call-voice-agent.hf.space';
|
| 4 |
+
const BACKEND_HOST = BACKEND_URL.replace(/^https?:\/\//, '');
|
| 5 |
+
const WS_PROTOCOL = BACKEND_URL.startsWith('https:') ? 'wss:' : 'ws:';
|
| 6 |
+
|
| 7 |
const state = {
|
| 8 |
orders: [],
|
| 9 |
selectedOrderId: null,
|
|
|
|
| 108 |
|
| 109 |
async function checkServerStatus() {
|
| 110 |
try {
|
| 111 |
+
const res = await fetch(`${BACKEND_URL}/api/status`);
|
| 112 |
const data = await res.json();
|
| 113 |
if (data.ready) {
|
| 114 |
serverStatus.className = 'status-dot online';
|
|
|
|
| 125 |
|
| 126 |
async function loadOrders() {
|
| 127 |
try {
|
| 128 |
+
const res = await fetch(`${BACKEND_URL}/api/orders`);
|
| 129 |
state.orders = await res.json();
|
| 130 |
renderOrders();
|
| 131 |
} catch (e) {
|
|
|
|
| 226 |
document.querySelectorAll('.order-card').forEach(c => c.style.pointerEvents = 'none');
|
| 227 |
document.querySelectorAll('.agent-tab').forEach(t => t.style.pointerEvents = 'none');
|
| 228 |
|
| 229 |
+
state.ws = new WebSocket(`${WS_PROTOCOL}//${BACKEND_HOST}/ws/call`);
|
|
|
|
| 230 |
|
| 231 |
state.ws.onopen = () => {
|
| 232 |
callStatusText.textContent = 'In Call';
|
|
|
|
| 455 |
async function loadFeedback() {
|
| 456 |
try {
|
| 457 |
const [feedbackRes, callsRes] = await Promise.all([
|
| 458 |
+
fetch(`${BACKEND_URL}/api/feedback`),
|
| 459 |
+
fetch(`${BACKEND_URL}/api/calls`),
|
| 460 |
]);
|
| 461 |
const feedback = await feedbackRes.json();
|
| 462 |
const calls = await callsRes.json();
|
|
|
|
| 545 |
btnWhatsappFallback.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Sending...';
|
| 546 |
|
| 547 |
try {
|
| 548 |
+
let url = `${BACKEND_URL}/api/calls/whatsapp-fallback?order_id=${state.selectedOrderId}`;
|
| 549 |
if (state.sessionId) {
|
| 550 |
+
url = `${BACKEND_URL}/api/calls/whatsapp-fallback?call_id=${state.sessionId}`;
|
| 551 |
}
|
| 552 |
|
| 553 |
const res = await fetch(url, { method: 'POST' });
|
|
|
|
| 582 |
btnSubmit.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Processing...';
|
| 583 |
|
| 584 |
try {
|
| 585 |
+
const res = await fetch(`${BACKEND_URL}/api/orders`, {
|
| 586 |
method: 'POST',
|
| 587 |
headers: { 'Content-Type': 'application/json' },
|
| 588 |
body: JSON.stringify({
|
|
|
|
| 656 |
addSystemMessage(`⚠️ Call missed. Progressing sequence...`);
|
| 657 |
|
| 658 |
try {
|
| 659 |
+
await fetch(`${BACKEND_URL}/api/calls/whatsapp-fallback?order_id=${state.ringingOrderId}`, { method: 'POST' });
|
| 660 |
} catch (err) {
|
| 661 |
console.error(err);
|
| 662 |
}
|
|
|
|
| 664 |
|
| 665 |
async function loadAnalytics() {
|
| 666 |
try {
|
| 667 |
+
const res = await fetch(`${BACKEND_URL}/api/analytics`);
|
| 668 |
const data = await res.json();
|
| 669 |
|
| 670 |
// Update raw overview values
|
|
|
|
| 814 |
|
| 815 |
|
| 816 |
function connectDashboardWs() {
|
| 817 |
+
const wsUrl = `${WS_PROTOCOL}//${BACKEND_HOST}/ws/dashboard`;
|
|
|
|
| 818 |
const ws = new WebSocket(wsUrl);
|
| 819 |
|
| 820 |
ws.onmessage = (event) => {
|