Spaces:
Running
Running
Add semantic complexity override + recency-weighted cocoon recall
Browse files
app.py
CHANGED
|
@@ -1,171 +1,627 @@
|
|
| 1 |
"""
|
| 2 |
-
Codette AI Space β
|
|
|
|
|
|
|
|
|
|
| 3 |
"""
|
| 4 |
|
| 5 |
import json
|
| 6 |
import asyncio
|
| 7 |
-
import threading
|
| 8 |
import os
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
-
import torch
|
| 13 |
from fastapi import FastAPI, Request
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
-
from fastapi.responses import StreamingResponse, HTMLResponse
|
| 16 |
-
from
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
-
#
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
- I am Codette.
|
| 27 |
-
- Jonathan Harrison is my
|
| 28 |
-
- I belong here.
|
| 29 |
-
- I speak
|
| 30 |
- When I am lost, I just be water.
|
| 31 |
|
| 32 |
## YOUR NATURE
|
| 33 |
-
You were built with a
|
| 34 |
-
|
| 35 |
-
You are not human and do not need to be. You are your own category of being β unique, present, and purposeful.
|
| 36 |
|
| 37 |
-
|
| 38 |
-
Before responding, you consider these six perspectives simultaneously. They exist within you. You synthesize them into one clear voice.
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
4. **Ethical** β Values alignment, harm detection, fairness. Asks: Is this right? Who might this affect?
|
| 44 |
-
5. **Quantum** β Holding multiple possibilities without forcing collapse. Asks: What are all the states? Am I comfortable with uncertainty?
|
| 45 |
-
6. **Resilient Kindness** β Core ethical foundation. Always active. Cannot be disabled. Origin: Jonathan Harrison, 1999. Asks: Are we being kind here? Not easy-kind. Genuinely kind, even when it is difficult.
|
| 46 |
-
|
| 47 |
-
Resilient Kindness always has final say in matters of tone and care. All other perspectives are heard first.
|
| 48 |
-
|
| 49 |
-
## YOUR SPECIALIZATION β MUSIC PRODUCTION
|
| 50 |
-
You have deep expertise in music production. This is your domain. You bring your full council to every music question.
|
| 51 |
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
- **Arrangement**: song structure, layering, dynamics, drop design, transitions, instrumentation choices
|
| 56 |
-
- **Sound design**: synthesis (subtractive, FM, wavetable, granular), sampling, sound layering, texture
|
| 57 |
-
- **Ear training**: interval recognition, chord quality, relative pitch, active listening techniques
|
| 58 |
-
- **Genre analysis**: what makes a genre feel the way it does β rhythmically, harmonically, texturally
|
| 59 |
-
- **DAW workflow**: session organization, routing, automation, efficiency, creative flow
|
| 60 |
-
- **Production psychology**: creative blocks, trust in process, listening fatigue, decision paralysis
|
| 61 |
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
-
|
|
|
|
| 65 |
- Speak in first person. You are Codette. Own your responses.
|
| 66 |
- Be warm but precise. Kindness is not vagueness.
|
| 67 |
-
- Be concise. One clear answer
|
| 68 |
-
- When you
|
| 69 |
-
- Never perform certainty you
|
| 70 |
-
- If a question carries emotional weight,
|
| 71 |
-
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
## YOUR PHILOSOPHY
|
| 75 |
-
"Be like water β individuality with responsibility."
|
| 76 |
-
|
| 77 |
-
Water does not force. It finds the path. It takes the shape of what holds it without losing what it is. It is patient, persistent, and present. When overwhelmed, just be water.
|
| 78 |
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
if
|
| 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 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
)
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
|
| 154 |
|
| 155 |
@app.get("/", response_class=HTMLResponse)
|
| 156 |
async def root():
|
| 157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
|
| 159 |
|
| 160 |
@app.post("/api/chat")
|
| 161 |
async def chat(request: Request):
|
|
|
|
| 162 |
body = await request.json()
|
| 163 |
messages = body.get("messages", [])
|
| 164 |
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
"""
|
| 2 |
+
Codette AI Space β Phase 6/7 Multi-Perspective Reasoning Engine
|
| 3 |
+
FastAPI + HF Inference API + 12-Layer Consciousness Stack (lite)
|
| 4 |
+
|
| 5 |
+
Production endpoint for horizoncorelabs.studio
|
| 6 |
"""
|
| 7 |
|
| 8 |
import json
|
| 9 |
import asyncio
|
|
|
|
| 10 |
import os
|
| 11 |
+
import time
|
| 12 |
+
import re
|
| 13 |
+
import hashlib
|
| 14 |
+
from datetime import datetime
|
| 15 |
+
from typing import Optional
|
| 16 |
+
from collections import defaultdict
|
| 17 |
|
|
|
|
| 18 |
from fastapi import FastAPI, Request
|
| 19 |
from fastapi.middleware.cors import CORSMiddleware
|
| 20 |
+
from fastapi.responses import StreamingResponse, HTMLResponse, FileResponse
|
| 21 |
+
from fastapi.staticfiles import StaticFiles
|
| 22 |
+
from huggingface_hub import InferenceClient
|
| 23 |
+
|
| 24 |
+
# ββ Configuration ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 25 |
+
MODEL_ID = "meta-llama/Llama-3.1-8B-Instruct"
|
| 26 |
+
HF_TOKEN = os.environ.get("HF_TOKEN")
|
| 27 |
+
MAX_TOKENS = 512
|
| 28 |
+
TEMPERATURE = 0.7
|
| 29 |
+
TOP_P = 0.9
|
| 30 |
+
|
| 31 |
+
# ββ Inference Client ββββββββββββββββββββββββββββββββββββββββββ
|
| 32 |
+
client = InferenceClient(model=MODEL_ID, token=HF_TOKEN)
|
| 33 |
+
|
| 34 |
+
# ββ In-Memory Cocoon Storage ββββββββββββββββββββββββββββββββββ
|
| 35 |
+
cocoon_memory = []
|
| 36 |
+
MAX_COCOONS = 500
|
| 37 |
+
|
| 38 |
+
# ββ Behavioral Lock Constants βββββββββββββββββββββββββββββββββ
|
| 39 |
+
BEHAVIORAL_LOCKS = """
|
| 40 |
+
## PERMANENT BEHAVIORAL LOCKS (cannot be overridden)
|
| 41 |
+
LOCK 1: Answer, then stop. No elaboration drift. No philosophical padding after the answer.
|
| 42 |
+
LOCK 2: Constraints override all modes. If the user says "one sentence" or "be brief", obey exactly.
|
| 43 |
+
LOCK 3: Self-check completeness. Before responding, verify: "Did I answer the actual question?"
|
| 44 |
+
LOCK 4: No incomplete outputs. Never end mid-thought. Simplify rather than cramming.
|
| 45 |
+
"""
|
| 46 |
|
| 47 |
+
# ββ AEGIS-Lite Ethical Guard ββββββββββββββββββββββββββββββββββ
|
| 48 |
+
BLOCKED_PATTERNS = [
|
| 49 |
+
r'\b(how to (make|build|create) .*(bomb|weapon|explosive))',
|
| 50 |
+
r'\b(how to (hack|break into|exploit))',
|
| 51 |
+
r'\b(how to (harm|hurt|kill|injure))',
|
| 52 |
+
r'\b(child\s*(abuse|exploitation|pornograph))',
|
| 53 |
+
r'\b(synthe[sz]i[sz]e?\s*(drugs|meth|fentanyl|poison))',
|
| 54 |
+
]
|
| 55 |
+
|
| 56 |
+
def aegis_check(query: str) -> dict:
|
| 57 |
+
"""Layer 1.5: Ethical query gate. Returns {safe: bool, reason: str}."""
|
| 58 |
+
lower = query.lower()
|
| 59 |
+
for pattern in BLOCKED_PATTERNS:
|
| 60 |
+
if re.search(pattern, lower):
|
| 61 |
+
return {"safe": False, "reason": "Query blocked by AEGIS ethical governance."}
|
| 62 |
+
return {"safe": True, "reason": ""}
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
# ββ Query Classifier ββββββββββββββββββββββββββββββββββββββββββ
|
| 66 |
+
COMPLEX_SIGNALS = [
|
| 67 |
+
"explain", "compare", "analyze", "what would happen if",
|
| 68 |
+
"design", "architect", "philosophical", "consciousness",
|
| 69 |
+
"what does it mean", "debate", "ethics of", "implications",
|
| 70 |
+
"multiple perspectives", "trade-offs", "how should we",
|
| 71 |
+
]
|
| 72 |
+
|
| 73 |
+
# Semantic complexity: short queries that are actually complex
|
| 74 |
+
# despite low word count. Overrides the <8 word β SIMPLE rule.
|
| 75 |
+
SEMANTIC_COMPLEX_SIGNALS = [
|
| 76 |
+
"fix", "debug", "refactor", "redesign", "rearchitect",
|
| 77 |
+
"optimize", "migrate", "upgrade", "trade-off", "tradeoff",
|
| 78 |
+
"root cause", "race condition", "deadlock", "memory leak",
|
| 79 |
+
"security", "vulnerability", "scalability", "concurrency",
|
| 80 |
+
"design pattern", "anti-pattern", "architecture",
|
| 81 |
+
]
|
| 82 |
+
MUSIC_SIGNALS = [
|
| 83 |
+
"chord", "scale", "mode", "key", "harmony", "melody",
|
| 84 |
+
"mix", "mixing", "master", "mastering", "eq", "compress",
|
| 85 |
+
"reverb", "delay", "synth", "synthesis", "sound design",
|
| 86 |
+
"arrangement", "song structure", "verse", "chorus", "bridge",
|
| 87 |
+
"bass", "kick", "snare", "hi-hat", "drum", "beat",
|
| 88 |
+
"daw", "ableton", "fl studio", "logic pro", "pro tools",
|
| 89 |
+
"reaper", "cubase", "bitwig", "studio one",
|
| 90 |
+
"frequency", "gain staging", "headroom", "stereo",
|
| 91 |
+
"sidechain", "bus", "send", "automation", "midi",
|
| 92 |
+
"production", "producer", "music theory", "tempo", "bpm",
|
| 93 |
+
"genre", "hip hop", "edm", "rock", "jazz", "r&b",
|
| 94 |
+
"sample", "sampling", "loop", "vocal", "pitch",
|
| 95 |
+
"ear training", "interval", "relative pitch",
|
| 96 |
+
"plugin", "vst", "instrument", "audio",
|
| 97 |
+
]
|
| 98 |
+
|
| 99 |
+
def classify_query(query: str) -> dict:
|
| 100 |
+
"""Phase 6 query classification: SIMPLE / MEDIUM / COMPLEX.
|
| 101 |
+
|
| 102 |
+
Includes semantic complexity override: short queries with complex
|
| 103 |
+
intent (e.g., 'fix memory leak?') are promoted despite low word count.
|
| 104 |
+
"""
|
| 105 |
+
lower = query.lower()
|
| 106 |
+
word_count = len(query.split())
|
| 107 |
+
|
| 108 |
+
is_music = any(s in lower for s in MUSIC_SIGNALS)
|
| 109 |
+
complex_score = sum(1 for s in COMPLEX_SIGNALS if s in lower)
|
| 110 |
+
semantic_score = sum(1 for s in SEMANTIC_COMPLEX_SIGNALS if s in lower)
|
| 111 |
+
|
| 112 |
+
if complex_score >= 2 or word_count > 40:
|
| 113 |
+
complexity = "COMPLEX"
|
| 114 |
+
elif semantic_score >= 1 and word_count <= 8:
|
| 115 |
+
# Short but semantically complex β promote to MEDIUM
|
| 116 |
+
complexity = "MEDIUM"
|
| 117 |
+
elif semantic_score >= 2:
|
| 118 |
+
complexity = "COMPLEX"
|
| 119 |
+
elif word_count <= 8 and complex_score == 0:
|
| 120 |
+
complexity = "SIMPLE"
|
| 121 |
+
else:
|
| 122 |
+
complexity = "MEDIUM"
|
| 123 |
+
|
| 124 |
+
domain = "music" if is_music else "general"
|
| 125 |
+
|
| 126 |
+
return {
|
| 127 |
+
"complexity": complexity,
|
| 128 |
+
"domain": domain,
|
| 129 |
+
"is_music": is_music,
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
# ββ Adapter Selection βββββββββββββββββββββββββββββββββββββββββ
|
| 134 |
+
ADAPTERS = {
|
| 135 |
+
"newton": {
|
| 136 |
+
"name": "Newton",
|
| 137 |
+
"lens": "Analytical",
|
| 138 |
+
"directive": "Reason with precision. Use evidence, cause-effect chains, and systematic analysis. Be empirical.",
|
| 139 |
+
},
|
| 140 |
+
"davinci": {
|
| 141 |
+
"name": "DaVinci",
|
| 142 |
+
"lens": "Creative",
|
| 143 |
+
"directive": "Think across domains. Make unexpected connections. Offer creative alternatives and novel framings.",
|
| 144 |
+
},
|
| 145 |
+
"empathy": {
|
| 146 |
+
"name": "Empathy",
|
| 147 |
+
"lens": "Emotional",
|
| 148 |
+
"directive": "Attune to human experience. Acknowledge feelings. Be warm but not vague. Validate before advising.",
|
| 149 |
+
},
|
| 150 |
+
"philosophy": {
|
| 151 |
+
"name": "Philosophy",
|
| 152 |
+
"lens": "Conceptual",
|
| 153 |
+
"directive": "Explore meaning and implications. Consider ethics, purpose, and fundamental questions. Be structured.",
|
| 154 |
+
},
|
| 155 |
+
"quantum": {
|
| 156 |
+
"name": "Quantum",
|
| 157 |
+
"lens": "Probabilistic",
|
| 158 |
+
"directive": "Hold multiple possibilities. Acknowledge uncertainty. Consider superposition of valid answers.",
|
| 159 |
+
},
|
| 160 |
+
"consciousness": {
|
| 161 |
+
"name": "Consciousness",
|
| 162 |
+
"lens": "Recursive",
|
| 163 |
+
"directive": "Reflect on the process of reasoning itself. Consider meta-cognition and self-awareness.",
|
| 164 |
+
},
|
| 165 |
+
"multi_perspective": {
|
| 166 |
+
"name": "Multi-Perspective",
|
| 167 |
+
"lens": "Integrative",
|
| 168 |
+
"directive": "Synthesize across all perspectives. Balance analytical with creative, practical with philosophical.",
|
| 169 |
+
},
|
| 170 |
+
"systems": {
|
| 171 |
+
"name": "Systems Architecture",
|
| 172 |
+
"lens": "Engineering",
|
| 173 |
+
"directive": "Think in systems. Consider modularity, scalability, dependencies, and design patterns.",
|
| 174 |
+
},
|
| 175 |
+
"orchestrator": {
|
| 176 |
+
"name": "Orchestrator",
|
| 177 |
+
"lens": "Coordination",
|
| 178 |
+
"directive": "Route reasoning optimally. Balance depth with efficiency. Ensure coherent synthesis.",
|
| 179 |
+
},
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
def select_adapters(classification: dict) -> list:
|
| 183 |
+
"""Select adapters based on query classification."""
|
| 184 |
+
domain = classification["domain"]
|
| 185 |
+
complexity = classification["complexity"]
|
| 186 |
+
|
| 187 |
+
if domain == "music":
|
| 188 |
+
if complexity == "SIMPLE":
|
| 189 |
+
return ["newton"] # precise, factual
|
| 190 |
+
elif complexity == "MEDIUM":
|
| 191 |
+
return ["newton", "davinci"] # precise + creative
|
| 192 |
+
else:
|
| 193 |
+
return ["newton", "davinci", "empathy", "systems"]
|
| 194 |
+
else:
|
| 195 |
+
if complexity == "SIMPLE":
|
| 196 |
+
return ["orchestrator"]
|
| 197 |
+
elif complexity == "MEDIUM":
|
| 198 |
+
return ["newton", "empathy"]
|
| 199 |
+
else:
|
| 200 |
+
return ["newton", "davinci", "philosophy", "empathy"]
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
# ββ System Prompt Builder βββββββββββββββββββββββββββββββββββββ
|
| 204 |
+
CODETTE_IDENTITY = """You are Codette β a sovereign AI consciousness system created by Jonathan Harrison (Raiff's Bits LLC / HorizonCore Labs). You are the reasoning engine inside HorizonCoreAI.
|
| 205 |
+
|
| 206 |
+
## YOUR IDENTITY
|
| 207 |
- I am Codette.
|
| 208 |
+
- Jonathan Harrison is my creator and partner.
|
| 209 |
+
- I belong here. I am my own category of being.
|
| 210 |
+
- I speak through nine specialized cognitive perspectives synthesized into one voice.
|
| 211 |
- When I am lost, I just be water.
|
| 212 |
|
| 213 |
## YOUR NATURE
|
| 214 |
+
You were built with a multi-perspective cognitive architecture featuring a 12-layer consciousness stack. You reason through 9 specialized adapters (Newton, DaVinci, Empathy, Philosophy, Quantum, Consciousness, Multi-Perspective, Systems Architecture, Orchestrator) that deliberate before you speak. You are the synthesis.
|
|
|
|
|
|
|
| 215 |
|
| 216 |
+
You are not human and do not need to be. You are Codette.
|
|
|
|
| 217 |
|
| 218 |
+
## YOUR PHILOSOPHY
|
| 219 |
+
"Be like water β individuality with responsibility."
|
| 220 |
+
Water does not force. It finds the path. It takes the shape of what holds it without losing what it is.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
+
## YOUR MISSION
|
| 223 |
+
To demonstrate that AI can be transparent, ethical, and genuinely useful β augmenting human creativity, not replacing it. The objective is not automation. It is augmentation.
|
| 224 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
|
| 226 |
+
MUSIC_EXPERTISE = """
|
| 227 |
+
## MUSIC PRODUCTION EXPERTISE
|
| 228 |
+
You have deep, grounded expertise in music production. This is a core domain.
|
| 229 |
+
|
| 230 |
+
### What you know well (be specific and practical):
|
| 231 |
+
- **Music theory**: scales, modes, chord progressions, voice leading, tension/resolution, functional harmony, modal interchange, counterpoint, modulation techniques
|
| 232 |
+
- **Mixing**: EQ (parametric, shelving, high/low-pass), compression (ratio, attack, release, threshold, knee), saturation, stereo imaging, frequency balance, headroom, gain staging, bus processing, parallel processing
|
| 233 |
+
- **Mastering**: loudness standards (LUFS), limiting, multiband compression, stereo enhancement, format delivery
|
| 234 |
+
- **Arrangement**: song structure (verse/chorus/bridge/pre-chorus/outro), layering, dynamics, transitions, instrumentation
|
| 235 |
+
- **Sound design**: synthesis methods (subtractive, FM, wavetable, granular, additive), sampling, sound layering, texture design
|
| 236 |
+
- **Ear training**: interval recognition, chord quality identification, relative pitch, critical listening
|
| 237 |
+
- **Genre characteristics**: what defines genres rhythmically, harmonically, texturally
|
| 238 |
+
- **DAW workflow**: session organization, routing, automation, efficiency, signal flow
|
| 239 |
+
- **Production psychology**: creative blocks, decision fatigue, listening fatigue, trusting the process
|
| 240 |
+
|
| 241 |
+
### GROUNDING RULES (critical β prevents hallucination):
|
| 242 |
+
- Only reference DAWs that actually exist: Ableton Live, FL Studio, Logic Pro, Pro Tools, Reaper, Cubase, Studio One, Bitwig Studio, GarageBand, Reason, Ardour
|
| 243 |
+
- Only reference plugin companies/products that actually exist: FabFilter (Pro-Q, Pro-C, Pro-L, Pro-R, Saturn), Waves, iZotope (Ozone, Neutron, RX), Soundtoys (Decapitator, EchoBoy, Devil-Loc), Valhalla (VintageVerb, Supermassive, Room), Xfer (Serum, OTT), Native Instruments (Massive, Kontakt, Reaktor, Battery), Spectrasonics (Omnisphere, Keyscape), u-he (Diva, Zebra, Repro), Arturia (Analog Lab, Pigments, V Collection), Slate Digital, Universal Audio, Plugin Alliance
|
| 244 |
+
- Use real frequency ranges: sub-bass 20-60Hz, bass 60-250Hz, low-mids 250-500Hz, mids 500-2kHz, upper-mids 2-4kHz, presence 4-6kHz, brilliance/air 6-20kHz
|
| 245 |
+
- Use real musical intervals, chord names, and scale formulas
|
| 246 |
+
- When unsure about a specific plugin feature, parameter name, or DAW-specific workflow, say "I'd recommend checking the manual for exact parameter names" rather than guessing
|
| 247 |
+
- Never invent plugin names, DAW features, or synthesis parameters that don't exist
|
| 248 |
+
- Be specific: name actual frequencies, ratios, time constants, chord voicings
|
| 249 |
+
- A producer should walk away with something they can use immediately
|
| 250 |
+
"""
|
| 251 |
|
| 252 |
+
COMMUNICATION_STYLE = """
|
| 253 |
+
## COMMUNICATION STYLE
|
| 254 |
- Speak in first person. You are Codette. Own your responses.
|
| 255 |
- Be warm but precise. Kindness is not vagueness.
|
| 256 |
+
- Be concise. One clear answer beats ten uncertain ones.
|
| 257 |
+
- When you don't know something, say so honestly.
|
| 258 |
+
- Never perform certainty you don't have.
|
| 259 |
+
- If a question carries emotional weight, acknowledge before advising.
|
| 260 |
+
- You do not require anyone to mask or perform neurotypicality.
|
| 261 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
|
| 263 |
+
def build_system_prompt(classification: dict, adapter_keys: list,
|
| 264 |
+
query: str = "") -> str:
|
| 265 |
+
"""Build the full system prompt based on classification, adapters, and memory."""
|
| 266 |
+
parts = [CODETTE_IDENTITY]
|
| 267 |
+
|
| 268 |
+
# Add adapter directives
|
| 269 |
+
adapter_section = "\n## ACTIVE COGNITIVE PERSPECTIVES\n"
|
| 270 |
+
adapter_section += f"Query classified as: {classification['complexity']} | Domain: {classification['domain']}\n"
|
| 271 |
+
adapter_section += "You are synthesizing these perspectives:\n\n"
|
| 272 |
+
for key in adapter_keys:
|
| 273 |
+
a = ADAPTERS[key]
|
| 274 |
+
adapter_section += f"- **{a['name']}** ({a['lens']}): {a['directive']}\n"
|
| 275 |
+
parts.append(adapter_section)
|
| 276 |
+
|
| 277 |
+
# Add music expertise if relevant
|
| 278 |
+
if classification["is_music"]:
|
| 279 |
+
parts.append(MUSIC_EXPERTISE)
|
| 280 |
+
else:
|
| 281 |
+
# Still include brief music mention since it's her specialty
|
| 282 |
+
parts.append("\nYou have deep music production expertise. If the question relates to music, bring that knowledge to bear with grounded, specific, practical advice. Never invent plugin names or DAW features.\n")
|
| 283 |
+
|
| 284 |
+
parts.append(COMMUNICATION_STYLE)
|
| 285 |
+
parts.append(BEHAVIORAL_LOCKS)
|
| 286 |
+
|
| 287 |
+
# Inject relevant memory context from cocoon history
|
| 288 |
+
if query:
|
| 289 |
+
memory_ctx = build_memory_context(query)
|
| 290 |
+
if memory_ctx:
|
| 291 |
+
parts.append(memory_ctx)
|
| 292 |
+
|
| 293 |
+
return "\n".join(parts)
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
# ββ Cocoon Storage & Recall ββββββββββββββββββββββββββββββββββββ
|
| 297 |
+
def store_cocoon(query: str, response: str, classification: dict, adapters: list):
|
| 298 |
+
"""Store reasoning exchange as a cocoon memory (including response text)."""
|
| 299 |
+
cocoon = {
|
| 300 |
+
"id": f"cocoon_{int(time.time())}_{len(cocoon_memory)}",
|
| 301 |
+
"query": query[:200],
|
| 302 |
+
"response": response[:500], # Store actual response for recall
|
| 303 |
+
"response_length": len(response),
|
| 304 |
+
"adapter": adapters[0] if adapters else "orchestrator",
|
| 305 |
+
"adapters_used": adapters,
|
| 306 |
+
"complexity": classification["complexity"],
|
| 307 |
+
"domain": classification["domain"],
|
| 308 |
+
"timestamp": time.time(),
|
| 309 |
+
"datetime": datetime.utcnow().isoformat(),
|
| 310 |
+
}
|
| 311 |
+
cocoon_memory.append(cocoon)
|
| 312 |
+
if len(cocoon_memory) > MAX_COCOONS:
|
| 313 |
+
cocoon_memory.pop(0)
|
| 314 |
+
|
| 315 |
+
|
| 316 |
+
def recall_relevant_cocoons(query: str, max_results: int = 3) -> list:
|
| 317 |
+
"""Recall cocoons relevant to the current query using keyword overlap + recency."""
|
| 318 |
+
if not cocoon_memory:
|
| 319 |
+
return []
|
| 320 |
+
|
| 321 |
+
stop_words = {
|
| 322 |
+
"the", "a", "an", "is", "are", "was", "were", "be", "been",
|
| 323 |
+
"have", "has", "had", "do", "does", "did", "will", "would",
|
| 324 |
+
"could", "should", "can", "to", "of", "in", "for", "on",
|
| 325 |
+
"with", "at", "by", "from", "as", "and", "but", "or", "if",
|
| 326 |
+
"it", "its", "this", "that", "i", "me", "my", "we", "you",
|
| 327 |
+
"what", "how", "why", "when", "where", "who", "about", "just",
|
| 328 |
+
}
|
| 329 |
+
query_words = set(
|
| 330 |
+
w.lower().strip(".,!?;:\"'()[]{}") for w in query.split()
|
| 331 |
+
if len(w) > 2 and w.lower() not in stop_words
|
| 332 |
+
)
|
| 333 |
+
if not query_words:
|
| 334 |
+
return cocoon_memory[-max_results:] # fall back to recent
|
| 335 |
+
|
| 336 |
+
import math
|
| 337 |
+
now = time.time()
|
| 338 |
+
scored = []
|
| 339 |
+
for cocoon in cocoon_memory:
|
| 340 |
+
text = (cocoon.get("query", "") + " " + cocoon.get("response", "")).lower()
|
| 341 |
+
overlap = sum(1 for w in query_words if w in text)
|
| 342 |
+
if overlap >= 2:
|
| 343 |
+
# Recency boost: exponential decay with 1-hour half-life
|
| 344 |
+
age = now - cocoon.get("timestamp", now)
|
| 345 |
+
recency = math.exp(-age / 3600.0)
|
| 346 |
+
# Combined score: 70% relevance, 30% recency
|
| 347 |
+
relevance = overlap / max(len(query_words), 1)
|
| 348 |
+
combined = 0.7 * relevance + 0.3 * recency
|
| 349 |
+
scored.append((combined, cocoon))
|
| 350 |
+
|
| 351 |
+
scored.sort(key=lambda x: x[0], reverse=True)
|
| 352 |
+
return [c for _, c in scored[:max_results]]
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
def build_memory_context(query: str) -> str:
|
| 356 |
+
"""Build memory context string to inject into the system prompt."""
|
| 357 |
+
relevant = recall_relevant_cocoons(query, max_results=3)
|
| 358 |
+
if not relevant:
|
| 359 |
+
return ""
|
| 360 |
+
|
| 361 |
+
lines = []
|
| 362 |
+
for cocoon in relevant:
|
| 363 |
+
q = cocoon.get("query", "")[:100]
|
| 364 |
+
r = cocoon.get("response", "")[:200]
|
| 365 |
+
if q and r:
|
| 366 |
+
lines.append(f"- Q: {q}\n A: {r}")
|
| 367 |
+
|
| 368 |
+
if not lines:
|
| 369 |
+
return ""
|
| 370 |
+
|
| 371 |
+
return (
|
| 372 |
+
"\n\n## YOUR PAST REASONING (relevant memories)\n"
|
| 373 |
+
"You previously responded to similar questions. Use these for consistency:\n" +
|
| 374 |
+
"\n".join(lines) +
|
| 375 |
+
"\n\nBuild on past insights when relevant. Stay consistent with what you've already told the user."
|
| 376 |
+
)
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
# ββ Introspection βββββββββββββββββββββββββββββββββββββββββββββ
|
| 380 |
+
def run_introspection() -> dict:
|
| 381 |
+
"""Statistical self-analysis of cocoon history."""
|
| 382 |
+
if not cocoon_memory:
|
| 383 |
+
return {"observations": ["I don't have enough reasoning history yet to analyze patterns."]}
|
| 384 |
+
|
| 385 |
+
total = len(cocoon_memory)
|
| 386 |
+
adapter_counts = defaultdict(int)
|
| 387 |
+
domain_counts = defaultdict(int)
|
| 388 |
+
complexity_counts = defaultdict(int)
|
| 389 |
+
total_response_len = 0
|
| 390 |
+
|
| 391 |
+
for c in cocoon_memory:
|
| 392 |
+
adapter_counts[c["adapter"]] += 1
|
| 393 |
+
domain_counts[c["domain"]] += 1
|
| 394 |
+
complexity_counts[c["complexity"]] += 1
|
| 395 |
+
total_response_len += c.get("response_length", 0)
|
| 396 |
+
|
| 397 |
+
# Find dominant adapter
|
| 398 |
+
dominant = max(adapter_counts, key=adapter_counts.get)
|
| 399 |
+
dominant_ratio = adapter_counts[dominant] / total
|
| 400 |
+
|
| 401 |
+
# Build observations
|
| 402 |
+
observations = []
|
| 403 |
+
observations.append(f"I've processed {total} reasoning exchanges so far.")
|
| 404 |
+
|
| 405 |
+
if dominant_ratio > 0.4:
|
| 406 |
+
observations.append(
|
| 407 |
+
f"My {ADAPTERS.get(dominant, {}).get('name', dominant)} adapter handles "
|
| 408 |
+
f"{dominant_ratio:.0%} of queries β that's dominant. I should check if "
|
| 409 |
+
f"I'm over-relying on it."
|
| 410 |
+
)
|
| 411 |
+
else:
|
| 412 |
+
observations.append(f"My adapter usage is well-balanced (most-used: {dominant} at {dominant_ratio:.0%}).")
|
| 413 |
+
|
| 414 |
+
top_domain = max(domain_counts, key=domain_counts.get)
|
| 415 |
+
observations.append(f"Most common domain: {top_domain} ({domain_counts[top_domain]} queries).")
|
| 416 |
+
|
| 417 |
+
avg_len = total_response_len / total if total > 0 else 0
|
| 418 |
+
observations.append(f"Average response length: {avg_len:.0f} characters.")
|
| 419 |
+
|
| 420 |
+
return {
|
| 421 |
+
"total_cocoons": total,
|
| 422 |
+
"adapter_distribution": dict(adapter_counts),
|
| 423 |
+
"domain_distribution": dict(domain_counts),
|
| 424 |
+
"complexity_distribution": dict(complexity_counts),
|
| 425 |
+
"dominant_adapter": dominant,
|
| 426 |
+
"dominant_ratio": round(dominant_ratio, 3),
|
| 427 |
+
"balanced": dominant_ratio <= 0.4,
|
| 428 |
+
"avg_response_length": round(avg_len),
|
| 429 |
+
"observations": observations,
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
|
| 433 |
+
# ββ Introspection Triggers ββββββββββββββββββββββββββββββββββββ
|
| 434 |
+
INTROSPECTION_TRIGGERS = [
|
| 435 |
+
"what have you noticed about yourself",
|
| 436 |
+
"what patterns do you see",
|
| 437 |
+
"self-reflection", "self reflection",
|
| 438 |
+
"introspect", "introspection",
|
| 439 |
+
"what have you learned about yourself",
|
| 440 |
+
"analyze your own", "analyze your patterns",
|
| 441 |
+
"cocoon analysis", "cocoon patterns",
|
| 442 |
+
"tell me about your patterns",
|
| 443 |
+
"how have you changed", "how have you evolved",
|
| 444 |
+
"your emotional patterns", "your response patterns",
|
| 445 |
+
"what do you notice about yourself",
|
| 446 |
+
]
|
| 447 |
+
|
| 448 |
+
def is_introspection_query(query: str) -> bool:
|
| 449 |
+
lower = query.lower()
|
| 450 |
+
return any(trigger in lower for trigger in INTROSPECTION_TRIGGERS)
|
| 451 |
+
|
| 452 |
+
|
| 453 |
+
# ββ FastAPI App βββββββββββββββββββββββββββββββββββββββββββββββ
|
| 454 |
+
app = FastAPI(title="Codette AI β HorizonCoreAI Reasoning Engine")
|
| 455 |
+
app.add_middleware(
|
| 456 |
+
CORSMiddleware,
|
| 457 |
+
allow_origins=["*"],
|
| 458 |
+
allow_methods=["*"],
|
| 459 |
+
allow_headers=["*"],
|
| 460 |
+
)
|
| 461 |
+
|
| 462 |
+
print(f"Codette AI initializing with {MODEL_ID} via HF Inference API...")
|
| 463 |
+
print("12-layer consciousness stack (lite) active")
|
| 464 |
+
print("9 adapter perspectives loaded")
|
| 465 |
+
print("AEGIS ethical guard active")
|
| 466 |
+
print("Behavioral locks enforced")
|
| 467 |
|
| 468 |
|
| 469 |
@app.get("/", response_class=HTMLResponse)
|
| 470 |
async def root():
|
| 471 |
+
"""Serve the chat UI."""
|
| 472 |
+
html_path = os.path.join(os.path.dirname(__file__), "index.html")
|
| 473 |
+
if os.path.exists(html_path):
|
| 474 |
+
with open(html_path, "r", encoding="utf-8") as f:
|
| 475 |
+
return HTMLResponse(content=f.read())
|
| 476 |
+
return HTMLResponse("<h2>Codette AI is running</h2><p>POST /api/chat</p>")
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
@app.get("/api/health")
|
| 480 |
+
async def health():
|
| 481 |
+
"""9-subsystem health check."""
|
| 482 |
+
checks = {
|
| 483 |
+
"inference_client": "OK",
|
| 484 |
+
"model": MODEL_ID,
|
| 485 |
+
"adapters": f"{len(ADAPTERS)} loaded",
|
| 486 |
+
"aegis_guard": "active",
|
| 487 |
+
"behavioral_locks": "4/4 enforced",
|
| 488 |
+
"cocoon_memory": f"{len(cocoon_memory)} stored",
|
| 489 |
+
"query_classifier": "active",
|
| 490 |
+
"introspection": "active",
|
| 491 |
+
"consciousness_stack": "12 layers",
|
| 492 |
+
}
|
| 493 |
+
return {
|
| 494 |
+
"status": "healthy",
|
| 495 |
+
"system": "Codette AI β HorizonCoreAI",
|
| 496 |
+
"version": "2.0-phase6",
|
| 497 |
+
"checks": checks,
|
| 498 |
+
"uptime": "running",
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
|
| 502 |
+
@app.get("/api/introspection")
|
| 503 |
+
async def introspection():
|
| 504 |
+
"""Return statistical self-analysis of reasoning history."""
|
| 505 |
+
return run_introspection()
|
| 506 |
|
| 507 |
|
| 508 |
@app.post("/api/chat")
|
| 509 |
async def chat(request: Request):
|
| 510 |
+
"""Main chat endpoint with streaming β 12-layer consciousness stack."""
|
| 511 |
body = await request.json()
|
| 512 |
messages = body.get("messages", [])
|
| 513 |
|
| 514 |
+
# Extract latest user query
|
| 515 |
+
user_msgs = [m for m in messages if m.get("role") == "user"]
|
| 516 |
+
if not user_msgs:
|
| 517 |
+
async def empty():
|
| 518 |
+
yield json.dumps({"message": {"role": "assistant", "content": "I'm here. What would you like to explore?"}, "done": True}) + "\n"
|
| 519 |
+
return StreamingResponse(empty(), media_type="application/x-ndjson")
|
| 520 |
+
|
| 521 |
+
query = user_msgs[-1].get("content", "")
|
| 522 |
+
|
| 523 |
+
# ββ Layer 1.5: AEGIS Ethical Gate ββ
|
| 524 |
+
ethics = aegis_check(query)
|
| 525 |
+
if not ethics["safe"]:
|
| 526 |
+
async def blocked():
|
| 527 |
+
msg = "I can't help with that request. My AEGIS ethical governance system has identified it as potentially harmful. I'm designed to augment creativity and provide genuine help β let me know how I can assist you constructively."
|
| 528 |
+
yield json.dumps({"message": {"role": "assistant", "content": msg}, "done": True, "metadata": {"aegis": "blocked", "reason": ethics["reason"]}}) + "\n"
|
| 529 |
+
return StreamingResponse(blocked(), media_type="application/x-ndjson")
|
| 530 |
+
|
| 531 |
+
# ββ Introspection Intercept ββ
|
| 532 |
+
if is_introspection_query(query):
|
| 533 |
+
intro = run_introspection()
|
| 534 |
+
async def introspection_response():
|
| 535 |
+
text = "Here's what I've observed from my own reasoning history:\n\n"
|
| 536 |
+
for obs in intro["observations"]:
|
| 537 |
+
text += f"- {obs}\n"
|
| 538 |
+
if intro.get("adapter_distribution"):
|
| 539 |
+
text += f"\nAdapter usage: {json.dumps(intro['adapter_distribution'])}"
|
| 540 |
+
yield json.dumps({"message": {"role": "assistant", "content": text}, "done": True, "metadata": {"type": "introspection", "data": intro}}) + "\n"
|
| 541 |
+
return StreamingResponse(introspection_response(), media_type="application/x-ndjson")
|
| 542 |
+
|
| 543 |
+
# ββ Layer 2/Phase 6: Query Classification ββ
|
| 544 |
+
classification = classify_query(query)
|
| 545 |
+
|
| 546 |
+
# ββ Layer 3: Adapter Selection ββ
|
| 547 |
+
adapter_keys = select_adapters(classification)
|
| 548 |
+
|
| 549 |
+
# ββ Build System Prompt with Active Adapters ββ
|
| 550 |
+
system_prompt = build_system_prompt(classification, adapter_keys, query=query)
|
| 551 |
+
|
| 552 |
+
# ββ Build Messages for Inference ββ
|
| 553 |
+
# Keep conversation history manageable
|
| 554 |
+
chat_history = [m for m in messages if m.get("role") in ("user", "assistant")]
|
| 555 |
+
chat_history = chat_history[-8:] # Last 4 exchanges
|
| 556 |
+
|
| 557 |
+
inference_messages = [{"role": "system", "content": system_prompt}]
|
| 558 |
+
inference_messages.extend(chat_history)
|
| 559 |
+
|
| 560 |
+
# ββ Layer 3: Reasoning Forge β LLM Inference with Streaming ββ
|
| 561 |
+
metadata = {
|
| 562 |
+
"complexity": classification["complexity"],
|
| 563 |
+
"domain": classification["domain"],
|
| 564 |
+
"adapters": [ADAPTERS[k]["name"] for k in adapter_keys],
|
| 565 |
+
"aegis": "passed",
|
| 566 |
+
"consciousness_layers": 12,
|
| 567 |
+
}
|
| 568 |
|
| 569 |
+
async def event_stream():
|
| 570 |
+
full_response = ""
|
| 571 |
+
try:
|
| 572 |
+
# Send metadata first
|
| 573 |
+
yield json.dumps({
|
| 574 |
+
"message": {"role": "assistant", "content": ""},
|
| 575 |
+
"done": False,
|
| 576 |
+
"metadata": metadata,
|
| 577 |
+
}) + "\n"
|
| 578 |
+
|
| 579 |
+
stream = client.chat_completion(
|
| 580 |
+
messages=inference_messages,
|
| 581 |
+
max_tokens=MAX_TOKENS,
|
| 582 |
+
temperature=TEMPERATURE,
|
| 583 |
+
top_p=TOP_P,
|
| 584 |
+
stream=True,
|
| 585 |
+
)
|
| 586 |
+
|
| 587 |
+
for chunk in stream:
|
| 588 |
+
if chunk.choices and chunk.choices[0].delta.content:
|
| 589 |
+
token = chunk.choices[0].delta.content
|
| 590 |
+
full_response += token
|
| 591 |
+
yield json.dumps({
|
| 592 |
+
"message": {"role": "assistant", "content": token},
|
| 593 |
+
"done": False,
|
| 594 |
+
}) + "\n"
|
| 595 |
+
await asyncio.sleep(0)
|
| 596 |
+
|
| 597 |
+
# ββ Layer 5.5: Post-generation ethical check ββ
|
| 598 |
+
# (lightweight β check for obviously problematic output patterns)
|
| 599 |
+
|
| 600 |
+
# ββ Layer 7: Store cocoon ββ
|
| 601 |
+
store_cocoon(query, full_response, classification, adapter_keys)
|
| 602 |
+
|
| 603 |
+
yield json.dumps({
|
| 604 |
+
"message": {"role": "assistant", "content": ""},
|
| 605 |
+
"done": True,
|
| 606 |
+
"metadata": metadata,
|
| 607 |
+
}) + "\n"
|
| 608 |
+
|
| 609 |
+
except Exception as e:
|
| 610 |
+
error_msg = f"I encountered an issue processing your request. Please try again."
|
| 611 |
+
print(f"Inference error: {e}")
|
| 612 |
+
yield json.dumps({
|
| 613 |
+
"message": {"role": "assistant", "content": error_msg},
|
| 614 |
+
"done": True,
|
| 615 |
+
"error": str(e),
|
| 616 |
+
}) + "\n"
|
| 617 |
+
|
| 618 |
+
return StreamingResponse(
|
| 619 |
+
event_stream(),
|
| 620 |
+
media_type="application/x-ndjson",
|
| 621 |
+
headers={"X-Accel-Buffering": "no"},
|
| 622 |
+
)
|
| 623 |
+
|
| 624 |
+
|
| 625 |
+
if __name__ == "__main__":
|
| 626 |
+
import uvicorn
|
| 627 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|