SIMON Master Console Rebuild
True command center for SIMON + WEB360
This rebuild gives you a cleaner production spine: interactive tree, live viewer, guarded editor, dynamic graphics, architecture map, and note storage. It is designed to sit beside your existing
console.php
and become the stronger replacement path.
Dashboard
Tree
Viewer
System Map
File Registry
Notes
Files
15,026
Folders
377
Scanned Size
3.79 GB
PHP Files
791
Editable Text Files
12,310
File viewer
guarded to /htdocs
/api/talk.php
<?php declare(strict_types=1); ini_set('display_errors', '0'); error_reporting(E_ALL); header('Content-Type: application/json; charset=utf-8'); const OPENAI_BASE = 'https://api.openai.com/v1'; const STORAGE_DIR = __DIR__ . '/tmp_audio'; const DEFAULT_TEXT_MODEL = 'gpt-5.1'; const DEFAULT_TRANSCRIBE_MODEL = 'gpt-4o-mini-transcribe'; const DEFAULT_TTS_MODEL = 'gpt-4o-mini-tts'; const DEFAULT_VOICE = 'fable'; const DEFAULT_FORMAT = 'mp3'; const MIN_AUDIO_BYTES = 2000; set_error_handler(function (int $severity, string $message, string $file, int $line): never { http_response_code(500); echo json_encode([ 'ok' => false, 'error' => "PHP error: {$message}", 'file' => basename($file), 'line' => $line ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); exit; }); set_exception_handler(function (Throwable $e): never { http_response_code(500); echo json_encode([ 'ok' => false, 'error' => 'Uncaught exception: ' . $e->getMessage() ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); exit; }); register_shutdown_function(function (): void { $err = error_get_last(); if ($err && in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) { http_response_code(500); echo json_encode([ 'ok' => false, 'error' => 'Fatal error: ' . $err['message'], 'file' => basename($err['file']), 'line' => $err['line'] ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } }); function respond(array $data, int $status = 200): never { http_response_code($status); echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); exit; } function ensureStorageDir(): void { if (!is_dir(STORAGE_DIR)) { if (!mkdir(STORAGE_DIR, 0775, true) && !is_dir(STORAGE_DIR)) { respond([ 'ok' => false, 'error' => 'Failed to create tmp_audio directory.' ], 500); } } if (!is_writable(STORAGE_DIR)) { respond([ 'ok' => false, 'error' => 'tmp_audio directory is not writable.' ], 500); } } function getJsonBody(): array { $raw = file_get_contents('php://input') ?: ''; if ($raw === '') { return []; } $decoded = json_decode($raw, true); return is_array($decoded) ? $decoded : []; } function getHeaderValue(string $name): ?string { $key = 'HTTP_' . strtoupper(str_replace('-', '_', $name)); return $_SERVER[$key] ?? null; } function getApiKey(array $json): string { $headerKey = trim((string)(getHeaderValue('X-Simon-Api-Key') ?? '')); $postKey = trim((string)($_POST['api_key'] ?? '')); $jsonKey = trim((string)($json['api_key'] ?? '')); $envKey = trim((string)(getenv('OPENAI_API_KEY') ?: '')); $key = $headerKey ?: ($postKey ?: ($jsonKey ?: $envKey)); if ($key === '') { respond([ 'ok' => false, 'error' => 'Missing OpenAI API key. Set OPENAI_API_KEY on the server or pass a temporary dev key.' ], 500); } return $key; } function safeBasename(string $path): string { return preg_replace('/[^a-zA-Z0-9._-]/', '_', basename($path)) ?: 'file.bin'; } function normalizeVoice(string $voice): string { $voice = trim($voice); return $voice !== '' ? $voice : DEFAULT_VOICE; } function normalizeFormat(string $format): string { $format = strtolower(trim($format)); return in_array($format, ['mp3', 'wav'], true) ? $format : DEFAULT_FORMAT; } function normalizeModel(string $model): string { $model = trim($model); return $model !== '' ? $model : DEFAULT_TEXT_MODEL; } function curlJsonRequest(string $method, string $url, string $apiKey, array $payload): array { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $apiKey, 'Content-Type: application/json' ], CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), CURLOPT_TIMEOUT => 120, ]); $body = curl_exec($ch); $errno = curl_errno($ch); $error = curl_error($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($errno !== 0) { respond([ 'ok' => false, 'error' => 'cURL JSON error: ' . $error ], 502); } $decoded = json_decode((string)$body, true); if ($code >= 400) { $msg = is_array($decoded) ? ($decoded['error']['message'] ?? $decoded['message'] ?? 'OpenAI JSON request failed') : ('OpenAI JSON request failed with HTTP ' . $code); respond([ 'ok' => false, 'error' => $msg, 'upstream' => $decoded ?: (string)$body ], 502); } if (!is_array($decoded)) { respond([ 'ok' => false, 'error' => 'Invalid JSON returned from upstream service.', 'raw' => substr((string)$body, 0, 1000) ], 502); } return $decoded; } function curlMultipartRequest(string $url, string $apiKey, array $fields): array { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $apiKey ], CURLOPT_POSTFIELDS => $fields, CURLOPT_TIMEOUT => 120, ]); $body = curl_exec($ch); $errno = curl_errno($ch); $error = curl_error($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($errno !== 0) { respond([ 'ok' => false, 'error' => 'cURL multipart error: ' . $error ], 502); } $decoded = json_decode((string)$body, true); if ($code >= 400) { $msg = is_array($decoded) ? ($decoded['error']['message'] ?? $decoded['message'] ?? 'OpenAI multipart request failed') : ('OpenAI multipart request failed with HTTP ' . $code); respond([ 'ok' => false, 'error' => $msg, 'upstream' => $decoded ?: (string)$body ], 502); } if (!is_array($decoded)) { respond([ 'ok' => false, 'error' => 'Invalid JSON returned from multipart upstream service.', 'raw' => substr((string)$body, 0, 1000) ], 502); } return $decoded; } function extractOutputText(array $response): string { if (!empty($response['output_text']) && is_string($response['output_text'])) { return trim($response['output_text']); } $pieces = []; if (!empty($response['output']) && is_array($response['output'])) { foreach ($response['output'] as $item) { if (($item['type'] ?? '') !== 'message') { continue; } $content = $item['content'] ?? []; if (!is_array($content)) { continue; } foreach ($content as $part) { if (($part['type'] ?? '') === 'output_text' && !empty($part['text'])) { $pieces[] = $part['text']; } } } } return trim(implode("\n", $pieces)); } function generateReply(string $apiKey, string $userText, string $model, string $systemPrompt): string { $payload = [ 'model' => normalizeModel($model), 'instructions' => $systemPrompt, 'input' => $userText ]; $response = curlJsonRequest('POST', OPENAI_BASE . '/responses', $apiKey, $payload); $text = extractOutputText($response); if ($text === '') { respond([ 'ok' => false, 'error' => 'No reply text returned from model.', 'response' => $response ], 502); } return $text; } function transcribeUploadedAudio(string $apiKey, array $file): string { if (!isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) { respond([ 'ok' => false, 'error' => 'Uploaded audio is missing or invalid.' ], 400); } $filename = safeBasename((string)($file['name'] ?? 'speech.webm')); $mime = (string)($file['type'] ?? 'audio/webm'); $curlFile = curl_file_create($file['tmp_name'], $mime, $filename); $fields = [ 'model' => DEFAULT_TRANSCRIBE_MODEL, 'file' => $curlFile, 'response_format' => 'json' ]; $response = curlMultipartRequest(OPENAI_BASE . '/audio/transcriptions', $apiKey, $fields); $text = trim((string)($response['text'] ?? '')); if ($text === '') { respond([ 'ok' => false, 'error' => 'No transcription text returned.', 'response' => $response ], 502); } return $text; } function curlBinarySpeech(string $apiKey, string $inputText, string $voice, string $format): string { $payload = [ 'model' => DEFAULT_TTS_MODEL, 'voice' => normalizeVoice($voice), 'input' => $inputText, 'format' => normalizeFormat($format) ]; $ch = curl_init(OPENAI_BASE . '/audio/speech'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $apiKey, 'Content-Type: application/json' ], CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), CURLOPT_TIMEOUT => 120 ]); $body = curl_exec($ch); $errno = curl_errno($ch); $error = curl_error($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); $contentType = (string)curl_getinfo($ch, CURLINFO_CONTENT_TYPE); curl_close($ch); if ($errno !== 0) { respond([ 'ok' => false, 'error' => 'Speech generation error: ' . $error ], 502); } if ($code >= 400) { $decoded = json_decode((string)$body, true); $msg = is_array($decoded) ? ($decoded['error']['message'] ?? $decoded['message'] ?? 'Speech generation failed') : ('Speech generation failed with HTTP ' . $code); respond([ 'ok' => false, 'error' => $msg, 'upstream' => $decoded ?: (string)$body ], 502); } if (str_contains(strtolower($contentType), 'application/json')) { $decoded = json_decode((string)$body, true); respond([ 'ok' => false, 'error' => 'Speech returned JSON instead of audio.', 'debug' => $decoded ?: (string)$body ], 502); } if (strlen((string)$body) < MIN_AUDIO_BYTES) { respond([ 'ok' => false, 'error' => 'Audio response too small and likely invalid.', 'size' => strlen((string)$body) ], 502); } return (string)$body; } function saveAudioFile(string $binaryAudio, string $format): string { ensureStorageDir(); if (strlen($binaryAudio) < MIN_AUDIO_BYTES) { respond([ 'ok' => false, 'error' => 'Invalid audio generated before save.' ], 500); } $ext = strtolower($format) === 'wav' ? 'wav' : 'mp3'; $filename = 'simon_' . date('Ymd_His') . '_' . bin2hex(random_bytes(5)) . '.' . $ext; $fullPath = STORAGE_DIR . '/' . $filename; $written = file_put_contents($fullPath, $binaryAudio); if ($written === false) { respond([ 'ok' => false, 'error' => 'Failed to write audio file to tmp_audio.' ], 500); } if (!is_file($fullPath)) { respond([ 'ok' => false, 'error' => 'Audio file was not created.' ], 500); } $scriptDir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/api/talk.php')), '/'); return $scriptDir . '/tmp_audio/' . rawurlencode($filename); } $json = getJsonBody(); $apiKey = getApiKey($json); $model = normalizeModel((string)($json['model'] ?? $_POST['model'] ?? DEFAULT_TEXT_MODEL)); $voice = normalizeVoice((string)($json['voice'] ?? $_POST['voice'] ?? DEFAULT_VOICE)); $format = normalizeFormat((string)($json['format'] ?? $_POST['format'] ?? DEFAULT_FORMAT)); $system = trim((string)($json['system'] ?? $_POST['system'] ?? 'You are SIMON Intelligence: precise, predictive, helpful, calm, and visually embodied as a cosmic AI guide.')); $userText = ''; if (isset($_FILES['audio'])) { $userText = transcribeUploadedAudio($apiKey, $_FILES['audio']); } else { $userText = trim((string)($json['text'] ?? '')); } if ($userText === '') { respond([ 'ok' => false, 'error' => 'No text or audio input received.' ], 400); } $reply = generateReply($apiKey, $userText, $model, $system); $audioBinary = curlBinarySpeech($apiKey, $reply, $voice, $format); $audioUrl = saveAudioFile($audioBinary, $format); respond([ 'ok' => true, 'heard' => $userText, 'reply' => $reply, 'audio_url' => $audioUrl, 'model' => $model, 'voice' => $voice, 'format' => $format ]);
Save file
Quick jump
open a path
Open