wiki-pathology at DuckDuckGo
Pathology
Pathology is the study of disease. The word pathology also refers to the study of disease in general, incorporating a wide range of biology research fields and medical practices. More at Wikipedia
Content fetched from html.duckduckgo.com
#awc-container {
--bg: #09090b; --surface: #18181b; --primary: #6366f1; --accent: #10b981; --danger: #ef4444;
--text: #f4f4f5; --muted: #a1a1aa;
font-family: 'Inter', sans-serif; background: var(--bg); color: var(--text);
height: 600px; width: 100%; max-width: 800px; margin: 40px auto; border-radius: 12px;
overflow: hidden; position: relative; display: flex; flex-direction: column;
box-shadow: 0 10px 30px rgba(0,0,0,0.5); border: 1px solid #27272a;
}
#awc-loader { position: absolute; inset: 0; background: var(--bg); z-index: 100; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.awc-ring { width: 40px; height: 40px; border: 3px solid var(--surface); border-top-color: var(--primary); border-radius: 50%; animation: awc-spin 1s linear infinite; margin-bottom: 15px; }
@keyframes awc-spin { to { transform: rotate(360deg); } }
#awc-app { display:none; height:100%; flex-direction:column; }
#awc-header { padding: 10px 15px; background: rgba(24, 24, 27, 0.95); border-bottom: 1px solid #27272a; display: flex; justify-content: space-between; align-items: center; }
/* Fine-Tuning Panel */
#awc-finetune-panel {
background: #18181b; border-bottom: 1px solid #27272a; padding: 10px 15px;
display: flex; gap: 10px; align-items: center; font-size: 12px;
}
#awc-bias-input {
background: #09090b; border: 1px solid #3f3f46; color: white; padding: 5px 10px;
border-radius: 4px; flex-grow: 1; font-family: 'JetBrains Mono', monospace;
}
#awc-set-bias-btn {
background: var(--primary); color: white; border: none; padding: 5px 10px;
border-radius: 4px; cursor: pointer; font-size: 11px; text-transform: uppercase;
}
#awc-visualizer { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; background: radial-gradient(circle at center, #1e1e24 0%, #09090b 70%); }
.awc-avatar { width: 80px; height: 80px; border-radius: 50%; background: linear-gradient(135deg, #312e81, #4338ca); display: flex; align-items: center; justify-content: center; font-size: 28px; transition: all 0.3s; }
.awc-avatar.listening { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0.2); background: #ef4444; transform: scale(1.1); }
.awc-avatar.speaking { box-shadow: 0 0 20px 5px rgba(16, 185, 129, 0.3); animation: awc-breathe 2s infinite; }
@keyframes awc-breathe { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } }
#awc-transcript { margin-top: 15px; text-align: center; padding: 0 20px; font-size: 14px; min-height: 40px; color: #e4e4e7; max-width: 90%; }
#awc-footer { padding: 15px; background: #18181b; border-top: 1px solid #27272a; display: flex; justify-content: center; gap: 15px; }
.awc-btn { width: 45px; height: 45px; border-radius: 50%; border: none; cursor: pointer; color: white; font-size: 18px; display: flex; align-items: center; justify-content: center; transition: transform 0.2s; background: #27272a; border: 1px solid #3f3f46; }
.awc-btn.active { background: var(--danger); border-color: var(--danger); animation: awc-pulse-red 1.5s infinite; }
@keyframes awc-pulse-red { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } }
.awc-status-pill { font-size: 10px; padding: 3px 8px; border-radius: 20px; background: #27272a; display: flex; gap: 5px; align-items: center; text-transform: uppercase; letter-spacing: 0.5px; }
.awc-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }
.awc-dot.busy { background: var(--primary); animation: awc-pulse 1s infinite; }
<div id="awc-container">
<div id="awc-loader">
<div class="awc-ring"></div>
<div style="font-size:12px;color:var(--muted)" id="awc-load-text">Initializing Whisper Engine...</div>
</div>
<div id="awc-app">
<!-- Fine-Tuning / Biasing Header -->
<div id="awc-finetune-panel">
<span style="color:var(--muted);white-space:nowrap">π§ Vocabulary Bias:</span>
<button id="awc-set-bias-btn">Update</button>
</div>
<div id="awc-header">
<span style="font-weight:600;font-size:14px">π Context Assistant</span>
<div class="awc-status-pill">
<div class="awc-dot" id="awc-status-dot"></div>
<span id="awc-status-text">IDLE</span>
</div>
</div>
<div id="awc-visualizer">
<div class="awc-avatar" id="awc-avatar">π€</div>
<div id="awc-transcript">Tap microphone to speak...</div>
</div>
<div id="awc-footer">
<button class="awc-btn" id="awc-mic" title="Speak">π€</button>
</div>
</div>
</div>
import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.0';
import * as webllm from "https://esm.run/@mlc-ai/web-llm";
// --- CONFIGURATION ---
const WHISPER_MODEL = "Xenova/whisper-tiny.en"; // Tiny English for speed
const LLM_MODEL = "SmolLM2-360M-Instruct-q4f16_1-MLC";
// --- STATE ---
let transcriber = null;
let llmEngine = null;
let isLoaded = false;
let isListening = false;
let isSpeaking = false;
let mediaRecorder = null;
let audioChunks = [];
let synth = window.speechSynthesis;
let conversationHistory = [];
let vocabularyHint = document.getElementById('awc-bias-input').value;
// --- DOM ELEMENTS ---
const els = {
loader: document.getElementById('awc-loader'),
loadText: document.getElementById('awc-load-text'),
app: document.getElementById('awc-app'),
micBtn: document.getElementById('awc-mic'),
avatar: document.getElementById('awc-avatar'),
transcript: document.getElementById('awc-transcript'),
statusDot: document.getElementById('awc-status-dot'),
statusText: document.getElementById('awc-status-text'),
biasInput: document.getElementById('awc-bias-input'),
setBiasBtn: document.getElementById('awc-set-bias-btn')
};
// --- INITIALIZATION ---
async function init() {
try {
// Load Whisper
els.loadText.innerText = "Loading Whisper ASR...";
transcriber = await pipeline('automatic-speech-recognition', WHISPER_MODEL);
// Load LLM
els.loadText.innerText = "Loading Neural Core...";
llmEngine = await webllm.CreateMLCEngine(LLM_MODEL, {
initProgressCallback: (p) => {
if(p.progress === 1 && !isLoaded) finishLoading();
}
});
} catch (e) {
console.error(e);
els.loadText.innerText = "Error loading models. Falling back to System Speech...";
fallbackToSystemSpeech();
}
}
function finishLoading() {
isLoaded = true;
els.loader.style.display = 'none';
els.app.style.display = 'flex';
// Set Initial Persona
const pageTitle = document.querySelector('h1') ? document.querySelector('h1').innerText : "General Topic";
conversationHistory.push({
role: "system",
content: `You are an expert assistant discussing "${pageTitle}". Use concise language.`
});
}
// --- FALLBACK SYSTEM SPEECH ---
let systemRecognition = null;
function fallbackToSystemSpeech() {
if ('webkitSpeechRecognition' in window) {
systemRecognition = new webkitSpeechRecognition();
systemRecognition.continuous = false;
systemRecognition.lang = 'en-US';
systemRecognition.onresult = (e) => handleUserMessage(e.results[0][0].transcript);
systemRecognition.onend = () => {
isListening = false;
els.micBtn.classList.remove('active');
els.avatar.classList.remove('listening');
};
els.loader.style.display = 'none';
els.app.style.display = 'flex';
els.loadText.innerText = "System Speech Ready";
setTimeout(finishLoading, 1000); // Still try to load LLM in background
} else {
els.loadText.innerText = "Browser not supported.";
}
}
// --- RECORDING LOGIC (WHISPER) ---
els.micBtn.onclick = async () => {
if (!isLoaded && !systemRecognition) return;
if (isListening) {
stopRecording();
} else {
startRecording();
}
};
async function startRecording() {
isListening = true;
audioChunks = [];
els.micBtn.classList.add('active');
els.avatar.classList.add('listening');
setStatus("LISTENING", "busy");
els.transcript.innerText = "Listening...";
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = e => audioChunks.push(e.data);
mediaRecorder.onstop = () => processAudio();
mediaRecorder.start();
} catch (err) {
console.error(err);
setStatus("ERROR", "");
isListening = false;
}
}
function stopRecording() {
if (mediaRecorder && mediaRecorder.state === 'recording') {
mediaRecorder.stop();
mediaRecorder.stream.getTracks().forEach(track => track.stop());
} else if (systemRecognition) {
systemRecognition.stop();
}
}
async function processAudio() {
setStatus("TRANSCRIBING", "busy");
els.avatar.classList.remove('listening');
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
const audioURL = URL.createObjectURL(audioBlob);
try {
// Use Vocabulary Hint for Biasing
const result = await transcriber(audioURL, {
language: "english",
task: "transcribe",
// This is the "Fine-Tuning" simulation via decoding hints
language_detection_hint: vocabularyHint
});
const text = result.text.trim();
els.transcript.innerText = text;
handleUserMessage(text);
} catch (e) {
console.error(e);
els.transcript.innerText = "Transcription failed.";
} finally {
URL.revokeObjectURL(audioURL);
}
}
// --- AGENT LOGIC ---
async function handleUserMessage(text) {
if(!llmEngine) return; // Wait for LLM if using Whisper
setStatus("THINKING", "busy");
conversationHistory.push({ role: "user", content: text });
try {
const stream = await llmEngine.chat.completions.create({
messages: conversationHistory,
stream: true,
temperature: 0.7
});
let fullResponse = "";
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content || "";
fullResponse += delta;
els.transcript.innerText = fullResponse;
}
speak(fullResponse);
conversationHistory.push({ role: "assistant", content: fullResponse });
} catch (e) {
els.transcript.innerText = "LLM Error: " + e.message;
}
}
// --- TEXT TO SPEECH ---
function speak(text) {
if (!text) return;
synth.cancel();
const utterance = new SpeechSynthesisUtterance(text);
utterance.rate = 1.1;
utterance.onstart = () => {
isSpeaking = true;
els.avatar.classList.add('speaking');
setStatus("SPEAKING", "busy");
};
utterance.onend = () => {
isSpeaking = false;
els.avatar.classList.remove('speaking');
setStatus("IDLE", "");
};
synth.speak(utterance);
}
// --- BIASING UI ---
els.setBiasBtn.onclick = () => {
vocabularyHint = els.biasInput.value;
els.setBiasBtn.innerText = "Saved!";
setTimeout(() => els.setBiasBtn.innerText = "Update", 2000);
};
function setStatus(text, type) {
els.statusText.innerText = text;
els.statusDot.className = `awc-dot ${type}`;
}
// Start
init();