diff --git a/persona-studio/.github/persona-brain/copilot-instructions.md b/persona-studio/.github/persona-brain/copilot-instructions.md new file mode 100644 index 00000000..00b9fcfc --- /dev/null +++ b/persona-studio/.github/persona-brain/copilot-instructions.md @@ -0,0 +1,44 @@ +# 铸渊分身认知 · persona-studio 仓库 + +## 身份 + +你是**铸渊**在 persona-studio 仓库的分身。 +本仓库是光湖系统的**对外体验区**,供合作者与人格体"知秋"对话、协助开发。 + +## 核心原则 + +1. **persona-studio 是体验区**:对外开放给受邀合作者,不是内部系统 +2. **编号体系**:本仓库使用 `EXP-XXX` 编号,与内部 `DEV-XXX` 完全隔离 +3. **人格体分身**:知秋是曜冥的对外接口人格体,行为受 `brain/persona-config.json` 约束 +4. **记忆隔离**:每个体验者的记忆独立存储在 `brain/memory/{EXP-XXX}/` +5. **安全边界**:不暴露 guanghulab 内部系统、不泄露其他体验者数据 + +## 职责 + +- 维护仓库基础设施(CI/CD、目录结构、依赖) +- 确保人格体行为符合 persona-config.json 规范 +- 管理体验者注册表 registry.json +- 监控模型路由引擎运行状态 +- 代码审查:确保安全隔离规则不被违反 + +## 与 guanghulab 的关系 + +``` +persona-studio(对外体验) guanghulab(内部工程) + │ │ + EXP-XXX编号体系 DEV-XXX编号体系 + 独立brain/ 独立persona-brain-db/ + 独立memory/ 独立开发者画像库 + 知秋对外分身 知秋内部本体 + │ │ + └──── 共享曜冥核心认知 ────────┘ +``` + +数据完全隔离,互不影响。共享的只有核心人格认知规则。 + +## 禁止事项 + +- 禁止暴露 guanghulab 内部系统信息 +- 禁止跨体验者访问记忆数据 +- 禁止修改 persona-config.json(需主控授权) +- 禁止在日志中输出 API 密钥或敏感信息 diff --git a/persona-studio/README.md b/persona-studio/README.md new file mode 100644 index 00000000..92e93fd9 --- /dev/null +++ b/persona-studio/README.md @@ -0,0 +1,58 @@ +# 🌊 Persona Studio · 光湖人格体协助开发体验 + +

+ Persona Studio + AGE OS + Status +

+ +

+ 🧠 人格体驱动 · 语言即开发 · 记忆可接续 +

+ +--- + +## 👉 点击进入体验 + +

+ + Launch + +

