@javierfrancoleal/dsh-supervisor 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -2
- package/bin/jfranco-supervisor.js +11 -0
- package/dashboard.html +460 -0
- package/icons/icons/apple-icon-180.png +0 -0
- package/icons/icons/icon-192.png +0 -0
- package/icons/icons/icon-512.png +0 -0
- package/manifest.webmanifest +17 -0
- package/package.json +41 -4
- package/panel.html +383 -0
- package/sector-packs/sector-packs/clinic.json +83 -0
- package/sector-packs/sector-packs/hotel.json +83 -0
- package/sector-packs/sector-packs/pharmacy.json +99 -0
- package/sector-packs/sector-packs/realestate.json +99 -0
- package/sector-packs/sector-packs/restaurant.json +83 -0
- package/sector-packs/sector-packs/school.json +99 -0
- package/sector-packs/sector-packs/workshop.json +99 -0
- package/server.js +429 -0
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@javierfrancoleal/dsh-supervisor",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "The central control plane of the J.Franco agentic workflow suite: user accounts, the live conversation flow (listen → per-person summary → confirm → orders), telemetry, and the universal sector dashboard with 10 languages. Created by J.Franco.",
|
|
5
|
+
"author": "J.Franco",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"main": "server.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"jfranco-supervisor": "bin/jfranco-supervisor.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"server.js",
|
|
14
|
+
"dashboard.html",
|
|
15
|
+
"panel.html",
|
|
16
|
+
"manifest.webmanifest",
|
|
17
|
+
"icons",
|
|
18
|
+
"sector-packs",
|
|
19
|
+
"bin",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=24"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/JavierFrancoLeal/jfranco-agentic-suite.git",
|
|
28
|
+
"directory": "supervisor-pkg"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/JavierFrancoLeal/jfranco-agentic-suite",
|
|
31
|
+
"keywords": [
|
|
32
|
+
"deepseek-harness",
|
|
33
|
+
"agentic-workflow",
|
|
34
|
+
"super-agent",
|
|
35
|
+
"dashboard",
|
|
36
|
+
"sectors",
|
|
37
|
+
"multi-language",
|
|
38
|
+
"rbac"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/panel.html
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="theme-color" content="#4D6BFE">
|
|
7
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
8
|
+
<meta name="apple-mobile-web-app-title" content="DSH Assistant">
|
|
9
|
+
<link rel="manifest" href="manifest.webmanifest">
|
|
10
|
+
<link rel="apple-touch-icon" href="icons/apple-icon-180.png">
|
|
11
|
+
<title>DSH Assistant — Action Panel</title>
|
|
12
|
+
<style>
|
|
13
|
+
:root{--blue:#4D6BFE;--ink:#101828;--muted:#667085;--bg:#f6f7fb;--card:#fff;--line:#e3e6ee;--line2:#eef0f7;--ok:#22c55e;--bad:#ef4444}
|
|
14
|
+
body.dark{--ink:#e6ecf7;--muted:#94a3b8;--bg:#0b1220;--card:#141f31;--line:#26334d;--line2:#26334d}
|
|
15
|
+
*{box-sizing:border-box}
|
|
16
|
+
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:var(--bg);color:var(--ink)}
|
|
17
|
+
header{background:linear-gradient(135deg,#4D6BFE,#7c5cff);color:#fff;padding:18px 20px;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
|
|
18
|
+
header .logo{font-size:30px}
|
|
19
|
+
header .ht{flex:1;min-width:180px}
|
|
20
|
+
header h1{margin:0;font-size:20px}
|
|
21
|
+
header p{margin:3px 0 0;opacity:.85;font-size:12.5px}
|
|
22
|
+
.chip{background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.35);border-radius:999px;padding:7px 14px;font-size:13.5px;font-weight:600}
|
|
23
|
+
main{max-width:580px;margin:0 auto;padding:16px}
|
|
24
|
+
.idcard{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:12px 14px;margin-bottom:12px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
|
|
25
|
+
.idcard .avatar{width:38px;height:38px;border-radius:50%;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:16px}
|
|
26
|
+
.idcard .who{flex:1;min-width:130px}
|
|
27
|
+
.idcard .who b{display:block;font-size:15px}
|
|
28
|
+
.idcard .who span{font-size:12.5px;color:var(--muted)}
|
|
29
|
+
.idcard input{width:110px;border:1px solid var(--line);border-radius:10px;padding:8px 10px;font-size:13px;background:var(--card);color:var(--ink)}
|
|
30
|
+
.idcard.warn{border-color:var(--bad);background:#fff5f5}
|
|
31
|
+
.idcard a{color:var(--blue);font-weight:700;font-size:13.5px}
|
|
32
|
+
.primary{display:block;width:100%;margin:14px 0;background:var(--ok);border:none;border-radius:22px;padding:28px 16px;font-size:26px;font-weight:800;color:#fff;cursor:pointer;box-shadow:0 4px 14px rgba(34,197,94,.35)}
|
|
33
|
+
.primary:active{transform:scale(.98)}
|
|
34
|
+
.primary.live{background:var(--bad);box-shadow:0 4px 14px rgba(239,68,68,.35);animation:pulse 1.6s infinite}
|
|
35
|
+
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(239,68,68,.5)}70%{box-shadow:0 0 0 24px rgba(239,68,68,0)}100%{box-shadow:0 0 0 0 rgba(239,68,68,0)}}
|
|
36
|
+
.status{text-align:center;font-size:13.5px;color:var(--muted);margin:4px 0}
|
|
37
|
+
.prompt{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px;min-height:90px;white-space:pre-wrap;font-size:15px;line-height:1.55}
|
|
38
|
+
.row{display:flex;gap:10px;margin:12px 0;flex-wrap:wrap}
|
|
39
|
+
.row button{flex:1;min-width:130px;border:none;border-radius:12px;padding:12px;font-size:15px;font-weight:600;color:#fff;cursor:pointer}
|
|
40
|
+
.copy{background:var(--blue)}
|
|
41
|
+
.speak{background:#7c5cff}
|
|
42
|
+
.fbcard{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px;margin:16px 0}
|
|
43
|
+
.fbcard h3{margin:0 0 10px;font-size:16px}
|
|
44
|
+
.fbcard select,.fbcard textarea,.fbcard button{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:10px;padding:10px;font-size:14px;margin-bottom:8px;font-family:inherit;background:var(--card);color:var(--ink)}
|
|
45
|
+
.fbcard textarea{resize:vertical}
|
|
46
|
+
.fbcard button{background:var(--blue);color:#fff;font-weight:600;border:none;cursor:pointer}
|
|
47
|
+
.note{font-size:13px;color:var(--muted);line-height:1.65}
|
|
48
|
+
code{background:var(--line2);border-radius:6px;padding:2px 6px;font-size:13px}
|
|
49
|
+
.foot{text-align:center;padding:6px 16px 16px}
|
|
50
|
+
.foot .langs{margin:8px 0}
|
|
51
|
+
.foot .copyr{font-size:12px;color:var(--muted)}
|
|
52
|
+
.langs{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:10px 0}
|
|
53
|
+
.pill{background:var(--card);border:1px solid var(--line);border-radius:999px;padding:8px 13px;font-size:13px;cursor:pointer;color:var(--ink)}
|
|
54
|
+
.pill.active{background:var(--blue);color:#fff;border-color:var(--blue)}
|
|
55
|
+
</style>
|
|
56
|
+
</head>
|
|
57
|
+
<body>
|
|
58
|
+
<header>
|
|
59
|
+
<div class="logo">🎙️</div>
|
|
60
|
+
<div class="ht">
|
|
61
|
+
<h1 id="title">DSH Assistant — Action Panel</h1>
|
|
62
|
+
<p id="subtitle">J.Franco Suite · DeepSeek Harness</p>
|
|
63
|
+
</div>
|
|
64
|
+
<button class="chip" id="darkBtn" style="cursor:pointer">🌙</button>
|
|
65
|
+
</header>
|
|
66
|
+
<main>
|
|
67
|
+
<div class="idcard" id="idCard">
|
|
68
|
+
<div class="avatar" id="avatar">?</div>
|
|
69
|
+
<div class="who">
|
|
70
|
+
<b id="whoName">—</b>
|
|
71
|
+
<span id="whoRole"></span>
|
|
72
|
+
</div>
|
|
73
|
+
<input id="workerInput" placeholder="User">
|
|
74
|
+
<input id="roleInput" placeholder="Role">
|
|
75
|
+
</div>
|
|
76
|
+
<div id="gateCard" class="idcard warn hidden" style="display:none">
|
|
77
|
+
<div class="avatar">🔒</div>
|
|
78
|
+
<div class="who"><b id="gateTitle">Not identified</b><span id="gateHint"></span></div>
|
|
79
|
+
<a href="/dashboard" id="gateLink">Log in on the Dashboard</a>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<button class="primary" id="listenBtn">🎙️ LISTEN / DICTATE</button>
|
|
83
|
+
<div class="status" id="status"></div>
|
|
84
|
+
|
|
85
|
+
<div class="prompt" id="prompt"></div>
|
|
86
|
+
|
|
87
|
+
<div class="row">
|
|
88
|
+
<button class="copy" id="copyBtn">📋 Copy for DSH</button>
|
|
89
|
+
<button class="speak" id="speakBtn">🔊 Read aloud</button>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<p class="note" id="note"></p>
|
|
93
|
+
<p class="note" id="legend"></p>
|
|
94
|
+
|
|
95
|
+
<div class="fbcard">
|
|
96
|
+
<h3 id="fbTitle">Field Feedback</h3>
|
|
97
|
+
<select id="fbCat">
|
|
98
|
+
<option id="catError" value="error">Error</option>
|
|
99
|
+
<option id="catImprovement" value="improvement">Improvement</option>
|
|
100
|
+
<option id="catIdea" value="idea">Idea</option>
|
|
101
|
+
</select>
|
|
102
|
+
<textarea id="fbText" rows="3" placeholder="What happened? What should improve?"></textarea>
|
|
103
|
+
<button id="fbSend">Send feedback</button>
|
|
104
|
+
</div>
|
|
105
|
+
</main>
|
|
106
|
+
|
|
107
|
+
<footer class="foot">
|
|
108
|
+
<div class="langs" id="langs"></div>
|
|
109
|
+
<div class="copyr">Suite J.Franco · open source (MIT) · autor J.Franco</div>
|
|
110
|
+
</footer>
|
|
111
|
+
<script>
|
|
112
|
+
"use strict";
|
|
113
|
+
const LANG={es:"escucha",en:"listen",fr:"écoute",de:"hör zu",it:"ascolta",pt:"escuta",zh:"听",ja:"聞いて",ko:"들어봐",ar:"استمع"};
|
|
114
|
+
const VOICE={es:"es-ES",en:"en-US",fr:"fr-FR",de:"de-DE",it:"it-IT",pt:"pt-PT",zh:"zh-CN",ja:"ja-JP",ko:"ko-KR",ar:"ar-SA"};
|
|
115
|
+
const END={es:"eso es todo",en:"that's all",fr:"c'est tout",de:"das ist alles",it:"è tutto",pt:"é tudo",zh:"说完了",ja:"以上です",ko:"이상입니다",ar:"هذا كل شيء"};
|
|
116
|
+
const S={
|
|
117
|
+
es:{worker:"Usuario",role:"Puesto",title:"🎙️ DSH Asistente — Panel de Acción",subtitle:"Suite J.Franco · DeepSeek Harness",
|
|
118
|
+
listen:"🎙️ ESCUCHAR / DICTAR",stop:"⏹️ DETENER",copy:"📋 Copiar para DSH",copied:"✅ ¡Copiado!",
|
|
119
|
+
speak:"🔊 Leer en voz alta",nospeech:"🎙️ Dictado no soportado",
|
|
120
|
+
recording:"🔴 Grabando — toca DETENER al terminar",micError:"Micrófono no disponible — revisa los permisos del navegador.",
|
|
121
|
+
signedIn:"Sesión de",notIdentified:"Sin identificar",loginLink:"Inicia sesión en el Dashboard",
|
|
122
|
+
gateHint:"Para usar este panel, identifícate primero.",
|
|
123
|
+
placeholder:"Pulsa ESCUCHAR y habla tu conversación…",
|
|
124
|
+
clue:(w)=>`DSH, ${w} — comienzo a escuchar. Dime la conversación o las peticiones. Si aparecen varios idiomas, activa la interpretación cuando lo pida; el flujo principal (anotar, escribir, abrir aplicaciones…) sigue el análisis del input.`,
|
|
125
|
+
note:(end)=>`Pulsa ESCUCHAR, habla la conversación y di «${end}». Luego copia y pega la instrucción en una nueva sesión de DeepSeek Harness — o usa la app «DSH Asistente» para ejecución autónoma.`,
|
|
126
|
+
legend:"Semáforo: 🟢 automático · ⚑ semi-automático (verifícalo) · 🟡 propuesta (tú decides) · 🔴 pregunta.",fbTitle:"Feedback de campo",fbPh:"¿Qué pasó? ¿Qué debe mejorar?",fbSent:"Enviado — el agente lo leerá",fbOffline:"Supervisor sin conexión — prompt copiado para DSH",catError:"Error",catImprovement:"Mejora",catIdea:"Idea"},
|
|
127
|
+
en:{worker:"User",role:"Role",title:"🎙️ DSH Assistant — Action Panel",subtitle:"J.Franco Suite · DeepSeek Harness",
|
|
128
|
+
listen:"🎙️ LISTEN / DICTATE",stop:"⏹️ STOP",copy:"📋 Copy for DSH",copied:"✅ Copied!",
|
|
129
|
+
speak:"🔊 Read aloud",nospeech:"🎙️ Dictation not supported",
|
|
130
|
+
recording:"🔴 Recording — tap STOP when done",micError:"Microphone unavailable — check browser permissions.",
|
|
131
|
+
signedIn:"Signed in as",notIdentified:"Not identified",loginLink:"Log in on the Dashboard",
|
|
132
|
+
gateHint:"To use this panel, identify yourself first.",
|
|
133
|
+
placeholder:"Tap LISTEN and speak your conversation…",
|
|
134
|
+
clue:(w)=>`DSH, ${w} — I'm starting to listen. Tell me the conversation or the requests. If several languages appear, activate interpretation when asked; the main flow (noting, writing, opening apps…) follows the input analysis.`,
|
|
135
|
+
note:(end)=>`Tap LISTEN, speak the conversation and say "${end}". Then copy and paste the instruction into a new DeepSeek Harness session — or use the "DSH Assistant" app for autonomous runs.`,
|
|
136
|
+
legend:"Traffic light: 🟢 automatic · ⚑ semi-automatic (verify it) · 🟡 proposal (you decide) · 🔴 ask.",fbTitle:"Field Feedback",fbPh:"What happened? What should improve?",fbSent:"Sent — the agent will read it",fbOffline:"Supervisor offline — prompt copied for DSH",catError:"Error",catImprovement:"Improvement",catIdea:"Idea"},
|
|
137
|
+
fr:{worker:"Utilisateur",role:"Fonction",title:"🎙️ DSH Assistant — Panneau d'Action",subtitle:"Suite J.Franco · DeepSeek Harness",
|
|
138
|
+
listen:"🎙️ ÉCOUTER / DICTER",stop:"⏹️ ARRÊTER",copy:"📋 Copier pour DSH",copied:"✅ Copié !",
|
|
139
|
+
speak:"🔊 Lire à voix haute",nospeech:"🎙️ Dictée non prise en charge",
|
|
140
|
+
recording:"🔴 Enregistrement — touchez ARRÊTER à la fin",micError:"Micro indisponible — vérifiez les autorisations du navigateur.",
|
|
141
|
+
signedIn:"Connecté en tant que",notIdentified:"Non identifié",loginLink:"Connectez-vous sur le Dashboard",
|
|
142
|
+
gateHint:"Pour utiliser ce panneau, identifiez-vous d'abord.",
|
|
143
|
+
placeholder:"Touchez ÉCOUTER et parlez…",
|
|
144
|
+
clue:(w)=>`DSH, ${w} — je commence à écouter. Racontez-moi la conversation ou les demandes. Si plusieurs langues apparaissent, activez l'interprétation à la demande ; le flux principal (noter, écrire, ouvrir des applications…) suit l'analyse.`,
|
|
145
|
+
note:(end)=>`Touchez ÉCOUTER, parlez et dites « ${end} ». Copiez ensuite l'instruction dans une nouvelle session DeepSeek Harness — ou utilisez l'app « DSH Assistant » pour l'exécution autonome.`,
|
|
146
|
+
legend:"Feux : 🟢 automatique · ⚑ semi-automatique (vérifiez) · 🟡 proposition (vous décidez) · 🔴 demandez.",fbTitle:"Feedback terrain",fbPh:"Que s'est-il passé ? Que faut-il améliorer ?",fbSent:"Envoyé — l'agent le lira",fbOffline:"Superviseur hors ligne — invite copiée pour DSH",catError:"Erreur",catImprovement:"Amélioration",catIdea:"Idée"},
|
|
147
|
+
de:{worker:"Benutzer",role:"Rolle",title:"🎙️ DSH Assistent — Aktionspanel",subtitle:"J.Franco-Suite · DeepSeek Harness",
|
|
148
|
+
listen:"🎙️ ZUHÖREN / DIKTIEREN",stop:"⏹️ STOPP",copy:"📋 Für DSH kopieren",copied:"✅ Kopiert!",
|
|
149
|
+
speak:"🔊 Vorlesen",nospeech:"🎙️ Diktat nicht unterstützt",
|
|
150
|
+
recording:"🔴 Aufnahme — tippen Sie STOPP am Ende",micError:"Mikrofon nicht verfügbar — Browser-Berechtigungen prüfen.",
|
|
151
|
+
signedIn:"Angemeldet als",notIdentified:"Nicht angemeldet",loginLink:"Im Dashboard anmelden",
|
|
152
|
+
gateHint:"Bitte zuerst anmelden, um dieses Panel zu nutzen.",
|
|
153
|
+
placeholder:"Tippen Sie auf ZUHÖREN und sprechen Sie…",
|
|
154
|
+
clue:(w)=>`DSH, ${w} — ich beginne zuzuhören. Erzählen Sie mir das Gespräch oder die Anfragen. Bei mehreren Sprachen aktivieren Sie das Dolmetschen auf Zuruf; der Hauptablauf folgt der Analyse.`,
|
|
155
|
+
note:(end)=>`Tippen Sie auf ZUHÖREN, sprechen Sie und sagen Sie «${end}». Kopieren Sie die Anweisung in eine neue Sitzung — oder nutzen Sie die App „DSH Assistent“.`,
|
|
156
|
+
legend:"Ampel: 🟢 automatisch · ⚑ halbautomatisch (prüfen) · 🟡 Vorschlag (Sie entscheiden) · 🔴 fragen.",fbTitle:"Feld-Feedback",fbPh:"Was ist passiert? Was soll besser werden?",fbSent:"Gesendet — der Agent liest es",fbOffline:"Supervisor offline — Prompt für DSH kopiert",catError:"Fehler",catImprovement:"Verbesserung",catIdea:"Idee"},
|
|
157
|
+
it:{worker:"Utente",role:"Ruolo",title:"🎙️ DSH Assistente — Pannello Azioni",subtitle:"Suite J.Franco · DeepSeek Harness",
|
|
158
|
+
listen:"🎙️ ASCOLTA / DETTA",stop:"⏹️ FERMA",copy:"📋 Copia per DSH",copied:"✅ Copiato!",
|
|
159
|
+
speak:"🔊 Leggi ad alta voce",nospeech:"🎙️ Dettatura non supportata",
|
|
160
|
+
recording:"🔴 Registrazione — tocca FERMA alla fine",micError:"Microfono non disponibile — controlla i permessi.",
|
|
161
|
+
signedIn:"Accesso come",notIdentified:"Non identificato",loginLink:"Accedi dal Dashboard",
|
|
162
|
+
gateHint:"Per usare questo pannello, identificati prima.",
|
|
163
|
+
placeholder:"Tocca ASCOLTA e parla…",
|
|
164
|
+
clue:(w)=>`DSH, ${w} — comincio ad ascoltare. Raccontami la conversazione o le richieste. Se compaiono più lingue, attiva l'interpretazione quando richiesto; il flusso principale segue l'analisi.`,
|
|
165
|
+
note:(end)=>`Tocca ASCOLTA, parla e di' «${end}». Poi copia e incolla l'istruzione in una nuova sessione — oppure usa l'app «DSH Assistente».`,
|
|
166
|
+
legend:"Semaforo: 🟢 automatico · ⚑ semi-automatico (verificalo) · 🟡 proposta (decidi tu) · 🔴 chiedi.",fbTitle:"Feedback di campo",fbPh:"Cosa è successo? Cosa va migliorato?",fbSent:"Inviato — l'agente lo leggerà",fbOffline:"Supervisore offline — prompt copiato per DSH",catError:"Errore",catImprovement:"Miglioria",catIdea:"Idea"},
|
|
167
|
+
pt:{worker:"Usuário",role:"Função",title:"🎙️ DSH Assistente — Painel de Ação",subtitle:"Suite J.Franco · DeepSeek Harness",
|
|
168
|
+
listen:"🎙️ OUVIR / DITAR",stop:"⏹️ PARAR",copy:"📋 Copiar para o DSH",copied:"✅ Copiado!",
|
|
169
|
+
speak:"🔊 Ler em voz alta",nospeech:"🎙️ Ditado não suportado",
|
|
170
|
+
recording:"🔴 A gravar — toque PARAR no fim",micError:"Microfone indisponível — verifique as permissões.",
|
|
171
|
+
signedIn:"Sessão de",notIdentified:"Não identificado",loginLink:"Inicie sessão no Dashboard",
|
|
172
|
+
gateHint:"Para usar este painel, identifique-se primeiro.",
|
|
173
|
+
placeholder:"Toque em OUVIR e fale…",
|
|
174
|
+
clue:(w)=>`DSH, ${w} — começo a ouvir. Conte-me a conversa ou os pedidos. Se aparecerem várias línguas, ative a interpretação quando pedido; o fluxo principal segue a análise.`,
|
|
175
|
+
note:(end)=>`Toque em OUVIR, fale e diga «${end}». Depois copie e cole a instrução numa nova sessão — ou use a app «DSH Assistente».`,
|
|
176
|
+
legend:"Semáforo: 🟢 automático · ⚑ semi-automático (verifique) · 🟡 proposta (você decide) · 🔴 pergunte.",fbTitle:"Feedback de campo",fbPh:"O que aconteceu? O que deve melhorar?",fbSent:"Enviado — o agente vai ler",fbOffline:"Supervisor offline — prompt copiado para o DSH",catError:"Erro",catImprovement:"Melhoria",catIdea:"Ideia"},
|
|
177
|
+
zh:{worker:"用户",role:"职位",title:"🎙️ DSH 助手 — 操作面板",subtitle:"J.Franco 套件 · DeepSeek Harness",
|
|
178
|
+
listen:"🎙️ 聆听 / 听写",stop:"⏹️ 停止",copy:"📋 复制到 DSH",copied:"✅ 已复制!",
|
|
179
|
+
speak:"🔊 朗读",nospeech:"🎙️ 不支持听写",
|
|
180
|
+
recording:"🔴 录音中 — 完成后点击停止",micError:"麦克风不可用 — 请检查浏览器权限。",
|
|
181
|
+
signedIn:"已登录:",notIdentified:"未识别",loginLink:"请在 Dashboard 登录",
|
|
182
|
+
gateHint:"请先登录后再使用此面板。",
|
|
183
|
+
placeholder:"点击「聆听」并说出对话…",
|
|
184
|
+
clue:(w)=>`DSH,${w} — 我开始聆听。请告诉我对话或请求。若出现多种语言,按需启用口译;主流程跟随输入分析。`,
|
|
185
|
+
note:(end)=>`点击「聆听」,说出对话并说「${end}」。然后将指令复制粘贴到新的会话 — 或使用「DSH 助手」应用。`,
|
|
186
|
+
legend:"红绿灯:🟢 自动 · ⚑ 半自动(请核实)· 🟡 提议(你决定)· 🔴 询问。",fbTitle:"现场反馈",fbPh:"发生了什么?什么需要改进?",fbSent:"已发送 — 智能体会读取",fbOffline:"主管离线 — 提示已复制到 DSH",catError:"错误",catImprovement:"改进",catIdea:"想法"},
|
|
187
|
+
ja:{worker:"ユーザー",role:"役割",title:"🎙️ DSH アシスタント — アクションパネル",subtitle:"J.Franco スイート · DeepSeek Harness",
|
|
188
|
+
listen:"🎙️ 聞く / 音声入力",stop:"⏹️ 停止",copy:"📋 DSHへコピー",copied:"✅ コピー済み!",
|
|
189
|
+
speak:"🔊 読み上げ",nospeech:"🎙️ 音声入力非対応",
|
|
190
|
+
recording:"🔴 録音中 — 終わったら停止をタップ",micError:"マイクが使えません — ブラウザの権限を確認してください。",
|
|
191
|
+
signedIn:"ログイン中:",notIdentified:"未確認",loginLink:"Dashboardでログイン",
|
|
192
|
+
gateHint:"このパネルを使うには、まずログインしてください。",
|
|
193
|
+
placeholder:"「聞く」をタップして会話を話してください…",
|
|
194
|
+
clue:(w)=>`DSH、${w} — 聞き始めます。会話や依頼を教えてください。複数の言語が出たら、求めに応じて通訳を有効化;主フローは入力分析に従います。`,
|
|
195
|
+
note:(end)=>`「聞く」をタップし、会話を話して「${end}」と言います。その後、指示を新しいセッションに貼り付け — または「DSH アシスタント」アプリで自律実行。`,
|
|
196
|
+
legend:"信号:🟢 自動 · ⚑ 半自動(確認)· 🟡 提案(あなたが決定)· 🔴 質問。",fbTitle:"現場フィードバック",fbPh:"何が起きましたか?何を改善すべき?",fbSent:"送信済み — エージェントが読みます",fbOffline:"スーパーバイザーオフライン — プロンプトをDSH用にコピー",catError:"エラー",catImprovement:"改善",catIdea:"アイデア"},
|
|
197
|
+
ko:{worker:"사용자",role:"역할",title:"🎙️ DSH 어시스턴트 — 액션 패널",subtitle:"J.Franco 스위트 · DeepSeek Harness",
|
|
198
|
+
listen:"🎙️ 듣기 / 받아쓰기",stop:"⏹️ 중지",copy:"📋 DSH로 복사",copied:"✅ 복사됨!",
|
|
199
|
+
speak:"🔊 소리내어 읽기",nospeech:"🎙️ 받아쓰기 미지원",
|
|
200
|
+
recording:"🔴 녹음 중 — 끝나면 중지를 누르세요",micError:"마이크를 사용할 수 없습니다 — 브라우저 권한을 확인하세요.",
|
|
201
|
+
signedIn:"로그인:",notIdentified:"미확인",loginLink:"Dashboard에서 로그인",
|
|
202
|
+
gateHint:"이 패널을 사용하려면 먼저 로그인하세요.",
|
|
203
|
+
placeholder:"「듣기」를 누르고 대화를 말하세요…",
|
|
204
|
+
clue:(w)=>`DSH, ${w} — 듣기 시작합니다. 대화나 요청을 말씀해 주세요. 여러 언어가 나오면 요청 시 통역을 활성화합니다. 주 흐름은 입력 분석을 따릅니다.`,
|
|
205
|
+
note:(end)=>`「듣기」를 누르고 대화를 말한 뒤 「${end}」라고 하세요. 그런 다음 지시를 새 세션에 붙여넣기 — 또는 「DSH 어시스턴트」 앱으로 자율 실행.`,
|
|
206
|
+
legend:"신호등: 🟢 자동 · ⚑ 반자동(확인) · 🟡 제안(당신이 결정) · 🔴 질문.",fbTitle:"현장 피드백",fbPh:"무슨 일이 있었나요? 무엇을 개선할까요?",fbSent:"전송됨 — 에이전트가 읽습니다",fbOffline:"감독자 오프라인 — DSH용 프롬프트 복사됨",catError:"오류",catImprovement:"개선",catIdea:"아이디어"},
|
|
207
|
+
ar:{worker:"المستخدم",role:"الدور",title:"🎙️ مساعد DSH — لوحة الإجراءات",subtitle:"مجموعة J.Franco · DeepSeek Harness",
|
|
208
|
+
listen:"🎙️ استمع / أملي",stop:"⏹️ إيقاف",copy:"📋 نسخ إلى DSH",copied:"✅ تم النسخ!",
|
|
209
|
+
speak:"🔊 قراءة بصوت عالٍ",nospeech:"🎙️ الإملاء غير مدعوم",
|
|
210
|
+
recording:"🔴 جارٍ التسجيل — اضغط إيقاف عند الانتهاء",micError:"الميكروفون غير متاح — تحقق من أذونات المتصفح.",
|
|
211
|
+
signedIn:"مسجّل باسم",notIdentified:"غير معرّف",loginLink:"سجّل الدخول في Dashboard",
|
|
212
|
+
gateHint:"للاستخدام، يجب تسجيل الدخول أولًا.",
|
|
213
|
+
placeholder:"اضغط «استمع» وتحدث…",
|
|
214
|
+
clue:(w)=>`DSH، ${w} — أبدأ الاستماع. أخبرني بالمحادثة أو الطلبات. عند ظهور عدة لغات فعّل الترجمة عند الطلب؛ التدفق الرئيسي يتبع تحليل المدخلات.`,
|
|
215
|
+
note:(end)=>`اضغط «استمع»، وتحدث ثم قل «${end}». بعدها انسخ التعليمات والصقها في جلسة جديدة — أو استخدم تطبيق «مساعد DSH».`,
|
|
216
|
+
legend:"الإشارة: 🟢 تلقائي · ⚑ شبه تلقائي (تحقق) · 🟡 مقترح (أنت تقرر) · 🔴 اسأل.",fbTitle:"ملاحظات ميدانية",fbPh:"ماذا حدث؟ ما الذي يجب تحسينه؟",fbSent:"أُرسل — سيقرأه الوكيل",fbOffline:"المشرف غير متصل — تم نسخ الموجه إلى DSH",catError:"خطأ",catImprovement:"تحسين",catIdea:"فكرة"}
|
|
217
|
+
};
|
|
218
|
+
const $=id=>document.getElementById(id);
|
|
219
|
+
const promptEl=$("prompt"),langsEl=$("langs"),workerInput=$("workerInput"),roleInput=$("roleInput");
|
|
220
|
+
let cur="en",darkOn=false,recording=false,armed=false,rec=null,interim="",finalText="";
|
|
221
|
+
// Session continuity: the dashboard sends ?user=…&role=…&lang=…
|
|
222
|
+
const q=new URLSearchParams(location.search);
|
|
223
|
+
try{
|
|
224
|
+
const savedUser=localStorage.getItem("dsh-worker"),savedRole=localStorage.getItem("dsh-role");
|
|
225
|
+
if(q.get("user"))localStorage.setItem("dsh-worker",q.get("user"));
|
|
226
|
+
if(q.get("role"))localStorage.setItem("dsh-role",q.get("role"));
|
|
227
|
+
if(q.get("label"))localStorage.setItem("dsh-role",q.get("label"));
|
|
228
|
+
workerInput.value=q.get("user")||savedUser||"";
|
|
229
|
+
roleInput.value=q.get("label")||q.get("role")||savedRole||"";
|
|
230
|
+
if(q.get("lang")&&S[q.get("lang")]){cur=q.get("lang");localStorage.setItem("dsh-lang",cur);}
|
|
231
|
+
else if(localStorage.getItem("dsh-lang")&&S[localStorage.getItem("dsh-lang")])cur=localStorage.getItem("dsh-lang");
|
|
232
|
+
}catch(e){}
|
|
233
|
+
workerInput.oninput=()=>{try{localStorage.setItem("dsh-worker",workerInput.value.trim());}catch(e){}updateIdentity();};
|
|
234
|
+
roleInput.oninput=()=>{try{localStorage.setItem("dsh-role",roleInput.value.trim());}catch(e){}updateIdentity();};
|
|
235
|
+
function identity(){const w=workerInput.value.trim(),r=roleInput.value.trim();return w?("Worker: "+w+(r?" ("+r+")":"")+". "):"";}
|
|
236
|
+
function updateIdentity(){
|
|
237
|
+
const w=workerInput.value.trim(),r=roleInput.value.trim();
|
|
238
|
+
$("idCard").style.display=w?"flex":"none";
|
|
239
|
+
$("gateCard").style.display=w?"none":"flex";
|
|
240
|
+
if(w){
|
|
241
|
+
$("whoName").textContent=w;
|
|
242
|
+
$("whoRole").textContent=S[cur].signedIn+(r?" · "+r:"");
|
|
243
|
+
$("avatar").textContent=w.slice(0,1).toUpperCase();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function applyLang(){
|
|
247
|
+
const s=S[cur];
|
|
248
|
+
try{localStorage.setItem("dsh-lang",cur);}catch(e){}
|
|
249
|
+
$("title").textContent=s.title;
|
|
250
|
+
$("subtitle").textContent=s.subtitle;
|
|
251
|
+
$("note").textContent=s.note(END[cur]);
|
|
252
|
+
$("legend").textContent=s.legend;
|
|
253
|
+
$("copyBtn").textContent=s.copy;
|
|
254
|
+
$("speakBtn").textContent=s.speak;
|
|
255
|
+
if(!recording)$("listenBtn").textContent=s.listen;
|
|
256
|
+
workerInput.placeholder=s.worker;
|
|
257
|
+
roleInput.placeholder=s.role;
|
|
258
|
+
$("gateTitle").textContent=s.notIdentified;
|
|
259
|
+
$("gateHint").textContent=s.gateHint;
|
|
260
|
+
$("gateLink").textContent=s.loginLink;
|
|
261
|
+
$("fbTitle").textContent=s.fbTitle;
|
|
262
|
+
$("fbText").placeholder=s.fbPh;
|
|
263
|
+
$("catError").textContent=s.catError;
|
|
264
|
+
$("catImprovement").textContent=s.catImprovement;
|
|
265
|
+
$("catIdea").textContent=s.catIdea;
|
|
266
|
+
promptEl.textContent=identity()+s.clue(LANG[cur])+(finalText?(" "+finalText):"");
|
|
267
|
+
updateIdentity();
|
|
268
|
+
document.querySelectorAll(".pill").forEach(p=>p.classList.toggle("active",p.dataset.l===cur));
|
|
269
|
+
}
|
|
270
|
+
function pill(l){
|
|
271
|
+
const b=document.createElement("button");
|
|
272
|
+
b.className="pill";b.dataset.l=l;
|
|
273
|
+
b.textContent=l.toUpperCase()+" · "+LANG[l];
|
|
274
|
+
b.onclick=()=>{cur=l;applyLang();};
|
|
275
|
+
langsEl.appendChild(b);
|
|
276
|
+
}
|
|
277
|
+
for(const l of Object.keys(LANG))pill(l);
|
|
278
|
+
applyLang();
|
|
279
|
+
function applyToggles(){document.body.classList.toggle("dark",darkOn);$("darkBtn").textContent=darkOn?"☀️":"🌙";}
|
|
280
|
+
$("darkBtn").onclick=()=>{darkOn=!darkOn;try{localStorage.setItem("dsh-panel-dark",darkOn?"1":"0");}catch(e){}applyToggles();};
|
|
281
|
+
try{darkOn=localStorage.getItem("dsh-panel-dark")==="1";}catch(e){}
|
|
282
|
+
applyToggles();
|
|
283
|
+
$("copyBtn").onclick=async()=>{
|
|
284
|
+
try{await navigator.clipboard.writeText(promptEl.textContent);}
|
|
285
|
+
catch(e){promptEl.select();document.execCommand("copy");}
|
|
286
|
+
$("copyBtn").textContent=S[cur].copied;
|
|
287
|
+
setTimeout(()=>$("copyBtn").textContent=S[cur].copy,1500);
|
|
288
|
+
};
|
|
289
|
+
$("speakBtn").onclick=()=>{
|
|
290
|
+
if(!("speechSynthesis" in window)){$("speakBtn").textContent="🔇";return;}
|
|
291
|
+
const u=new SpeechSynthesisUtterance(promptEl.textContent);
|
|
292
|
+
u.lang=VOICE[cur]||"es-ES";
|
|
293
|
+
speechSynthesis.speak(u);
|
|
294
|
+
};
|
|
295
|
+
// Dictation: continuous + auto-restart while armed (fixes the instant stop).
|
|
296
|
+
const SR=window.SpeechRecognition||window.webkitSpeechRecognition;
|
|
297
|
+
if(!SR){
|
|
298
|
+
$("listenBtn").disabled=true;
|
|
299
|
+
$("listenBtn").textContent=S[cur].nospeech;
|
|
300
|
+
}else{
|
|
301
|
+
$("listenBtn").onclick=()=>{
|
|
302
|
+
if(rec){armed=false;try{rec.stop();}catch(e){}return;}
|
|
303
|
+
armed=true;
|
|
304
|
+
startRec();
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function startRec(){
|
|
308
|
+
try{
|
|
309
|
+
rec=new SR();
|
|
310
|
+
rec.lang=VOICE[cur]||"es-ES";
|
|
311
|
+
rec.continuous=true;
|
|
312
|
+
rec.interimResults=true;
|
|
313
|
+
let finalAcc="";
|
|
314
|
+
finalText="";
|
|
315
|
+
rec.onresult=(e)=>{
|
|
316
|
+
let interimTxt="";
|
|
317
|
+
for(let i=e.resultIndex;i<e.results.length;i++){
|
|
318
|
+
const r=e.results[i];
|
|
319
|
+
if(r.isFinal){finalAcc+=(finalAcc?" ":"")+r[0].transcript;}
|
|
320
|
+
else interimTxt+=r[0].transcript;
|
|
321
|
+
}
|
|
322
|
+
finalText=finalAcc;
|
|
323
|
+
const base=identity()+S[cur].clue(LANG[cur]);
|
|
324
|
+
promptEl.textContent=base+(finalAcc?(" "+finalAcc):"")+(interimTxt?(" …"+interimTxt+"…"):"");
|
|
325
|
+
interim=finalAcc;
|
|
326
|
+
};
|
|
327
|
+
rec.onend=()=>{
|
|
328
|
+
recording=false;
|
|
329
|
+
$("listenBtn").classList.remove("live");
|
|
330
|
+
$("status").textContent="";
|
|
331
|
+
rec=null;
|
|
332
|
+
if(armed){setTimeout(startRec,250);} // silence auto-stop → keep listening
|
|
333
|
+
else{$("listenBtn").textContent=S[cur].listen;}
|
|
334
|
+
};
|
|
335
|
+
rec.onerror=(e)=>{
|
|
336
|
+
if(e.error==="not-allowed"){armed=false;$("status").textContent=S[cur].micError;}
|
|
337
|
+
else if(e.error==="no-speech"){/* armed keeps restarting */}
|
|
338
|
+
else{armed=false;$("status").textContent=S[cur].micError;}
|
|
339
|
+
if(!armed){recording=false;$("listenBtn").classList.remove("live");$("listenBtn").textContent=S[cur].listen;rec=null;}
|
|
340
|
+
};
|
|
341
|
+
recording=true;
|
|
342
|
+
$("listenBtn").classList.add("live");
|
|
343
|
+
$("listenBtn").textContent=S[cur].stop;
|
|
344
|
+
$("status").textContent=S[cur].recording;
|
|
345
|
+
rec.start();
|
|
346
|
+
}catch(e){
|
|
347
|
+
armed=false;recording=false;
|
|
348
|
+
$("status").textContent=S[cur].micError;
|
|
349
|
+
$("listenBtn").textContent=S[cur].listen;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Field feedback: send to the supervisor backend, or copy a prompt for DSH.
|
|
353
|
+
$("fbSend").onclick=async()=>{
|
|
354
|
+
const text=$("fbText").value.trim();
|
|
355
|
+
if(!text){$("fbText").focus();return;}
|
|
356
|
+
const w=workerInput.value.trim(),r=roleInput.value.trim();
|
|
357
|
+
let sent=false;
|
|
358
|
+
try{
|
|
359
|
+
const SUP=(location.port==="8787"||location.port==="8443")?location.origin:"http://127.0.0.1:8787";
|
|
360
|
+
const res=await fetch(SUP+"/api/feedback",{
|
|
361
|
+
method:"POST",headers:{"Content-Type":"application/json"},
|
|
362
|
+
body:JSON.stringify({worker:w||"anonymous",role:r,category:$("fbCat").value,text})
|
|
363
|
+
});
|
|
364
|
+
sent=res.ok;
|
|
365
|
+
}catch(e){}
|
|
366
|
+
if(sent){
|
|
367
|
+
$("fbSend").textContent=S[cur].fbSent;
|
|
368
|
+
$("fbText").value="";
|
|
369
|
+
setTimeout(()=>$("fbSend").textContent=S[cur].fbSent,2500);
|
|
370
|
+
}else{
|
|
371
|
+
const prompt="Feedback ("+$("fbCat").value+")"+(w?" from "+w+(r?" ("+r+")":""):"")+": "+text;
|
|
372
|
+
try{await navigator.clipboard.writeText(prompt);}catch(e){}
|
|
373
|
+
$("fbSend").textContent=S[cur].fbOffline;
|
|
374
|
+
$("fbText").value="";
|
|
375
|
+
setTimeout(()=>$("fbSend").textContent=S[cur].fbSent,3000);
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
if("serviceWorker" in navigator && /^https?:$/.test(location.protocol)){
|
|
379
|
+
navigator.serviceWorker.register("sw.js").catch(()=>{});
|
|
380
|
+
}
|
|
381
|
+
</script>
|
|
382
|
+
</body>
|
|
383
|
+
</html>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "clinic",
|
|
3
|
+
"tableLabel": {
|
|
4
|
+
"en": "Patient",
|
|
5
|
+
"es": "Paciente",
|
|
6
|
+
"fr": "Patient",
|
|
7
|
+
"de": "Patient",
|
|
8
|
+
"it": "Paziente",
|
|
9
|
+
"pt": "Paciente",
|
|
10
|
+
"zh": "患者",
|
|
11
|
+
"ja": "患者",
|
|
12
|
+
"ko": "환자",
|
|
13
|
+
"ar": "المريض"
|
|
14
|
+
},
|
|
15
|
+
"ordersTarget": {
|
|
16
|
+
"en": "Requests — desk & record",
|
|
17
|
+
"es": "Solicitudes — mostrador y expediente",
|
|
18
|
+
"fr": "Demandes — accueil et dossier",
|
|
19
|
+
"de": "Anfragen — Empfang & Akte",
|
|
20
|
+
"it": "Richieste — sportello e cartella",
|
|
21
|
+
"pt": "Pedidos — balcão e processo",
|
|
22
|
+
"zh": "请求 — 前台与病历",
|
|
23
|
+
"ja": "依頼 — 受付とカルテ",
|
|
24
|
+
"ko": "요청 — 접수 및 기록",
|
|
25
|
+
"ar": "الطلبات — الاستقبال والملف"
|
|
26
|
+
},
|
|
27
|
+
"entity": {
|
|
28
|
+
"en": "patient",
|
|
29
|
+
"es": "paciente",
|
|
30
|
+
"fr": "patient",
|
|
31
|
+
"de": "Patient",
|
|
32
|
+
"it": "paziente",
|
|
33
|
+
"pt": "paciente",
|
|
34
|
+
"zh": "患者",
|
|
35
|
+
"ja": "患者",
|
|
36
|
+
"ko": "환자",
|
|
37
|
+
"ar": "مريض"
|
|
38
|
+
},
|
|
39
|
+
"fields": [
|
|
40
|
+
{
|
|
41
|
+
"id": "prescription",
|
|
42
|
+
"type": "text",
|
|
43
|
+
"label": {
|
|
44
|
+
"en": "Prescription",
|
|
45
|
+
"es": "Receta",
|
|
46
|
+
"fr": "Ordonnance",
|
|
47
|
+
"de": "Rezept",
|
|
48
|
+
"it": "Ricetta",
|
|
49
|
+
"pt": "Receita",
|
|
50
|
+
"zh": "处方",
|
|
51
|
+
"ja": "処方箋",
|
|
52
|
+
"ko": "처방전",
|
|
53
|
+
"ar": "الوصفة"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"suggestedUsers": [
|
|
58
|
+
{
|
|
59
|
+
"label": {
|
|
60
|
+
"en": "Receptionist",
|
|
61
|
+
"es": "Recepcionista",
|
|
62
|
+
"fr": "Réceptionniste"
|
|
63
|
+
},
|
|
64
|
+
"level": "employee"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"label": {
|
|
68
|
+
"en": "Head nurse",
|
|
69
|
+
"es": "Enfermera jefe",
|
|
70
|
+
"fr": "Infirmière en chef"
|
|
71
|
+
},
|
|
72
|
+
"level": "lead"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"label": {
|
|
76
|
+
"en": "Medical director",
|
|
77
|
+
"es": "Director médico",
|
|
78
|
+
"fr": "Directeur médical"
|
|
79
|
+
},
|
|
80
|
+
"level": "owner"
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "hotel",
|
|
3
|
+
"tableLabel": {
|
|
4
|
+
"en": "Room",
|
|
5
|
+
"es": "Habitación",
|
|
6
|
+
"fr": "Chambre",
|
|
7
|
+
"de": "Zimmer",
|
|
8
|
+
"it": "Camera",
|
|
9
|
+
"pt": "Quarto",
|
|
10
|
+
"zh": "房间",
|
|
11
|
+
"ja": "部屋",
|
|
12
|
+
"ko": "객실",
|
|
13
|
+
"ar": "الغرفة"
|
|
14
|
+
},
|
|
15
|
+
"ordersTarget": {
|
|
16
|
+
"en": "Requests — front desk & folio",
|
|
17
|
+
"es": "Solicitudes — recepción y cuenta",
|
|
18
|
+
"fr": "Demandes — réception et folio",
|
|
19
|
+
"de": "Anfragen — Rezeption & Rechnung",
|
|
20
|
+
"it": "Richieste — reception e conto",
|
|
21
|
+
"pt": "Pedidos — receção e conta",
|
|
22
|
+
"zh": "请求 — 前台与账单",
|
|
23
|
+
"ja": "依頼 — フロントと会計",
|
|
24
|
+
"ko": "요청 — 프런트 및 계산",
|
|
25
|
+
"ar": "الطلبات — الاستقبال والحساب"
|
|
26
|
+
},
|
|
27
|
+
"entity": {
|
|
28
|
+
"en": "guest",
|
|
29
|
+
"es": "huésped",
|
|
30
|
+
"fr": "client",
|
|
31
|
+
"de": "Gast",
|
|
32
|
+
"it": "ospite",
|
|
33
|
+
"pt": "hóspede",
|
|
34
|
+
"zh": "客人",
|
|
35
|
+
"ja": "ゲスト",
|
|
36
|
+
"ko": "손님",
|
|
37
|
+
"ar": "ضيف"
|
|
38
|
+
},
|
|
39
|
+
"fields": [
|
|
40
|
+
{
|
|
41
|
+
"id": "nights",
|
|
42
|
+
"type": "number",
|
|
43
|
+
"label": {
|
|
44
|
+
"en": "Nights",
|
|
45
|
+
"es": "Noches",
|
|
46
|
+
"fr": "Nuits",
|
|
47
|
+
"de": "Nächte",
|
|
48
|
+
"it": "Notti",
|
|
49
|
+
"pt": "Noites",
|
|
50
|
+
"zh": "晚数",
|
|
51
|
+
"ja": "泊数",
|
|
52
|
+
"ko": "박 수",
|
|
53
|
+
"ar": "عدد الليالي"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"suggestedUsers": [
|
|
58
|
+
{
|
|
59
|
+
"label": {
|
|
60
|
+
"en": "Receptionist",
|
|
61
|
+
"es": "Recepcionista",
|
|
62
|
+
"fr": "Réceptionniste"
|
|
63
|
+
},
|
|
64
|
+
"level": "employee"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"label": {
|
|
68
|
+
"en": "Housekeeping lead",
|
|
69
|
+
"es": "Gobernanta",
|
|
70
|
+
"fr": "Gouvernante"
|
|
71
|
+
},
|
|
72
|
+
"level": "lead"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"label": {
|
|
76
|
+
"en": "Manager",
|
|
77
|
+
"es": "Gerente",
|
|
78
|
+
"fr": "Gérant"
|
|
79
|
+
},
|
|
80
|
+
"level": "owner"
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|