Files
GenericAgent/frontends/desktop/static/index.html
T
dd3xp cace868fc9 fix(desktop): pollSession retries with backoff before giving up
When the phone goes to background, JS is paused and HTTP keepalive

connections die. On return, the first poll's fetch can hit "Failed to

fetch" because of a stale connection / DNS / TLS state. The original

code showed an error immediately on a single failure.

Now: same polling loop tolerates up to 5 consecutive errors with

exponential backoff (1s, 2s, 4s, 8s) before surfacing showError. Any

successful poll resets the error counter. This rides through the

typical 1-3 second post-resume blip without any user-visible failure.

Pairs with the earlier WS auto-reconnect + visibilitychange handler

(both bridge channels — WS and HTTP polling — now recover cleanly).

Bump app.js?v=87 -> 88.
2026-06-04 04:04:20 +08:00

575 lines
30 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>GenericAgent</title>
<link rel="stylesheet" href="assets/fonts/fonts.css">
<link rel="stylesheet" href="styles.css?v=97">
<!-- KaTeX: LaTeX 公式渲染 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css" crossorigin="anonymous">
<!-- highlight.js: 代码高亮 -->
<link id="hljs-theme" rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github.min.css" crossorigin="anonymous">
<!-- Flatpickr: 日期选择器 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.css" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/l10n/zh.js" crossorigin="anonymous"></script>
<script>
(function(){
var t=localStorage.getItem('ga_theme'); if(t) document.documentElement.dataset.theme=t;
var l=localStorage.getItem('ga_lang'); if(l==='en') document.documentElement.lang='en';
var legacy=localStorage.getItem('ga_style');
var app=localStorage.getItem('ga_appearance');
if(!app&&legacy){
if(legacy==='dark') app='dark';
else{ app='light'; if(legacy==='classic') localStorage.setItem('ga_plain','1'); }
localStorage.setItem('ga_appearance',app);
localStorage.removeItem('ga_style');
}
app=app||'light';
document.documentElement.dataset.appearance=app;
if(app==='light'&&localStorage.getItem('ga_plain')==='1') document.documentElement.dataset.plain='1';
var LEGACY_FONT={sm:12,md:14,lg:16};
function chatFontPx(v){
if(v&&LEGACY_FONT[v]) return LEGACY_FONT[v];
var n=parseInt(v,10); if(!isNaN(n)&&n>=10&&n<=20) return n;
return 14;
}
var fs=localStorage.getItem('ga_font_size');
var cfp=chatFontPx(fs);
document.documentElement.dataset.chatFont=String(cfp);
document.documentElement.style.setProperty('--chat-font',cfp+'px');
var hljs=document.getElementById('hljs-theme');
if(hljs&&app==='dark') hljs.href='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github-dark.min.css';
try{ var sraw=localStorage.getItem('ga_sessions'); if(sraw && JSON.parse(sraw).length) document.documentElement.dataset.bootHasSessions='1'; }catch(_){}
})();
</script>
</head>
<body>
<div id="app">
<div class="body">
<!-- ① 左侧边栏 -->
<aside class="sidebar">
<div class="brand">
<div class="brand-text">
<div class="brand-name ga-wordmark">Generic Agent</div>
<div class="brand-sub" data-i18n="brand.sub"></div>
</div>
</div>
<nav class="nav" id="nav">
<a class="nav-item active" data-page="chat">
<span class="ic" data-ga-icon="chatTeardropText"></span>
<span data-i18n="nav.chat"></span>
</a>
<a class="nav-item" data-page="collab">
<span class="ic" aria-hidden="true"></span>
<span data-i18n="nav.collab"></span>
<span id="collab-badge" class="collab-nav-badge" hidden></span>
</a>
<a class="nav-item" data-page="services">
<span class="ic" data-ga-icon="broadcast"></span>
<span data-i18n="nav.services"></span>
</a>
<a class="nav-item" data-page="token">
<span class="ic" data-ga-icon="coins"></span>
<span data-i18n="nav.token"></span>
</a>
</nav>
<div class="sidebar-foot">
<a class="foot-row" id="settings-btn">
<span class="fr-l">
<span class="ic" data-ga-icon="gear"></span>
<span data-i18n="foot.settings"></span>
</span>
<span class="chev" data-ga-icon="caretRight"></span>
</a>
<div class="foot-ver" data-i18n="foot.ver"></div>
</div>
</aside>
<div class="sb-resize" id="sb-resize"></div>
<!-- 中间主区 -->
<main class="main">
<div id="pages">
<!-- 聊天 -->
<section class="page active" data-page="chat"
>
<div class="page-top">
<button type="button" class="pt-icon pt-sb-toggle" aria-label="toggle sidebar">
<span data-ga-icon="caretLeft"></span>
</button>
<button class="run-state" id="run-toggle">
<i class="dot"></i> <span class="rs-label"></span>
</button>
<button type="button" class="pt-icon pt-rp-toggle" aria-label="toggle conversations">
<span data-ga-icon="caretRight"></span>
</button>
</div>
<div class="msg-area">
<div class="chat-start">
<div class="feature-head">
<div class="page-title" data-i18n="chat.startTitle"></div>
<div class="page-sub" data-i18n="chat.startSub"></div>
</div>
<div class="feature-grid"></div>
</div>
<div class="msg-loading" id="msg-loading" hidden aria-live="polite">
<span class="ga-spin" aria-hidden="true"></span>
<span data-i18n="chat.interrupting"></span>
</div>
</div>
<div class="composer">
<div class="composer-top">
<button class="ic-btn" id="upload-btn" data-i18n-title="upload.button" title="">
<span data-ga-icon="paperclip"></span>
</button>
<button class="ic-btn" id="preset-btn">
<span data-ga-icon="lightning"></span>
</button>
</div>
<div class="input" contenteditable="true" role="textbox" aria-multiline="true" data-i18n-ph="composer.placeholder"></div>
<input type="file" id="img-input" multiple hidden>
<div class="thumb-strip" id="thumb-strip" hidden></div>
<div class="composer-bot">
<button class="chip" id="model-chip" data-i18n-title="model.menuLabel" title=""><span class="model-name"></span> <span class="chip-ic" data-ga-icon="caretDown"></span></button>
<button class="send" id="send-btn" type="button">
<span data-ga-icon="paperPlaneTilt"></span>
</button>
</div>
<div class="ga-menu" id="model-menu" hidden></div>
</div>
</section>
<!-- 后台服务:消息通道 + 状态面板 -->
<section class="page" data-page="services">
<div class="page-top">
<button type="button" class="pt-icon pt-sb-toggle" aria-label="toggle sidebar">
<span data-ga-icon="caretLeft"></span>
</button>
<span class="pt-spacer"></span>
<button type="button" class="pt-icon pt-rp-toggle" aria-label="toggle conversations">
<span data-ga-icon="caretRight"></span>
</button>
</div>
<div class="page-pad">
<div class="page-title" data-i18n="page.services.title"></div>
<div class="page-sub" data-i18n="page.services.sub"></div>
<div class="svc-tabs" id="svc-tabs">
<button type="button" class="svc-tab active" data-tab="channels" data-i18n="page.channels.title"></button>
<button type="button" class="svc-tab" data-tab="status" data-i18n="page.status.title"></button>
</div>
<div class="svc-panel active" data-svc-panel="channels">
<div class="list" id="chan-list"></div>
<div class="list-empty" id="chan-empty" hidden data-i18n="ch.empty"></div>
</div>
<div class="svc-panel" data-svc-panel="status">
<div class="list" id="status-list"></div>
</div>
</div>
</section>
<!-- 指挥家 Conductor -->
<section class="page" data-page="collab">
<div class="collab-offline" id="collab-offline" hidden>
<span data-i18n="collab.offline"></span>
<button type="button" class="chip sm" id="collab-retry" data-i18n="collab.retry"></button>
</div>
<div class="collab-reconnect" id="collab-reconnect" hidden data-i18n="collab.reconnect"></div>
<div class="page-top">
<button type="button" class="pt-icon pt-sb-toggle" aria-label="toggle sidebar">
<span data-ga-icon="caretLeft"></span>
</button>
<button class="run-state" id="collab-run-toggle" type="button">
<i class="dot"></i> <span class="rs-label"></span>
</button>
<button type="button" class="pt-icon pt-rp-toggle" aria-label="toggle conversations">
<span data-ga-icon="caretRight"></span>
</button>
</div>
<div class="msg-area collab-msgs" id="collab-msgs">
<div class="collab-scroll">
<div class="collab-guide" id="collab-welcome" hidden>
<div class="feature-head">
<div class="page-title" data-i18n="collab.guideTitle"></div>
<p class="page-sub" data-i18n="collab.guideWhen"></p>
</div>
<div class="collab-guide-steps">
<div class="collab-guide-step">
<span class="collab-guide-ic" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>
<span class="collab-guide-txt"><span class="collab-guide-label" data-i18n="collab.guideStep1t"></span><span class="collab-guide-desc" data-i18n="collab.guideStep1d"></span></span>
</div>
<div class="collab-guide-step">
<span class="collab-guide-ic" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg></span>
<span class="collab-guide-txt"><span class="collab-guide-label" data-i18n="collab.guideStep2t"></span><span class="collab-guide-desc" data-i18n="collab.guideStep2d"></span></span>
</div>
<div class="collab-guide-step">
<span class="collab-guide-ic" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M9 15l2 2 4-4"/></svg></span>
<span class="collab-guide-txt"><span class="collab-guide-label" data-i18n="collab.guideStep3t"></span><span class="collab-guide-desc" data-i18n="collab.guideStep3d"></span></span>
</div>
<div class="collab-guide-step">
<span class="collab-guide-ic" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg></span>
<span class="collab-guide-txt"><span class="collab-guide-label" data-i18n="collab.guideStep4t"></span><span class="collab-guide-desc" data-i18n="collab.guideStep4d"></span></span>
</div>
</div>
</div>
<div class="msgs" id="collab-msg-list" hidden></div>
</div>
<div class="collab-overlay">
<div class="collab-rail" id="collab-rail" hidden>
<button type="button" class="collab-rail-handle" id="collab-rail-toggle" data-i18n-title="collab.showProgressTitle" title="">
<span class="collab-rail-grip" aria-hidden="true"></span>
<svg class="collab-rail-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
<span class="collab-rail-badge collab-rail-run" id="collab-rail-run" hidden>
<span class="collab-rail-spin" aria-hidden="true"></span>
<span class="n" id="collab-rail-run-n">0</span>
</span>
<span class="collab-rail-badge collab-rail-done" id="collab-rail-done" hidden>
<span class="collab-rail-dot" aria-hidden="true"></span>
<span class="n" id="collab-rail-done-n">0</span>
</span>
</button>
</div>
<aside class="collab-prog-panel" id="collab-prog-panel">
<div class="collab-prog-panel-head">
<span data-i18n="collab.progressTitle"></span>
<button type="button" class="ic-btn collab-prog-close" id="collab-prog-close" aria-label="close">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div class="collab-prog-stats" id="collab-progress-stats" hidden></div>
<div class="collab-progress-empty" id="collab-progress-empty" data-i18n="collab.progressEmpty"></div>
<div id="collab-workers"></div>
</aside>
</div>
</div>
<div class="composer cdb-composer" id="cdb-composer">
<div class="collab-quick" id="collab-quick">
<button type="button" class="pill" data-prompt-key="collab.chipProgress" data-i18n="collab.chipProgress"></button>
<button type="button" class="pill" data-prompt-key="collab.chipPause" data-i18n="collab.chipPause"></button>
<button type="button" class="pill" data-prompt-key="collab.chipSummary" data-i18n="collab.chipSummary"></button>
</div>
<div class="cdb-inset">
<div class="thumb-strip" id="cdb-thumb-strip" hidden></div>
<div class="input" id="cdb-input" contenteditable="true" role="textbox" aria-multiline="true" data-i18n-ph="collab.placeholder"></div>
<div class="composer-bot">
<div class="cdb-plus-wrap">
<button type="button" class="ic-btn cdb-plus" id="cdb-plus-btn" aria-haspopup="menu" aria-expanded="false" data-i18n-title="collab.plusMenu" title="">
<span data-ga-icon="plus"></span>
</button>
<div class="ga-menu cdb-menu" id="cdb-menu" hidden role="menu">
<button type="button" class="ga-menu-item" id="cdb-menu-upload" role="menuitem">
<span data-ga-icon="paperclip"></span>
<span data-i18n="upload.button"></span>
</button>
</div>
</div>
<span class="spacer"></span>
<button type="button" class="chip" id="cdb-model-chip" data-i18n-title="model.menuLabel" title="">
<span class="model-name"></span>
<span class="chip-ic" data-ga-icon="caretDown"></span>
</button>
<button type="button" class="send" id="cdb-send" aria-label="send">
<span data-ga-icon="paperPlaneTilt"></span>
</button>
</div>
</div>
<div class="ga-menu" id="cdb-model-menu" hidden></div>
<input type="file" id="cdb-file-input" multiple hidden>
</div>
</section>
<!-- Token 统计 -->
<section class="page" data-page="token">
<div class="page-top">
<button type="button" class="pt-icon pt-sb-toggle" aria-label="toggle sidebar">
<span data-ga-icon="caretLeft"></span>
</button>
<span class="pt-spacer"></span>
<button type="button" class="pt-icon pt-rp-toggle" aria-label="toggle conversations">
<span data-ga-icon="caretRight"></span>
</button>
</div>
<div class="page-pad">
<div class="page-title" data-i18n="page.token.title"></div>
<div class="tok-tabs" id="tok-tabs">
<button class="tok-tab active" data-tab="chat" data-i18n="tok.tabAll"></button>
<button class="tok-tab" data-tab="conductor" data-i18n="tok.tabConductor"></button>
</div>
<div class="tok-filter">
<label data-i18n="tok.from"></label>
<input type="text" id="tok-since" class="tok-date" readonly>
<label data-i18n="tok.to"></label>
<input type="text" id="tok-until" class="tok-date" readonly>
<button class="tok-reset" id="tok-reset" data-i18n="tok.reset"></button>
</div>
<div class="stat-row">
<div class="stat"><div class="s-n" id="tok-total-n">0</div><div class="s-l" data-i18n="tok.total"></div></div>
<div class="stat"><div class="s-n" id="tok-cost-n">¥ 0</div><div class="s-l" data-i18n="tok.cost"></div></div>
<div class="stat"><div class="s-n" id="tok-today-n">0</div><div class="s-l" data-i18n="tok.today"></div></div>
</div>
<div class="tok-chart-wrap" id="tok-chart-wrap">
<button class="tok-chart-toggle" id="tok-chart-toggle" type="button" data-i18n="tok.chartToggle"></button>
<div class="tok-chart" id="tok-chart" hidden></div>
</div>
<table class="tok-table" id="tok-table">
<thead><tr>
<th data-i18n="tok.colSession"></th>
<th data-i18n="tok.colIn"></th>
<th data-i18n="tok.colOut"></th>
<th data-i18n="tok.colCacheW"></th>
<th data-i18n="tok.colCache"></th>
<th data-i18n="tok.cost"></th>
</tr></thead>
<tbody id="tok-tbody"></tbody>
</table>
<div class="tok-pager" id="tok-pager"></div>
<p style="color:var(--muted);font-size:12px;margin-top:12px;text-align:center" data-i18n="tok.disclaimer"></p>
</div>
</section>
</div>
</main>
<!-- ④ 右侧会话面板 -->
<div class="rp-resize" id="rp-resize"></div>
<aside class="rightpanel" id="rightpanel">
<div class="search">
<span class="search-ic" data-ga-icon="magnifyingGlass"></span>
<input data-i18n-ph="search.placeholder" placeholder="" maxlength="50">
</div>
<button class="new-conv">
<span data-ga-icon="plus"></span>
<span data-i18n="conv.new"></span>
</button>
<div class="conv-list"></div>
<!-- 会话操作菜单 -->
<div class="ctx-menu" id="conv-menu" hidden>
<div class="ctx-item" data-act="pin">
<span data-ga-icon="pushPinSimple"></span>
<span data-i18n="ctx.pin"></span>
</div>
<div class="ctx-item" data-act="rename">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>
<span data-i18n="ctx.rename"></span>
</div>
<div class="ctx-item danger" data-act="del">
<span data-ga-icon="trash"></span>
<span data-i18n="ctx.del"></span>
</div>
</div>
</aside>
</div>
<!-- 预设功能 弹窗 -->
<div class="modal" id="preset-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card" role="dialog">
<div class="modal-head">
<div class="modal-title" data-i18n="modal.preset"></div>
<button id="preset-restore-btn" class="preset-restore" type="button" data-i18n="builtinPreset.restoreBtn" hidden></button>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<span data-ga-icon="x"></span>
</button>
</div>
<div class="modal-body preset-pop">
<div class="feature-grid"></div>
</div>
</div>
</div>
<!-- 添加模型 弹窗(模板,未实现)-->
<div class="modal" id="add-model-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card" role="dialog">
<div class="modal-head">
<div class="modal-title" id="model-form-title" data-i18n="modal.addModel"></div>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<span data-ga-icon="x"></span>
</button>
</div>
<div class="modal-body model-form-body">
<form id="add-model-form" class="model-form" autocomplete="off">
<label><span class="field-label"><span data-i18n="model.model"></span><span class="field-req" aria-hidden="true">*</span></span><input name="model" required data-i18n-ph="model.modelPh" maxlength="50"><span class="field-hint" data-i18n="model.modelHint"></span></label>
<label id="model-apikey-label"><span class="field-label"><span data-i18n="model.apikey"></span><span class="field-req" aria-hidden="true">*</span></span><input name="apikey" type="password" data-i18n-ph="model.apikeyPh" id="model-apikey-input" maxlength="200"></label>
<label><span class="field-label"><span data-i18n="model.apibase"></span><span class="field-req" aria-hidden="true">*</span></span><input name="apibase" required data-i18n-ph="model.apibasePh" maxlength="200"></label>
<div class="model-form-field"><span class="field-label"><span data-i18n="model.protocol"></span><span class="field-req" aria-hidden="true">*</span></span>
<div class="seg-group" role="radiogroup">
<label class="seg-opt"><input type="radio" name="protocol" value="oai" required><span data-i18n="model.protocolOai"></span></label>
<label class="seg-opt"><input type="radio" name="protocol" value="claude" required><span data-i18n="model.protocolClaude"></span></label>
</div>
</div>
<label><span data-i18n="model.name"></span><input name="name" data-i18n-ph="model.namePh" data-optional-ph maxlength="50"></label>
<div class="model-form-row">
<label class="model-form-mini"><span data-i18n="model.retries"></span><input name="max_retries" type="text" inputmode="numeric" pattern="[0-9]*" min="1" max="20" value="5"></label>
<label class="model-form-mini"><span data-i18n="model.connTimeout"></span><input name="connect_timeout" type="text" inputmode="numeric" pattern="[0-9]*" min="1" max="300" value="15"></label>
<label class="model-form-mini"><span data-i18n="model.readTimeout"></span><input name="read_timeout" type="text" inputmode="numeric" pattern="[0-9]*" min="5" max="3600" value="300"></label>
</div>
<p class="model-form-err" id="add-model-err" hidden></p>
<div class="model-form-actions">
<button type="button" class="set-btn ghost" data-close data-i18n="common.cancel"></button>
<button type="submit" class="set-btn primary"><span data-i18n="model.save"></span></button>
</div>
</form>
</div>
</div>
</div>
<!-- 自定义预设 弹窗 -->
<div class="modal" id="custom-preset-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card" role="dialog">
<div class="modal-head">
<div class="modal-title" data-i18n="modal.customPreset"></div>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<span data-ga-icon="x"></span>
</button>
</div>
<div class="modal-body cp-body">
<input class="cp-input" id="cp-title" type="text" data-i18n-ph="customPreset.titlePh" placeholder="" maxlength="50">
<textarea class="cp-textarea" id="cp-prompt" rows="6" data-i18n-ph="customPreset.promptPh" placeholder="" maxlength="10000"></textarea>
<div class="cp-error" id="cp-error" hidden></div>
<div class="cp-actions">
<button class="cp-btn" data-close data-i18n="common.cancel" type="button"></button>
<button class="cp-btn cp-btn-primary" id="cp-save" data-i18n="common.save" type="button"></button>
</div>
</div>
</div>
</div>
<!-- 渠道日志 弹窗 -->
<div class="modal" id="chan-log-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card modal-card-wide modal-card-inset" role="dialog">
<div class="modal-head">
<div class="modal-title" id="chan-log-title" data-i18n="modal.channelLogs"></div>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<span data-ga-icon="x"></span>
</button>
</div>
<div class="modal-body modal-body-inset">
<pre class="chan-log-pre" id="chan-log-pre"></pre>
</div>
</div>
</div>
<!-- mykey 配置 弹窗 -->
<div class="modal" id="chan-config-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card modal-card-wide modal-card-inset" role="dialog">
<div class="modal-head">
<div class="modal-title" id="chan-config-title" data-i18n="modal.mykeyConfig"></div>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<span data-ga-icon="x"></span>
</button>
</div>
<div class="modal-body modal-body-inset chan-config-body">
<textarea id="chan-config-editor" class="mykey-editor" spellcheck="false" maxlength="20000"></textarea>
<div class="chan-config-foot">
<button type="button" class="chan-config-save" id="chan-config-save" data-i18n="common.save"></button>
</div>
</div>
</div>
</div>
<!-- 配置 弹窗 -->
<div class="modal" id="settings-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card" role="dialog">
<div class="modal-head">
<div class="modal-title" data-i18n="modal.settings"></div>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<span data-ga-icon="x"></span>
</button>
</div>
<div class="modal-body set-body">
<div class="set-block">
<div class="set-sec-t" data-i18n="set.appearance"></div>
<div class="appear-cards" id="appearance-seg" role="radiogroup">
<button class="appear-card sel" type="button" data-appearance="light" role="radio" aria-checked="true">
<span class="appear-preview appear-preview-light" aria-hidden="true"></span>
<span class="appear-name" data-i18n="appearance.light"></span>
</button>
<button class="appear-card" type="button" data-appearance="dark" role="radio" aria-checked="false">
<span class="appear-preview appear-preview-dark" aria-hidden="true"></span>
<span class="appear-name" data-i18n="appearance.dark"></span>
</button>
</div>
<div class="set-toggle-row" id="plain-ui-row" hidden>
<span class="set-toggle-label" data-i18n="set.plainUi"></span>
<button class="set-switch" type="button" id="plain-ui-switch" role="switch" aria-checked="false">
<span class="set-switch-knob" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="set-block">
<div class="set-sec-t" id="chat-font-label" data-i18n="set.fontSize"></div>
<div class="chat-font-panel">
<div class="chat-font-stepper" id="chat-font-stepper" role="slider"
aria-valuemin="10" aria-valuemax="20" aria-valuenow="14"
aria-valuetext="14px" aria-labelledby="chat-font-label" tabindex="0">
<div class="chat-font-segments" id="chat-font-segments"></div>
</div>
<span class="chat-font-value" id="chat-font-value" aria-hidden="true">14px</span>
<div class="chat-font-scale" aria-hidden="true">
<span class="chat-font-scale-min">10</span>
<span class="chat-font-scale-max">20</span>
</div>
</div>
</div>
<div class="set-block">
<div class="set-sec-t" data-i18n="set.theme"></div>
<div class="color-grid" id="theme-swatches">
<span class="swatch sel" data-theme="1" role="button" tabindex="0" aria-label="1"></span>
<span class="swatch" data-theme="2" role="button" tabindex="0" aria-label="2"></span>
<span class="swatch" data-theme="3" role="button" tabindex="0" aria-label="3"></span>
<span class="swatch" data-theme="4" role="button" tabindex="0" aria-label="4"></span>
<span class="swatch" data-theme="5" role="button" tabindex="0" aria-label="5"></span>
<span class="swatch" data-theme="6" role="button" tabindex="0" aria-label="6"></span>
<span class="swatch" data-theme="7" role="button" tabindex="0" aria-label="7"></span>
<span class="swatch" data-theme="8" role="button" tabindex="0" aria-label="8"></span>
</div>
</div>
<div class="set-block">
<div class="set-sec-t" data-i18n="set.lang"></div>
<div class="model-list lang-list" id="lang-list"></div>
</div>
<div>
<div class="set-sec-t" data-i18n="set.model"></div>
<div class="model-list" id="model-list"></div>
<button class="set-btn" id="add-model-btn" type="button">
<span data-ga-icon="plus"></span>
<span data-i18n="set.addModel"></span>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 图片预览 lightbox -->
<div class="lightbox" id="lightbox" hidden>
<div class="lightbox-backdrop" data-close></div>
<button class="lightbox-x" data-close data-i18n-title="lightbox.closeTitle" title="">×</button>
<img class="lightbox-img" id="lightbox-img" alt="">
</div>
<div id="toast-root" class="toast-root" aria-live="polite"></div>
<script src="vendor/marked.min.js"></script>
<!-- KaTeX JS -->
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js" crossorigin="anonymous"></script>
<!-- highlight.js -->
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js" crossorigin="anonymous"></script>
<script src="phosphor-icons.js"></script>
<script src="app.js?v=88"></script>
</body>
</html>