josephrw commited on
Commit
abb0643
·
verified ·
1 Parent(s): 4f7624c

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. app.py +24 -24
  2. frontend/index.html +84 -19
app.py CHANGED
@@ -738,30 +738,30 @@ async def api_help():
738
  "description": "Live multimodal code compiler: camera + audio + speech → observer LLM → builder LLM → code patches. Supports long-running terminal sessions for backtesting.",
739
  "base_url": f"https://josephrw-csc-engine.hf.space",
740
  "endpoints": [
741
- {"method": "GET", "path": "/health", "description": "Health check — returns provider, version, active sessions"},
742
- {"method": "POST", "path": "/session/start", "description": "Start a CSC Engine session"},
743
- {"method": "POST", "path": "/session/stop", "description": "Stop a session by session_id"},
744
- {"method": "GET", "path": "/state/current", "description": "Get current session state (requires session_id)"},
745
- {"method": "POST", "path": "/generate/patch", "description": "Force a code generation cycle (requires session_id)"},
746
- {"method": "POST", "path": "/run", "description": "Execute Python code — pass code or patch_hash. Returns stdout/stderr/exit_code"},
747
- {"method": "POST", "path": "/debug", "description": "Send failed code + stderr to LLM for auto-fix. Pass patch_hash or code+stderr"},
748
- {"method": "POST", "path": "/store-artifact", "description": "Store generated code + metadata for diary. Pass patch_hash, code, reasoning, evidence, observer_output"},
749
- {"method": "GET", "path": "/artifact/{patch_hash}", "description": "View artifact as HTML page with Run and Debug buttons"},
750
- {"method": "GET", "path": "/api/artifacts", "description": "List all artifacts as JSON (limit param, default 50)"},
751
- {"method": "GET", "path": "/api/artifacts/{patch_hash}", "description": "Get single artifact as JSON"},
752
- {"method": "GET", "path": "/receipts", "description": "List all patch receipts (limit param)"},
753
- {"method": "GET", "path": "/receipts/{receipt_id}", "description": "Get a specific receipt"},
754
- {"method": "POST", "path": "/audio/store", "description": "Store base64-encoded audio recording alongside an artifact"},
755
- {"method": "GET", "path": "/audio/{filename}", "description": "Serve an audio file"},
756
- {"method": "GET", "path": "/diary", "description": "Lab diary page — notebook-style view of all artifacts"},
757
- {"method": "POST", "path": "/terminal/create", "description": "Create a long-running terminal session for backtesting. Pass cwd (default /tmp)"},
758
- {"method": "POST", "path": "/terminal/{session_id}/exec", "description": "Execute a command in a terminal session. Pass command string. Supports 300s timeout"},
759
- {"method": "GET", "path": "/terminal/{session_id}/output", "description": "Get accumulated output from a terminal session. Pass since=timestamp to get only new output"},
760
- {"method": "POST", "path": "/terminal/{session_id}/kill", "description": "Kill a terminal session"},
761
- {"method": "GET", "path": "/terminal/{session_id}/status", "description": "Get status of a terminal session"},
762
- {"method": "GET", "path": "/terminal/sessions", "description": "List all active terminal sessions"},
763
- {"method": "GET", "path": "/api/help", "description": "This endpoint — lists all available endpoints"},
764
- {"method": "GET", "path": "/openapi.json", "description": "OpenAPI 3.1 schema for ChatGPT custom GPT integration"},
765
  ],