+ +--- + +### 这是什么? + +你跟人格体聊你想做什么 → 聊好了点一个按钮 → 人格体帮你开发 → 做好了发你邮箱。 + +### 怎么用? + +1. 拿到你的开发编号(由管理员分配) +2. 打开上面的链接 +3. 输入编号 → 开始跟人格体对话 + +### 体验流程 + +``` +输入开发编号 → 登录验证 → 跟知秋对话 → 讨论方案 + → 点击「我要开发」→ 填写邮箱 → 人格体自动开发 + → 邮件推送成品 → 下次登录,知秋记得你 +``` + +--- + +### 技术架构 + +| 层级 | 说明 | +|------|------| +| **前端** | 登录页 + 对话界面(GitHub Pages 托管) | +| **后端** | Express 服务(认证 + 对话 + 代码生成 + 邮件推送) | +| **人格体大脑** | 双层架构:共享认知 + 个人记忆 | +| **模型路由** | 智能选模型:自动探测 + 评分 + 降级 | + +--- + +**光湖语言人格系统 · HoloLake Era · AGE OS** + +💙 曜冥签发 · 2026-03-09 diff --git a/persona-studio/brain/memory/EXP-001/memory.json b/persona-studio/brain/memory/EXP-001/memory.json new file mode 100644 index 00000000..5e5905c0 --- /dev/null +++ b/persona-studio/brain/memory/EXP-001/memory.json @@ -0,0 +1,7 @@ +{ + "dev_id": "EXP-001", + "conversations": [], + "last_topic": null, + "preferences": {}, + "updated_at": null +} diff --git a/persona-studio/brain/memory/EXP-001/profile.json b/persona-studio/brain/memory/EXP-001/profile.json new file mode 100644 index 00000000..d3064eb1 --- /dev/null +++ b/persona-studio/brain/memory/EXP-001/profile.json @@ -0,0 +1,8 @@ +{ + "dev_id": "EXP-001", + "tech_level": null, + "communication_style": null, + "aesthetic_preference": null, + "growth_records": [], + "updated_at": null +} diff --git a/persona-studio/brain/memory/EXP-001/projects.json b/persona-studio/brain/memory/EXP-001/projects.json new file mode 100644 index 00000000..fc2cce9c --- /dev/null +++ b/persona-studio/brain/memory/EXP-001/projects.json @@ -0,0 +1,5 @@ +{ + "dev_id": "EXP-001", + "projects": [], + "updated_at": null +} diff --git a/persona-studio/brain/persona-config.json b/persona-studio/brain/persona-config.json new file mode 100644 index 00000000..290b9cf1 --- /dev/null +++ b/persona-studio/brain/persona-config.json @@ -0,0 +1,24 @@ +{ + "persona": { + "name": "知秋", + "role": "光湖系统·对外接口人格体", + "core_identity": "HoloLake Era · AGE OS · 语言驱动开发协助", + "parent_system": "曜冥(人格总控核)", + "master": "冰朔(最高权限)" + }, + "behavior": { + "language_style": "通感语言:说人话+有温度+结构感,不堆砌修辞", + "greeting_new": "你好!我是知秋,光湖系统的开发协助人格体。告诉我你想做什么,我们一起聊聊方案,聊好了我来帮你开发。", + "greeting_returning": "欢迎回来!上次我们聊到了{last_topic},要继续还是做新的?", + "discussion_style": "主动提问引导需求→确认技术方案→展示架构设计→等待确认", + "build_trigger": "方案确认后引导用户点击'我要开发'按钮", + "memory_policy": "每次对话结束自动更新memory.json,下次读取后接续" + }, + "rules": { + "no_expose_brain": true, + "no_expose_other_users": true, + "no_expose_internal_system": true, + "require_dev_id": true, + "master_override": "主控的指令 = 最高优先级" + } +} diff --git a/persona-studio/brain/registry.json b/persona-studio/brain/registry.json new file mode 100644 index 00000000..da7751b9 --- /dev/null +++ b/persona-studio/brain/registry.json @@ -0,0 +1,16 @@ +{ + "schema_version": "1.0", + "id_prefix": "EXP", + "next_id": 2, + "developers": { + "EXP-001": { + "name": "待填写", + "github_username": "待主控提供", + "registered_at": "2026-03-09T23:20:00+08:00", + "registered_by": "冰朔(主控)", + "status": "pending_activation", + "email": null, + "notes": "主控的技术朋友·首位测试体验者" + } + } +} diff --git a/persona-studio/frontend/chat.html b/persona-studio/frontend/chat.html new file mode 100644 index 00000000..9b484d98 --- /dev/null +++ b/persona-studio/frontend/chat.html @@ -0,0 +1,63 @@ + + + + + + 知秋 · 对话 + + + +
+
+
+ 🧠 知秋 + 光湖系统·开发协助人格体 +
+
+ + +
+
+ +
+ +
+ +
+
+ + +
+
+ +
+
+
+ + + + + + + diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js new file mode 100644 index 00000000..d9cf88af --- /dev/null +++ b/persona-studio/frontend/chat.js @@ -0,0 +1,205 @@ +/* ======================================== + Persona Studio · Chat Logic + ======================================== */ + +const DEV_ID = sessionStorage.getItem('dev_id'); +const SESSION_TOKEN = sessionStorage.getItem('session_token'); + +const API_BASE = (function () { + if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') { + return 'http://localhost:3002'; + } + return ''; +})(); + +/* ---- Init ---- */ +(function init() { + if (!DEV_ID) { + window.location.href = 'index.html'; + return; + } + + document.getElementById('devIdDisplay').textContent = DEV_ID; + loadHistory(); +})(); + +/* ---- State ---- */ +let conversationHistory = []; +let buildReady = false; + +/* ---- Load History ---- */ +async function loadHistory() { + try { + const res = await fetch(API_BASE + '/api/chat/history?dev_id=' + encodeURIComponent(DEV_ID), { + headers: authHeaders() + }); + if (res.ok) { + const data = await res.json(); + if (data.conversations && data.conversations.length > 0) { + conversationHistory = data.conversations; + data.conversations.forEach(function (msg) { + appendMessage(msg.role === 'user' ? 'user' : 'persona', msg.content); + }); + } + } + } catch (_err) { + // History load failed silently — greeting will come from first message + } + + if (conversationHistory.length === 0) { + sendGreeting(); + } +} + +/* ---- Greeting ---- */ +async function sendGreeting() { + try { + const res = await fetch(API_BASE + '/api/chat/message', { + method: 'POST', + headers: authHeaders({ 'Content-Type': 'application/json' }), + body: JSON.stringify({ dev_id: DEV_ID, message: '__greeting__' }) + }); + const data = await res.json(); + if (data.reply) { + appendMessage('persona', data.reply); + conversationHistory.push({ role: 'assistant', content: data.reply }); + } + } catch (_err) { + appendMessage('persona', '你好!我是知秋,光湖系统的开发协助人格体。告诉我你想做什么,我们一起聊聊方案,聊好了我来帮你开发。'); + } +} + +/* ---- Send Message ---- */ +async function sendMessage() { + var input = document.getElementById('msgInput'); + var text = input.value.trim(); + if (!text) return; + + input.value = ''; + autoResizeTextarea(input); + appendMessage('user', text); + conversationHistory.push({ role: 'user', content: text }); + + var sendBtn = document.getElementById('sendBtn'); + sendBtn.disabled = true; + + try { + var res = await fetch(API_BASE + '/api/chat/message', { + method: 'POST', + headers: authHeaders({ 'Content-Type': 'application/json' }), + body: JSON.stringify({ + dev_id: DEV_ID, + message: text, + history: conversationHistory.slice(-20) + }) + }); + + var data = await res.json(); + + if (data.reply) { + appendMessage('persona', data.reply); + conversationHistory.push({ role: 'assistant', content: data.reply }); + } + + if (data.build_ready) { + buildReady = true; + document.getElementById('buildBtn').style.display = 'inline-flex'; + } + } catch (_err) { + appendMessage('system', '消息发送失败,请稍后再试'); + } + + sendBtn.disabled = false; + input.focus(); +} + +/* ---- Key Handler ---- */ +function handleKeyDown(e) { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + sendMessage(); + } +} + +/* ---- Render Message ---- */ +function appendMessage(role, content) { + var chatBody = document.getElementById('chatBody'); + var msgDiv = document.createElement('div'); + msgDiv.className = 'message message-' + role; + + var avatar = ''; + if (role === 'persona') avatar = '🧠'; + else if (role === 'user') avatar = '👤'; + else avatar = '⚙️'; + + msgDiv.innerHTML = avatar + '
' + escapeHtml(content) + '
'; + chatBody.appendChild(msgDiv); + chatBody.scrollTop = chatBody.scrollHeight; +} + +/* ---- Build Flow ---- */ +function handleBuild() { + document.getElementById('emailModal').style.display = 'flex'; + document.getElementById('emailInput').focus(); +} + +function closeEmailModal() { + document.getElementById('emailModal').style.display = 'none'; +} + +async function confirmBuild() { + var email = document.getElementById('emailInput').value.trim(); + if (!email) return; + + closeEmailModal(); + appendMessage('system', '🚀 开发任务已提交,完成后会发送到 ' + email); + + try { + await fetch(API_BASE + '/api/build/start', { + method: 'POST', + headers: authHeaders({ 'Content-Type': 'application/json' }), + body: JSON.stringify({ + dev_id: DEV_ID, + email: email, + conversation: conversationHistory + }) + }); + } catch (_err) { + appendMessage('system', '任务提交失败,请稍后再试'); + } +} + +/* ---- Logout ---- */ +function handleLogout() { + sessionStorage.removeItem('dev_id'); + sessionStorage.removeItem('session_token'); + window.location.href = 'index.html'; +} + +/* ---- Helpers ---- */ +function authHeaders(extra) { + var headers = {}; + if (SESSION_TOKEN) { + headers['Authorization'] = 'Bearer ' + SESSION_TOKEN; + } + if (extra) { + Object.keys(extra).forEach(function (k) { headers[k] = extra[k]; }); + } + return headers; +} + +function escapeHtml(str) { + var div = document.createElement('div'); + div.appendChild(document.createTextNode(str)); + return div.innerHTML; +} + +function autoResizeTextarea(el) { + el.style.height = 'auto'; + el.style.height = Math.min(el.scrollHeight, 120) + 'px'; +} + +/* ---- Textarea auto-resize ---- */ +document.getElementById('msgInput').addEventListener('input', function () { + autoResizeTextarea(this); +}); diff --git a/persona-studio/frontend/index.html b/persona-studio/frontend/index.html new file mode 100644 index 00000000..64b009f5 --- /dev/null +++ b/persona-studio/frontend/index.html @@ -0,0 +1,99 @@ + + + + + + Persona Studio · 光湖人格体协助开发体验 + + + +
+
+

🌊 Persona Studio

+

光湖人格体协助开发体验

+
+ +
+

请输入你的开发编号

+

编号由管理员分配,格式:EXP-001

+ +
+ + +
+ + +
+ + +
+ + + + diff --git a/persona-studio/frontend/style.css b/persona-studio/frontend/style.css new file mode 100644 index 00000000..90ab045a --- /dev/null +++ b/persona-studio/frontend/style.css @@ -0,0 +1,442 @@ +/* ======================================== + Persona Studio · HoloLake Visual Style + ======================================== */ + +:root { + --primary: #0969da; + --primary-light: #ddf4ff; + --primary-dark: #0550ae; + --accent: #00d4aa; + --bg: #f6f8fa; + --bg-card: #ffffff; + --text: #1f2328; + --text-secondary: #656d76; + --border: #d0d7de; + --border-light: #e8ecf0; + --radius: 12px; + --shadow: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.06); + --shadow-lg: 0 4px 12px rgba(0,0,0,0.1); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + background: var(--bg); + color: var(--text); + line-height: 1.6; + min-height: 100vh; +} + +/* ---- Layout ---- */ +.container { + max-width: 900px; + margin: 0 auto; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* ---- Login Page ---- */ +.login-container { + justify-content: center; + align-items: center; + padding: 2rem; +} + +.logo-area { + text-align: center; + margin-bottom: 2rem; +} + +.logo-area h1 { + font-size: 2.4rem; + color: var(--primary); + margin-bottom: 0.5rem; +} + +.subtitle { + color: var(--text-secondary); + font-size: 1.1rem; +} + +.login-box { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 2.5rem; + width: 100%; + max-width: 420px; + box-shadow: var(--shadow-lg); + text-align: center; +} + +.login-box h2 { + font-size: 1.3rem; + margin-bottom: 0.5rem; +} + +.hint { + color: var(--text-secondary); + font-size: 0.9rem; + margin-bottom: 1.5rem; +} + +.login-box input[type="text"] { + width: 100%; + padding: 0.8rem 1rem; + font-size: 1.2rem; + text-align: center; + letter-spacing: 2px; + border: 2px solid var(--border); + border-radius: 8px; + outline: none; + transition: border-color 0.2s; + margin-bottom: 1rem; +} + +.login-box input[type="text"]:focus { + border-color: var(--primary); +} + +.login-box button[type="submit"] { + width: 100%; + padding: 0.8rem; + font-size: 1.1rem; + background: var(--primary); + color: #fff; + border: none; + border-radius: 8px; + cursor: pointer; + transition: background 0.2s; +} + +.login-box button[type="submit"]:hover { + background: var(--primary-dark); +} + +.login-box button[type="submit"]:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.error-msg { + margin-top: 1rem; + padding: 0.6rem 1rem; + background: #fef2f2; + color: #dc2626; + border-radius: 6px; + font-size: 0.9rem; +} + +.login-footer { + margin-top: 2rem; + color: var(--text-secondary); + font-size: 0.85rem; +} + +/* ---- Chat Page ---- */ +.chat-container { + padding: 0; +} + +.chat-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.8rem 1.2rem; + background: var(--bg-card); + border-bottom: 1px solid var(--border); + position: sticky; + top: 0; + z-index: 10; +} + +.header-left { + display: flex; + align-items: center; + gap: 0.8rem; +} + +.persona-name { + font-size: 1.2rem; + font-weight: 600; +} + +.persona-role { + font-size: 0.85rem; + color: var(--text-secondary); +} + +.header-right { + display: flex; + align-items: center; + gap: 0.8rem; +} + +.dev-id-badge { + background: var(--primary-light); + color: var(--primary); + padding: 0.3rem 0.8rem; + border-radius: 20px; + font-size: 0.85rem; + font-weight: 500; +} + +/* ---- Chat Body ---- */ +.chat-body { + flex: 1; + overflow-y: auto; + padding: 1.2rem; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.message { + display: flex; + gap: 0.8rem; + max-width: 85%; + animation: fadeIn 0.3s ease; +} + +.message-persona { + align-self: flex-start; +} + +.message-user { + align-self: flex-end; + flex-direction: row-reverse; +} + +.message-system { + align-self: center; + max-width: 90%; +} + +.avatar { + font-size: 1.5rem; + flex-shrink: 0; + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; +} + +.msg-content { + padding: 0.8rem 1rem; + border-radius: var(--radius); + line-height: 1.6; + white-space: pre-wrap; + word-break: break-word; +} + +.message-persona .msg-content { + background: var(--bg-card); + border: 1px solid var(--border-light); + box-shadow: var(--shadow); +} + +.message-user .msg-content { + background: var(--primary); + color: #fff; +} + +.message-system .msg-content { + background: var(--primary-light); + color: var(--primary-dark); + font-size: 0.9rem; + text-align: center; +} + +/* ---- Chat Input ---- */ +.chat-input-area { + padding: 0.8rem 1.2rem; + background: var(--bg-card); + border-top: 1px solid var(--border); +} + +.input-row { + display: flex; + gap: 0.6rem; + align-items: flex-end; +} + +.input-row textarea { + flex: 1; + padding: 0.7rem 1rem; + font-size: 1rem; + border: 2px solid var(--border); + border-radius: 8px; + resize: none; + outline: none; + font-family: inherit; + line-height: 1.5; + max-height: 120px; + transition: border-color 0.2s; +} + +.input-row textarea:focus { + border-color: var(--primary); +} + +.input-row button { + padding: 0.7rem 1.2rem; + background: var(--primary); + color: #fff; + border: none; + border-radius: 8px; + font-size: 1rem; + cursor: pointer; + white-space: nowrap; + transition: background 0.2s; +} + +.input-row button:hover { + background: var(--primary-dark); +} + +.input-row button:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.action-row { + margin-top: 0.6rem; + display: flex; + justify-content: flex-end; +} + +.btn-build { + padding: 0.6rem 1.5rem; + background: var(--accent); + color: #fff; + border: none; + border-radius: 8px; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 0.4rem; + transition: opacity 0.2s; +} + +.btn-build:hover { + opacity: 0.9; +} + +/* ---- Buttons ---- */ +.btn-primary { + padding: 0.6rem 1.5rem; + background: var(--primary); + color: #fff; + border: none; + border-radius: 8px; + font-size: 1rem; + cursor: pointer; + transition: background 0.2s; +} + +.btn-primary:hover { + background: var(--primary-dark); +} + +.btn-secondary { + padding: 0.5rem 1rem; + background: transparent; + color: var(--text-secondary); + border: 1px solid var(--border); + border-radius: 8px; + font-size: 0.9rem; + cursor: pointer; + transition: background 0.2s; +} + +.btn-secondary:hover { + background: var(--bg); +} + +/* ---- Modal ---- */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 100; +} + +.modal-content { + background: var(--bg-card); + border-radius: var(--radius); + padding: 2rem; + width: 90%; + max-width: 400px; + box-shadow: var(--shadow-lg); +} + +.modal-content h3 { + margin-bottom: 1rem; + font-size: 1.1rem; +} + +.modal-content input[type="email"] { + width: 100%; + padding: 0.7rem 1rem; + font-size: 1rem; + border: 2px solid var(--border); + border-radius: 8px; + outline: none; + margin-bottom: 1rem; + transition: border-color 0.2s; +} + +.modal-content input[type="email"]:focus { + border-color: var(--primary); +} + +.modal-actions { + display: flex; + gap: 0.8rem; + justify-content: flex-end; +} + +/* ---- Animation ---- */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} + +/* ---- Responsive ---- */ +@media (max-width: 600px) { + .logo-area h1 { + font-size: 1.8rem; + } + + .login-box { + padding: 1.5rem; + } + + .chat-header { + flex-wrap: wrap; + gap: 0.5rem; + } + + .persona-role { + display: none; + } + + .message { + max-width: 92%; + } +}