File size: 5,050 Bytes
7eab030
42442d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8c8ab5b
42442d5
 
 
 
 
 
 
 
 
 
8c8ab5b
42442d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7eab030
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Devseis Chat</title>
<style>
  :root{
    --bg:#0b0e14; --panel:#11151d; --border:#232a37; --text:#e8ecf4; --muted:#8b94a7;
    --accent:#2f6bff; --accent-text:#ffffff; --bubble-user:#1c2636; --bubble-bot:#161c27;
  }
  @media (prefers-color-scheme: light){
    :root{ --bg:#f4f6fb; --panel:#ffffff; --border:#e2e6ee; --text:#171a21; --muted:#666f80;
      --accent:#2f6bff; --accent-text:#ffffff; --bubble-user:#eaf0ff; --bubble-bot:#f1f2f5; }
  }
  *{box-sizing:border-box;}
  body{margin:0;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;height:100vh;display:flex;flex-direction:column;}
  header{display:flex;align-items:center;gap:12px;padding:14px 20px;border-bottom:1px solid var(--border);background:var(--panel);}
  header img{height:32px;width:auto;}
  header .title{font-weight:600;font-size:15px;}
  header .sub{font-size:12px;color:var(--muted);}
  main{flex:1;overflow-y:auto;padding:20px;max-width:820px;width:100%;margin:0 auto;}
  .msg{display:flex;margin-bottom:14px;}
  .msg.user{justify-content:flex-end;}
  .bubble{max-width:75%;padding:10px 14px;border-radius:14px;line-height:1.45;font-size:14.5px;white-space:pre-wrap;}
  .msg.user .bubble{background:var(--bubble-user);border-bottom-right-radius:4px;}
  .msg.bot .bubble{background:var(--bubble-bot);border-bottom-left-radius:4px;}
  .msg.bot.loading .bubble{color:var(--muted);}
  form{display:flex;gap:10px;padding:16px 20px;border-top:1px solid var(--border);background:var(--panel);max-width:820px;width:100%;margin:0 auto;}
  textarea{flex:1;resize:none;border:1px solid var(--border);background:var(--bg);color:var(--text);border-radius:10px;padding:10px 12px;font-size:14.5px;font-family:inherit;max-height:140px;}
  button{background:var(--accent);color:var(--accent-text);border:none;border-radius:10px;padding:0 18px;font-size:14px;font-weight:600;cursor:pointer;}
  button:disabled{opacity:.5;cursor:not-allowed;}
  footer{text-align:center;font-size:11px;color:var(--muted);padding:8px 0 14px;}
  a{color:var(--accent);}
</style>
</head>
<body>
<header>
  <img src="devseis-logo.png" alt="Devseis" />
  <div>
    <div class="title">Devseis Chat</div>
    <div class="sub">Free public AI chat &middot; Llama-3.2-3B</div>
  </div>
</header>
<main id="thread"></main>
<form id="form">
  <textarea id="input" rows="1" placeholder="Type a message..." autofocus></textarea>
  <button type="submit" id="send">Send</button>
</form>
<footer>Powered by an open 3B model &middot; Made by <a href="https://www.devseis.com" target="_blank" rel="noopener">Devseis</a></footer>

<script>
const WORKER_URL = "https://devseis-chat-proxy.umer-wasim.workers.dev";

const thread = document.getElementById('thread');
const form = document.getElementById('form');
const input = document.getElementById('input');
const sendBtn = document.getElementById('send');

let history = [
  { role: "system", content: "You are Devseis Chat, a friendly, helpful assistant." }
];

function addMessage(role, text, opts={}) {
  const row = document.createElement('div');
  row.className = 'msg ' + (role === 'user' ? 'user' : 'bot') + (opts.loading ? ' loading' : '');
  const bubble = document.createElement('div');
  bubble.className = 'bubble';
  bubble.textContent = text;
  row.appendChild(bubble);
  thread.appendChild(row);
  thread.scrollTop = thread.scrollHeight;
  return bubble;
}

input.addEventListener('input', () => {
  input.style.height = 'auto';
  input.style.height = Math.min(input.scrollHeight, 140) + 'px';
});

input.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    form.requestSubmit();
  }
});

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const text = input.value.trim();
  if (!text) return;
  input.value = '';
  input.style.height = 'auto';
  sendBtn.disabled = true;

  addMessage('user', text);
  history.push({ role: 'user', content: text });

  const loadingBubble = addMessage('bot', 'Thinking…', { loading: true });

  try {
    const res = await fetch(WORKER_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ messages: history })
    });
    if (!res.ok) throw new Error('Request failed: ' + res.status);
    const data = await res.json();
    const reply = data.reply || '(no response)';
    loadingBubble.parentElement.classList.remove('loading');
    loadingBubble.textContent = reply;
    history.push({ role: 'assistant', content: reply });
  } catch (err) {
    loadingBubble.parentElement.classList.remove('loading');
    loadingBubble.textContent = 'Sorry, something went wrong. Please try again in a moment.';
    console.error(err);
  } finally {
    sendBtn.disabled = false;
    input.focus();
  }
});

addMessage('bot', "Moien! I'm Devseis Chat. Ask me anything.");
</script>
</body>
</html>