mihailik commited on
Commit
24b4542
·
1 Parent(s): 65c899d

Another try.

Browse files
Files changed (1) hide show
  1. chat3.html +69 -64
chat3.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
- <title>AI Chat App</title>
7
  <style>
8
  body {
9
  margin: 0;
@@ -13,16 +13,11 @@
13
  height: 100vh;
14
  background: #f5f5f5;
15
  }
16
- header {
17
- padding: 10px;
18
- background: #333;
19
- color: white;
20
- text-align: center;
21
- }
22
  #model-select {
23
- width: 100%;
24
  padding: 10px;
25
  font-size: 1em;
 
 
26
  }
27
  #chat {
28
  flex: 1;
@@ -35,13 +30,14 @@
35
  padding: 10px;
36
  border-radius: 5px;
37
  max-width: 80%;
 
38
  }
39
  .user {
40
  background: #d1e7dd;
41
  align-self: flex-end;
42
  }
43
  .bot {
44
- background: #e2e3e5;
45
  align-self: flex-start;
46
  }
47
  #input-area {
@@ -67,9 +63,6 @@
67
  </style>
68
  </head>
69
  <body>
70
- <header>
71
- <h1>AI Chat App</h1>
72
- </header>
73
  <select id="model-select">
74
  <option value="Xenova/distilgpt2">Xenova/distilgpt2</option>
75
  <option value="Xenova/phi-3-mini-4k-instruct">Xenova/phi-3-mini-4k-instruct</option>
@@ -81,23 +74,55 @@
81
  <div id="status">Select a model to begin</div>
82
  <div id="chat"></div>
83
  <div id="input-area">
84
- <input type="text" id="user-input" placeholder="Type your message..." />
85
  <button id="send-btn">Send</button>
86
  </div>
87
 
88
  <script type="module">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  const chat = document.getElementById('chat');
90
  const input = document.getElementById('user-input');
91
  const sendBtn = document.getElementById('send-btn');
92
  const modelSelect = document.getElementById('model-select');
93
  const status = document.getElementById('status');
94
 
95
- let worker;
96
- let busy = false;
97
 
98
  function appendMessage(text, sender) {
99
  const msg = document.createElement('div');
100
- msg.className = `message ${sender}`;
101
  msg.textContent = text;
102
  chat.appendChild(msg);
103
  chat.scrollTop = chat.scrollHeight;
@@ -107,63 +132,41 @@
107
  status.textContent = text;
108
  }
109
 
110
- function initWorker(model) {
111
- if (worker) worker.terminate();
112
- setStatus('Loading model...');
113
- busy = true;
114
- worker = new Worker(URL.createObjectURL(new Blob([`
115
- importScripts('https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0/dist/transformers.min.js');
116
-
117
- let pipeline;
118
- self.onmessage = async (e) => {
119
- const { type, data } = e.data;
120
- try {
121
- if (type === 'load') {
122
- pipeline = await window.transformers.pipeline('text-generation', data.model, { progress_callback: (x) => self.postMessage({ type: 'progress', data: x }) });
123
- self.postMessage({ type: 'ready' });
124
- } else if (type === 'generate') {
125
- const output = await pipeline(data.text, { max_new_tokens: 100 });
126
- self.postMessage({ type: 'response', data: output[0].generated_text });
127
- }
128
- } catch (err) {
129
- self.postMessage({ type: 'error', data: err.stack });
130
- }
131
- };
132
- `], { type: 'application/javascript' })));
133
 
134
- worker.onmessage = (e) => {
135
- const { type, data } = e.data;
136
- if (type === 'ready') {
137
- setStatus('Model ready');
138
- busy = false;
139
- } else if (type === 'progress') {
140
- setStatus('Loading... ' + Math.round(data * 100) + '%');
141
- } else if (type === 'response') {
142
- appendMessage(data, 'bot');
143
- setStatus('Model ready');
144
- busy = false;
145
- } else if (type === 'error') {
146
- appendMessage('Error: ' + data, 'bot');
147
- setStatus('Error occurred');
148
- busy = false;
149
- }
150
- };
151
 
152
- worker.postMessage({ type: 'load', data: { model } });
153
- }
 
 
 
 
 
 
 
 
 
 
154
 
155
  modelSelect.addEventListener('change', () => {
156
- initWorker(modelSelect.value);
 
 
157
  });
158
 
159
  sendBtn.addEventListener('click', () => {
160
- if (busy) return;
161
  const text = input.value.trim();
162
  if (!text) return;
163
  appendMessage(text, 'user');
164
  input.value = '';
165
- setStatus('Generating response...');
166
- busy = true;
167
  worker.postMessage({ type: 'generate', data: { text } });
168
  });
169
 
@@ -171,8 +174,10 @@
171
  if (e.key === 'Enter') sendBtn.click();
172
  });
173
 
174
- // Load default model
175
- initWorker(modelSelect.value);
 
 
176
  </script>
177
  </body>
178
  </html>
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>Mobile Chat App with Transformers.js</title>
7
  <style>
