Spaces:
Paused
Paused
Upload folder using huggingface_hub
Browse files- Dockerfile +1 -1
- app.py +1 -1
- frontend/index.html +24 -27
- src/builder_llm.py +26 -9
- src/observer_llm.py +37 -9
Dockerfile
CHANGED
|
@@ -16,7 +16,7 @@ COPY frontend/ ./frontend/
|
|
| 16 |
RUN mkdir -p /app/data/receipts
|
| 17 |
|
| 18 |
ENV PORT=7860
|
| 19 |
-
ENV PROVIDER=
|
| 20 |
EXPOSE 7860
|
| 21 |
|
| 22 |
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
|
| 16 |
RUN mkdir -p /app/data/receipts
|
| 17 |
|
| 18 |
ENV PORT=7860
|
| 19 |
+
ENV PROVIDER=grok
|
| 20 |
EXPOSE 7860
|
| 21 |
|
| 22 |
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
app.py
CHANGED
|
@@ -57,7 +57,7 @@ def health():
|
|
| 57 |
"ok": True,
|
| 58 |
"app": "csc-engine",
|
| 59 |
"version": "1.0.0",
|
| 60 |
-
"provider": os.getenv("PROVIDER", "
|
| 61 |
"sessions_active": len(sessions),
|
| 62 |
"time": datetime.now(timezone.utc).isoformat(),
|
| 63 |
}
|
|
|
|
| 57 |
"ok": True,
|
| 58 |
"app": "csc-engine",
|
| 59 |
"version": "1.0.0",
|
| 60 |
+
"provider": os.getenv("PROVIDER", "grok"),
|
| 61 |
"sessions_active": len(sessions),
|
| 62 |
"time": datetime.now(timezone.utc).isoformat(),
|
| 63 |
}
|
frontend/index.html
CHANGED
|
@@ -84,7 +84,7 @@
|
|
| 84 |
<header>
|
| 85 |
<div>
|
| 86 |
<h1>CSC <span>Engine</span></h1>
|
| 87 |
-
<div class="sub">Continuity Sensory Code Engine — camera + audio
|
| 88 |
</div>
|
| 89 |
<div id="status"><span class="status-dot dot-idle"></span>Idle</div>
|
| 90 |
</header>
|
|
@@ -102,14 +102,8 @@
|
|
| 102 |
<option value="research_prism">research_prism</option>
|
| 103 |
</select>
|
| 104 |
</label>
|
| 105 |
-
<label>Instruction
|
| 106 |
-
<textarea id="instruction" rows="1" placeholder="What do you want to build?"></textarea>
|
| 107 |
-
</label>
|
| 108 |
<label>Frame ms
|
| 109 |
-
<input id="frameMs" value="
|
| 110 |
-
</label>
|
| 111 |
-
<label>Synth sec
|
| 112 |
-
<input id="synthSec" value="8" style="width:40px" />
|
| 113 |
</label>
|
| 114 |
</div>
|
| 115 |
|
|
@@ -147,7 +141,7 @@
|
|
| 147 |
<div class="pane" id="pane-patches">
|
| 148 |
<h2>Generated Code Patches</h2>
|
| 149 |
<div id="patchStream">
|
| 150 |
-
<div style="color:#6e7681;font-size:13px;padding:20px;text-align:center">No patches yet. Camera
|
| 151 |
</div>
|
| 152 |
</div>
|
| 153 |
</div>
|
|
@@ -252,18 +246,10 @@ function sendFrame(force = false) {
|
|
| 252 |
ws.send(JSON.stringify({
|
| 253 |
type: "frame",
|
| 254 |
frame: dataUrl,
|
| 255 |
-
instruction: document.getElementById("instruction").value,
|
| 256 |
mode: document.getElementById("mode").value,
|
| 257 |
auto: true,
|
| 258 |
force,
|
| 259 |
-
synthesis_interval: Number(document.getElementById("synthSec").value || 8)
|
| 260 |
}));
|
| 261 |
-
if (document.getElementById("instruction").value.trim()) {
|
| 262 |
-
ws.send(JSON.stringify({
|
| 263 |
-
type: "transcript",
|
| 264 |
-
text: document.getElementById("instruction").value
|
| 265 |
-
}));
|
| 266 |
-
}
|
| 267 |
}
|
| 268 |
|
| 269 |
async function startLive() {
|
|
@@ -296,8 +282,7 @@ function startSpeech() {
|
|
| 296 |
text += event.results[i][0].transcript + " ";
|
| 297 |
}
|
| 298 |
text = text.trim();
|
| 299 |
-
|
| 300 |
-
if (ws && ws.readyState === WebSocket.OPEN) {
|
| 301 |
ws.send(JSON.stringify({ type: "transcript", text }));
|
| 302 |
}
|
| 303 |
};
|
|
@@ -337,14 +322,26 @@ function addPatchEntry(output, hash, receipt, qvd) {
|
|
| 337 |
const div = document.createElement("div");
|
| 338 |
div.className = "patch-entry";
|
| 339 |
const ts = new Date().toLocaleTimeString();
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
patchStream.prepend(div);
|
| 349 |
}
|
| 350 |
|
|
|
|
| 84 |
<header>
|
| 85 |
<div>
|
| 86 |
<h1>CSC <span>Engine</span></h1>
|
| 87 |
+
<div class="sub">Continuity Sensory Code Engine — camera + audio → LLM infers intent → generates code from movement & sound</div>
|
| 88 |
</div>
|
| 89 |
<div id="status"><span class="status-dot dot-idle"></span>Idle</div>
|
| 90 |
</header>
|
|
|
|
| 102 |
<option value="research_prism">research_prism</option>
|
| 103 |
</select>
|
| 104 |
</label>
|
|
|
|
|
|
|
|
|
|
| 105 |
<label>Frame ms
|
| 106 |
+
<input id="frameMs" value="1500" style="width:60px" />
|
|
|
|
|
|
|
|
|
|
| 107 |
</label>
|
| 108 |
</div>
|
| 109 |
|
|
|
|
| 141 |
<div class="pane" id="pane-patches">
|
| 142 |
<h2>Generated Code Patches</h2>
|
| 143 |
<div id="patchStream">
|
| 144 |
+
<div style="color:#6e7681;font-size:13px;padding:20px;text-align:center">No patches yet. Camera movement or sound will trigger code generation.</div>
|
| 145 |
</div>
|
| 146 |
</div>
|
| 147 |
</div>
|
|
|
|
| 246 |
ws.send(JSON.stringify({
|
| 247 |
type: "frame",
|
| 248 |
frame: dataUrl,
|
|
|
|
| 249 |
mode: document.getElementById("mode").value,
|
| 250 |
auto: true,
|
| 251 |
force,
|
|
|
|
| 252 |
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
}
|
| 254 |
|
| 255 |
async function startLive() {
|
|
|
|
| 282 |
text += event.results[i][0].transcript + " ";
|
| 283 |
}
|
| 284 |
text = text.trim();
|
| 285 |
+
if (text && ws && ws.readyState === WebSocket.OPEN) {
|
|
|
|
| 286 |
ws.send(JSON.stringify({ type: "transcript", text }));
|
| 287 |
}
|
| 288 |
};
|
|
|
|
| 322 |
const div = document.createElement("div");
|
| 323 |
div.className = "patch-entry";
|
| 324 |
const ts = new Date().toLocaleTimeString();
|
| 325 |
+
const reasoningMatch = output.match(/REASONING:?\s*([\s\S]*?)(?=\n\s*(?:CODE|RUN|TEST|ATTRIBUTION|INSUFFICIENT)|$)/i);
|
| 326 |
+
const codeMatch = output.match(/CODE:?\s*([\s\S]*?)(?=\n\s*(?:RUN|TEST|ATTRIBUTION)|$)/i);
|
| 327 |
+
const reasoning = reasoningMatch ? reasoningMatch[1].trim() : '';
|
| 328 |
+
const code = codeMatch ? codeMatch[1].trim() : '';
|
| 329 |
+
|
| 330 |
+
let html = `<div class="meta"><span>${ts}</span><span>hash: ${hash.slice(0, 12)}</span>`;
|
| 331 |
+
if (qvd !== undefined) html += `<span>QVD: ${qvd.toFixed(3)}</span>`;
|
| 332 |
+
html += `</div>`;
|
| 333 |
+
|
| 334 |
+
if (reasoning) {
|
| 335 |
+
html += `<div style="color:#00d4ff;font-size:11px;text-transform:uppercase;margin:6px 0 3px">Reasoning</div>`;
|
| 336 |
+
html += `<pre style="color:#8b949e;font-style:italic">${escapeHtml(reasoning)}</pre>`;
|
| 337 |
+
}
|
| 338 |
+
if (code) {
|
| 339 |
+
html += `<div style="color:#34d399;font-size:11px;text-transform:uppercase;margin:8px 0 3px">Code</div>`;
|
| 340 |
+
html += `<pre style="color:#e8ecf4">${escapeHtml(code)}</pre>`;
|
| 341 |
+
} else {
|
| 342 |
+
html += `<pre>${escapeHtml(output)}</pre>`;
|
| 343 |
+
}
|
| 344 |
+
div.innerHTML = html;
|
| 345 |
patchStream.prepend(div);
|
| 346 |
}
|
| 347 |
|
src/builder_llm.py
CHANGED
|
@@ -15,16 +15,19 @@ from .stream_state import SessionState, sha256_text
|
|
| 15 |
BUILDER_PROMPT = """You are the Builder in a Continuity Sensory Code Engine.
|
| 16 |
|
| 17 |
You receive an observation from the Observer LLM and generate:
|
| 18 |
-
1.
|
| 19 |
-
2.
|
| 20 |
-
3.
|
| 21 |
-
4.
|
|
|
|
| 22 |
|
| 23 |
Rules:
|
| 24 |
- Do not execute code automatically.
|
| 25 |
- Do not generate malware, surveillance, or credential theft.
|
| 26 |
-
-
|
|
|
|
| 27 |
- If the observation is insufficient, return INSUFFICIENT_EVIDENCE.
|
|
|
|
| 28 |
- Be concise and practical.
|
| 29 |
"""
|
| 30 |
|
|
@@ -51,6 +54,19 @@ def call_openai(prompt: str) -> str:
|
|
| 51 |
return response.choices[0].message.content
|
| 52 |
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
def call_hf_inference(prompt: str) -> str:
|
| 55 |
"""Call HF Inference API for code generation."""
|
| 56 |
from huggingface_hub import InferenceClient
|
|
@@ -76,20 +92,21 @@ def build(state: SessionState, observation: dict) -> dict:
|
|
| 76 |
OBSERVER OUTPUT:
|
| 77 |
{observation.get('observer_output', '')}
|
| 78 |
|
| 79 |
-
USER INSTRUCTION: {state.user_instruction or '[none]'}
|
| 80 |
MODE: {state.mode}
|
| 81 |
|
| 82 |
-
|
| 83 |
|
| 84 |
-
provider = os.getenv("PROVIDER", "
|
| 85 |
if provider == "ollama":
|
| 86 |
output = call_ollama(prompt)
|
| 87 |
elif provider == "openai":
|
| 88 |
output = call_openai(prompt)
|
|
|
|
|
|
|
| 89 |
elif provider == "huggingface":
|
| 90 |
output = call_hf_inference(prompt)
|
| 91 |
else:
|
| 92 |
-
raise RuntimeError(f"PROVIDER must be 'ollama', 'openai', or 'huggingface', got: {provider!r}.")
|
| 93 |
|
| 94 |
# Build patch receipt
|
| 95 |
patch_hash = sha256_text(output + str(time.time()))
|
|
|
|
| 15 |
BUILDER_PROMPT = """You are the Builder in a Continuity Sensory Code Engine.
|
| 16 |
|
| 17 |
You receive an observation from the Observer LLM and generate:
|
| 18 |
+
1. REASONING: Think step by step about what code to write based on the observer's inferred intent and sensory evidence.
|
| 19 |
+
2. CODE: complete runnable Python code or patch
|
| 20 |
+
3. RUN: exact run command
|
| 21 |
+
4. TEST: a minimal test or verification step
|
| 22 |
+
5. ATTRIBUTION: which sensory evidence (camera movement, sound, visual scene) triggered this code
|
| 23 |
|
| 24 |
Rules:
|
| 25 |
- Do not execute code automatically.
|
| 26 |
- Do not generate malware, surveillance, or credential theft.
|
| 27 |
+
- The code must be directly correlated with what the camera saw or what audio detected.
|
| 28 |
+
- If the observer reported movement or sound, your code should relate to that evidence.
|
| 29 |
- If the observation is insufficient, return INSUFFICIENT_EVIDENCE.
|
| 30 |
+
- Always show reasoning before code.
|
| 31 |
- Be concise and practical.
|
| 32 |
"""
|
| 33 |
|
|
|
|
| 54 |
return response.choices[0].message.content
|
| 55 |
|
| 56 |
|
| 57 |
+
def call_grok(prompt: str) -> str:
|
| 58 |
+
"""Call x.ai Grok API for code generation."""
|
| 59 |
+
from openai import OpenAI
|
| 60 |
+
model = os.getenv("GROK_TEXT_MODEL", "grok-2-1212")
|
| 61 |
+
client = OpenAI(api_key=os.getenv("GROK_API_KEY"), base_url="https://api.x.ai/v1")
|
| 62 |
+
response = client.chat.completions.create(
|
| 63 |
+
model=model,
|
| 64 |
+
messages=[{"role": "user", "content": prompt}],
|
| 65 |
+
max_tokens=2000,
|
| 66 |
+
)
|
| 67 |
+
return response.choices[0].message.content
|
| 68 |
+
|
| 69 |
+
|
| 70 |
def call_hf_inference(prompt: str) -> str:
|
| 71 |
"""Call HF Inference API for code generation."""
|
| 72 |
from huggingface_hub import InferenceClient
|
|
|
|
| 92 |
OBSERVER OUTPUT:
|
| 93 |
{observation.get('observer_output', '')}
|
| 94 |
|
|
|
|
| 95 |
MODE: {state.mode}
|
| 96 |
|
| 97 |
+
The observer has inferred the intent from camera + audio. Generate code based on that inferred intent now."""
|
| 98 |
|
| 99 |
+
provider = os.getenv("PROVIDER", "grok").lower().strip()
|
| 100 |
if provider == "ollama":
|
| 101 |
output = call_ollama(prompt)
|
| 102 |
elif provider == "openai":
|
| 103 |
output = call_openai(prompt)
|
| 104 |
+
elif provider == "grok":
|
| 105 |
+
output = call_grok(prompt)
|
| 106 |
elif provider == "huggingface":
|
| 107 |
output = call_hf_inference(prompt)
|
| 108 |
else:
|
| 109 |
+
raise RuntimeError(f"PROVIDER must be 'grok', 'ollama', 'openai', or 'huggingface', got: {provider!r}.")
|
| 110 |
|
| 111 |
# Build patch receipt
|
| 112 |
patch_hash = sha256_text(output + str(time.time()))
|
src/observer_llm.py
CHANGED
|
@@ -11,22 +11,29 @@ import requests
|
|
| 11 |
from .stream_state import SessionState
|
| 12 |
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
OBSERVER_PROMPT = """You are the Observer in a Continuity Sensory Code Engine.
|
| 15 |
|
| 16 |
You receive a compressed sensory state from live camera + audio streams.
|
| 17 |
-
|
|
|
|
| 18 |
|
| 19 |
-
1.
|
| 20 |
-
2.
|
| 21 |
-
3.
|
| 22 |
-
4.
|
| 23 |
-
5.
|
|
|
|
| 24 |
|
| 25 |
Rules:
|
| 26 |
- Do not hallucinate. If evidence is insufficient, say so.
|
| 27 |
- Separate user speech from background audio.
|
| 28 |
- Do not generate code. That is the Builder's job.
|
| 29 |
-
-
|
|
|
|
| 30 |
"""
|
| 31 |
|
| 32 |
|
|
@@ -60,6 +67,25 @@ def call_openai(prompt: str, frame_b64: str | None = None) -> str:
|
|
| 60 |
return response.choices[0].message.content
|
| 61 |
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
def call_hf_inference(prompt: str, frame_b64: str | None = None) -> str:
|
| 64 |
"""Call HF Inference API using huggingface_hub InferenceClient.
|
| 65 |
|
|
@@ -96,15 +122,17 @@ COMPRESSED SENSORY STATE:
|
|
| 96 |
|
| 97 |
Produce your observation now."""
|
| 98 |
|
| 99 |
-
provider = os.getenv("PROVIDER", "
|
| 100 |
if provider == "ollama":
|
| 101 |
output = call_ollama(prompt, frame_b64)
|
| 102 |
elif provider == "openai":
|
| 103 |
output = call_openai(prompt, frame_b64)
|
|
|
|
|
|
|
| 104 |
elif provider == "huggingface":
|
| 105 |
output = call_hf_inference(prompt, frame_b64)
|
| 106 |
else:
|
| 107 |
-
raise RuntimeError(f"PROVIDER must be 'ollama', 'openai', or 'huggingface', got: {provider!r}.")
|
| 108 |
|
| 109 |
return {
|
| 110 |
"observer_output": output,
|
|
|
|
| 11 |
from .stream_state import SessionState
|
| 12 |
|
| 13 |
|
| 14 |
+
GROK_API_KEY = os.getenv("GROK_API_KEY", "")
|
| 15 |
+
GROK_BASE_URL = "https://api.x.ai/v1"
|
| 16 |
+
|
| 17 |
+
|
| 18 |
OBSERVER_PROMPT = """You are the Observer in a Continuity Sensory Code Engine.
|
| 19 |
|
| 20 |
You receive a compressed sensory state from live camera + audio streams.
|
| 21 |
+
You infer intent from what the camera sees and what audio detects — the user does NOT type instructions.
|
| 22 |
+
Your job is to produce a visible reasoning trace, then a compact observation:
|
| 23 |
|
| 24 |
+
1. REASONING: Think step by step about what you see and hear. What is the user doing? What are they looking at? What code problem is visible? What is the environment?
|
| 25 |
+
2. SCENE: what is visible (objects, screens, code, people, environment)
|
| 26 |
+
3. INFERRED_INTENT: what the user seems to want — infer this from the visual + audio evidence, not from typed instructions
|
| 27 |
+
4. SIGNALS: what audio/speech signals are present, separated by speaker
|
| 28 |
+
5. CANDIDATE_TASK: what code/artifact should be generated based on the inferred intent
|
| 29 |
+
6. UNCERTAINTY: what you cannot determine from the evidence
|
| 30 |
|
| 31 |
Rules:
|
| 32 |
- Do not hallucinate. If evidence is insufficient, say so.
|
| 33 |
- Separate user speech from background audio.
|
| 34 |
- Do not generate code. That is the Builder's job.
|
| 35 |
+
- Always show your reasoning first, then the structured observation.
|
| 36 |
+
- If there is camera movement or sound, that IS the signal — infer what the user wants from it.
|
| 37 |
"""
|
| 38 |
|
| 39 |
|
|
|
|
| 67 |
return response.choices[0].message.content
|
| 68 |
|
| 69 |
|
| 70 |
+
def call_grok(prompt: str, frame_b64: str | None = None) -> str:
|
| 71 |
+
"""Call x.ai Grok API (OpenAI-compatible) with vision support."""
|
| 72 |
+
from openai import OpenAI
|
| 73 |
+
model = os.getenv("GROK_MODEL", "grok-2-vision-1212")
|
| 74 |
+
client = OpenAI(api_key=os.getenv("GROK_API_KEY"), base_url="https://api.x.ai/v1")
|
| 75 |
+
content = [{"type": "text", "text": prompt}]
|
| 76 |
+
if frame_b64:
|
| 77 |
+
content.append({
|
| 78 |
+
"type": "image_url",
|
| 79 |
+
"image_url": {"url": f"data:image/jpeg;base64,{frame_b64}"},
|
| 80 |
+
})
|
| 81 |
+
response = client.chat.completions.create(
|
| 82 |
+
model=model,
|
| 83 |
+
messages=[{"role": "user", "content": content}],
|
| 84 |
+
max_tokens=1000,
|
| 85 |
+
)
|
| 86 |
+
return response.choices[0].message.content
|
| 87 |
+
|
| 88 |
+
|
| 89 |
def call_hf_inference(prompt: str, frame_b64: str | None = None) -> str:
|
| 90 |
"""Call HF Inference API using huggingface_hub InferenceClient.
|
| 91 |
|
|
|
|
| 122 |
|
| 123 |
Produce your observation now."""
|
| 124 |
|
| 125 |
+
provider = os.getenv("PROVIDER", "grok").lower().strip()
|
| 126 |
if provider == "ollama":
|
| 127 |
output = call_ollama(prompt, frame_b64)
|
| 128 |
elif provider == "openai":
|
| 129 |
output = call_openai(prompt, frame_b64)
|
| 130 |
+
elif provider == "grok":
|
| 131 |
+
output = call_grok(prompt, frame_b64)
|
| 132 |
elif provider == "huggingface":
|
| 133 |
output = call_hf_inference(prompt, frame_b64)
|
| 134 |
else:
|
| 135 |
+
raise RuntimeError(f"PROVIDER must be 'grok', 'ollama', 'openai', or 'huggingface', got: {provider!r}.")
|
| 136 |
|
| 137 |
return {
|
| 138 |
"observer_output": output,
|