ttp-agent-sdk 2.46.3 → 2.48.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/dist/agent-widget.dev.js +1404 -192
- package/dist/agent-widget.esm.js +1 -2
- package/dist/agent-widget.js +1 -2
- package/dist/demos/index.html +19 -0
- package/dist/demos/rimon-trips.html +415 -0
- package/dist/examples/rimon-trips.html +415 -0
- package/dist/examples/test-index.html +19 -0
- package/examples/rimon-trips.html +415 -0
- package/examples/test-index.html +19 -0
- package/package.json +8 -3
- package/dist/agent-widget.dev.js.map +0 -1
- package/dist/agent-widget.esm.js.map +0 -1
- package/dist/agent-widget.js.map +0 -1
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="he" dir="rtl">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>רימון טיולים — חיפוש חוברות טיול</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
|
|
10
|
+
body {
|
|
11
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans Hebrew', Arial, sans-serif;
|
|
12
|
+
background: #f4f6fb;
|
|
13
|
+
color: #111827;
|
|
14
|
+
min-height: 100vh;
|
|
15
|
+
padding: 32px 16px 64px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.container { max-width: 860px; margin: 0 auto; }
|
|
19
|
+
|
|
20
|
+
.header { margin-bottom: 24px; }
|
|
21
|
+
|
|
22
|
+
.header h1 { font-size: 28px; font-weight: 700; }
|
|
23
|
+
|
|
24
|
+
.header p { margin-top: 6px; color: #6b7280; font-size: 15px; }
|
|
25
|
+
|
|
26
|
+
.search-card {
|
|
27
|
+
background: white;
|
|
28
|
+
border-radius: 14px;
|
|
29
|
+
box-shadow: 0 6px 24px rgba(17, 24, 39, 0.07);
|
|
30
|
+
padding: 20px;
|
|
31
|
+
position: sticky;
|
|
32
|
+
top: 16px;
|
|
33
|
+
z-index: 2;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.search-row { display: flex; gap: 10px; align-items: center; }
|
|
37
|
+
|
|
38
|
+
#search {
|
|
39
|
+
flex: 1;
|
|
40
|
+
font: inherit;
|
|
41
|
+
font-size: 18px;
|
|
42
|
+
padding: 14px 16px;
|
|
43
|
+
border: 2px solid #e5e7eb;
|
|
44
|
+
border-radius: 10px;
|
|
45
|
+
background: #fbfcfe;
|
|
46
|
+
transition: border-color 0.15s ease, background 0.15s ease;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#search:focus {
|
|
50
|
+
outline: none;
|
|
51
|
+
border-color: #6366f1;
|
|
52
|
+
background: white;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.clear-btn {
|
|
56
|
+
font: inherit;
|
|
57
|
+
font-size: 15px;
|
|
58
|
+
padding: 12px 16px;
|
|
59
|
+
border: 1px solid #e5e7eb;
|
|
60
|
+
border-radius: 10px;
|
|
61
|
+
background: white;
|
|
62
|
+
color: #4b5563;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.clear-btn:hover { background: #f3f4f6; }
|
|
67
|
+
|
|
68
|
+
.status { margin-top: 12px; font-size: 14px; color: #6b7280; min-height: 20px; }
|
|
69
|
+
|
|
70
|
+
.status--error { color: #b91c1c; }
|
|
71
|
+
|
|
72
|
+
.results { margin-top: 20px; display: flex; flex-direction: column; gap: 10px; }
|
|
73
|
+
|
|
74
|
+
.trip {
|
|
75
|
+
background: white;
|
|
76
|
+
border-radius: 12px;
|
|
77
|
+
box-shadow: 0 2px 10px rgba(17, 24, 39, 0.06);
|
|
78
|
+
padding: 16px 18px;
|
|
79
|
+
display: flex;
|
|
80
|
+
gap: 16px;
|
|
81
|
+
align-items: center;
|
|
82
|
+
flex-wrap: wrap;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.trip__main { flex: 1; min-width: 220px; }
|
|
86
|
+
|
|
87
|
+
.trip__name { font-size: 17px; font-weight: 600; line-height: 1.4; }
|
|
88
|
+
|
|
89
|
+
.trip__name mark { background: #fde68a; color: inherit; border-radius: 3px; padding: 0 2px; }
|
|
90
|
+
|
|
91
|
+
.trip__meta {
|
|
92
|
+
margin-top: 6px;
|
|
93
|
+
display: flex;
|
|
94
|
+
gap: 8px;
|
|
95
|
+
flex-wrap: wrap;
|
|
96
|
+
align-items: center;
|
|
97
|
+
font-size: 13px;
|
|
98
|
+
color: #6b7280;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.badge {
|
|
102
|
+
display: inline-block;
|
|
103
|
+
padding: 3px 9px;
|
|
104
|
+
border-radius: 999px;
|
|
105
|
+
font-size: 12px;
|
|
106
|
+
font-weight: 600;
|
|
107
|
+
letter-spacing: 0.3px;
|
|
108
|
+
background: #ede9fe;
|
|
109
|
+
color: #5b21b6;
|
|
110
|
+
direction: ltr;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.badge--sellable { background: #dcfce7; color: #166534; }
|
|
114
|
+
|
|
115
|
+
.badge--closed { background: #f3f4f6; color: #6b7280; }
|
|
116
|
+
|
|
117
|
+
.trip__actions { display: flex; gap: 8px; align-items: center; }
|
|
118
|
+
|
|
119
|
+
.pdf-link {
|
|
120
|
+
display: inline-flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
gap: 6px;
|
|
123
|
+
background: #dc2626;
|
|
124
|
+
color: white;
|
|
125
|
+
text-decoration: none;
|
|
126
|
+
font-size: 14px;
|
|
127
|
+
font-weight: 600;
|
|
128
|
+
padding: 10px 16px;
|
|
129
|
+
border-radius: 9px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.pdf-link:hover { background: #b91c1c; }
|
|
133
|
+
|
|
134
|
+
.copy-btn {
|
|
135
|
+
font: inherit;
|
|
136
|
+
font-size: 14px;
|
|
137
|
+
padding: 10px 12px;
|
|
138
|
+
border: 1px solid #e5e7eb;
|
|
139
|
+
border-radius: 9px;
|
|
140
|
+
background: white;
|
|
141
|
+
color: #4b5563;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.copy-btn:hover { background: #f3f4f6; }
|
|
146
|
+
|
|
147
|
+
.no-pdf { font-size: 14px; color: #9ca3af; }
|
|
148
|
+
|
|
149
|
+
.empty {
|
|
150
|
+
background: white;
|
|
151
|
+
border-radius: 12px;
|
|
152
|
+
padding: 32px;
|
|
153
|
+
text-align: center;
|
|
154
|
+
color: #6b7280;
|
|
155
|
+
box-shadow: 0 2px 10px rgba(17, 24, 39, 0.06);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.footer { margin-top: 28px; font-size: 13px; color: #9ca3af; text-align: center; }
|
|
159
|
+
|
|
160
|
+
.footer code { direction: ltr; display: inline-block; }
|
|
161
|
+
|
|
162
|
+
@media (max-width: 600px) {
|
|
163
|
+
.trip { align-items: flex-start; }
|
|
164
|
+
.trip__actions { width: 100%; }
|
|
165
|
+
.pdf-link { flex: 1; justify-content: center; }
|
|
166
|
+
}
|
|
167
|
+
</style>
|
|
168
|
+
</head>
|
|
169
|
+
<body>
|
|
170
|
+
<div class="container">
|
|
171
|
+
<div class="header">
|
|
172
|
+
<h1>חיפוש חוברות טיול — רימון טיולים</h1>
|
|
173
|
+
<p>הקלידו שם טיול (או קוד סדרה) וקבלו קישור לחוברת ה-PDF.</p>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<div class="search-card">
|
|
177
|
+
<div class="search-row">
|
|
178
|
+
<input id="search" type="search" placeholder="לדוגמה: יפן, לפלנד, SLF…" autocomplete="off" autofocus
|
|
179
|
+
aria-label="חיפוש שם טיול">
|
|
180
|
+
<button id="clear" class="clear-btn" type="button">נקה</button>
|
|
181
|
+
</div>
|
|
182
|
+
<div id="status" class="status">טוען טיולים…</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<div id="results" class="results"></div>
|
|
186
|
+
|
|
187
|
+
<div class="footer">
|
|
188
|
+
נתונים מהמראה המקומית של פיד רימון (מתעדכן בסנכרון היומי).
|
|
189
|
+
אפשר להצביע על בקאנד אחר עם <code>?api=http://localhost:8765</code>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<script>
|
|
194
|
+
(function () {
|
|
195
|
+
var PRODUCTION_API = 'https://backend.talktopc.com';
|
|
196
|
+
var MAX_RENDERED = 60;
|
|
197
|
+
|
|
198
|
+
var searchInput = document.getElementById('search');
|
|
199
|
+
var clearButton = document.getElementById('clear');
|
|
200
|
+
var statusEl = document.getElementById('status');
|
|
201
|
+
var resultsEl = document.getElementById('results');
|
|
202
|
+
|
|
203
|
+
var allTrips = [];
|
|
204
|
+
|
|
205
|
+
function apiBase() {
|
|
206
|
+
var override = new URLSearchParams(location.search).get('api');
|
|
207
|
+
if (override) return override.replace(/\/$/, '');
|
|
208
|
+
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
|
|
209
|
+
return 'http://localhost:8765';
|
|
210
|
+
}
|
|
211
|
+
return PRODUCTION_API;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Hebrew trip names carry gershayim/apostrophes inconsistently (ארה"ב vs ארה״ב),
|
|
216
|
+
* so both haystack and needle are stripped of them before matching — otherwise
|
|
217
|
+
* typing the name as it sounds misses the trip.
|
|
218
|
+
*/
|
|
219
|
+
function normalize(text) {
|
|
220
|
+
return (text || '').toLowerCase().replace(/["'\u05f3\u05f4\u2018\u2019\u201c\u201d]/g, '');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function tokensOf(query) {
|
|
224
|
+
return normalize(query).split(/\s+/).filter(Boolean);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function matches(trip, tokens) {
|
|
228
|
+
var haystack = normalize(trip.name + ' ' + (trip.series || ''));
|
|
229
|
+
return tokens.every(function (token) { return haystack.indexOf(token) !== -1; });
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Builds the trip name with matched tokens wrapped in <mark>, as text nodes only.
|
|
234
|
+
* Tokens are located in the plain lower-cased name, so a token that only matched
|
|
235
|
+
* thanks to quote-stripping simply goes un-highlighted instead of shifting the
|
|
236
|
+
* offsets of every character after it.
|
|
237
|
+
*/
|
|
238
|
+
function highlightedName(name, tokens) {
|
|
239
|
+
var fragment = document.createDocumentFragment();
|
|
240
|
+
if (!tokens.length) {
|
|
241
|
+
fragment.appendChild(document.createTextNode(name));
|
|
242
|
+
return fragment;
|
|
243
|
+
}
|
|
244
|
+
var lower = name.toLowerCase();
|
|
245
|
+
var marked = new Array(name.length).fill(false);
|
|
246
|
+
tokens.forEach(function (token) {
|
|
247
|
+
var from = 0;
|
|
248
|
+
var at;
|
|
249
|
+
while ((at = lower.indexOf(token, from)) !== -1) {
|
|
250
|
+
for (var k = at; k < at + token.length; k++) marked[k] = true;
|
|
251
|
+
from = at + token.length;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
var buffer = '';
|
|
255
|
+
var bufferMarked = false;
|
|
256
|
+
function flush() {
|
|
257
|
+
if (!buffer) return;
|
|
258
|
+
if (bufferMarked) {
|
|
259
|
+
var mark = document.createElement('mark');
|
|
260
|
+
mark.textContent = buffer;
|
|
261
|
+
fragment.appendChild(mark);
|
|
262
|
+
} else {
|
|
263
|
+
fragment.appendChild(document.createTextNode(buffer));
|
|
264
|
+
}
|
|
265
|
+
buffer = '';
|
|
266
|
+
}
|
|
267
|
+
for (var j = 0; j < name.length; j++) {
|
|
268
|
+
if (marked[j] !== bufferMarked) {
|
|
269
|
+
flush();
|
|
270
|
+
bufferMarked = marked[j];
|
|
271
|
+
}
|
|
272
|
+
buffer += name[j];
|
|
273
|
+
}
|
|
274
|
+
flush();
|
|
275
|
+
return fragment;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function tripRow(trip, tokens) {
|
|
279
|
+
var row = document.createElement('div');
|
|
280
|
+
row.className = 'trip';
|
|
281
|
+
|
|
282
|
+
var main = document.createElement('div');
|
|
283
|
+
main.className = 'trip__main';
|
|
284
|
+
|
|
285
|
+
var name = document.createElement('div');
|
|
286
|
+
name.className = 'trip__name';
|
|
287
|
+
name.appendChild(highlightedName(trip.name || '(ללא שם)', tokens));
|
|
288
|
+
main.appendChild(name);
|
|
289
|
+
|
|
290
|
+
var meta = document.createElement('div');
|
|
291
|
+
meta.className = 'trip__meta';
|
|
292
|
+
|
|
293
|
+
if (trip.series) {
|
|
294
|
+
var series = document.createElement('span');
|
|
295
|
+
series.className = 'badge';
|
|
296
|
+
series.textContent = trip.series;
|
|
297
|
+
meta.appendChild(series);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
var availability = document.createElement('span');
|
|
301
|
+
if (trip.sellable_departures > 0) {
|
|
302
|
+
availability.className = 'badge badge--sellable';
|
|
303
|
+
availability.textContent = trip.sellable_departures + ' יציאות פתוחות';
|
|
304
|
+
} else {
|
|
305
|
+
availability.className = 'badge badge--closed';
|
|
306
|
+
availability.textContent = 'אין יציאות פתוחות';
|
|
307
|
+
}
|
|
308
|
+
meta.appendChild(availability);
|
|
309
|
+
|
|
310
|
+
if (trip.next_departure) {
|
|
311
|
+
var next = document.createElement('span');
|
|
312
|
+
next.textContent = 'היציאה הקרובה: ' + trip.next_departure;
|
|
313
|
+
meta.appendChild(next);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
main.appendChild(meta);
|
|
317
|
+
row.appendChild(main);
|
|
318
|
+
|
|
319
|
+
var actions = document.createElement('div');
|
|
320
|
+
actions.className = 'trip__actions';
|
|
321
|
+
if (trip.itinerary_url) {
|
|
322
|
+
var link = document.createElement('a');
|
|
323
|
+
link.className = 'pdf-link';
|
|
324
|
+
link.href = trip.itinerary_url;
|
|
325
|
+
link.target = '_blank';
|
|
326
|
+
link.rel = 'noopener noreferrer';
|
|
327
|
+
link.textContent = 'פתח חוברת PDF';
|
|
328
|
+
actions.appendChild(link);
|
|
329
|
+
|
|
330
|
+
var copy = document.createElement('button');
|
|
331
|
+
copy.className = 'copy-btn';
|
|
332
|
+
copy.type = 'button';
|
|
333
|
+
copy.textContent = 'העתק קישור';
|
|
334
|
+
copy.addEventListener('click', function () {
|
|
335
|
+
navigator.clipboard.writeText(trip.itinerary_url).then(function () {
|
|
336
|
+
copy.textContent = 'הועתק!';
|
|
337
|
+
setTimeout(function () { copy.textContent = 'העתק קישור'; }, 1500);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
actions.appendChild(copy);
|
|
341
|
+
} else {
|
|
342
|
+
var none = document.createElement('span');
|
|
343
|
+
none.className = 'no-pdf';
|
|
344
|
+
none.textContent = 'אין חוברת PDF';
|
|
345
|
+
actions.appendChild(none);
|
|
346
|
+
}
|
|
347
|
+
row.appendChild(actions);
|
|
348
|
+
return row;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function render() {
|
|
352
|
+
var query = searchInput.value.trim();
|
|
353
|
+
var tokens = tokensOf(query);
|
|
354
|
+
var found = tokens.length
|
|
355
|
+
? allTrips.filter(function (trip) { return matches(trip, tokens); })
|
|
356
|
+
: allTrips;
|
|
357
|
+
|
|
358
|
+
resultsEl.textContent = '';
|
|
359
|
+
if (!found.length) {
|
|
360
|
+
var empty = document.createElement('div');
|
|
361
|
+
empty.className = 'empty';
|
|
362
|
+
empty.textContent = 'לא נמצא טיול בשם "' + query + '".';
|
|
363
|
+
resultsEl.appendChild(empty);
|
|
364
|
+
statusEl.textContent = '0 מתוך ' + allTrips.length + ' טיולים';
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
var shown = found.slice(0, MAX_RENDERED);
|
|
369
|
+
shown.forEach(function (trip) { resultsEl.appendChild(tripRow(trip, tokens)); });
|
|
370
|
+
statusEl.className = 'status';
|
|
371
|
+
statusEl.textContent = found.length === allTrips.length
|
|
372
|
+
? allTrips.length + ' טיולים'
|
|
373
|
+
: found.length + ' מתוך ' + allTrips.length + ' טיולים';
|
|
374
|
+
if (found.length > shown.length) {
|
|
375
|
+
statusEl.textContent += ' — מוצגים ' + shown.length + ' הראשונים, המשיכו להקליד לצמצום';
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function load() {
|
|
380
|
+
statusEl.className = 'status';
|
|
381
|
+
statusEl.textContent = 'טוען טיולים…';
|
|
382
|
+
fetch(apiBase() + '/api/public/rimon/trips', { headers: { Accept: 'application/json' } })
|
|
383
|
+
.then(function (response) {
|
|
384
|
+
if (!response.ok) throw new Error('HTTP ' + response.status);
|
|
385
|
+
return response.json();
|
|
386
|
+
})
|
|
387
|
+
.then(function (data) {
|
|
388
|
+
allTrips = (data && data.trips) || [];
|
|
389
|
+
render();
|
|
390
|
+
})
|
|
391
|
+
.catch(function (error) {
|
|
392
|
+
statusEl.className = 'status status--error';
|
|
393
|
+
statusEl.textContent = 'טעינת הטיולים נכשלה (' + error.message + '). ' +
|
|
394
|
+
'הדף מוגש רק מדומיין talktopc — בפיתוח מקומי הריצו מ-localhost.';
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
searchInput.addEventListener('input', render);
|
|
399
|
+
searchInput.addEventListener('keydown', function (event) {
|
|
400
|
+
if (event.key === 'Escape') {
|
|
401
|
+
searchInput.value = '';
|
|
402
|
+
render();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
clearButton.addEventListener('click', function () {
|
|
406
|
+
searchInput.value = '';
|
|
407
|
+
searchInput.focus();
|
|
408
|
+
render();
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
load();
|
|
412
|
+
})();
|
|
413
|
+
</script>
|
|
414
|
+
</body>
|
|
415
|
+
</html>
|
|
@@ -351,6 +351,25 @@
|
|
|
351
351
|
</div>
|
|
352
352
|
</div>
|
|
353
353
|
|
|
354
|
+
<div class="section">
|
|
355
|
+
<h2 class="section__title">Customer Test Tools</h2>
|
|
356
|
+
<div class="test-grid">
|
|
357
|
+
<a href="rimon-trips.html" class="test-card">
|
|
358
|
+
<span class="test-card__icon">📄</span>
|
|
359
|
+
<h3 class="test-card__title">Rimon Trip Brochures</h3>
|
|
360
|
+
<p class="test-card__description">
|
|
361
|
+
Type a trip name (Hebrew or series code) and get the itinerary PDF the
|
|
362
|
+
Rimon agent is talking about. Reads the mirrored trips feed from the
|
|
363
|
+
control plane — no login needed, talktopc domains only.
|
|
364
|
+
</p>
|
|
365
|
+
<div class="test-card__badges">
|
|
366
|
+
<span class="badge badge--sdk">Rimon</span>
|
|
367
|
+
<span class="badge badge--new">Testing</span>
|
|
368
|
+
</div>
|
|
369
|
+
</a>
|
|
370
|
+
</div>
|
|
371
|
+
</div>
|
|
372
|
+
|
|
354
373
|
<div class="footer">
|
|
355
374
|
<p>
|
|
356
375
|
<strong>TTP Agent SDK</strong> - Voice & Text AI Agent Integration
|