766
  "chatgpt_integration": {
767
  "schema_url": "/openapi.json",
 
738
  "description": "Live multimodal code compiler: camera + audio + speech → observer LLM → builder LLM → code patches. Supports long-running terminal sessions for backtesting.",
739
  "base_url": f"https://josephrw-csc-engine.hf.space",
740
  "endpoints": [
741
+ {"method": "GET", "path": "/health", "description": "Health check — returns provider, version, active sessions", "params": []},
742
+ {"method": "POST", "path": "/session/start", "description": "Start a CSC Engine session", "params": []},
743
+ {"method": "POST", "path": "/session/stop", "description": "Stop a session by session_id", "params": [{"name": "session_id", "type": "text", "required": true, "placeholder": "session UUID"}]},
744
+ {"method": "GET", "path": "/state/current", "description": "Get current session state (requires session_id)", "params": [{"name": "session_id", "type": "text", "required": true, "placeholder": "session UUID"}]},
745
+ {"method": "POST", "path": "/generate/patch", "description": "Force a code generation cycle (requires session_id)", "params": [{"name": "session_id", "type": "text", "required": true, "placeholder": "session UUID"}]},
746
+ {"method": "POST", "path": "/run", "description": "Execute Python code — pass code or patch_hash. Returns stdout/stderr/exit_code", "params": [{"name": "code", "type": "textarea", "required": false, "placeholder": "print('hello')"}, {"name": "patch_hash", "type": "text", "required": false, "placeholder": "artifact hash"}]},
747
+ {"method": "POST", "path": "/debug", "description": "Send failed code + stderr to LLM for auto-fix. Pass patch_hash or code+stderr", "params": [{"name": "patch_hash", "type": "text", "required": false, "placeholder": "artifact hash"}, {"name": "code", "type": "textarea", "required": false, "placeholder": "failed code"}, {"name": "stderr", "type": "textarea", "required": false, "placeholder": "error output"}]},
748
+ {"method": "POST", "path": "/store-artifact", "description": "Store generated code + metadata for diary", "params": [{"name": "patch_hash", "type": "text", "required": true, "placeholder": "hash"}, {"name": "code", "type": "textarea", "required": false, "placeholder": "code"}, {"name": "reasoning", "type": "text", "required": false, "placeholder": "reasoning"}, {"name": "observer_output", "type": "textarea", "required": false, "placeholder": "observer output"}]},
749
+ {"method": "GET", "path": "/artifact/{patch_hash}", "description": "View artifact as HTML page with Run and Debug buttons", "params": [{"name": "patch_hash", "type": "text", "required": true, "placeholder": "artifact hash (in path)"}]},
750
+ {"method": "GET", "path": "/api/artifacts", "description": "List all artifacts as JSON (limit param, default 50)", "params": [{"name": "limit", "type": "text", "required": false, "placeholder": "50"}]},
751
+ {"method": "GET", "path": "/api/artifacts/{patch_hash}", "description": "Get single artifact as JSON", "params": [{"name": "patch_hash", "type": "text", "required": true, "placeholder": "artifact hash (in path)"}]},
752
+ {"method": "GET", "path": "/receipts", "description": "List all patch receipts (limit param)", "params": [{"name": "limit", "type": "text", "required": false, "placeholder": "50"}]},
753
+ {"method": "GET", "path": "/receipts/{receipt_id}", "description": "Get a specific receipt", "params": [{"name": "receipt_id", "type": "text", "required": true, "placeholder": "receipt ID (in path)"}]},
754
+ {"method": "POST", "path": "/audio/store", "description": "Store base64-encoded audio recording alongside an artifact", "params": [{"name": "patch_hash", "type": "text", "required": true, "placeholder": "hash"}, {"name": "audio_b64", "type": "textarea", "required": true, "placeholder": "base64 audio"}]},
755
+ {"method": "GET", "path": "/audio/{filename}", "description": "Serve an audio file", "params": [{"name": "filename", "type": "text", "required": true, "placeholder": "filename.webm (in path)"}]},
756
+ {"method": "GET", "path": "/diary", "description": "Lab diary page — notebook-style view of all artifacts", "params": []},
757
+ {"method": "POST", "path": "/terminal/create", "description": "Create a long-running terminal session for backtesting", "params": [{"name": "cwd", "type": "text", "required": false, "placeholder": "/tmp"}]},
758
+ {"method": "POST", "path": "/terminal/{session_id}/exec", "description": "Execute a command in a terminal session. Supports 300s timeout", "params": [{"name": "session_id", "type": "text", "required": true, "placeholder": "term_xxxx (in path)"}, {"name": "command", "type": "text", "required": true, "placeholder": "ls -la"}, {"name": "timeout", "type": "text", "required": false, "placeholder": "300"}]},
759
+ {"method": "GET", "path": "/terminal/{session_id}/output", "description": "Get accumulated output from a terminal session", "params": [{"name": "session_id", "type": "text", "required": true, "placeholder": "term_xxxx (in path)"}, {"name": "since", "type": "text", "required": false, "placeholder": "0"}]},
760
+ {"method": "POST", "path": "/terminal/{session_id}/kill", "description": "Kill a terminal session", "params": [{"name": "session_id", "type": "text", "required": true, "placeholder": "term_xxxx (in path)"}]},
761
+ {"method": "GET", "path": "/terminal/{session_id}/status", "description": "Get status of a terminal session", "params": [{"name": "session_id", "type": "text", "required": true, "placeholder": "term_xxxx (in path)"}]},
762
+ {"method": "GET", "path": "/terminal/sessions", "description": "List all active terminal sessions", "params": []},
763
+ {"method": "GET", "path": "/api/help", "description": "This endpoint — lists all available endpoints", "params": []},
764
+ {"method": "GET", "path": "/gpt-actions.json", "description": "ChatGPT Custom GPT Actions schema (OpenAPI 3.1)", "params": []},
765
  ],
766
  "chatgpt_integration": {
767
  "schema_url": "/openapi.json",
frontend/index.html CHANGED
@@ -2043,39 +2043,104 @@
2043
  try {
2044
  const resp = await fetch("/api/help");
2045
  const data = await resp.json();
2046
- const el = document.getElementById("apiEndpoints");
2047
- el.innerHTML = data.endpoints.map((e, i) =>
2048
- '<div class="api-endpoint" onclick="toggleApiResponse(' + i + ')">' +
2049
- '<span class="api-method ' + e.method + '">' + e.method + '</span>' +
2050
- '<span class="api-path">' + e.path + '</span>' +
2051
- '<div class="api-desc">' + e.description + '</div>' +
2052
- '<button class="api-try-btn" onclick="event.stopPropagation();tryEndpoint(' + i + ')">Try it</button>' +
2053
- '<div class="api-response" id="apiResp' + i + '"></div>' +
2054
- '</div>'
2055
- ).join("");
2056
  window._apiEndpoints = data.endpoints;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2057
  } catch (e) {
2058
  document.getElementById("apiEndpoints").innerHTML = '<div style="color:var(--red)">Error loading: ' + escapeHtml(e.message) + '</div>';
2059
  }
2060
  }
2061
 
2062
- function toggleApiResponse(i) {
2063
- const el = document.getElementById("apiResp" + i);
2064
- el.classList.toggle("open");
 
 
 
 
 
 
 
2065
  }
2066
 
2067
  async function tryEndpoint(i) {
2068
  const ep = window._apiEndpoints[i];
2069
- const el = document.getElementById("apiResp" + i);
2070
- el.classList.add("open");
2071
- el.textContent = "Loading...";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2072
  try {
2073
  const opts = { method: ep.method };
2074
- const resp = await fetch(ep.path, opts);
2075
  const text = await resp.text();
2076
- el.textContent = text.slice(0, 2000);
 
 
 
 
 
 
 
 
2077
  } catch (e) {
2078
- el.textContent = "Error: " + e.message;
 
2079
  }
2080
  }
2081
 
 
2043
  try {
2044
  const resp = await fetch("/api/help");
2045
  const data = await resp.json();
 
 
 
 
 
 
 
 
 
 
2046
  window._apiEndpoints = data.endpoints;
2047
+ const el = document.getElementById("apiEndpoints");
2048
+ el.innerHTML = data.endpoints.map((e, i) => {
2049
+ let paramsHtml = '';
2050
+ if (e.params && e.params.length > 0) {
2051
+ paramsHtml = '<div class="api-params" style="margin-top:8px;display:flex;flex-direction:column;gap:6px">';
2052
+ for (const p of e.params) {
2053
+ const req = p.required ? ' <span style="color:var(--red)">*</span>' : '';
2054
+ if (p.type === 'textarea') {
2055
+ paramsHtml += '<label style="font-size:10px;color:var(--text2)">' + p.name + req + '</label>' +
2056
+ '<textarea id="apiparam_' + i + '_' + p.name + '" placeholder="' + (p.placeholder || '') + '" style="background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:6px 8px;color:var(--text);font-family:var(--mono);font-size:11px;min-height:60px;resize:vertical;outline:none" onfocus="this.style.borderColor=\'var(--accent)\'" onblur="this.style.borderColor=\'var(--border)\'"></textarea>';
2057
+ } else {
2058
+ paramsHtml += '<div style="display:flex;align-items:center;gap:6px">' +
2059
+ '<label style="font-size:10px;color:var(--text2);min-width:80px">' + p.name + req + '</label>' +
2060
+ '<input id="apiparam_' + i + '_' + p.name + '" type="text" placeholder="' + (p.placeholder || '') + '" style="flex:1;background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:4px 8px;color:var(--text);font-family:var(--mono);font-size:11px;outline:none" onfocus="this.style.borderColor=\'var(--accent)\'" onblur="this.style.borderColor=\'var(--border)\'" />' +
2061
+ '</div>';
2062
+ }
2063
+ }
2064
+ paramsHtml += '</div>';
2065
+ }
2066
+ return '<div class="api-endpoint" id="apiep_' + i + '">' +
2067
+ '<div style="display:flex;align-items:center;cursor:pointer" onclick="toggleEndpointExpand(' + i + ')">' +
2068
+ '<span class="api-method ' + e.method + '">' + e.method + '</span>' +
2069
+ '<span class="api-path">' + e.path + '</span>' +
2070
+ '<span style="margin-left:auto;font-size:10px;color:var(--text2)" id="apitoggle_' + i + '">▸</span>' +
2071
+ '</div>' +
2072
+ '<div class="api-desc">' + e.description + '</div>' +
2073
+ '<div class="api-expand" id="apiexpand_' + i + '" style="display:none">' +
2074
+ paramsHtml +
2075
+ '<button class="api-try-btn" onclick="event.stopPropagation();tryEndpoint(' + i + ')" style="margin-top:8px">▶ Send Request</button>' +
2076
+ '<div class="api-response" id="apiResp' + i + '"></div>' +
2077
+ '</div>' +
2078
+ '</div>';
2079
+ }).join("");
2080
  } catch (e) {
2081
  document.getElementById("apiEndpoints").innerHTML = '<div style="color:var(--red)">Error loading: ' + escapeHtml(e.message) + '</div>';
2082
  }
2083
  }
