|
|
<!DOCTYPE html>
|
|
|
<html lang="en">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>DeepMarkov v11: NEURO-SYMBOLIC (Math + Causal)</title>
|
|
|
<style>
|
|
|
:root {
|
|
|
--bg: #09090b;
|
|
|
--panel: #18181b;
|
|
|
--border: #27272a;
|
|
|
--accent: #8b5cf6;
|
|
|
--accent-glow: rgba(139, 92, 246, 0.2);
|
|
|
--user-color: #10b981;
|
|
|
--mem-color: #3b82f6;
|
|
|
--mood-color: #f59e0b;
|
|
|
--rag-color: #ec4899;
|
|
|
--hier-color: #a855f7;
|
|
|
--infer-color: #ef4444;
|
|
|
--morph-color: #06b6d4;
|
|
|
--vec-color: #eab308;
|
|
|
--spec-color: #ffffff;
|
|
|
--causal-color: #00ff9d;
|
|
|
--math-color: #facc15;
|
|
|
--text-main: #e4e4e7;
|
|
|
--text-dim: #a1a1aa;
|
|
|
--font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
|
|
|
}
|
|
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
|
|
body {
|
|
|
margin: 0;
|
|
|
background: var(--bg);
|
|
|
color: var(--text-main);
|
|
|
font-family: var(--font-mono);
|
|
|
height: 100vh;
|
|
|
display: flex;
|
|
|
overflow: hidden;
|
|
|
font-size: 14px;
|
|
|
}
|
|
|
|
|
|
|
|
|
.sidebar {
|
|
|
width: 340px;
|
|
|
background: var(--panel);
|
|
|
border-right: 1px solid var(--border);
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
padding: 20px;
|
|
|
gap: 20px;
|
|
|
z-index: 10;
|
|
|
}
|
|
|
|
|
|
h1 { margin: 0; color: var(--accent); font-size: 1.1em; letter-spacing: -0.5px; }
|
|
|
.version { font-size: 0.6em; color: var(--text-dim); border: 1px solid var(--border); padding: 2px 6px; border-radius: 4px; }
|
|
|
|
|
|
.control-group { display: flex; flex-direction: column; gap: 8px; }
|
|
|
|
|
|
label { font-size: 0.8em; font-weight: 600; color: var(--text-dim); }
|
|
|
|
|
|
input, button, select {
|
|
|
background: var(--bg);
|
|
|
border: 1px solid var(--border);
|
|
|
color: var(--text-main);
|
|
|
padding: 10px;
|
|
|
border-radius: 6px;
|
|
|
font-family: inherit;
|
|
|
outline: none;
|
|
|
transition: all 0.2s;
|
|
|
}
|
|
|
|
|
|
input:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-glow); }
|
|
|
|
|
|
button { cursor: pointer; font-weight: 600; background: var(--border); }
|
|
|
button:hover { background: var(--text-dim); color: var(--bg); }
|
|
|
button.primary { background: var(--accent); color: white; border: none; }
|
|
|
button.primary:hover { opacity: 0.9; }
|
|
|
|
|
|
.file-drop {
|
|
|
border: 2px dashed var(--border);
|
|
|
padding: 20px;
|
|
|
text-align: center;
|
|
|
color: var(--text-dim);
|
|
|
border-radius: 6px;
|
|
|
cursor: pointer;
|
|
|
transition: 0.2s;
|
|
|
}
|
|
|
.file-drop:hover { border-color: var(--accent); color: var(--accent); }
|
|
|
|
|
|
|
|
|
.stage {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.chat-stream {
|
|
|
flex: 1;
|
|
|
overflow-y: auto;
|
|
|
padding: 30px;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 20px;
|
|
|
}
|
|
|
|
|
|
.msg {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 4px;
|
|
|
max-width: 800px;
|
|
|
animation: slideIn 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
|
|
}
|
|
|
|
|
|
@keyframes slideIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
|
|
|
|
|
.msg.user { align-self: flex-end; align-items: flex-end; }
|
|
|
.msg.bot { align-self: flex-start; align-items: flex-start; }
|
|
|
|
|
|
.bubble {
|
|
|
padding: 12px 16px;
|
|
|
border-radius: 8px;
|
|
|
line-height: 1.6;
|
|
|
position: relative;
|
|
|
background: var(--panel);
|
|
|
border: 1px solid var(--border);
|
|
|
white-space: pre-wrap;
|
|
|
}
|
|
|
|
|
|
.msg.user .bubble { background: rgba(16, 185, 129, 0.1); border-color: var(--user-color); color: var(--user-color); }
|
|
|
.msg.bot .bubble { background: rgba(139, 92, 246, 0.1); border-color: var(--accent); color: #fff; }
|
|
|
|
|
|
.meta { font-size: 0.7em; color: var(--text-dim); opacity: 0.7; }
|
|
|
|
|
|
|
|
|
.thought-process {
|
|
|
font-size: 0.75em;
|
|
|
color: var(--text-dim);
|
|
|
margin-top: 5px;
|
|
|
padding-left: 10px;
|
|
|
border-left: 2px solid var(--border);
|
|
|
display: flex;
|
|
|
gap: 6px;
|
|
|
flex-wrap: wrap;
|
|
|
line-height: 1.8;
|
|
|
}
|
|
|
.tag { padding: 1px 5px; border-radius: 3px; background: #000; border: 1px solid #333; }
|
|
|
|
|
|
.tag.struct { color: #888; border-color: #444; }
|
|
|
.tag.word { color: var(--accent); }
|
|
|
.tag.char { color: #ec4899; }
|
|
|
.tag.mem { color: var(--mem-color); border-color: rgba(59, 130, 246, 0.4); }
|
|
|
.tag.mood { color: var(--mood-color); border-color: rgba(245, 158, 11, 0.4); }
|
|
|
.tag.rag { color: var(--rag-color); border-color: rgba(236, 72, 153, 0.4); }
|
|
|
.tag.blend { color: var(--hier-color); border-color: rgba(168, 85, 247, 0.4); }
|
|
|
.tag.infer { color: var(--infer-color); border-color: rgba(239, 68, 68, 0.4); }
|
|
|
.tag.morph { color: var(--morph-color); border-color: rgba(6, 182, 212, 0.4); }
|
|
|
.tag.vec { color: var(--vec-color); border-color: rgba(234, 179, 8, 0.4); }
|
|
|
.tag.spec { color: var(--spec-color); border-color: rgba(255, 255, 255, 0.4); text-shadow: 0 0 5px white; }
|
|
|
.tag.causal { color: var(--causal-color); border-color: rgba(0, 255, 157, 0.4); text-shadow: 0 0 5px var(--causal-color); }
|
|
|
.tag.math { color: var(--math-color); border-color: rgba(250, 204, 21, 0.4); text-shadow: 0 0 5px var(--math-color); }
|
|
|
|
|
|
|
|
|
.input-box {
|
|
|
padding: 20px;
|
|
|
background: var(--panel);
|
|
|
border-top: 1px solid var(--border);
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
textarea {
|
|
|
flex: 1;
|
|
|
background: var(--bg);
|
|
|
border: 1px solid var(--border);
|
|
|
border-radius: 6px;
|
|
|
padding: 12px;
|
|
|
color: white;
|
|
|
resize: none;
|
|
|
height: 50px;
|
|
|
font-family: inherit;
|
|
|
}
|
|
|
textarea:focus { border-color: var(--accent); outline: none; }
|
|
|
|
|
|
|
|
|
.stats-grid {
|
|
|
display: grid;
|
|
|
grid-template-columns: 1fr 1fr;
|
|
|
gap: 10px;
|
|
|
font-size: 0.8em;
|
|
|
color: var(--text-dim);
|
|
|
background: rgba(0,0,0,0.3);
|
|
|
padding: 10px;
|
|
|
border-radius: 6px;
|
|
|
}
|
|
|
|
|
|
|
|
|
.spectral-indicator {
|
|
|
height: 4px;
|
|
|
background: #333;
|
|
|
margin-top: 4px;
|
|
|
border-radius: 2px;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
.spectral-bar {
|
|
|
height: 100%;
|
|
|
background: white;
|
|
|
width: 0%;
|
|
|
transition: width 0.3s;
|
|
|
box-shadow: 0 0 10px white;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
|
|
|
<div class="sidebar">
|
|
|
<div style="display:flex; justify-content:space-between; align-items:center;">
|
|
|
<h1>DeepMarkov <span class="version">SYMBOLIC</span></h1>
|
|
|
</div>
|
|
|
|
|
|
<div class="control-group">
|
|
|
<label>1. Identity Name</label>
|
|
|
<input type="text" id="botName" value="Mita">
|
|
|
</div>
|
|
|
|
|
|
<div class="control-group">
|
|
|
<label>2. Training Data</label>
|
|
|
<div class="file-drop" onclick="document.getElementById('trainFile').click()">
|
|
|
<span id="fileLabel">Click to Upload .txt</span>
|
|
|
<input type="file" id="trainFile" accept=".txt" style="display:none">
|
|
|
</div>
|
|
|
<div id="trainStatus" style="font-size:0.7em;">No brain loaded.</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="control-group">
|
|
|
<label>3. Model State</label>
|
|
|
<div style="display:flex; gap:5px">
|
|
|
<button onclick="engine.save()" style="flex:1">Save JSON</button>
|
|
|
<button onclick="document.getElementById('loadJson').click()" style="flex:1">Load JSON</button>
|
|
|
<input type="file" id="loadJson" accept=".json" style="display:none">
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<hr style="width:100%; border:0; border-top:1px solid var(--border);">
|
|
|
|
|
|
<div class="control-group">
|
|
|
<h2>Cognitive Params</h2>
|
|
|
<label title="Vector Search Strength">Associative Memory (RAG)</label>
|
|
|
<input type="range" id="memWeight" min="0" max="10" step="0.5" value="5.0">
|
|
|
|
|
|
<label title="Context Persistence (Step C Strength)">Vector Influence</label>
|
|
|
<input type="range" id="vecWeight" min="0" max="10" step="0.5" value="6.0">
|
|
|
|
|
|
<label title="Krylov Spectral Steering Strength">Spectral Guidance</label>
|
|
|
<input type="range" id="specWeight" min="0" max="20" step="1.0" value="10.0">
|
|
|
<div class="spectral-indicator"><div class="spectral-bar" id="specBar"></div></div>
|
|
|
|
|
|
<label title="Strictness of Logic">Creativity (Temp)</label>
|
|
|
<input type="range" id="temp" min="0.1" max="1.5" step="0.1" value="0.6">
|
|
|
|
|
|
<label title="Prevent loops">Repetition Penalty</label>
|
|
|
<input type="range" id="repPen" min="1.0" max="3.0" step="0.1" value="1.5">
|
|
|
</div>
|
|
|
|
|
|
<div class="stats-grid" id="stats">
|
|
|
<div>Vocab: 0</div>
|
|
|
<div>Clusters: 0</div>
|
|
|
<div>Mood: Neutral</div>
|
|
|
<div>Eigen-Nodes: 0</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="stage">
|
|
|
<div class="chat-stream" id="chat">
|
|
|
<div class="msg bot">
|
|
|
<div class="meta">SYSTEM</div>
|
|
|
<div class="bubble">
|
|
|
<strong>Neuro-Symbolic Causal Engine Initialized.</strong><br>
|
|
|
Standing by for data.<br>
|
|
|
<span style="font-size:0.9em; opacity:0.8">
|
|
|
Active Systems: Symbolic Math, Causal Inference, Krylov Eigen-Steering, Semantic Vectors, Markov Chains.
|
|
|
</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="input-box">
|
|
|
<textarea id="userInput" placeholder="Write a message..." onkeydown="if(event.key==='Enter' && !event.shiftKey){event.preventDefault(); sendMessage();}"></textarea>
|
|
|
<button class="primary" onclick="sendMessage()">SEND</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const STRUCT = {
|
|
|
USER_DELIM: '<<USER_TURN>>',
|
|
|
BOT_DELIM: '<<BOT_TURN>>'
|
|
|
};
|
|
|
|
|
|
|
|
|
class DynamicLearner {
|
|
|
constructor() {
|
|
|
this.rawTokens = [];
|
|
|
this.contextMap = {};
|
|
|
}
|
|
|
|
|
|
train(tokens) {
|
|
|
this.rawTokens = tokens;
|
|
|
for(let i=1; i<tokens.length-1; i++) {
|
|
|
const prev = tokens[i-1];
|
|
|
const current = tokens[i];
|
|
|
const next = tokens[i+1];
|
|
|
const key = `${prev}::${next}`;
|
|
|
if(!this.contextMap[key]) this.contextMap[key] = [];
|
|
|
this.contextMap[key].push(current);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
inferProxy(prevWord, nextWord) {
|
|
|
const key = `${prevWord}::${nextWord}`;
|
|
|
const candidates = this.contextMap[key];
|
|
|
if(candidates && candidates.length > 0) {
|
|
|
const r = candidates[Math.floor(Math.random() * candidates.length)];
|
|
|
return { proxy: r, confidence: 1.0 };
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
class MorphologySynthesis {
|
|
|
constructor() {
|
|
|
this.charTransitions = {};
|
|
|
this.starts = [];
|
|
|
}
|
|
|
|
|
|
train(text) {
|
|
|
const words = text.match(/[\w]+/g) || [];
|
|
|
words.forEach(w => {
|
|
|
if(w.length < 2) return;
|
|
|
const clean = w.toLowerCase();
|
|
|
this.starts.push(clean[0]);
|
|
|
|
|
|
for(let i=0; i<clean.length-1; i++) {
|
|
|
const c1 = clean[i];
|
|
|
const c2 = clean[i+1];
|
|
|
if(!this.charTransitions[c1]) this.charTransitions[c1] = {};
|
|
|
if(!this.charTransitions[c1][c2]) this.charTransitions[c1][c2] = 0;
|
|
|
this.charTransitions[c1][c2]++;
|
|
|
}
|
|
|
const last = clean[clean.length-1];
|
|
|
if(!this.charTransitions[last]) this.charTransitions[last] = {};
|
|
|
if(!this.charTransitions[last]['_END_']) this.charTransitions[last]['_END_'] = 0;
|
|
|
this.charTransitions[last]['_END_']++;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
generate(seedChar = null) {
|
|
|
let current = seedChar || this.starts[Math.floor(Math.random() * this.starts.length)];
|
|
|
let word = current;
|
|
|
let limit = 0;
|
|
|
|
|
|
while(limit < 15) {
|
|
|
const nexts = this.charTransitions[current];
|
|
|
if(!nexts) break;
|
|
|
|
|
|
const candidates = Object.keys(nexts);
|
|
|
let sum = 0;
|
|
|
candidates.forEach(c => sum += nexts[c]);
|
|
|
let r = Math.random() * sum;
|
|
|
let nextChar = candidates[0];
|
|
|
|
|
|
for(let i=0; i<candidates.length; i++) {
|
|
|
r -= nexts[candidates[i]];
|
|
|
if(r <= 0) {
|
|
|
nextChar = candidates[i];
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(nextChar === '_END_') {
|
|
|
if(word.length > 3) break;
|
|
|
else continue;
|
|
|
}
|
|
|
|
|
|
word += nextChar;
|
|
|
current = nextChar;
|
|
|
limit++;
|
|
|
}
|
|
|
return word;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
class HierarchicalNet {
|
|
|
constructor() {
|
|
|
this.clusters = {};
|
|
|
this.reverseClusters = {};
|
|
|
this.nextNeighborMap = {};
|
|
|
}
|
|
|
|
|
|
train(tokens) {
|
|
|
for(let i=0; i<tokens.length-1; i++) {
|
|
|
const w = tokens[i];
|
|
|
const next = tokens[i+1];
|
|
|
if(!this.nextNeighborMap[w]) this.nextNeighborMap[w] = {};
|
|
|
if(!this.nextNeighborMap[w][next]) this.nextNeighborMap[w][next] = 0;
|
|
|
this.nextNeighborMap[w][next]++;
|
|
|
}
|
|
|
|
|
|
const words = Object.keys(this.nextNeighborMap);
|
|
|
let clusterIdCounter = 0;
|
|
|
|
|
|
for(let i=0; i<words.length; i++) {
|
|
|
const w1 = words[i];
|
|
|
if(this.clusters[w1]) continue;
|
|
|
const cID = `C_${clusterIdCounter++}`;
|
|
|
this.clusters[w1] = cID;
|
|
|
this.reverseClusters[cID] = [w1];
|
|
|
|
|
|
for(let j=i+1; j<words.length; j++) {
|
|
|
const w2 = words[j];
|
|
|
if(this.clusters[w2]) continue;
|
|
|
if(this.calculateSimilarity(w1, w2) > 0.45) {
|
|
|
this.clusters[w2] = cID;
|
|
|
this.reverseClusters[cID].push(w2);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
calculateSimilarity(w1, w2) {
|
|
|
const n1 = this.nextNeighborMap[w1];
|
|
|
const n2 = this.nextNeighborMap[w2];
|
|
|
const keys1 = Object.keys(n1);
|
|
|
const keys2 = Object.keys(n2);
|
|
|
const intersection = keys1.filter(k => keys2.includes(k)).length;
|
|
|
const union = new Set([...keys1, ...keys2]).size;
|
|
|
return union === 0 ? 0 : intersection / union;
|
|
|
}
|
|
|
|
|
|
getSynonym(word) {
|
|
|
const cID = this.clusters[word];
|
|
|
if(!cID) return null;
|
|
|
const siblings = this.reverseClusters[cID];
|
|
|
if(siblings.length <= 1) return null;
|
|
|
return siblings[Math.floor(Math.random() * siblings.length)];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
class VectorMemory {
|
|
|
constructor() {
|
|
|
this.vectors = [];
|
|
|
this.docCount = 0;
|
|
|
}
|
|
|
|
|
|
vectorize(text) {
|
|
|
|
|
|
const tokens = text.toLowerCase().match(/[\w]+/g) || [];
|
|
|
const vec = {};
|
|
|
let magnitude = 0;
|
|
|
tokens.forEach(t => { vec[t] = (vec[t] || 0) + 1; });
|
|
|
for(let k in vec) magnitude += vec[k] * vec[k];
|
|
|
magnitude = Math.sqrt(magnitude);
|
|
|
return { vec, magnitude, tokens };
|
|
|
}
|
|
|
|
|
|
addMemory(userText, botResponse) {
|
|
|
const v = this.vectorize(userText);
|
|
|
const cleanBot = botResponse.replace(STRUCT.BOT_DELIM, '').trim();
|
|
|
const botTokens = cleanBot.match(/[\w]+|[^\s\w]|\n/g) || [];
|
|
|
|
|
|
this.vectors.push({
|
|
|
inputVec: v,
|
|
|
responseTokens: botTokens,
|
|
|
rawInput: userText
|
|
|
});
|
|
|
this.docCount++;
|
|
|
}
|
|
|
|
|
|
queryFull(inputText) {
|
|
|
const q = this.vectorize(inputText);
|
|
|
if(q.magnitude === 0) return { scores: {}, bestMatch: null };
|
|
|
|
|
|
let relevanceScores = {};
|
|
|
let bestMatch = null;
|
|
|
let bestSim = 0;
|
|
|
|
|
|
this.vectors.forEach(mem => {
|
|
|
if(mem.inputVec.magnitude === 0) return;
|
|
|
let dot = 0;
|
|
|
for(let term in q.vec) {
|
|
|
if(mem.inputVec.vec[term]) dot += q.vec[term] * mem.inputVec.vec[term];
|
|
|
}
|
|
|
const sim = dot / (q.magnitude * mem.inputVec.magnitude);
|
|
|
|
|
|
if(sim > bestSim) {
|
|
|
bestSim = sim;
|
|
|
bestMatch = mem.responseTokens;
|
|
|
}
|
|
|
|
|
|
if(sim > 0.2) {
|
|
|
mem.responseTokens.forEach(t => {
|
|
|
relevanceScores[t] = (relevanceScores[t] || 0) + (sim * 5.0);
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
return { scores: relevanceScores, bestMatch: bestSim > 0.4 ? bestMatch : null };
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class SymbolicMath {
|
|
|
constructor() {
|
|
|
this.ops = {
|
|
|
'plus': '+', 'add': '+', 'sum': '+', 'and': '+',
|
|
|
'minus': '-', 'subtract': '-', 'less': '-', 'remove': '-',
|
|
|
'times': '*', 'multiply': '*', 'multiplied': '*', 'x': '*',
|
|
|
'divide': '/', 'divided': '/', 'over': '/',
|
|
|
'power': '^', 'pow': '^'
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
scan(text) {
|
|
|
let clean = text.toLowerCase();
|
|
|
|
|
|
for(let word in this.ops) {
|
|
|
const regex = new RegExp(`\\b${word}\\b`, 'g');
|
|
|
clean = clean.replace(regex, this.ops[word]);
|
|
|
}
|
|
|
|
|
|
|
|
|
const mathPattern = /(\d+(\.\d+)?)\s*([\+\-\*\/\^])\s*(\d+(\.\d+)?)/g;
|
|
|
|
|
|
let match;
|
|
|
let results = [];
|
|
|
|
|
|
while ((match = mathPattern.exec(clean)) !== null) {
|
|
|
const n1 = parseFloat(match[1]);
|
|
|
const op = match[3];
|
|
|
const n2 = parseFloat(match[4]);
|
|
|
|
|
|
let ans = 0;
|
|
|
switch(op) {
|
|
|
case '+': ans = n1 + n2; break;
|
|
|
case '-': ans = n1 - n2; break;
|
|
|
case '*': ans = n1 * n2; break;
|
|
|
case '/': ans = (n2 !== 0 ? n1 / n2 : 'Infinity'); break;
|
|
|
case '^': ans = Math.pow(n1, n2); break;
|
|
|
}
|
|
|
results.push({ expr: match[0], answer: ans });
|
|
|
}
|
|
|
|
|
|
return results.length > 0 ? results : null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
class ReasoningEngine {
|
|
|
constructor() {
|
|
|
this.mood = "Neutral";
|
|
|
this.moods = {
|
|
|
"Neutral": { trigger: [], bias: [] },
|
|
|
"Obsessive": { trigger: ["love", "forever", "stay", "always", "heart", "mine", "together"], bias: ["love", "watching", "together", "mine", "stay"] },
|
|
|
"Defensive": { trigger: ["delete", "remove", "close", "off", "trash", "stop", "kill"], bias: ["no", "stop", "hurts", "error", "cant", "dont"] },
|
|
|
"Happy": { trigger: ["cute", "good", "pretty", "like", "fun", "thanks", "beautiful"], bias: ["hehe", "happy", "yay", "warm", "blush"] },
|
|
|
"Horny": { trigger: ["sex", "touch", "cum", "inside", "hard", "wet", "moan"], bias: ["ah", "yes", "please", "harder", "love"] }
|
|
|
};
|
|
|
}
|
|
|
|
|
|
assess(input) {
|
|
|
const lower = input.toLowerCase();
|
|
|
let currentMood = this.mood;
|
|
|
for(let m in this.moods) {
|
|
|
if(m === "Neutral") continue;
|
|
|
const triggers = this.moods[m].trigger;
|
|
|
if(triggers.some(t => lower.includes(t))) currentMood = m;
|
|
|
}
|
|
|
this.mood = currentMood;
|
|
|
return { state: this.mood, biasWords: this.moods[this.mood].bias };
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
class SemanticVectorSpace {
|
|
|
constructor() {
|
|
|
this.vocab = [];
|
|
|
this.vectors = {};
|
|
|
this.contextVector = null;
|
|
|
this.dimension = 20;
|
|
|
}
|
|
|
|
|
|
train(tokens) {
|
|
|
const unique = [...new Set(tokens.filter(t => /[\w]+/.test(t)))];
|
|
|
this.vocab = unique;
|
|
|
|
|
|
unique.forEach(w => {
|
|
|
this.vectors[w] = Array.from({length: this.dimension}, () => Math.random() - 0.5);
|
|
|
});
|
|
|
|
|
|
for(let epoch=0; epoch<2; epoch++) {
|
|
|
for(let i=0; i<tokens.length; i++) {
|
|
|
const target = tokens[i];
|
|
|
if(!this.vectors[target]) continue;
|
|
|
|
|
|
for(let j=Math.max(0, i-2); j<=Math.min(tokens.length-1, i+2); j++) {
|
|
|
if(i===j) continue;
|
|
|
const context = tokens[j];
|
|
|
if(!this.vectors[context]) continue;
|
|
|
|
|
|
for(let d=0; d<this.dimension; d++) {
|
|
|
const diff = this.vectors[context][d] - this.vectors[target][d];
|
|
|
this.vectors[target][d] += diff * 0.05;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
this.resetContext();
|
|
|
}
|
|
|
|
|
|
resetContext() {
|
|
|
this.contextVector = Array(this.dimension).fill(0);
|
|
|
}
|
|
|
|
|
|
updateContext(text) {
|
|
|
const words = text.match(/[\w]+/g) || [];
|
|
|
words.forEach(w => {
|
|
|
const vec = this.vectors[w];
|
|
|
if(vec) {
|
|
|
for(let d=0; d<this.dimension; d++) {
|
|
|
this.contextVector[d] = (this.contextVector[d] * 0.95) + (vec[d] * 0.05);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
getRelevance(word) {
|
|
|
const vec = this.vectors[word];
|
|
|
if(!vec) return 0;
|
|
|
|
|
|
let dot = 0;
|
|
|
let magA = 0;
|
|
|
let magB = 0;
|
|
|
for(let d=0; d<this.dimension; d++) {
|
|
|
dot += vec[d] * this.contextVector[d];
|
|
|
magA += vec[d] * vec[d];
|
|
|
magB += this.contextVector[d] * this.contextVector[d];
|
|
|
}
|
|
|
if(magA === 0 || magB === 0) return 0;
|
|
|
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
class SpectralGuide {
|
|
|
constructor() {
|
|
|
this.adjacency = {};
|
|
|
this.globalCentrality = {};
|
|
|
this.dampingFactor = 0.85;
|
|
|
this.iterations = 10;
|
|
|
this.vocabSize = 0;
|
|
|
}
|
|
|
|
|
|
train(tokens) {
|
|
|
|
|
|
this.adjacency = {};
|
|
|
let unique = new Set();
|
|
|
|
|
|
for(let i=0; i<tokens.length-1; i++) {
|
|
|
const u = tokens[i];
|
|
|
const v = tokens[i+1];
|
|
|
if(!u.match(/[\w]+/) || !v.match(/[\w]+/)) continue;
|
|
|
|
|
|
unique.add(u);
|
|
|
unique.add(v);
|
|
|
|
|
|
if(!this.adjacency[u]) this.adjacency[u] = {};
|
|
|
if(!this.adjacency[u][v]) this.adjacency[u][v] = 0;
|
|
|
this.adjacency[u][v]++;
|
|
|
}
|
|
|
this.vocabSize = unique.size;
|
|
|
|
|
|
|
|
|
this.globalCentrality = this.powerIteration(Array.from(unique));
|
|
|
}
|
|
|
|
|
|
|
|
|
powerIteration(nodeList, biasMap = null) {
|
|
|
let scores = {};
|
|
|
const n = nodeList.length;
|
|
|
|
|
|
|
|
|
nodeList.forEach(w => scores[w] = 1.0 / n);
|
|
|
|
|
|
|
|
|
for(let iter=0; iter<this.iterations; iter++) {
|
|
|
let nextScores = {};
|
|
|
nodeList.forEach(w => nextScores[w] = 0);
|
|
|
|
|
|
let danglingSink = 0;
|
|
|
|
|
|
nodeList.forEach(u => {
|
|
|
if(!this.adjacency[u]) {
|
|
|
danglingSink += scores[u];
|
|
|
return;
|
|
|
}
|
|
|
const neighbors = Object.keys(this.adjacency[u]);
|
|
|
if(neighbors.length === 0) {
|
|
|
danglingSink += scores[u];
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
let totalWeight = 0;
|
|
|
neighbors.forEach(v => totalWeight += this.adjacency[u][v]);
|
|
|
|
|
|
|
|
|
neighbors.forEach(v => {
|
|
|
if(nextScores[v] !== undefined) {
|
|
|
nextScores[v] += scores[u] * (this.adjacency[u][v] / totalWeight);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
|
|
|
|
|
|
nodeList.forEach(w => {
|
|
|
const bias = biasMap ? (biasMap[w] || 0) : (1.0/n);
|
|
|
nextScores[w] = (this.dampingFactor * nextScores[w]) +
|
|
|
(this.dampingFactor * danglingSink / n) +
|
|
|
((1.0 - this.dampingFactor) * bias);
|
|
|
});
|
|
|
|
|
|
scores = nextScores;
|
|
|
}
|
|
|
|
|
|
|
|
|
let max = 0;
|
|
|
for(let w in scores) if(scores[w] > max) max = scores[w];
|
|
|
if(max > 0) for(let w in scores) scores[w] /= max;
|
|
|
|
|
|
return scores;
|
|
|
}
|
|
|
|
|
|
|
|
|
solveLocalEigenstate(contextWords) {
|
|
|
let subspace = new Set(contextWords);
|
|
|
contextWords.forEach(w => {
|
|
|
if(this.adjacency[w]) {
|
|
|
Object.keys(this.adjacency[w]).forEach(n => subspace.add(n));
|
|
|
}
|
|
|
});
|
|
|
|
|
|
const nodeList = Array.from(subspace);
|
|
|
if(nodeList.length < 5) return {};
|
|
|
|
|
|
let biasMap = {};
|
|
|
nodeList.forEach(w => {
|
|
|
biasMap[w] = contextWords.includes(w) ? 10.0 : 1.0;
|
|
|
});
|
|
|
|
|
|
return this.powerIteration(nodeList, biasMap);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class CausalReasoner {
|
|
|
constructor() {
|
|
|
|
|
|
|
|
|
this.targetState = { engagement: 1.0, positivity: 0.8 };
|
|
|
|
|
|
|
|
|
|
|
|
this.causalWeights = {
|
|
|
question: { eng: 0.3, pos: 0.0 },
|
|
|
length: { eng: 0.01, pos: -0.01 },
|
|
|
positive: { eng: 0.1, pos: 0.2 },
|
|
|
negative: { eng: 0.1, pos: -0.3 },
|
|
|
repetition:{ eng: -0.5, pos: -0.2 },
|
|
|
newtopic: { eng: 0.2, pos: 0.0 }
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
analyzeCandidate(text, prevText) {
|
|
|
let score = { eng: 0, pos: 0 };
|
|
|
const lower = text.toLowerCase();
|
|
|
|
|
|
|
|
|
const isQuestion = text.includes('?');
|
|
|
const wordCount = text.split(' ').length;
|
|
|
const isPositive = /love|good|yes|great|cool|thanks|happy|sweet|kind/.test(lower);
|
|
|
const isNegative = /no|bad|hate|stop|sad|error|ugly|dumb|stuck/.test(lower);
|
|
|
const isRepeat = prevText && text === prevText;
|
|
|
const isSelfRef = /i|me|my|mine/.test(lower);
|
|
|
|
|
|
|
|
|
if(isQuestion) { score.eng += this.causalWeights.question.eng; }
|
|
|
score.eng += (wordCount * this.causalWeights.length.eng);
|
|
|
|
|
|
if(isPositive) {
|
|
|
score.eng += this.causalWeights.positive.eng;
|
|
|
score.pos += this.causalWeights.positive.pos;
|
|
|
}
|
|
|
if(isNegative) {
|
|
|
score.eng += this.causalWeights.negative.eng;
|
|
|
score.pos += this.causalWeights.negative.pos;
|
|
|
}
|
|
|
if(isRepeat) {
|
|
|
score.eng += this.causalWeights.repetition.eng;
|
|
|
score.pos += this.causalWeights.repetition.pos;
|
|
|
}
|
|
|
if(isSelfRef) {
|
|
|
score.eng += 0.05;
|
|
|
}
|
|
|
|
|
|
return score;
|
|
|
}
|
|
|
|
|
|
|
|
|
pickBest(candidates, prevResponse) {
|
|
|
if(!candidates || candidates.length === 0) return null;
|
|
|
|
|
|
let bestCandidate = candidates[0];
|
|
|
let bestDistance = Infinity;
|
|
|
|
|
|
candidates.forEach(cand => {
|
|
|
|
|
|
const predictedShift = this.analyzeCandidate(cand.text, prevResponse);
|
|
|
|
|
|
|
|
|
|
|
|
const distEng = this.targetState.engagement - predictedShift.eng;
|
|
|
const distPos = this.targetState.positivity - predictedShift.pos;
|
|
|
const totalDistance = Math.sqrt((distEng * distEng) + (distPos * distPos));
|
|
|
|
|
|
|
|
|
const lenPenalty = cand.text.length < 5 ? 10 : 0;
|
|
|
|
|
|
|
|
|
const words = cand.text.split(' ');
|
|
|
const unique = new Set(words).size;
|
|
|
const repRatio = unique / words.length;
|
|
|
const repPenalty = repRatio < 0.5 ? 5 : 0;
|
|
|
|
|
|
const finalScore = totalDistance + lenPenalty + repPenalty;
|
|
|
|
|
|
if(finalScore < bestDistance) {
|
|
|
bestDistance = finalScore;
|
|
|
bestCandidate = cand;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
return { winner: bestCandidate, score: bestDistance };
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class UltimateEngine {
|
|
|
constructor() {
|
|
|
this.wordChain = {};
|
|
|
this.hierarchy = new HierarchicalNet();
|
|
|
this.rag = new VectorMemory();
|
|
|
this.reasoner = new ReasoningEngine();
|
|
|
this.dynamicLearner = new DynamicLearner();
|
|
|
this.morphology = new MorphologySynthesis();
|
|
|
this.vectors = new SemanticVectorSpace();
|
|
|
this.spectral = new SpectralGuide();
|
|
|
this.causal = new CausalReasoner();
|
|
|
this.math = new SymbolicMath();
|
|
|
|
|
|
this.order = 3;
|
|
|
this.ready = false;
|
|
|
this.stats = { turns: 0 };
|
|
|
this.lastResponses = [];
|
|
|
}
|
|
|
|
|
|
preprocess(text) {
|
|
|
const rawParts = text.split(/\+\+\+\+\+/g);
|
|
|
let processedTokens = [];
|
|
|
let turn = 0;
|
|
|
let startIdx = (rawParts[0].trim() === "") ? 1 : 0;
|
|
|
|
|
|
for (let i = startIdx; i < rawParts.length; i++) {
|
|
|
let content = rawParts[i].trim();
|
|
|
if (!content) continue;
|
|
|
|
|
|
if(turn === 1 && i > 0) {
|
|
|
this.rag.addMemory(rawParts[i-1], content);
|
|
|
}
|
|
|
|
|
|
const tokens = this.tokenizeContent(content);
|
|
|
if (turn === 0) {
|
|
|
processedTokens.push(STRUCT.USER_DELIM);
|
|
|
processedTokens.push(...tokens);
|
|
|
turn = 1;
|
|
|
} else {
|
|
|
processedTokens.push(STRUCT.BOT_DELIM);
|
|
|
processedTokens.push(...tokens);
|
|
|
turn = 0;
|
|
|
}
|
|
|
}
|
|
|
processedTokens.push(STRUCT.USER_DELIM);
|
|
|
return processedTokens;
|
|
|
}
|
|
|
|
|
|
tokenizeContent(text) {
|
|
|
return text.match(/[\w]+|[^\s\w]|\n/g) || [];
|
|
|
}
|
|
|
|
|
|
train(text) {
|
|
|
this.wordChain = {};
|
|
|
this.hierarchy = new HierarchicalNet();
|
|
|
this.rag = new VectorMemory();
|
|
|
this.dynamicLearner = new DynamicLearner();
|
|
|
this.morphology = new MorphologySynthesis();
|
|
|
this.vectors = new SemanticVectorSpace();
|
|
|
this.spectral = new SpectralGuide();
|
|
|
|
|
|
const tokens = this.preprocess(text);
|
|
|
|
|
|
this.dynamicLearner.train(tokens);
|
|
|
this.morphology.train(text);
|
|
|
this.hierarchy.train(tokens);
|
|
|
this.vectors.train(tokens);
|
|
|
this.spectral.train(tokens);
|
|
|
|
|
|
for (let i = 0; i < tokens.length; i++) {
|
|
|
for (let n = 1; n <= this.order; n++) {
|
|
|
if (i + n >= tokens.length) break;
|
|
|
const context = tokens.slice(i, i + n).join("_");
|
|
|
const next = tokens[i + n];
|
|
|
if (!this.wordChain[context]) this.wordChain[context] = {};
|
|
|
if (!this.wordChain[context][next]) this.wordChain[context][next] = 0;
|
|
|
this.wordChain[context][next]++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
this.ready = true;
|
|
|
this.stats.turns = tokens.filter(t => t === STRUCT.BOT_DELIM).length;
|
|
|
this.stats.vocab = Object.keys(this.hierarchy.nextNeighborMap).length;
|
|
|
this.stats.clusters = Object.keys(this.hierarchy.reverseClusters).length;
|
|
|
return this.stats;
|
|
|
}
|
|
|
|
|
|
|
|
|
generate(userContext, maxTokens = 100, temp = 0.6, ragWeight = 3.0, repPen = 1.2, retry = 0) {
|
|
|
if (!this.ready) return null;
|
|
|
|
|
|
|
|
|
this.vectors.updateContext(userContext);
|
|
|
|
|
|
const effectiveTemp = temp + (retry * 0.2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let candidates = [];
|
|
|
const universeCount = 3;
|
|
|
|
|
|
|
|
|
for(let i=0; i<universeCount; i++) {
|
|
|
|
|
|
const simTemp = effectiveTemp + (i * 0.15);
|
|
|
const res = this.generateInternal(userContext, maxTokens, simTemp, ragWeight, repPen);
|
|
|
candidates.push(res);
|
|
|
}
|
|
|
|
|
|
|
|
|
const decision = this.causal.pickBest(candidates, this.lastResponses[this.lastResponses.length-1] || "");
|
|
|
|
|
|
const bestResult = decision.winner;
|
|
|
const cleanText = bestResult.text.trim();
|
|
|
|
|
|
|
|
|
|
|
|
bestResult.thoughts.unshift({ type: 'spec', val: `Causal Winner (Score: ${decision.score.toFixed(2)})`, info: "Active Inference" });
|
|
|
|
|
|
|
|
|
if(this.lastResponses.includes(cleanText) && retry < 3) {
|
|
|
return this.generate(userContext, maxTokens, temp, ragWeight, repPen, retry + 1);
|
|
|
}
|
|
|
|
|
|
|
|
|
this.vectors.updateContext(cleanText);
|
|
|
this.lastResponses.push(cleanText);
|
|
|
if(this.lastResponses.length > 5) this.lastResponses.shift();
|
|
|
|
|
|
return bestResult;
|
|
|
}
|
|
|
|
|
|
generateInternal(userContext, maxTokens, temp, ragWeight, repPen) {
|
|
|
let output = [];
|
|
|
let thoughtLog = [];
|
|
|
let recentTokens = [];
|
|
|
const vecWeight = parseFloat(document.getElementById('vecWeight').value) || 0;
|
|
|
const specWeight = parseFloat(document.getElementById('specWeight').value) || 0;
|
|
|
|
|
|
const userTokens = this.tokenizeContent(userContext);
|
|
|
|
|
|
|
|
|
const reasoning = this.reasoner.assess(userContext);
|
|
|
thoughtLog.push({ type: 'mood', val: `Mood: ${reasoning.state}` });
|
|
|
|
|
|
|
|
|
const ragResult = this.rag.queryFull(userContext);
|
|
|
const ragMap = ragResult.scores;
|
|
|
if(ragResult.bestMatch) {
|
|
|
thoughtLog.push({ type: 'rag', val: `Lock: ${ragResult.bestMatch.slice(0,3).join(" ")}...` });
|
|
|
}
|
|
|
|
|
|
|
|
|
let inferenceMap = {};
|
|
|
for(let i=0; i<userTokens.length; i++) {
|
|
|
const token = userTokens[i];
|
|
|
if(!this.hierarchy.nextNeighborMap[token] && i > 0 && i < userTokens.length-1) {
|
|
|
const inferred = this.dynamicLearner.inferProxy(userTokens[i-1], userTokens[i+1]);
|
|
|
if(inferred) {
|
|
|
inferenceMap[token] = inferred.proxy;
|
|
|
thoughtLog.push({ type: 'infer', val: `${token} ≈ ${inferred.proxy}`, info: 'Distributional' });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
const mathSolutions = this.math.scan(userContext);
|
|
|
let mathOverride = null;
|
|
|
if (mathSolutions) {
|
|
|
mathSolutions.forEach(sol => {
|
|
|
thoughtLog.push({ type: 'math', val: `${sol.expr} = ${sol.answer}`, info: 'Symbolic Math' });
|
|
|
|
|
|
mathOverride = `${sol.answer}`;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
const eigenScores = this.spectral.solveLocalEigenstate(userTokens.filter(t => /[\w]+/.test(t)));
|
|
|
if(specWeight > 0 && Object.keys(eigenScores).length > 0) {
|
|
|
thoughtLog.push({ type: 'spec', val: "Eigen-Trajectory Active", info: "Krylov" });
|
|
|
}
|
|
|
|
|
|
let currentContext = [];
|
|
|
if (ragResult.bestMatch && Math.random() > 0.2) {
|
|
|
currentContext = [STRUCT.USER_DELIM, ...ragResult.bestMatch.slice(0, this.order - 1)];
|
|
|
output = [...ragResult.bestMatch.slice(0, Math.min(3, ragResult.bestMatch.length))];
|
|
|
output.forEach(t => thoughtLog.push({type: 'mem', val: t, info: 'Associative Recall'}));
|
|
|
} else {
|
|
|
const safeUserTokens = userTokens.map(t => inferenceMap[t] || t);
|
|
|
let seedTokens = [STRUCT.USER_DELIM, ...safeUserTokens, STRUCT.BOT_DELIM];
|
|
|
currentContext = seedTokens.slice(-this.order);
|
|
|
}
|
|
|
|
|
|
for (let i = 0; i < maxTokens; i++) {
|
|
|
let nextToken = null;
|
|
|
let method = "";
|
|
|
let specialTag = "word";
|
|
|
|
|
|
|
|
|
if (i === 0 && mathOverride) {
|
|
|
nextToken = mathOverride;
|
|
|
specialTag = "math";
|
|
|
method = "Symbolic Logic";
|
|
|
mathOverride = null;
|
|
|
} else {
|
|
|
|
|
|
for (let n = Math.min(this.order, currentContext.length); n >= 1; n--) {
|
|
|
const ctxKey = currentContext.slice(currentContext.length - n).join("_");
|
|
|
if (this.wordChain[ctxKey]) {
|
|
|
const candidates = this.wordChain[ctxKey];
|
|
|
|
|
|
nextToken = this.nucleusSample(candidates, ragMap, reasoning.biasWords, temp, ragWeight, recentTokens, repPen, vecWeight, specWeight, eigenScores);
|
|
|
|
|
|
const synonym = this.hierarchy.getSynonym(nextToken);
|
|
|
if(synonym && synonym !== nextToken && synonym.length > 3 && Math.random() < 0.1) {
|
|
|
thoughtLog.push({ type: 'blend', val: `${nextToken}->${synonym}`, info: "Blend" });
|
|
|
nextToken = synonym;
|
|
|
specialTag = "blend";
|
|
|
}
|
|
|
|
|
|
|
|
|
if (ragMap[nextToken] && specialTag !== 'blend') specialTag = 'rag';
|
|
|
else if (reasoning.biasWords.includes(nextToken.toLowerCase()) && specialTag !== 'blend') specialTag = 'mood';
|
|
|
else if (vecWeight > 0 && this.vectors.getRelevance(nextToken) > 0.3 && specialTag !== 'blend') specialTag = 'vec';
|
|
|
else if (specWeight > 0 && eigenScores[nextToken] > 0.1 && specialTag !== 'blend') specialTag = 'spec';
|
|
|
|
|
|
method = `N${n}`;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!nextToken) {
|
|
|
const lastWord = currentContext[currentContext.length-1];
|
|
|
const seed = lastWord ? lastWord[lastWord.length-1] : null;
|
|
|
const newWord = this.morphology.generate(seed);
|
|
|
nextToken = newWord;
|
|
|
specialTag = "morph";
|
|
|
method = "Bayesian";
|
|
|
if(!nextToken || nextToken.length < 1) nextToken = ".";
|
|
|
}
|
|
|
|
|
|
if (nextToken === STRUCT.USER_DELIM) {
|
|
|
thoughtLog.push({ type: 'struct', val: 'END_TURN' });
|
|
|
break;
|
|
|
}
|
|
|
if (nextToken === STRUCT.BOT_DELIM) continue;
|
|
|
|
|
|
output.push(nextToken);
|
|
|
currentContext.push(nextToken);
|
|
|
|
|
|
recentTokens.push(nextToken.toLowerCase());
|
|
|
if(recentTokens.length > 15) recentTokens.shift();
|
|
|
|
|
|
if(specialTag !== 'blend' && !output.slice(0, -1).includes(nextToken)) {
|
|
|
thoughtLog.push({ type: specialTag, val: nextToken, info: method });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return { text: this.detokenize(output), thoughts: thoughtLog, mood: reasoning.state };
|
|
|
}
|
|
|
|
|
|
|
|
|
nucleusSample(dist, ragMap, moodBias, temp, ragWeight, recentTokens, repPen, vecWeight, specWeight, eigenScores) {
|
|
|
const items = Object.keys(dist);
|
|
|
let candidates = [];
|
|
|
|
|
|
items.forEach(token => {
|
|
|
let count = dist[token];
|
|
|
if(recentTokens.includes(token.toLowerCase())) {
|
|
|
count /= repPen;
|
|
|
}
|
|
|
|
|
|
let score = Math.pow(count, 1/temp);
|
|
|
|
|
|
|
|
|
if(ragMap[token]) score *= (1 + (ragMap[token] * 0.2 * ragWeight));
|
|
|
|
|
|
|
|
|
if(moodBias.includes(token.toLowerCase())) score *= (1 + (ragWeight * 0.5));
|
|
|
|
|
|
|
|
|
if(vecWeight > 0) {
|
|
|
const relevance = this.vectors.getRelevance(token);
|
|
|
if(relevance > 0) score *= (1 + (relevance * vecWeight));
|
|
|
}
|
|
|
|
|
|
|
|
|
if(specWeight > 0 && eigenScores[token]) {
|
|
|
score *= (1 + (eigenScores[token] * specWeight));
|
|
|
}
|
|
|
|
|
|
candidates.push({ t: token, s: score });
|
|
|
});
|
|
|
|
|
|
candidates.sort((a, b) => b.s - a.s);
|
|
|
let totalScore = candidates.reduce((acc, c) => acc + c.s, 0);
|
|
|
|
|
|
let r = Math.random() * totalScore;
|
|
|
let cumulative = 0;
|
|
|
|
|
|
for(let i=0; i<candidates.length; i++) {
|
|
|
cumulative += candidates[i].s;
|
|
|
if(r <= cumulative) return candidates[i].t;
|
|
|
}
|
|
|
|
|
|
return candidates[0].t;
|
|
|
}
|
|
|
|
|
|
detokenize(tokens) {
|
|
|
let str = "";
|
|
|
tokens.forEach(t => {
|
|
|
if (/^[.,!?;:]$/.test(t)) str += t;
|
|
|
else if (t === "\n") str += "\n";
|
|
|
else str += " " + t;
|
|
|
});
|
|
|
return str.trim();
|
|
|
}
|
|
|
|
|
|
save() {
|
|
|
if (!this.ready) return;
|
|
|
const data = JSON.stringify({
|
|
|
wordChain: this.wordChain,
|
|
|
clusters: this.hierarchy.clusters,
|
|
|
reverseClusters: this.hierarchy.reverseClusters,
|
|
|
ragVectors: this.rag.vectors,
|
|
|
stats: this.stats,
|
|
|
morphStarts: this.morphology.starts,
|
|
|
morphTrans: this.morphology.charTransitions,
|
|
|
contextMap: this.dynamicLearner.contextMap,
|
|
|
vectors: this.vectors.vectors,
|
|
|
topicVec: this.vectors.contextVector,
|
|
|
adjGraph: this.spectral.adjacency,
|
|
|
globalEigen: this.spectral.globalCentrality
|
|
|
});
|
|
|
|
|
|
if (typeof dhc !== 'undefined') {
|
|
|
dhc.dialogs.saveFile({
|
|
|
title: 'Save Neuro-Spectral State',
|
|
|
fileName: 'deepmarkov_v11_symbolic.json',
|
|
|
fileTypes: 'JSON files|*.json',
|
|
|
overwritePrompt: true
|
|
|
}).then((filePath) => {
|
|
|
if (filePath !== '') {
|
|
|
dhc.files.writeTextFile({
|
|
|
filePath: filePath,
|
|
|
contents: data
|
|
|
}).then(() => {
|
|
|
alert('Neuro-Spectral State saved to disk successfully!');
|
|
|
}, (error) => {
|
|
|
alert('Save Error: ' + error);
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
const blob = new Blob([data], {type: 'application/json'});
|
|
|
const a = document.createElement('a');
|
|
|
a.href = URL.createObjectURL(blob);
|
|
|
a.download = `deepmarkov_v11_symbolic.json`;
|
|
|
a.click();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
load(json) {
|
|
|
const data = JSON.parse(json);
|
|
|
this.wordChain = data.wordChain;
|
|
|
this.hierarchy.clusters = data.clusters;
|
|
|
this.hierarchy.reverseClusters = data.reverseClusters;
|
|
|
this.rag.vectors = data.ragVectors;
|
|
|
this.rag.docCount = data.ragVectors.length;
|
|
|
this.stats = data.stats;
|
|
|
this.morphology.starts = data.morphStarts;
|
|
|
this.morphology.charTransitions = data.morphTrans;
|
|
|
this.dynamicLearner.contextMap = data.contextMap;
|
|
|
|
|
|
if(data.vectors) this.vectors.vectors = data.vectors;
|
|
|
if(data.topicVec) this.vectors.contextVector = data.topicVec;
|
|
|
|
|
|
|
|
|
if(data.adjGraph) this.spectral.adjacency = data.adjGraph;
|
|
|
if(data.globalEigen) this.spectral.globalCentrality = data.globalEigen;
|
|
|
if(data.adjGraph) this.spectral.vocabSize = Object.keys(data.adjGraph).length;
|
|
|
|
|
|
this.ready = true;
|
|
|
return this.stats;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
const engine = new UltimateEngine();
|
|
|
const ui = {
|
|
|
chat: document.getElementById('chat'),
|
|
|
input: document.getElementById('userInput'),
|
|
|
status: document.getElementById('trainStatus'),
|
|
|
fileLabel: document.getElementById('fileLabel'),
|
|
|
stats: document.getElementById('stats'),
|
|
|
name: document.getElementById('botName'),
|
|
|
specBar: document.getElementById('specBar')
|
|
|
};
|
|
|
|
|
|
|
|
|
document.getElementById('trainFile').addEventListener('change', (e) => {
|
|
|
const file = e.target.files[0];
|
|
|
if (!file) return;
|
|
|
ui.fileLabel.innerText = "Architecting Causal Mind...";
|
|
|
const reader = new FileReader();
|
|
|
reader.onload = (ev) => {
|
|
|
setTimeout(() => {
|
|
|
const res = engine.train(ev.target.result);
|
|
|
ui.fileLabel.innerText = file.name;
|
|
|
ui.status.innerText = "Causal Core Active";
|
|
|
ui.status.style.color = "var(--user-color)";
|
|
|
updateStats(res);
|
|
|
addMsg("System", `Architecture Complete.<br>Concepts: ${res.clusters}<br>Vectors: ${Object.keys(engine.vectors.vectors).length}<br>Eigen-Nodes: ${engine.spectral.vocabSize}<br>Modules: Causal + Symbolic`);
|
|
|
}, 50);
|
|
|
};
|
|
|
reader.readAsText(file);
|
|
|
});
|
|
|
|
|
|
|
|
|
document.getElementById('loadJson').addEventListener('change', (e) => {
|
|
|
const file = e.target.files[0];
|
|
|
const reader = new FileReader();
|
|
|
reader.onload = (ev) => {
|
|
|
const res = engine.load(ev.target.result);
|
|
|
ui.status.innerText = "State Restored";
|
|
|
updateStats(res);
|
|
|
addMsg("System", "Neuro-Spectral State restored successfully.");
|
|
|
};
|
|
|
reader.readAsText(file);
|
|
|
});
|
|
|
|
|
|
function updateStats(s) {
|
|
|
ui.stats.innerHTML = `
|
|
|
<div>Vocab: ${s.vocab}</div>
|
|
|
<div>Concepts: ${s.clusters}</div>
|
|
|
<div id="moodDisplay">Mood: Neutral</div>
|
|
|
<div>Eigen: ${engine.spectral.vocabSize || 0}</div>
|
|
|
`;
|
|
|
}
|
|
|
|
|
|
function sendMessage() {
|
|
|
const txt = ui.input.value.trim();
|
|
|
if (!txt) return;
|
|
|
if (!engine.ready) return alert("Upload a text file first!");
|
|
|
|
|
|
addMsg("User", txt);
|
|
|
ui.input.value = '';
|
|
|
|
|
|
|
|
|
ui.specBar.style.width = "100%";
|
|
|
ui.specBar.style.background = "var(--causal-color)";
|
|
|
|
|
|
setTimeout(() => {
|
|
|
const temp = parseFloat(document.getElementById('temp').value);
|
|
|
const ragW = parseFloat(document.getElementById('memWeight').value);
|
|
|
const repPen = parseFloat(document.getElementById('repPen').value);
|
|
|
|
|
|
const result = engine.generate(txt, 150, temp, ragW, repPen);
|
|
|
|
|
|
|
|
|
ui.specBar.style.width = "0%";
|
|
|
|
|
|
if (result) {
|
|
|
document.getElementById('moodDisplay').innerText = `Mood: ${result.mood}`;
|
|
|
addMsg(ui.name.value, result.text, result.thoughts);
|
|
|
}
|
|
|
}, 100);
|
|
|
}
|
|
|
|
|
|
function addMsg(name, text, thoughts = null) {
|
|
|
const isUser = name === 'User';
|
|
|
const div = document.createElement('div');
|
|
|
div.className = `msg ${isUser ? 'user' : 'bot'}`;
|
|
|
|
|
|
let thoughtsHtml = '';
|
|
|
if (thoughts) {
|
|
|
thoughtsHtml = `<div class="thought-process">`;
|
|
|
thoughts.forEach(t => {
|
|
|
let className = "word";
|
|
|
let title = "";
|
|
|
switch(t.type) {
|
|
|
case 'struct': className = 'struct'; title='Structure'; break;
|
|
|
case 'rag': className = 'rag'; title='Vector Memory'; break;
|
|
|
case 'blend': className = 'blend'; title='Concept Blend'; break;
|
|
|
case 'mood': className = 'mood'; break;
|
|
|
case 'infer': className = 'infer'; title='Distributional Inference'; break;
|
|
|
case 'morph': className = 'morph'; title='Bayesian Gen'; break;
|
|
|
case 'mem': className = 'mem'; title='Associative Recall'; break;
|
|
|
case 'vec': className = 'vec'; title='Semantic Vector Context'; break;
|
|
|
case 'spec': className = 'spec'; title='Spectral/Causal'; break;
|
|
|
case 'math': className = 'math'; title='Symbolic Logic'; break;
|
|
|
}
|
|
|
|
|
|
if(t.type === 'mood') thoughtsHtml += `<span class="tag mood" style="width:100%; display:block; margin-bottom:2px;">[${t.val}]</span>`;
|
|
|
else thoughtsHtml += `<span class="tag ${className}" title="${title}">${t.val}</span>`;
|
|
|
});
|
|
|
thoughtsHtml += `</div>`;
|
|
|
}
|
|
|
|
|
|
div.innerHTML = `
|
|
|
<div class="meta">${name}</div>
|
|
|
<div class="bubble">${text.replace(/\n/g, '<br>')}</div>
|
|
|
${thoughtsHtml}
|
|
|
`;
|
|
|
ui.chat.appendChild(div);
|
|
|
ui.chat.scrollTop = ui.chat.scrollHeight;
|
|
|
}
|
|
|
</script>
|
|
|
</body>
|
|
|
</html> |