8
  body {
9
  margin: 0;
 
13
  height: 100vh;
14
  background: #f5f5f5;
15
  }
 
 
 
 
 
 
16
  #model-select {
 
17
  padding: 10px;
18
  font-size: 1em;
19
+ width: 100%;
20
+ box-sizing: border-box;
21
  }
22
  #chat {
23
  flex: 1;
 
30
  padding: 10px;
31
  border-radius: 5px;
32
  max-width: 80%;
33
+ word-wrap: break-word;
34
  }
35
  .user {
36
  background: #d1e7dd;
37
  align-self: flex-end;
38
  }
39
  .bot {
40
+ background: #f8d7da;
41
  align-self: flex-start;
42
  }
43
  #input-area {
 
63
  </style>
64
  </head>
65
  <body>
 
 
 
66
  <select id="model-select">
67
  <option value="Xenova/distilgpt2">Xenova/distilgpt2</option>
68
  <option value="Xenova/phi-3-mini-4k-instruct">Xenova/phi-3-mini-4k-instruct</option>
 
74
  <div id="status">Select a model to begin</div>
75
  <div id="chat"></div>
76
  <div id="input-area">
77
+ <input type="text" id="user-input" placeholder="Type a message..." />
78
  <button id="send-btn">Send</button>
79
  </div>
80
 
81
  <script type="module">
82
+ import { pipeline } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0/dist/transformers.min.js';
83
+
84
+ let worker = new Worker(URL.createObjectURL(new Blob([`
85
+ importScripts('https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0/dist/transformers.min.js');
86
+
87
+ let chatPipeline = null;
88
+ let currentModel = null;
89
+
90
+ self.onmessage = async (e) => {
91
+ const { type, data } = e.data;
92
+ try {
93
+ if (type === 'load') {
94
+ self.postMessage({ type: 'status', data: 'Loading model...' });
95
+ chatPipeline = await window.pipeline('text-generation', data.model, { progress_callback: (x) => self.postMessage({ type: 'status', data: 'Progress: ' + x }) });
96
+ currentModel = data.model;
97
+ self.postMessage({ type: 'status', data: 'Model loaded: ' + currentModel });
98
+ } else if (type === 'generate') {
99
+ if (!chatPipeline) throw new Error('Model not loaded');
100
+ self.postMessage({ type: 'status', data: 'Generating response...' });
101
+ const output = await chatPipeline(data.text, { max_new_tokens: 100 });
102
+ self.postMessage({ type: 'response', data: output[0].generated_text });
103
+ self.postMessage({ type: 'status', data: 'Ready' });
104
+ }
105
+ } catch (err) {
106
+ self.postMessage({ type: 'error', data: err.stack });
107
+ }
108
+ };
109
+
110
+ self.onerror = (e) => {
111
+ self.postMessage({ type: 'error', data: e.message + '\\n' + e.filename + ':' + e.lineno });
112
+ };
113
+ `], { type: 'application/javascript' })));
114
+
115
  const chat = document.getElementById('chat');
116
  const input = document.getElementById('user-input');
117
  const sendBtn = document.getElementById('send-btn');
118
  const modelSelect = document.getElementById('model-select');
119
  const status = document.getElementById('status');
120
 
121
+ let isBusy = false;
 
122
 
123
  function appendMessage(text, sender) {
124
  const msg = document.createElement('div');
125
+ msg.className = 'message ' + sender;
126
  msg.textContent = text;
127
  chat.appendChild(msg);
128
  chat.scrollTop = chat.scrollHeight;
 
132
  status.textContent = text;
133
  }
134
 
135
+ function handleError(err) {
136
+ appendMessage('Error: ' + err, 'bot');
137
+ setStatus('Error occurred');
138
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
+ window.onerror = (msg, src, line, col, err) => {
141
+ handleError(err?.stack || msg);
142
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
+ worker.onmessage = (e) => {
145
+ const { type, data } = e.data;
146
+ if (type === 'response') {
147
+ appendMessage(data, 'bot');
148
+ isBusy = false;
149
+ } else if (type === 'status') {
150
+ setStatus(data);
151
+ } else if (type === 'error') {
152
+ handleError(data);
153
+ isBusy = false;
154
+ }
155
+ };
156
 
157
  modelSelect.addEventListener('change', () => {
158
+ const model = modelSelect.value;
159
+ isBusy = true;
160
+ worker.postMessage({ type: 'load', data: { model } });
161
  });
162
 
163
  sendBtn.addEventListener('click', () => {
164
+ if (isBusy) return;
165
  const text = input.value.trim();
166
  if (!text) return;
167
  appendMessage(text, 'user');
168
  input.value = '';
169
+ isBusy = true;
 
170
  worker.postMessage({ type: 'generate', data: { text } });
171
  });
172
 
 
174
  if (e.key === 'Enter') sendBtn.click();
175
  });
176
 
177
+ // Auto-load default model
178
+ window.addEventListener('load', () => {
179
+ modelSelect.dispatchEvent(new Event('change'));
180
+ });
181
  </script>
182
  </body>
183
  </html>