148 lines
6.3 KiB
C
148 lines
6.3 KiB
C
#pragma once
|
|
|
|
static const char ONBOARD_HTML[] =
|
|
"<!DOCTYPE html><html><head>"
|
|
"<meta charset='utf-8'>"
|
|
"<meta name='viewport' content='width=device-width,initial-scale=1'>"
|
|
"<title>MimiClaw Setup</title>"
|
|
"<style>"
|
|
"*{box-sizing:border-box;margin:0;padding:0}"
|
|
"body{font-family:-apple-system,sans-serif;background:#f5f5f5;color:#333;padding:16px;max-width:480px;margin:0 auto}"
|
|
"h1{text-align:center;margin:16px 0;font-size:1.4em;color:#1a73e8}"
|
|
".card{background:#fff;border-radius:12px;margin:12px 0;box-shadow:0 1px 3px rgba(0,0,0,.12);overflow:hidden}"
|
|
".card-hdr{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;cursor:pointer;user-select:none;font-weight:600;font-size:.95em}"
|
|
".card-hdr::after{content:'\\25BC';font-size:.7em;transition:transform .2s}"
|
|
".card.collapsed .card-hdr::after{transform:rotate(-90deg)}"
|
|
".card.collapsed .card-body{display:none}"
|
|
".card-body{padding:0 16px 16px}"
|
|
"label{display:block;margin:10px 0 4px;font-size:.85em;color:#555}"
|
|
"input,select{width:100%;padding:10px 12px;border:1px solid #ddd;border-radius:8px;font-size:.95em;outline:none}"
|
|
"input:focus,select:focus{border-color:#1a73e8}"
|
|
".btn{display:block;width:100%;padding:12px;border:none;border-radius:8px;font-size:1em;font-weight:600;cursor:pointer;margin:8px 0}"
|
|
".btn-scan{background:#e8f0fe;color:#1a73e8}"
|
|
".btn-save{background:#1a73e8;color:#fff;margin-top:20px;font-size:1.1em}"
|
|
".btn:active{opacity:.8}"
|
|
".ap-list{max-height:200px;overflow-y:auto;border:1px solid #ddd;border-radius:8px;margin:8px 0}"
|
|
".ap-item{padding:10px 12px;border-bottom:1px solid #eee;cursor:pointer;display:flex;justify-content:space-between}"
|
|
".ap-item:last-child{border-bottom:none}"
|
|
".ap-item:active{background:#e8f0fe}"
|
|
".ap-rssi{color:#888;font-size:.85em}"
|
|
".ap-lock::before{content:'\\1F512';font-size:.75em;margin-right:4px}"
|
|
".status{text-align:center;padding:20px;color:#1a73e8;font-size:1.1em;display:none}"
|
|
"</style></head><body>"
|
|
"<h1>MimiClaw Setup</h1>"
|
|
"<p style='text-align:center;color:#666;font-size:.9em;margin-bottom:12px'>"
|
|
"This local portal remains available at 192.168.4.1 for later updates."
|
|
"</p>"
|
|
|
|
/* WiFi section (expanded by default) */
|
|
"<div class='card' id='sec-wifi'>"
|
|
"<div class='card-hdr' onclick='toggle(this)'>WiFi Configuration</div>"
|
|
"<div class='card-body'>"
|
|
"<button class='btn btn-scan' onclick='scan()'>Scan WiFi Networks</button>"
|
|
"<div class='ap-list' id='ap-list' style='display:none'></div>"
|
|
"<label>SSID</label>"
|
|
"<input id='ssid' placeholder='WiFi network name'>"
|
|
"<label>Password</label>"
|
|
"<input id='password' type='password' placeholder='WiFi password'>"
|
|
"</div></div>"
|
|
|
|
/* LLM section */
|
|
"<div class='card collapsed' id='sec-llm'>"
|
|
"<div class='card-hdr' onclick='toggle(this)'>LLM Configuration</div>"
|
|
"<div class='card-body'>"
|
|
"<label>API Key</label>"
|
|
"<input id='api_key' type='password' placeholder='sk-...'>"
|
|
"<label>Model</label>"
|
|
"<input id='model' placeholder='claude-opus-4-5' value='claude-opus-4-5'>"
|
|
"<label>Provider</label>"
|
|
"<select id='provider'>"
|
|
"<option value='anthropic'>Anthropic</option>"
|
|
"<option value='openai'>OpenAI</option>"
|
|
"</select>"
|
|
"</div></div>"
|
|
|
|
/* Telegram section */
|
|
"<div class='card collapsed' id='sec-tg'>"
|
|
"<div class='card-hdr' onclick='toggle(this)'>Telegram Bot</div>"
|
|
"<div class='card-body'>"
|
|
"<label>Bot Token</label>"
|
|
"<input id='tg_token' placeholder='123456:ABC-DEF...'>"
|
|
"</div></div>"
|
|
|
|
/* Feishu section */
|
|
"<div class='card collapsed' id='sec-feishu'>"
|
|
"<div class='card-hdr' onclick='toggle(this)'>Feishu</div>"
|
|
"<div class='card-body'>"
|
|
"<label>App ID</label>"
|
|
"<input id='feishu_app_id' placeholder='cli_xxxx'>"
|
|
"<label>App Secret</label>"
|
|
"<input id='feishu_app_secret' type='password' placeholder='App Secret'>"
|
|
"</div></div>"
|
|
|
|
/* Proxy section */
|
|
"<div class='card collapsed' id='sec-proxy'>"
|
|
"<div class='card-hdr' onclick='toggle(this)'>Proxy</div>"
|
|
"<div class='card-body'>"
|
|
"<label>Host</label>"
|
|
"<input id='proxy_host' placeholder='192.168.1.100'>"
|
|
"<label>Port</label>"
|
|
"<input id='proxy_port' type='number' placeholder='7890'>"
|
|
"<label>Type</label>"
|
|
"<select id='proxy_type'>"
|
|
"<option value=''>None</option>"
|
|
"<option value='http'>HTTP</option>"
|
|
"<option value='socks5'>SOCKS5</option>"
|
|
"</select>"
|
|
"</div></div>"
|
|
|
|
/* Search section */
|
|
"<div class='card collapsed' id='sec-search'>"
|
|
"<div class='card-hdr' onclick='toggle(this)'>Search</div>"
|
|
"<div class='card-body'>"
|
|
"<label>Brave Search API Key</label>"
|
|
"<input id='search_key' type='password' placeholder='BSA...'>"
|
|
"<label>Tavily API Key</label>"
|
|
"<input id='tavily_key' type='password' placeholder='tvly-...'>"
|
|
"</div></div>"
|
|
|
|
"<button class='btn btn-save' onclick='save()'>Save & Restart</button>"
|
|
"<div class='status' id='status'>Saving... Device will restart.</div>"
|
|
|
|
"<script>"
|
|
"function toggle(el){"
|
|
"el.parentElement.classList.toggle('collapsed')}"
|
|
|
|
"function loadConfig(){"
|
|
"fetch('/config').then(r=>r.json()).then(cfg=>{"
|
|
"Object.keys(cfg).forEach(k=>{"
|
|
"var el=document.getElementById(k);"
|
|
"if(el && cfg[k] !== undefined && cfg[k] !== null){el.value=cfg[k]}"
|
|
"})"
|
|
"}).catch(()=>{})}"
|
|
|
|
"function scan(){"
|
|
"var btn=event.target;btn.textContent='Scanning...';btn.disabled=true;"
|
|
"fetch('/scan').then(r=>r.json()).then(list=>{"
|
|
"var el=document.getElementById('ap-list');el.style.display='block';el.innerHTML='';"
|
|
"list.forEach(ap=>{"
|
|
"var d=document.createElement('div');d.className='ap-item';"
|
|
"d.innerHTML='<span>'+(ap.auth?'<span class=ap-lock></span>':'')+ap.ssid+'</span><span class=ap-rssi>'+ap.rssi+' dBm</span>';"
|
|
"d.onclick=function(){document.getElementById('ssid').value=ap.ssid};"
|
|
"el.appendChild(d)});"
|
|
"btn.textContent='Scan WiFi Networks';btn.disabled=false;"
|
|
"}).catch(()=>{btn.textContent='Scan WiFi Networks';btn.disabled=false})}"
|
|
|
|
"function save(){"
|
|
"var fields=['ssid','password','api_key','model','provider','tg_token',"
|
|
"'feishu_app_id','feishu_app_secret','proxy_host','proxy_port','proxy_type','search_key','tavily_key'];"
|
|
"var data={};"
|
|
"fields.forEach(f=>{data[f]=document.getElementById(f).value.trim()});"
|
|
"document.getElementById('status').style.display='block';"
|
|
"fetch('/save',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)})"
|
|
".then(()=>{document.getElementById('status').textContent='Saved! Restarting...';})"
|
|
".catch(()=>{document.getElementById('status').textContent='Error. Please try again.';})}"
|
|
"loadConfig();"
|
|
"</script>"
|
|
"</body></html>";
|