Nerdur commited on
Commit
789cbca
·
verified ·
1 Parent(s): d73313a

Delete index.html

Browse files
Files changed (1) hide show
  1. index.html +0 -767
index.html DELETED
@@ -1,767 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="hr">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
- <title>AgentScope AI Chat</title>
7
- <meta name="description" content="Kompaktan PWA Chat aplikacija sa podrškom za HuggingFace i OpenAI kompatibilne API-je.">
8
-
9
- <!-- Font Awesome -->
10
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
-
12
- <!-- Google Fonts -->
13
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
14
-
15
- <style>
16
- /* --- CSS VARIJABLE I RESET --- */
17
- :root {
18
- --bg-color: #121212;
19
- --surface-color: #1e1e1e;
20
- --surface-hover: #2c2c2c;
21
- --input-bg: #2a2a2a; /* Dodano: Pozadina za input polja */
22
- --primary-color: #3b82f6;
23
- --primary-hover: #2563eb;
24
- --text-main: #e5e5e5;
25
- --text-secondary: #a3a3a3;
26
- --border-color: #333;
27
- --user-msg-bg: #2563eb;
28
- --ai-msg-bg: #2c2c2c;
29
- --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.5);
30
- --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5);
31
- }
32
-
33
- * {
34
- box-sizing: border-box;
35
- margin: 0;
36
- padding: 0;
37
- -webkit-tap-highlight-color: transparent;
38
- }
39
-
40
- body {
41
- font-family: 'Inter', sans-serif;
42
- background-color: var(--bg-color);
43
- color: var(--text-main);
44
- height: 100vh;
45
- display: flex;
46
- flex-direction: column;
47
- overflow: hidden;
48
- }
49
-
50
- /* --- LAYOUT --- */
51
- header {
52
- background-color: var(--surface-color);
53
- padding: 1rem;
54
- display: flex;
55
- justify-content: space-between;
56
- align-items: center;
57
- border-bottom: 1px solid var(--border-color);
58
- z-index: 10;
59
- }
60
-
61
- .app-title {
62
- font-size: 1.1rem;
63
- font-weight: 600;
64
- display: flex;
65
- align-items: center;
66
- gap: 0.5rem;
67
- }
68
-
69
- .settings-btn {
70
- background: none;
71
- border: none;
72
- color: var(--text-main);
73
- font-size: 1.2rem;
74
- cursor: pointer;
75
- padding: 0.5rem;
76
- transition: color 0.2s;
77
- }
78
-
79
- .settings-btn:hover {
80
- color: var(--primary-color);
81
- }
82
-
83
- main {
84
- flex: 1;
85
- overflow-y: auto;
86
- padding: 1rem;
87
- display: flex;
88
- flex-direction: column;
89
- gap: 1rem;
90
- scroll-behavior: smooth;
91
- }
92
-
93
- /* --- CHAT MESSAGES --- */
94
- .message {
95
- max-width: 85%;
96
- padding: 0.8rem 1rem;
97
- border-radius: 12px;
98
- font-size: 0.95rem;
99
- line-height: 1.5;
100
- position: relative;
101
- animation: fadeIn 0.3s ease;
102
- word-wrap: break-word;
103
- }
104
-
105
- @keyframes fadeIn {
106
- from { opacity: 0; transform: translateY(10px); }
107
- to { opacity: 1; transform: translateY(0); }
108
- }
109
-
110
- .message.user {
111
- align-self: flex-end;
112
- background-color: var(--user-msg-bg);
113
- color: white;
114
- border-bottom-right-radius: 2px;
115
- }
116
-
117
- .message.ai {
118
- align-self: flex-start;
119
- background-color: var(--ai-msg-bg);
120
- color: var(--text-main);
121
- border-bottom-left-radius: 2px;
122
- }
123
-
124
- .message.system {
125
- align-self: center;
126
- background: transparent;
127
- color: var(--text-secondary);
128
- font-size: 0.8rem;
129
- padding: 0.2rem 0.5rem;
130
- }
131
-
132
- /* --- INPUT AREA --- */
133
- .input-area {
134
- background-color: var(--surface-color);
135
- padding: 0.8rem;
136
- border-top: 1px solid var(--border-color);
137
- display: flex;
138
- gap: 0.5rem;
139
- align-items: flex-end;
140
- }
141
-
142
- .input-wrapper {
143
- flex: 1;
144
- position: relative;
145
- }
146
-
147
- textarea {
148
- width: 100%;
149
- background-color: var(--input-bg); /* Koristi novu varijablu */
150
- border: 1px solid var(--border-color);
151
- border-radius: 8px;
152
- color: var(--text-main);
153
- padding: 0.8rem;
154
- font-family: inherit;
155
- resize: none;
156
- max-height: 120px;
157
- min-height: 48px;
158
- outline: none;
159
- font-size: 0.95rem;
160
- transition: border-color 0.2s;
161
- }
162
-
163
- textarea:focus {
164
- border-color: var(--primary-color);
165
- }
166
-
167
- .send-btn {
168
- background-color: var(--primary-color);
169
- color: white;
170
- border: none;
171
- border-radius: 8px;
172
- width: 48px;
173
- height: 48px;
174
- display: flex;
175
- align-items: center;
176
- justify-content: center;
177
- cursor: pointer;
178
- transition: background 0.2s;
179
- }
180
-
181
- .send-btn:hover {
182
- background-color: var(--primary-hover);
183
- }
184
-
185
- .send-btn:disabled {
186
- background-color: var(--surface-hover);
187
- color: var(--text-secondary);
188
- cursor: not-allowed;
189
- }
190
-
191
- .spinner {
192
- border: 3px solid rgba(255,255,255,0.3);
193
- border-radius: 50%;
194
- border-top: 3px solid #fff;
195
- width: 20px;
196
- height: 20px;
197
- animation: spin 1s linear infinite;
198
- display: none;
199
- }
200
-
201
- @keyframes spin {
202
- 0% { transform: rotate(0deg); }
203
- 100% { transform: rotate(360deg); }
204
- }
205
-
206
- /* --- SETTINGS MODAL --- */
207
- .modal-overlay {
208
- position: fixed;
209
- top: 0;
210
- left: 0;
211
- width: 100%;
212
- height: 100%;
213
- background: rgba(0, 0, 0, 0.7);
214
- display: flex;
215
- justify-content: center;
216
- align-items: center;
217
- z-index: 100;
218
- opacity: 0;
219
- pointer-events: none;
220
- transition: opacity 0.3s;
221
- backdrop-filter: blur(2px);
222
- }
223
-
224
- .modal-overlay.open {
225
- opacity: 1;
226
- pointer-events: auto;
227
- }
228
-
229
- .modal {
230
- background-color: var(--surface-color);
231
- width: 90%;
232
- max-width: 400px;
233
- border-radius: 12px;
234
- padding: 1.5rem;
235
- border: 1px solid var(--border-color);
236
- transform: scale(0.9);
237
- transition: transform 0.3s;
238
- }
239
-
240
- .modal-overlay.open .modal {
241
- transform: scale(1);
242
- }
243
-
244
- .modal-header {
245
- display: flex;
246
- justify-content: space-between;
247
- align-items: center;
248
- margin-bottom: 1rem;
249
- }
250
-
251
- .modal-title {
252
- font-size: 1.2rem;
253
- font-weight: 600;
254
- }
255
-
256
- .close-modal {
257
- background: none;
258
- border: none;
259
- color: var(--text-secondary);
260
- font-size: 1.5rem;
261
- cursor: pointer;
262
- }
263
-
264
- .form-group {
265
- margin-bottom: 1rem;
266
- }
267
-
268
- .form-group label {
269
- display: block;
270
- margin-bottom: 0.5rem;
271
- font-size: 0.9rem;
272
- color: var(--text-secondary);
273
- }
274
-
275
- .form-group input, .form-group select {
276
- width: 100%;
277
- padding: 0.8rem;
278
- background-color: var(--bg-color);
279
- border: 1px solid var(--border-color);
280
- border-radius: 6px;
281
- color: white;
282
- outline: none;
283
- }
284
-
285
- .form-group select:focus {
286
- border-color: var(--primary-color);
287
- }
288
-
289
- .save-btn {
290
- width: 100%;
291
- padding: 0.8rem;
292
- background-color: var(--primary-color);
293
- color: white;
294
- border: none;
295
- border-radius: 6px;
296
- font-weight: 600;
297
- cursor: pointer;
298
- margin-top: 0.5rem;
299
- }
300
-
301
- /* --- PWA INSTALL PROMPT --- */
302
- #install-prompt {
303
- display: none;
304
- position: fixed;
305
- bottom: 0;
306
- left: 0;
307
- width: 100%;
308
- background-color: var(--surface-color);
309
- padding: 1rem;
310
- border-top: 1px solid var(--border-color);
311
- text-align: center;
312
- z-index: 50;
313
- }
314
-
315
- #install-prompt button {
316
- background-color: var(--primary-color);
317
- color: white;
318
- border: none;
319
- padding: 0.5rem 1rem;
320
- border-radius: 4px;
321
- font-weight: bold;
322
- }
323
- </style>
324
- </head>
325
- <body>
326
-
327
- <!-- Header -->
328
- <header>
329
- <div class="app-title">
330
- <i class="fa-solid fa-robot" style="color: var(--primary-color);"></i>
331
- AgentScope AI
332
- </div>
333
- <button class="settings-btn" id="open-settings" aria-label="Postavke">
334
- <i class="fa-solid fa-gear"></i>
335
- </button>
336
- </header>
337
-
338
- <!-- Main Chat Area -->
339
- <main id="chat-container">
340
- <div class="message system">Dobrodošao. Odaberi model i unesi API Ključ u postavkama za početak.</div>
341
- </main>
342
-
343
- <!-- Input Area -->
344
- <div class="input-area">
345
- <div class="input-wrapper">
346
- <textarea id="user-input" rows="1" placeholder="Napiši poruku..."></textarea>
347
- </div>
348
- <button id="send-btn" class="send-btn" disabled>
349
- <div class="spinner" id="loading-spinner"></div>
350
- <i class="fa-solid fa-paper-plane" id="send-icon"></i>
351
- </button>
352
- </div>
353
-
354
- <!-- Install Prompt -->
355
- <div id="install-prompt">
356
- <button id="install-btn">Instaliraj Aplikaciju</button>
357
- </div>
358
-
359
- <!-- Settings Modal -->
360
- <div class="modal-overlay" id="settings-modal">
361
- <div class="modal">
362
- <div class="modal-header">
363
- <h3 class="modal-title">Postavke</h3>
364
- <button class="close-modal" id="close-settings">&times;</button>
365
- </div>
366
-
367
- <div class="form-group">
368
- <label for="provider-select">Provider (API)</label>
369
- <select id="provider-select">
370
- <option value="huggingface">Hugging Face (Inference API)</option>
371
- <option value="openai">OpenAI (Classic)</option>
372
- </select>
373
- </div>
374
-
375
- <div class="form-group" id="api-key-group">
376
- <label for="api-key">API Ključ (Bearer Token)</label>
377
- <input type="password" id="api-key" placeholder="Nh... your-key-here">
378
- <small style="color: var(--text-secondary); display: block; margin-top: 0.4rem; font-size: 0.75rem;">
379
- Ključ se čuva samo lokalno u ovom browseru (localStorage) i šalje se direktno API provideru. Ne deli ovaj uređaj/link s drugima dok je ključ upisan.
380
- </small>
381
- </div>
382
-
383
- <div class="form-group">
384
- <label for="model-select">Model</label>
385
- <select id="model-select">
386
- <!-- Options will be populated dynamically -->
387
- <option value="" disabled selected>Učitavanje...</option>
388
- </select>
389
- </div>
390
-
391
- <div class="form-group">
392
- <label for="system-prompt">System Prompt</label>
393
- <input type="text" id="system-prompt" value="Ti si pomoćni asistent." placeholder="System instruction...">
394
- </div>
395
-
396
- <button class="save-btn" id="save-settings">Spremi</button>
397
- <button class="save-btn" id="clear-settings" style="background-color: transparent; border: 1px solid var(--border-color); color: var(--text-secondary); margin-top: 0.5rem;">Obriši sačuvani API ključ</button>
398
- </div>
399
- </div>
400
-
401
- <!-- PWA Manifest & SW Injection Script -->
402
- <script>
403
- // --- 1. PWA MANIFEST GENERATION ---
404
- const manifest = {
405
- "name": "AgentScope AI",
406
- "short_name": "AgentScope",
407
- "start_url": "./index.html",
408
- "display": "standalone",
409
- "background_color": "#121212",
410
- "theme_color": "#121212",
411
- "icons": [
412
- {
413
- "src": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 192 192'%3E%3Crect width='192' height='192' fill='%23121212'/%3E%3Ccircle cx='96' cy='96' r='60' fill='%233b82f6'/%3E%3Ccircle cx='75' cy='88' r='10' fill='%23121212'/%3E%3Ccircle cx='117' cy='88' r='10' fill='%23121212'/%3E%3Crect x='66' y='118' width='60' height='10' rx='5' fill='%23121212'/%3E%3C/svg%3E",
414
- "sizes": "192x192",
415
- "type": "image/svg+xml"
416
- },
417
- {
418
- "src": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Crect width='512' height='512' fill='%23121212'/%3E%3Ccircle cx='256' cy='256' r='160' fill='%233b82f6'/%3E%3Ccircle cx='200' cy='235' r='26' fill='%23121212'/%3E%3Ccircle cx='312' cy='235' r='26' fill='%23121212'/%3E%3Crect x='176' y='315' width='160' height='26' rx='13' fill='%23121212'/%3E%3C/svg%3E",
419
- "sizes": "512x512",
420
- "type": "image/svg+xml"
421
- }
422
- ]
423
- };
424
-
425
- // Create a Blob URL for the manifest and inject it dynamically
426
- const manifestBlob = new Blob([JSON.stringify(manifest)], {type: 'application/json'});
427
- const manifestUrl = URL.createObjectURL(manifestBlob);
428
-
429
- // Create link tag if it doesn't exist
430
- let manifestLink = document.querySelector('link[rel="manifest"]');
431
- if (!manifestLink) {
432
- manifestLink = document.createElement('link');
433
- manifestLink.rel = 'manifest';
434
- document.head.appendChild(manifestLink);
435
- }
436
- manifestLink.href = manifestUrl;
437
-
438
- // --- 2. SERVICE WORKER (Offline Support) ---
439
- if ('serviceWorker' in navigator) {
440
- // Service Worker code inline as a string
441
- const swCode = `
442
- const CACHE_NAME = 'agentscope-v1';
443
- const urlsToCache = ['/', './index.html'];
444
-
445
- self.addEventListener('install', event => {
446
- event.waitUntil(
447
- caches.open(CACHE_NAME)
448
- .then(cache => cache.addAll(urlsToCache))
449
- );
450
- self.skipWaiting();
451
- });
452
-
453
- self.addEventListener('activate', event => {
454
- event.waitUntil(self.clients.claim());
455
- });
456
-
457
- self.addEventListener('fetch', event => {
458
- event.respondWith(
459
- caches.match(event.request)
460
- .then(response => response || fetch(event.request))
461
- );
462
- });
463
- `;
464
-
465
- const blob = new Blob([swCode], {type: 'application/javascript'});
466
- const swUrl = URL.createObjectURL(blob);
467
-
468
- navigator.serviceWorker.register(swUrl)
469
- .then(reg => console.log('SW Registered'))
470
- .catch(err => console.log('SW Failed:', err));
471
- }
472
-
473
- // --- 3. APP LOGIC ---
474
- const UI = {
475
- chatContainer: document.getElementById('chat-container'),
476
- userInput: document.getElementById('user-input'),
477
- sendBtn: document.getElementById('send-btn'),
478
- loadingSpinner: document.getElementById('loading-spinner'),
479
- sendIcon: document.getElementById('send-icon'),
480
- modal: document.getElementById('settings-modal'),
481
- openSettingsBtn: document.getElementById('open-settings'),
482
- closeSettingsBtn: document.getElementById('close-settings'),
483
- saveSettingsBtn: document.getElementById('save-settings'),
484
- clearSettingsBtn: document.getElementById('clear-settings'),
485
-
486
- // Inputs
487
- providerSelect: document.getElementById('provider-select'),
488
- apiKeyInput: document.getElementById('api-key'),
489
- modelSelect: document.getElementById('model-select'),
490
- systemPromptInput: document.getElementById('system-prompt'),
491
- installBtn: document.getElementById('install-btn'),
492
- installPrompt: document.getElementById('install-prompt')
493
- };
494
-
495
- const App = {
496
- config: {
497
- provider: 'huggingface',
498
- apiKey: '',
499
- model: '',
500
- systemPrompt: 'Ti si pomoćni asistent.'
501
- },
502
-
503
- // Historija razgovora (bez system poruke) - koristi se za kontekst u API pozivima
504
- messages: [],
505
-
506
- // HuggingFace Inference Providers - OpenAI-kompatibilan router (router.huggingface.co)
507
- // ":auto" znači da HF sam bira najbrži dostupan provider za odabrani model
508
- freeModels: [
509
- "openai/gpt-oss-120b:auto",
510
- "openai/gpt-oss-20b:auto",
511
- "deepseek-ai/DeepSeek-R1:auto",
512
- "meta-llama/Llama-3.3-70B-Instruct:auto",
513
- "Qwen/Qwen2.5-72B-Instruct:auto"
514
- ],
515
-
516
- // Aktuelna OpenAI Chat Completions lista modela
517
- openaiModels: [
518
- "gpt-5.5",
519
- "gpt-5.4",
520
- "gpt-5.4-mini",
521
- "gpt-5.4-nano",
522
- "gpt-4.1-mini",
523
- "gpt-4o-mini"
524
- ],
525
-
526
- init() {
527
- this.loadSettings();
528
- this.populateModels();
529
- this.bindEvents();
530
- this.setupPWAInstall();
531
- },
532
-
533
- loadSettings() {
534
- const saved = localStorage.getItem('agentscope_settings');
535
- if (saved) {
536
- try {
537
- const parsed = JSON.parse(saved);
538
- // Spoji sa defaultima da stariji zapisi (npr. prazan systemPrompt) ne pokvare UI
539
- this.config = { ...this.config, ...parsed };
540
- if (!this.config.systemPrompt) {
541
- this.config.systemPrompt = 'Ti si pomoćni asistent.';
542
- }
543
- } catch (e) {
544
- console.error('Neispravne sačuvane postavke, koristim default.', e);
545
- }
546
- UI.providerSelect.value = this.config.provider;
547
- UI.apiKeyInput.value = this.config.apiKey;
548
- UI.systemPromptInput.value = this.config.systemPrompt;
549
- this.updateModelList();
550
- }
551
- },
552
-
553
- saveSettings() {
554
- this.config.provider = UI.providerSelect.value;
555
- this.config.apiKey = UI.apiKeyInput.value.trim();
556
- this.config.systemPrompt = UI.systemPromptInput.value;
557
- localStorage.setItem('agentscope_settings', JSON.stringify(this.config));
558
-
559
- this.updateModelList();
560
-
561
- UI.modal.classList.remove('open');
562
- this.addSystemMessage("Postavke spremljene.");
563
- },
564
-
565
- clearSettings() {
566
- localStorage.removeItem('agentscope_settings');
567
- this.config = {
568
- provider: 'huggingface',
569
- apiKey: '',
570
- model: '',
571
- systemPrompt: 'Ti si pomoćni asistent.'
572
- };
573
- UI.providerSelect.value = this.config.provider;
574
- UI.apiKeyInput.value = '';
575
- UI.systemPromptInput.value = this.config.systemPrompt;
576
- this.updateModelList();
577
- this.addSystemMessage('Sačuvane postavke (uklj. API ključ) su obrisane.');
578
- },
579
-
580
- updateModelList() {
581
- UI.modelSelect.innerHTML = '';
582
- const models = this.config.provider === 'huggingface' ? this.freeModels : this.openaiModels;
583
-
584
- models.forEach(m => {
585
- const opt = document.createElement('option');
586
- opt.value = m;
587
- opt.textContent = m;
588
- UI.modelSelect.appendChild(opt);
589
- });
590
-
591
- // Set default model if not set
592
- if (!this.config.model || !models.includes(this.config.model)) {
593
- this.config.model = models[0];
594
- }
595
- },
596
-
597
- populateModels() {
598
- this.updateModelList();
599
- },
600
-
601
- bindEvents() {
602
- // Textarea auto-resize
603
- UI.userInput.addEventListener('input', function() {
604
- this.style.height = 'auto';
605
- this.style.height = (this.scrollHeight) + 'px';
606
- UI.sendBtn.disabled = this.value.trim() === '';
607
- });
608
-
609
- // Send on Enter (but Shift+Enter for new line)
610
- UI.userInput.addEventListener('keydown', (e) => {
611
- if (e.key === 'Enter' && !e.shiftKey) {
612
- e.preventDefault();
613
- this.sendMessage();
614
- }
615
- });
616
-
617
- UI.sendBtn.addEventListener('click', () => this.sendMessage());
618
-
619
- // Modal controls
620
- UI.openSettingsBtn.addEventListener('click', () => UI.modal.classList.add('open'));
621
- UI.closeSettingsBtn.addEventListener('click', () => UI.modal.classList.remove('open'));
622
- UI.saveSettingsBtn.addEventListener('click', () => this.saveSettings());
623
- UI.clearSettingsBtn.addEventListener('click', () => this.clearSettings());
624
-
625
- // PWA Install
626
- window.addEventListener('beforeinstallprompt', (e) => {
627
- e.preventDefault();
628
- UI.installPrompt.style.display = 'block';
629
- UI.installBtn.addEventListener('click', () => {
630
- UI.installPrompt.style.display = 'none';
631
- e.prompt();
632
- });
633
- });
634
- },
635
-
636
- setupPWAInstall() {
637
- window.addEventListener('appinstalled', () => {
638
- UI.installPrompt.style.display = 'none';
639
- });
640
- },
641
-
642
- addUserMessage(text) {
643
- const div = document.createElement('div');
644
- div.className = 'message user';
645
- div.textContent = text;
646
- UI.chatContainer.appendChild(div);
647
- this.scrollToBottom();
648
- },
649
-
650
- addAIMessage(text) {
651
- const div = document.createElement('div');
652
- div.className = 'message ai';
653
- div.textContent = text;
654
- UI.chatContainer.appendChild(div);
655
- this.scrollToBottom();
656
- },
657
-
658
- addSystemMessage(text) {
659
- const div = document.createElement('div');
660
- div.className = 'message system';
661
- div.textContent = text;
662
- UI.chatContainer.appendChild(div);
663
- this.scrollToBottom();
664
- },
665
-
666
- scrollToBottom() {
667
- UI.chatContainer.scrollTop = UI.chatContainer.scrollHeight;
668
- },
669
-
670
- async sendMessage() {
671
- const text = UI.userInput.value.trim();
672
- if (!text) return;
673
-
674
- // Reset Input
675
- UI.userInput.value = '';
676
- UI.userInput.style.height = 'auto';
677
- UI.sendBtn.disabled = true;
678
-
679
- // UI Updates
680
- this.addUserMessage(text);
681
- UI.loadingSpinner.style.display = 'block';
682
- UI.sendIcon.style.display = 'none';
683
- UI.sendBtn.disabled = true;
684
-
685
- // Dodaj korisničku poruku u historiju razgovora (koristi se kao kontekst za API)
686
- this.messages.push({ role: 'user', content: text });
687
-
688
- try {
689
- const { provider, apiKey, model, systemPrompt } = this.config;
690
-
691
- if (!apiKey) {
692
- throw new Error("API Ključ nije postavljen. Idite u Postavke.");
693
- }
694
-
695
- // Oba providera (HuggingFace Inference Providers i OpenAI) koriste
696
- // isti OpenAI-kompatibilan /v1/chat/completions format, pa se poziv
697
- // gradi jednom i samo se menja endpoint/parametar za max tokene.
698
- const endpoint = provider === 'huggingface'
699
- ? 'https://router.huggingface.co/v1/chat/completions'
700
- : 'https://api.openai.com/v1/chat/completions';
701
-
702
- const payload = {
703
- model: model,
704
- messages: [
705
- { role: "system", content: systemPrompt || "Ti si pomoćni asistent." },
706
- ...this.messages
707
- ]
708
- };
709
-
710
- // Novije OpenAI modele (gpt-5.x) treba pozivati sa max_completion_tokens;
711
- // HuggingFace router prihvata standardni max_tokens.
712
- if (provider === 'openai') {
713
- payload.max_completion_tokens = 500;
714
- } else {
715
- payload.max_tokens = 500;
716
- }
717
-
718
- const response = await fetch(endpoint, {
719
- method: 'POST',
720
- headers: {
721
- 'Content-Type': 'application/json',
722
- 'Authorization': `Bearer ${apiKey}`
723
- },
724
- body: JSON.stringify(payload)
725
- });
726
-
727
- const data = await response.json().catch(() => ({}));
728
-
729
- if (!response.ok) {
730
- const providerName = provider === 'huggingface' ? 'HuggingFace' : 'OpenAI';
731
- throw new Error(`${providerName} Error: ${data.error?.message || response.status}`);
732
- }
733
-
734
- const responseText = data.choices?.[0]?.message?.content;
735
- if (!responseText) {
736
- throw new Error("Neočekivan format odgovora.");
737
- }
738
-
739
- // Dodaj AI odgovor u historiju da bi sledeća poruka imala kontekst
740
- this.messages.push({ role: 'assistant', content: responseText });
741
-
742
- // Ograniči historiju da poziv ne raste u nedogled (zadrži zadnjih 20 poruka)
743
- if (this.messages.length > 20) {
744
- this.messages = this.messages.slice(-20);
745
- }
746
-
747
- this.addAIMessage(responseText);
748
-
749
- } catch (error) {
750
- console.error(error);
751
- this.addSystemMessage("Greška: " + error.message);
752
- } finally {
753
- UI.loadingSpinner.style.display = 'none';
754
- UI.sendIcon.style.display = 'block';
755
- UI.sendBtn.disabled = UI.userInput.value.trim() === '';
756
- }
757
- }
758
- };
759
-
760
- // Start App
761
- document.addEventListener('DOMContentLoaded', () => {
762
- App.init();
763
- });
764
-
765
- </script>
766
- </body>
767
- </html>