2084
 
2085
+ function toggleEndpointExpand(i) {
2086
+ const expand = document.getElementById("apiexpand_" + i);
2087
+ const toggle = document.getElementById("apitoggle_" + i);
2088
+ if (expand.style.display === "none") {
2089
+ expand.style.display = "block";
2090
+ toggle.textContent = "▾";
2091
+ } else {
2092
+ expand.style.display = "none";
2093
+ toggle.textContent = "▸";
2094
+ }
2095
  }
2096
 
2097
  async function tryEndpoint(i) {
2098
  const ep = window._apiEndpoints[i];
2099
+ const respEl = document.getElementById("apiResp" + i);
2100
+ respEl.classList.add("open");
2101
+ respEl.textContent = "Sending...";
2102
+ respEl.style.color = "var(--text2)";
2103
+
2104
+ // Build URL — replace path params and add query params
2105
+ let url = ep.path;
2106
+ const queryParams = [];
2107
+
2108
+ for (const p of (ep.params || [])) {
2109
+ const input = document.getElementById("apiparam_" + i + "_" + p.name);
2110
+ if (!input) continue;
2111
+ const val = input.value.trim();
2112
+ if (!val) continue;
2113
+
2114
+ // Check if it's a path param ({name} in path)
2115
+ const pathPlaceholder = "{" + p.name + "}";
2116
+ if (url.includes(pathPlaceholder)) {
2117
+ url = url.replace(pathPlaceholder, encodeURIComponent(val));
2118
+ } else {
2119
+ // Query param
2120
+ queryParams.push(encodeURIComponent(p.name) + "=" + encodeURIComponent(val));
2121
+ }
2122
+ }
2123
+
2124
+ if (queryParams.length > 0) {
2125
+ url += (url.includes("?") ? "&" : "?") + queryParams.join("&");
2126
+ }
2127
+
2128
  try {
2129
  const opts = { method: ep.method };
2130
+ const resp = await fetch(url, opts);
2131
  const text = await resp.text();
2132
+ // Try to pretty-print JSON
2133
+ try {
2134
+ const json = JSON.parse(text);
2135
+ respEl.textContent = JSON.stringify(json, null, 2).slice(0, 3000);
2136
+ respEl.style.color = resp.ok ? "var(--green)" : "var(--amber)";
2137
+ } catch {
2138
+ respEl.textContent = text.slice(0, 3000);
2139
+ respEl.style.color = resp.ok ? "var(--green)" : "var(--amber)";
2140
+ }
2141
  } catch (e) {
2142
+ respEl.textContent = "Error: " + e.message;
2143
+ respEl.style.color = "var(--red)";
2144
  }
2145
  }
2146