File size: 10,452 Bytes
71c9f40 7f9ecf5 71c9f40 8933026 71c9f40 b4cdd98 8933026 b4cdd98 71c9f40 81d8f02 71c9f40 b4cdd98 71c9f40 18bbaa5 71c9f40 18bbaa5 71c9f40 7e26975 71c9f40 7e26975 71c9f40 7e26975 71c9f40 7e26975 71c9f40 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Skills">
<meta name="theme-color" content="#0B0D12">
<title>Skills</title>
<link rel="manifest" href="./manifest.json">
<link rel="icon" type="image/svg+xml" href="./icon.svg">
<link rel="apple-touch-icon" href="./icon.svg">
<link rel="stylesheet" href="./style.css">
<script>
// 预判登录态,防刷新闪烁
if (sessionStorage.getItem('skill_auth') === '1') {
document.documentElement.classList.add('authed');
}
</script>
<style>
/* 未登录时隐藏主界面,防闪烁 */
html:not(.authed) body > :not(#loginGate):not(script):not(style) { display: none !important; }
#loginGate { display: flex; }
html.authed #loginGate { display: none; }
</style>
</head>
<body>
<!-- 商用登录页 -->
<div id="loginGate" class="login-gate" hidden>
<div class="login-card">
<div class="login-logo">💬</div>
<h2 class="login-title">Skills</h2>
<p class="login-sub">AI 助手 · 请输入访问密码</p>
<div class="login-input-wrap">
<input id="loginPwd" type="password" placeholder="访问密码" autocomplete="off" autocapitalize="off">
<button id="loginBtn" class="login-btn">进入</button>
</div>
<p id="loginErr" class="login-err" hidden>密码错误,请重试</p>
<p class="login-foot">© 2026 Skills · 仅授权用户可用</p>
</div>
</div>
<header class="header">
<div class="header-left">
<img src="./icon.svg" alt="S" class="avatar">
<div class="title-wrap">
<h1>Skills</h1>
<span class="subtitle">AI Assistant</span>
</div>
</div>
<span id="relayStatus" class="relay-status" title="本地中继状态">●</span>
<!-- 模型提供商快速切换:一键切智谱/CHATSAM/ChatGPT -->
<select id="quickProvSwitch" class="quick-prov-switch" aria-label="切换模型提供商" title="一键切换模型提供商">
<option value="zhipu">🧠 智谱 GLM</option>
<option value="chatsam">🪙 CHATSAM 免Key</option>
<option value="chatgpt">🤖 ChatGPT 官网</option>
</select>
<button id="settingsBtn" class="icon-btn" aria-label="设置">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</svg>
</button>
</header>
<main id="messages" class="messages">
<div class="welcome" id="welcome">
<div class="welcome-icon">把对方的话发过来</div>
<p class="welcome-text">截图、文字、对方资料都行。<br>帮你看清局面,给你能直接发回去的话。</p>
<div class="suggest">
<button class="chip" data-q="她突然说「最近好累啊」,我该回什么">她喊累</button>
<button class="chip" data-q="她回我消息越来越慢了,咋办">回得越来越慢</button>
<button class="chip" data-q="她问我「你是不是对谁都这么好」怎么回">送命题</button>
<button class="chip" data-q="刚加的女生,第一句怎么开口不尴尬">开场白</button>
</div>
</div>
</main>
<div id="imgPreview" class="img-preview" style="display:none"></div>
<footer class="input-bar">
<button id="imgBtn" class="img-btn" type="button" aria-label="发截图">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
<circle cx="12" cy="13" r="4"/>
</svg>
</button>
<input id="imgInput" type="file" accept="image/*" hidden>
<textarea id="input" rows="1" placeholder="把对方发的话贴过来,或点左边发截图..." autocomplete="off"></textarea>
<button id="sendBtn" class="send-btn" aria-label="发送">
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
<path d="M3.4 20.4l17.45-7.48a1 1 0 0 0 0-1.84L3.4 3.6a.993.993 0 0 0-1.39.91L2 9.12c0 .5.37.93.87.99L17 12 2.87 13.88c-.5.07-.87.5-.87 1l.01 4.61c0 .71.73 1.2 1.39.91z"/>
</svg>
</button>
</footer>
<!-- 设置面板 -->
<div id="settingsModal" class="modal" hidden>
<div class="modal-mask"></div>
<div class="modal-body">
<div class="modal-head">
<h2>设置</h2>
<button id="closeSettings" class="icon-btn" aria-label="关闭">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
</button>
</div>
<div class="field">
<label>女生档案(自动记录,互不混淆)</label>
<div id="girlsList" class="girls-list"></div>
</div>
<div class="field">
<label for="provider">AI 模型</label>
<select id="provider">
<option value="chatsam" selected>CHATSAM(内置号池·免配置·推荐)</option>
<option value="chatgpt">ChatGPT 官网多账号池(免费·无限制)</option>
<option value="zhipu">智谱 AI(GLM 系列模型轮调)</option>
</select>
</div>
<!-- 各平台 API 获取说明(切换 provider 自动更新) -->
<div id="providerGuide" class="provider-guide"></div>
<!-- 智谱模型余额显示 -->
<div id="zhipuQuotas" class="field" style="display:none"></div>
<!-- 本地中继状态 -->
<div id="relayBox" class="field relay-box">
<label>本地中继 <span id="relayDot" class="relay-dot offline">●</span></label>
<p class="hint" id="relayHint">本地中继未启动,正在使用 Cloudflare Worker(可能遇到 403 限流)</p>
<div class="relay-cmd">
<code id="relayCmd">node relay.mjs</code>
<button id="copyRelayCmd" class="ghost-btn" type="button" title="复制启动命令">复制</button>
</div>
</div>
<!-- 自定义 Base URL(不再需要,Worker 已硬编码) -->
<div class="field" id="baseUrlField" style="display:none">
<label for="baseUrl">Base URL(自定义后端)</label>
<input type="text" id="baseUrl" placeholder="http://localhost:3000/v1/chat/completions" autocomplete="off">
<p class="hint hint-tip">只对需要本机后端的平台显示(如 chatsam-hf)。填完整 endpoint,不要带 Bearer。</p>
</div>
<!-- 账号池(access_token / API Key,根据 provider 动态切换) -->
<div class="field" id="keyField">
<label id="keyFieldLabel">账号池(多 Key 自动轮询)</label>
<div id="keyList" class="key-list"></div>
<div class="key-add-row" id="keyAddRow">
<input type="text" id="newKeyName" placeholder="备注(如:账号1)" autocomplete="off">
<input type="password" id="newKeyVal" placeholder="粘贴 API Key / access_token" autocomplete="off">
<select id="newKeyModel" class="model-select">
<option value="gpt-4o" selected>GPT-4o</option>
<option value="gpt-4o-mini">GPT-4o mini</option>
<option value="gpt-4.1">GPT-4.1</option>
<option value="gpt-4.1-mini">GPT-4.1 mini</option>
<option value="o1">o1</option>
<option value="o1-mini">o1 mini</option>
<option value="o3">o3</option>
<option value="o3-mini">o3 mini</option>
</select>
<button id="addKeyBtn" class="add-key-btn" type="button">添加</button>
</div>
<a id="getKeyLink" class="hint" href="https://chatgpt.com" target="_blank" rel="noopener">→ 打开 chatgpt.com 登录账号拿 access_token</a>
<p class="hint hint-tip" id="keyHintTip">多账号 token 都加进来,自动轮询;单账号限流/失效不影响其他。Token 存本机 localStorage,不上传服务器。</p>
</div>
<!-- 账号仪表盘(类型 / 状态 / 账号信息 / 额度 / 恢复时间 / 成功 / 失败 / 操作) -->
<div class="field">
<div class="dash-head">
<label>账号仪表盘</label>
<button id="refreshAllBtn" class="ghost-btn" type="button" title="批量刷新所有账号的 session/探测">🔄 全部刷新</button>
</div>
<div class="dash-wrap">
<table class="dash-table">
<thead>
<tr>
<th>类型</th>
<th>状态</th>
<th>账号信息</th>
<th>额度</th>
<th>恢复时间</th>
<th>成功</th>
<th>失败</th>
<th>操作</th>
</tr>
</thead>
<tbody id="dashBody">
<tr><td colspan="8" class="empty-tip">还没添加账号</td></tr>
</tbody>
</table>
</div>
</div>
<div class="field-row">
<button id="clearChat" class="ghost-btn">清空对话</button>
<button id="saveSettings" class="primary-btn">保存</button>
</div>
<p class="footnote">Key 只存在你本机浏览器,不会上传。换设备需重新填。</p>
</div>
</div>
<script src="./app.js"></script>
</body>
</html>
|