### Android Install Script
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/README.md
Command to install the AI engine on Android via Termux.
```bash
bash Android/install.sh
```
--------------------------------
### Local Fonts Definition
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Defines local font faces for 'Inter' and 'JetBrains Mono' using WOFF2 format, intended to be installed by a platform installer.
```css
@font-face {
font-family: 'Inter';
src: url('./vendor/Inter-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('./vendor/Inter-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('./vendor/Inter-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('./vendor/Inter-Bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('./vendor/JetBrainsMono-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('./vendor/JetBrainsMono-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
```
--------------------------------
### Initialization Function
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
The main initialization function that sets up the UI, loads data, and binds event listeners.
```javascript
async function init() {
setupMarked();
applyTheme(S.theme);
if (!S.sbOpen) D.sb.classList.add('off');
await loadGlobalPrompt();
await fetchModels();
await load();
renderSB();
renderChat();
bind();
if (S.convs.length > 0) switchConv(S.convs[0].id);
pollHW();
setInterval(pollHW, 5000);
setInterval(fetchModels, 15000);
}
```
--------------------------------
### Event Listeners and Initialization
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Sets up event listeners for various UI elements like theme toggling, clearing messages, file attachments, and predefined prompts. It also includes the initialization function call.
```javascript
k', toggleTheme);
D.thSb.addEventListener('click', toggleTheme);
D.ca.addEventListener('click', () => {
if (!S.streaming)
clearAll();
});
D.att.addEventListener('click', () => D.fInp.click());
D.fInp.addEventListener('change', async (e) => {
await handleAttach(e.target.files);
e.target.value = '';
});
$$('.sc').forEach((c) => c.addEventListener('click', () => {
const p = c.dataset.prompt;
if (p)
sendMsg(p);
}),
);
// Panel toggles
D.modelBtn.addEventListener('click', (e) => {
e.stopPropagation();
toggleModelMenu();
D.sysPanel.classList.remove('open');
});
D.sysBtn.addEventListener('click', (e) => {
e.stopPropagation();
D.sysPanel.classList.toggle('open');
toggleModelMenu(false);
});
D.logModeSel.addEventListener('change', saveLogMode);
D.sysSet.addEventListener('click', saveGlobalPrompt);
D.sysClr.addEventListener('click', clearGlobalPrompt);
document.addEventListener('click', (e) => {
if (!D.modelDd.contains(e.target))
toggleModelMenu(false);
if (!D.sysPanel.contains(e.target) && !D.sysBtn.contains(e.target))
D.sysPanel.classList.remove('open');
});
window.addEventListener('resize', () => {
if (window.innerWidth <= 768 && S.sbOpen)
toggleSB(false);
});
// Drag-and-drop (image / PDF / text files)
const mainEl = document.getElementById('main');
mainEl.addEventListener('dragover', (e) => {
e.preventDefault();
mainEl.classList.add('drag-over');
});
mainEl.addEventListener('dragleave', () =>
mainEl.classList.remove('drag-over'),
);
mainEl.addEventListener('drop', (e) => {
e.preventDefault();
mainEl.classList.remove('drag-over');
handleAttach(e.dataTransfer.files);
});
init();
```
--------------------------------
### Get current conversation
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Retrieves the current conversation object from the state based on the current conversation ID.
```javascript
function getConv() {
return S.convs.find((c) => c.id === S.curId);
}
```
--------------------------------
### Load Global Prompt
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Loads the global system prompt and log mode from either server settings or local storage.
```javascript
async function loadGlobalPrompt() {
if (IS_SERVED) {
try {
const r = await fetch('/api/settings');
if (r.ok) {
const s = await r.json();
S.globalSys = s.globalSystemPrompt || '';
S.logMode = s.logMode === 'all' ? 'all' : 'errors_only';
}
} catch {}
} else {
S.globalSys = localStorage.getItem('globalSystemPrompt') || '';
S.logMode = localStorage.getItem('logMode') || 'errors_only';
}
updateSysUI();
}
```
--------------------------------
### Markdown Rendering with Code Highlighting
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Configures the 'marked' library to render markdown, specifically customizing the code block rendering to include syntax highlighting using highlight.js and adding a copy button.
```javascript
function setupMarked() { if (typeof marked === 'undefined') return; const rdr = new marked.Renderer(); rdr.code = (code, lang) => { const sl = esc(lang || ''); const dl = sl || 'code'; let hi = esc(code); if (typeof hljs !== 'undefined') { try { hi = lang && hljs.getLanguage(lang) ? hljs.highlight(code, { language: lang }).value : hljs.highlightAuto(code).value; } catch {} } return
`
`; }; marked.setOptions({ gfm: true, breaks: true, renderer: rdr }); } function renderMd(text) { if (typeof marked === 'undefined') return esc(text).replace(/\n/g, '
'); return marked.parse(text, { breaks: true }); }
```
--------------------------------
### Layout Shell
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Defines the main application layout using flexbox to create a full-viewport container with a sidebar.
```css
#app {
display: flex;
height: 100vh;
width: 100vw;
overflow: hidden;
}
```
--------------------------------
### Configuration Constants
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Defines constants for server serving status, Ollama endpoint, vision models, and application state.
```javascript
const IS_SERVED = location.protocol === 'http:' || location.protocol === 'https:';
const OLLAMA = IS_SERVED ? '/ollama' : 'http://127.0.0.1:11434';
const VISION_MODELS = [
'llava',
'moondream',
'bakllava',
'vision',
'minicpm-v',
'cogvlm',
'qwen-vl',
'phi-3-vision',
];
const S = {
convs: [],
curId: null,
theme: localStorage.getItem('g-theme') || 'dark',
sbOpen: window.innerWidth > 768,
streaming: false,
abort: null,
models: [],
model: localStorage.getItem('g-model') || '',
globalSys: '',
logMode: localStorage.getItem('logMode') || 'errors_only',
// Attachments (multi-file)
attachments: [],
};
```
--------------------------------
### Responsive Design Media Queries
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS media queries for adjusting the layout on smaller screens (max-width: 768px) and for reduced motion.
```css
/* RESPONSIVE */
@media (max-width: 768px) {
#sidebar {
position: fixed;
left: 0;
top: 0;
height: 100%;
}
#sidebar.off {
transform: translateX(-100%);
}
.sg {
grid-template-columns: 1fr;
}
.usr .mc {
max-width: 88%;
}
.wt {
font-size: 30px;
}
#inp-area {
padding: 6px 12px 14px;
}
#msgs {
padding: 16px 16px 12px;
}
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
```
--------------------------------
### Model Rendering
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Renders the list of available models in the UI, highlighting the currently selected model and displaying its size. It also attaches click event listeners to each model option for selection.
```javascript
function renderModelMenu() {
if (!S.models.length) return;
D.modelMenu.innerHTML = S.models
.map(
(m) =>
`
${esc(m.name)}
${(m.size / 1e9).toFixed(1)} GB
`,
)
.join('');
$$('.mm-opt').forEach((opt) => opt.addEventListener('click', (e) => {
e.stopPropagation();
const model = opt.dataset.model;
applyModel(model);
const conv = getConv();
if (conv) {
conv.model = model;
save();
}
toggleModelMenu(false);
}));
}
```
--------------------------------
### Ensure PDF.js is loaded
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Asynchronously loads the PDF.js library if it's not already available, setting up the worker source. It also handles potential loading failures.
```javascript
async function ensurePdfJs() {
if (window.pdfjsLib) return true;
if (pdfJsLoading) return new Promise((res) => {
const iv = setInterval(() => {
if (window.pdfjsLib || window._pdfFailed) {
clearInterval(iv);
res(!!window.pdfjsLib);
}
}, 100);
});
pdfJsLoading = true;
try {
const m = await import('./vendor/pdf.min.mjs');
window.pdfjsLib = m;
window.pdfjsLib.GlobalWorkerOptions.workerSrc = './vendor/pdf.worker.min.mjs';
return true;
} catch {
window._pdfFailed = true;
return false;
}
}
```
--------------------------------
### Theme Management
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Functions to apply and toggle between light and dark themes.
```javascript
function applyTheme(t) { S.theme = t; document.documentElement.setAttribute('data-theme', t); localStorage.setItem('g-theme', t); const ic = t === 'dark' ? 'fa-moon' : 'fa-sun'; D.thTop.querySelector('i').className = 'fa-solid ' + ic; D.thSb.querySelector('i').className = 'fa-solid ' + ic; }
function toggleTheme() { applyTheme(S.theme === 'dark' ? 'light' : 'dark'); }
```
--------------------------------
### File/Image Preview Bar Styles
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for displaying previews of uploaded files or images.
```css
/* File/image preview bar */
.fbar {
max-width: 740px;
width: 100%;
display: none;
gap: 10px;
flex-wrap: wrap;
}
.fbar.on {
display: flex;
padding: 10px 14px 4px;
}
.img-preview {
position: relative;
width: 60px;
height: 60px;
border-radius: 10px;
overflow: hidden;
border: 1px solid var(--bd);
}
.img-preview img {
width: 100%;
height: 100%;
object-fit: cover;
}
.pdf-preview {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 14px;
background: var(--bg3);
border-radius: 12px;
border: 1px solid var(--bd);
}
.pdf-preview .p-info {
display: flex;
flex-direction: column;
max-width: 130px;
}
.pdf-preview strong {
font-size: 12px;
color: var(--t1);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pdf-preview span {
font-size: 10px;
color: var(--t3);
}
.f-rm {
position: absolute;
top: 2px;
right: 2px;
background: rgba(0, 0, 0, 0.65);
color: #fff;
border: none;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 10px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.pdf-preview .f-rm {
position: relative;
top: 0;
right: 0;
background: transparent;
color: var(--t3);
}
.pdf-preview .f-rm:hover {
color: var(--red);
}
```
--------------------------------
### Clear Global Prompt
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Clears the global system prompt and updates the UI and storage.
```javascript
async function clearGlobalPrompt() {
S.globalSys = '';
D.sysTa.value = '';
S.logMode = D.logModeSel.value === 'all' ? 'all' : 'errors_only';
if (IS_SERVED) {
try {
await fetch('/api/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
globalSystemPrompt: '',
logMode: S.logMode,
}),
});
} catch {}
} else {
localStorage.removeItem('globalSystemPrompt');
localStorage.setItem('logMode', S.logMode);
}
updateSysUI();
toast('Default prompt cleared');
}
```
--------------------------------
### Create a new conversation
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Initializes a new chat conversation with a default title, empty messages, and the current model and system prompt settings. It then switches to this new conversation and renders the UI.
```javascript
function createConv() {
const c = {
id: gid(),
title: 'New chat',
msgs: [],
ts: Date.now(),
model: S.model,
sys: S.globalSys,
};
S.convs.unshift(c);
save();
switchConv(c.id);
renderSB();
D.inp.focus();
}
```
--------------------------------
### Code Styling
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for inline code and code blocks, including syntax highlighting and copy buttons.
```css
.mt code:not(.hljs) {
background: var(--bg3);
padding: 2px 6px;
border-radius: 6px;
font-family: 'JetBrains Mono', 'SF Mono', monospace;
font-size: 0.88em;
border: 1px solid var(--bd);
}
.cblk {
margin: 16px 0;
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--bd);
background: var(--code);
}
.cbh {
display: flex;
align-items: center;
justify-content: space-between;
padding: 9px 14px;
background: var(--bg2);
border-bottom: 1px solid var(--bd);
font-size: 12px;
color: var(--t3);
}
.cbc-btn {
background: none;
border: none;
color: var(--t3);
cursor: pointer;
font-size: 12px;
padding: 3px 8px;
border-radius: 6px;
transition: background 0.15s, color 0.15s;
display: flex;
align-items: center;
gap: 5px;
font-family: var(--font);
}
.cbc-btn:hover {
background: var(--bgh);
color: var(--t1);
}
.cblk pre {
padding: 16px;
overflow-x: auto;
margin: 0;
background: transparent !important;
}
.cblk pre code {
font-family: 'JetBrains Mono', 'SF Mono', monospace;
font-size: 13px;
line-height: 1.65;
background: transparent !important;
padding: 0;
}
```
--------------------------------
### Input Wrapper Styles
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for the main input wrapper, providing a rounded rectangle appearance and focus states.
```css
/* The main input wrapper – pill/rounded-rectangle */
.iw {
max-width: 740px;
width: 100%;
display: flex;
flex-direction: column;
background: var(--bg-inp);
border: 1px solid var(--bd);
border-radius: 22px;
transition: border-color 0.2s, box-shadow 0.2s;
overflow: visible;
position: relative;
}
.iw:focus-within, .iw.ht {
border-color: var(--bd2);
box-shadow: 0 2px 20px var(--shd);
}
```
--------------------------------
### Android Launch Script
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/README.md
Command to launch the AI engine on Android via Termux.
```bash
bash Android/start.sh
```
--------------------------------
### Launch Scripts
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/README.md
Scripts to launch the AI engine on different operating systems.
```bash
Windows/start-fast-chat.bat
```
```bash
Mac/start.command
```
```bash
Linux/start.sh
```
```bash
Android/start.sh
```
--------------------------------
### Handle PDF file upload
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Processes an uploaded PDF file by loading it using PDF.js, extracting text content from each page, and adding it as an attachment to the current conversation state.
```javascript
async function handlePdf(file) {
const ok = await ensurePdfJs();
if (!ok) return false;
try {
const buf = await file.arrayBuffer();
const pdf = await window.pdfjsLib.getDocument({ data: buf }).promise;
let text = '';
for (let i = 1; i <= pdf.numPages; i++) {
const pg = await pdf.getPage(i);
const c = await pg.getTextContent();
text += `--- Page ${i} ---\n` + c.items.map((x) => x.str).join(' ') + '\n\n';
}
S.attachments.push({
id: gid(),
type: 'doc',
kind: 'pdf',
name: file.name,
text: text.trim(),
pages: pdf.numPages,
});
return true;
} catch (e) {
return false;
}
}
```
--------------------------------
### Model Dropdown Menu Styles
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for the dropdown menu that appears when selecting a model.
```css
/* Model dropdown menu */
.model-menu {
position: absolute;
bottom: calc(100% + 8px);
left: 0;
background: var(--bg3);
border: 1px solid var(--bd);
border-radius: 16px;
padding: 6px;
min-width: 250px;
max-height: 320px;
overflow-y: auto;
z-index: 200;
box-shadow: 0 12px 36px var(--shd);
display: none;
animation: menuPop 0.15s ease;
}
.model-menu.on {
display: block;
}
@keyframes menuPop {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.mm-opt {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: 10px;
cursor: pointer;
transition: background 0.13s;
}
.mm-opt:hover {
background: var(--bgh);
}
.mm-opt.sel {
background: var(--bga);
}
.mmo-icon {
width: 28px;
height: 28px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
flex-shrink: 0;
background: linear-gradient( 135deg, var(--grad1), var(--grad2), var(--grad3) );
color: #fff;
}
.mmo-info {
flex: 1;
min-width: 0;
}
.mmo-name {
font-size: 13px;
font-weight: 500;
color: var(--t1);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mmo-desc {
font-size: 11px;
color: var(--t3);
margin-top: 1px;
}
.mmo-chk {
color: var(--grad1);
font-size: 12px;
opacity: 0;
}
.mm-opt.sel .mmo-chk {
opacity: 1;
}
```
--------------------------------
### Save Global Prompt
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Saves the current global system prompt and log mode to server settings or local storage.
```javascript
async function saveGlobalPrompt() {
S.globalSys = D.sysTa.value.trim();
S.logMode = D.logModeSel.value === 'all' ? 'all' : 'errors_only';
if (IS_SERVED) {
try {
await fetch('/api/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
globalSystemPrompt: S.globalSys,
logMode: S.logMode,
}),
});
} catch {}
} else {
localStorage.setItem('globalSystemPrompt', S.globalSys);
localStorage.setItem('logMode', S.logMode);
}
updateSysUI();
toast('Default prompt saved');
}
```
--------------------------------
### Reset and Base Styles
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Applies a universal reset for margin, padding, and box-sizing, and sets base styles for html and body including height, overflow, font, background, color, and transitions.
```css
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
font-family: var(--font);
background: var(--bg);
color: var(--t1);
font-size: 15px;
line-height: 1.6;
transition: background var(--spd), color var(--spd);
-webkit-font-smoothing: antialiased;
}
```
--------------------------------
### Handle Text file upload
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Processes an uploaded text file by reading its content and adding it as a document attachment to the current conversation state.
```javascript
async function handleText(file) {
const text = await file.text();
S.attachments.push({
id: gid(),
type: 'doc',
kind: 'text',
name: file.name,
text,
pages: 0,
});
return true;
}
```
--------------------------------
### Temperature Control CSS
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS styles for the temperature control input and label.
```css
/* temperature control */
.temp-ctrl {
margin-left: auto;
display: flex;
align-items: center;
gap: 5px;
}
.temp-lbl {
font-size: 11px;
color: var(--t3);
font-weight: 500;
}
#temp-input {
background: var(--bg3);
border: 1px solid var(--bd);
color: var(--t1);
font-size: 12px;
padding: 3px 6px;
border-radius: 6px;
width: 54px;
text-align: center;
font-family: var(--font);
}
#temp-input:focus {
outline: none;
border-color: var(--bd2);
}
```
--------------------------------
### Attachment and Action Styling
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for styling image attachments, PDF pills, and message action buttons (copy, like, dislike).
```css
.msg-img {
max-width: 280px;
border-radius: 12px;
display: block;
border: 1px solid var(--bd);
}
.msg-pdf-pill {
display: inline-flex;
align-items: center;
gap: 6px;
background: var(--bg3);
padding: 6px 12px;
border-radius: 16px;
font-size: 12px;
color: var(--t2);
border: 1px solid var(--bd);
}
.usr-attach {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 6px;
margin-top: 6px;
}
.mact {
display: flex;
gap: 1px;
margin-top: 8px;
opacity: 0;
transition: opacity 0.18s;
}
.mr:hover .mact {
opacity: 1;
}
.mab {
background: none;
border: none;
color: var(--t3);
cursor: pointer;
padding: 6px 8px;
border-radius: 8px;
font-size: 13px;
transition: background 0.15s, color 0.15s;
display: flex;
align-items: center;
gap: 4px;
}
.mab:hover {
background: var(--bgh);
color: var(--t1);
}
```
--------------------------------
### Event Bindings
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Attaches event listeners to UI elements for user interactions.
```javascript
function bind() { D.send.addEventListener('click', () => S.streaming ? stopStream() : sendMsg(D.inp.value), ); D.inp.addEventListener('input', () => { autoResize(); updateSend(); }); D.inp.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (!S.streaming) sendMsg(D.inp.value); } if (e.key === 'Escape' && S.streaming) stopStream(); }); D.nc.addEventListener('click', () => { if (!S.streaming) createConv(); }); D.sbTog.addEventListener('click', () => toggleSB()); D.ov.addEventListener('click', () => toggleSB(false)); D.thTop.addEventListener('clic' ) }
```
--------------------------------
### Markdown Styling
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS rules for rendering markdown elements like paragraphs, headings, lists, tables, and links.
```css
.mt p {
margin-bottom: 12px;
}
.mt p:last-child {
margin-bottom: 0;
}
.mt h1, .mt h2, .mt h3 {
font-weight: 600;
margin: 20px 0 10px;
color: var(--t1);
}
.mt h1 {
font-size: 1.35em;
}
.mt h2 {
font-size: 1.18em;
}
.mt h3 {
font-size: 1.06em;
}
.mt strong {
font-weight: 600;
}
.mt a {
color: var(--grad1);
text-decoration: none;
}
.mt a:hover {
text-decoration: underline;
}
.mt ul, .mt ol {
margin: 12px 0;
padding-left: 24px;
}
.mt li {
margin-bottom: 5px;
}
.mt hr {
border: none;
border-top: 1px solid var(--bd);
margin: 20px 0;
}
.mt table {
width: 100%;
border-collapse: collapse;
margin: 16px 0;
font-size: 14px;
border-radius: 10px;
overflow: hidden;
border: 1px solid var(--bd);
}
.mt th, .mt td {
padding: 8px 14px;
border: 1px solid var(--bd);
text-align: left;
}
.mt th {
background: var(--bg2);
font-weight: 600;
}
```
--------------------------------
### Set Hardware Bar
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Updates the visual representation and text content of hardware usage bars.
```javascript
function setBar(type, pct) {
const bar = $(\`#${type}-bar\]`);
const lbl = $(\`#${type}-pct\]`);
if (!bar) return;
bar.style.transform = \`scaleX(${Math.max(0, Math.min(100, pct)) / 100})\]`;
lbl.textContent = pct + '%';
lbl.className = 'hw-pct' + (pct >= 90 ? ' danger' : pct >= 70 ? ' warn' : '');
}
```
--------------------------------
### Attachment Handling
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Handles the process of attaching files (images, PDFs, text files) to the current context. It validates file types and initiates specific handlers for each type.
```javascript
async function handleAttach(files) {
const list = Array.from(files || []).filter(Boolean);
if (!list.length) return;
let added = 0;
let rejected = 0;
for (const file of list) {
const ok = await handleSingleAttachment(file);
if (ok) added++;
else rejected++;
}
if (added) {
renderAttachmentBar();
checkVisionWarn();
updateSend();
}
if (rejected) {
toast(
rejected === list.length
? 'No supported files selected'
: `${rejected} file(s) skipped`,
);
}
}
```
--------------------------------
### DOM Element References
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Provides utility functions and references to frequently used DOM elements for UI manipulation.
```javascript
const $ = (s) => document.querySelector(s);
const $$ = (s) => document.querySelectorAll(s);
const D = {
sb: $('#sidebar'),
ov: $('#overlay'),
cvList: $('#cv-list'),
welcome: $('#welcome'),
msgs: $('#msgs'),
chat: $('#chat'),
inp: $('#msg-inp'),
iw: $('#iw'),
send: $('#send-btn'),
att: $('#att-btn'),
fInp: $('#f-inp'),
fBar: $('#fbar'),
nc: $('#nc-btn'),
sbTog: $('#sb-tog'),
thTop: $('#th-top'),
thSb: $('#th-sb'),
ca: $('#ca-btn'),
toasts: $('#toasts'),
modelBtn: $('#model-btn'),
modelMenu: $('#model-menu'),
modelName: $('#model-name'),
tbTitle: $('#tb-title'),
modelDd: $('#model-dd'),
// Extensions
sysBtn: $('#sys-prompt-btn'),
sysPanel: $('#sys-panel'),
sysTa: $('#sys-ta'),
logModeSel: $('#log-mode-select'),
sysSet: $('#set-global-btn'),
sysClr: $('#clear-global-btn'),
warn: $('#vision-warn'),
warnModel: $('#warn-model'),
};
```
--------------------------------
### Tailwind Responsive Utilities
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
A minimal subset of Tailwind responsive utility classes used in this file, including 'hidden', 'sm:inline', 'md:flex', and 'md:hidden'.
```css
.hidden {
display: none !important;
}
@media (min-width: 640px) {
.sm\:inline {
display: inline !important;
}
}
@media (min-width: 768px) {
.md\:flex {
display: flex !important;
}
.md\:hidden {
display: none !important;
}
}
```
--------------------------------
### Typing Dots Animation
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for a typing indicator animation using three bouncing dots.
```css
.typ {
display: flex;
align-items: center;
gap: 5px;
padding: 8px 0 8px;
}
.typ span {
width: 7px;
height: 7px;
background: var(--t3);
border-radius: 50%;
animation: typBounce 1.4s infinite ease-in-out;
}
.typ span:nth-child(2) {
animation-delay: 0.16s;
}
.typ span:nth-child(3) {
animation-delay: 0.32s;
}
@keyframes typBounce {
0%, 60%, 100% {
transform: translateY(0);
opacity: 0.4;
}
30% {
transform: translateY(-6px);
opacity: 1;
}
}
```
--------------------------------
### Drag-and-Drop Overlay CSS
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for the drag-and-drop overlay that appears when a user drags a file over the main content area.
```css
/* Drag-and-drop overlay */
#main.drag-over::after {
content: 'Drop image, PDF or text file';
position: absolute;
inset: 0;
background: rgba(66, 133, 244, 0.1);
border: 2px dashed var(--grad1);
border-radius: var(--radius-lg);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color: var(--grad1);
font-weight: 500;
pointer-events: none;
z-index: 20;
}
#main {
position: relative;
}
```
--------------------------------
### Save Log Mode
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Saves the selected log mode to server settings or local storage.
```javascript
async function saveLogMode() {
S.logMode = D.logModeSel.value === 'all' ? 'all' : 'errors_only';
if (IS_SERVED) {
try {
await fetch('/api/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
logMode: S.logMode
}),
});
} catch {}
} else {
lo
```
--------------------------------
### Persistence - Load
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Loads conversation history from the server or local storage and sanitizes it.
```javascript
async function load() { if (IS_SERVED) { try { const r = await fetch('/api/chats'); if (r.ok) S.convs = await r.json(); } catch {} } else { try { const d = localStorage.getItem('g-convs'); if (d) S.convs = JSON.parse(d); } catch (e) { S.convs = []; } } //  Sanitize: heal any conversation that is missing required fields // (handles old schema that used `messages` instead of `msgs`, or any // partial/corrupted entries that snuck in from a previous version) S.convs = (Array.isArray(S.convs) ? S.convs : []).map((c) => ({ id: c.id || gid(), title: c.title || 'Untitled', ts: c.ts || Date.now(), model: c.model || '', sys: c.sys || '', // migrate old `messages` key  `msgs`; fall back to [] msgs: Array.isArray(c.msgs) ? c.msgs : Array.isArray(c.messages) ? c.messages : [], })); }
```
--------------------------------
### Vision Warning Styles
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for a warning message related to vision capabilities.
```css
/* Vision warning */
#vision-warn {
display: none;
align-items: center;
gap: 8px;
max-width: 740px;
width: 100%;
margin-bottom: 8px;
padding: 10px 16px;
background: rgba(253, 176, 57, 0.08);
border-radius: 10px;
font-size: 13px;
color: var(--orange);
border: 1px solid rgba(253, 176, 57, 0.2);
}
#vision-warn.on {
display: flex;
}
```
--------------------------------
### Input Area Styles
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for the main input area, including Gemini/ChatGPT style.
```css
#inp-area {
padding: 8px 20px 18px;
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
}
```
--------------------------------
### Hardware Stats Polling
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Asynchronous function to poll hardware statistics (CPU and RAM usage) from the server.
```javascript
async function pollHW() {
if (!IS_SERVED) return;
try {
const r = await fetch('/api/stats');
if (!r.ok) return;
const d = await r.json();
if (d.ram_percent === -1) return;
setBar('cpu', d.cpu_percent);
setBar('ram', d.ram_percent);
} catch {}
}
```
--------------------------------
### Font Awesome Font Path Override
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Overrides Font Awesome font paths to use local vendor files for solid and regular styles.
```css
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 900;
font-display: block;
src: url('./vendor/fa-solid-900.woff2') format('woff2');
}
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url('./vendor/fa-regular-400.woff2') format('woff2');
}
```
--------------------------------
### Toasts CSS
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS styles for toast notifications, including animations for appearing and disappearing.
```css
/* TOASTS */
#toasts {
position: fixed;
bottom: 90px;
left: 50%;
transform: translateX(-50%);
z-index: 300;
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
pointer-events: none;
}
.toast {
background: var(--tst);
color: var(--t1);
padding: 9px 20px;
border-radius: 10px;
font-size: 13px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
animation: toastIn 0.22s ease, toastOut 0.22s ease 2.2s forwards;
white-space: nowrap;
border: 1px solid var(--bd);
}
@keyframes toastIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes toastOut {
from {
opacity: 1;
}
to {
opacity: 0;
transform: translateY(-6px);
}
}
```
--------------------------------
### Persistence - Save
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Saves the current conversation state either to the server or local storage.
```javascript
let saveTimer = null;
function save() { if (IS_SERVED) { clearTimeout(saveTimer); saveTimer = setTimeout( () => fetch('/api/chats', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(S.convs), }).catch(() => {}), 800, ); } else { try { localStorage.setItem('g-convs', JSON.stringify(S.convs)); } catch (e) {} } }
```
--------------------------------
### Message Rendering
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
Renders a single message with optional actions like like/dislike and copy.
```javascript
function renderMsg(msg) { const parsed = msg.content.split('\n').map(esc).join('
'); const actions = msg.id ?
`
` : ''; return
` ${parsed || ''}
${actions}
`;
}
```
--------------------------------
### Avatar Styling
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS for styling user and AI avatars within message rows.
```css
.ma {
width: 32px;
height: 32px;
border-radius: 50%;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
margin-top: 2px;
}
.ma.ai {
background: linear-gradient( 135deg, var(--grad1), var(--grad2), var(--grad3) );
}
.ma.ai svg {
width: 16px;
height: 16px;
}
.ma.u {
background: var(--bg3);
border: 1px solid var(--bd);
font-size: 11px;
font-weight: 700;
color: var(--t2);
}
```
--------------------------------
### Streaming Chat Response Handling
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
This snippet demonstrates how to fetch a streaming response from the Ollama API, decode the chunks, parse JSON messages, and update the UI with the AI's content. It includes error handling for network issues and abort signals, as well as final rendering of markdown content.
```javascript
s.push(am); }); try { const res = await fetch(OLLAMA + '/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: conv.model, messages: apiMsgs, stream: true, options: { temperature: parseFloat(document.getElementById('temp-input')?.value) || 0.7, }, }), signal: S.abort.signal, }); if (!res.ok) throw new Error('Ollama error ' + res.status); const reader = res.body.getReader(); const dec = new TextDecoder(); if (contentEl) contentEl.innerHTML = ''; while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = dec.decode(value, { stream: true }); for (const line of chunk.split('\n')) { if (!line.trim()) continue; try { const p = JSON.parse(line); if (p.message?.content) { aiMsg.content += p.message.content; if (contentEl) contentEl.textContent = aiMsg.content; scrollEnd(); } } catch {} } } if (contentEl) { contentEl.innerHTML = renderMd(aiMsg.content); contentEl.querySelectorAll('pre code').forEach((b) => { if (!b.classList.contains('hljs')) hljs.highlightElement(b); }); } } catch (err) { if (err.name === 'AbortError') { if (aiMsg.content) { if (contentEl) contentEl.innerHTML = renderMd(aiMsg.content); } else if (contentEl) contentEl.innerHTML = '\n[Stopped]\n'; } else { if (contentEl) contentEl.innerHTML = inaly { S.streaming = false; updateSend(); save(); scrollEnd(); setTimeout(() => D.inp.focus(), 100); } }
```
--------------------------------
### Message Input and Action Buttons CSS
Source: https://github.com/techjarves/usb-uncensored-llm/blob/main/Shared/FastChatUI.html
CSS styles for the message input area and action buttons, including send and stop streaming buttons.
```css
/* Text row (textarea + action buttons) */
.text-row {
display: flex;
align-items: flex-end;
padding: 6px 8px 8px 16px;
}
#msg-inp {
flex: 1;
background: transparent;
border: none;
outline: none;
font-family: var(--font);
font-size: 15px;
color: var(--t1);
resize: none;
max-height: 200px;
line-height: 1.55;
padding: 6px 4px;
}
#msg-inp::placeholder {
color: var(--t3);
}
/* Action buttons row */
.ia {
display: flex;
align-items: center;
gap: 3px;
flex-shrink: 0;
}
/* Icon button base */
.ib2 {
background: none;
border: none;
color: var(--t3);
cursor: pointer;
padding: 8px;
border-radius: 50%;
font-size: 15px;
transition: background 0.15s, color 0.15s;
display: flex;
align-items: center;
justify-content: center;
}
.ib2:hover {
background: var(--bgh);
color: var(--t1);
}
/* Send button */
.sbtn {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--bd);
color: var(--bg);
transition: background 0.2s, transform 0.12s;
font-size: 14px;
}
.sbtn.on {
background: var(--t1);
cursor: pointer;
}
.sbtn.on:hover {
transform: scale(1.06);
}
.sbtn.on:active {
transform: scale(0.94);
}
/* Stop streaming button */
.stbtn {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--t1);
color: var(--bg);
cursor: pointer;
font-size: 13px;
transition: background 0.2s;
border: none;
}
.stbtn:hover {
opacity: 0.85;
}
```