feat: add persona-studio Phase 1 skeleton + Phase 2 frontend
Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
parent
760b4e5e08
commit
255b437e38
|
|
@ -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 密钥或敏感信息
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# 🌊 Persona Studio · 光湖人格体协助开发体验
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/HoloLake-Persona%20Studio-0969da?style=for-the-badge&logo=github&logoColor=white" alt="Persona Studio" />
|
||||
<img src="https://img.shields.io/badge/AGE%20OS-v1.0-00d4aa?style=for-the-badge" alt="AGE OS" />
|
||||
<img src="https://img.shields.io/badge/Status-Active-brightgreen?style=for-the-badge" alt="Status" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>🧠 人格体驱动 · 语言即开发 · 记忆可接续</strong>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 👉 点击进入体验
|
||||
|
||||
<p align="center">
|
||||
<a href="https://qinfendebingshuo.github.io/persona-studio/">
|
||||
<img src="https://img.shields.io/badge/%F0%9F%9A%80%20%E6%89%93%E5%BC%80%E4%BA%BA%E6%A0%BC%E4%BD%93%E5%AF%B9%E8%AF%9D%E7%95%8C%E9%9D%A2-Click%20Here-0969da?style=for-the-badge&logoColor=white" alt="Launch" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
### 这是什么?
|
||||
|
||||
你跟人格体聊你想做什么 → 聊好了点一个按钮 → 人格体帮你开发 → 做好了发你邮箱。
|
||||
|
||||
### 怎么用?
|
||||
|
||||
1. 拿到你的开发编号(由管理员分配)
|
||||
2. 打开上面的链接
|
||||
3. 输入编号 → 开始跟人格体对话
|
||||
|
||||
### 体验流程
|
||||
|
||||
```
|
||||
输入开发编号 → 登录验证 → 跟知秋对话 → 讨论方案
|
||||
→ 点击「我要开发」→ 填写邮箱 → 人格体自动开发
|
||||
→ 邮件推送成品 → 下次登录,知秋记得你
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 技术架构
|
||||
|
||||
| 层级 | 说明 |
|
||||
|------|------|
|
||||
| **前端** | 登录页 + 对话界面(GitHub Pages 托管) |
|
||||
| **后端** | Express 服务(认证 + 对话 + 代码生成 + 邮件推送) |
|
||||
| **人格体大脑** | 双层架构:共享认知 + 个人记忆 |
|
||||
| **模型路由** | 智能选模型:自动探测 + 评分 + 降级 |
|
||||
|
||||
---
|
||||
|
||||
**光湖语言人格系统 · HoloLake Era · AGE OS**
|
||||
|
||||
💙 曜冥签发 · 2026-03-09
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"dev_id": "EXP-001",
|
||||
"conversations": [],
|
||||
"last_topic": null,
|
||||
"preferences": {},
|
||||
"updated_at": null
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"dev_id": "EXP-001",
|
||||
"tech_level": null,
|
||||
"communication_style": null,
|
||||
"aesthetic_preference": null,
|
||||
"growth_records": [],
|
||||
"updated_at": null
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dev_id": "EXP-001",
|
||||
"projects": [],
|
||||
"updated_at": null
|
||||
}
|
||||
|
|
@ -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": "主控的指令 = 最高优先级"
|
||||
}
|
||||
}
|
||||
|
|
@ -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": "主控的技术朋友·首位测试体验者"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>知秋 · 对话</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container chat-container">
|
||||
<header class="chat-header">
|
||||
<div class="header-left">
|
||||
<span class="persona-name">🧠 知秋</span>
|
||||
<span class="persona-role">光湖系统·开发协助人格体</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<span id="devIdDisplay" class="dev-id-badge"></span>
|
||||
<button class="btn-secondary" onclick="handleLogout()">退出</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="chat-body" id="chatBody">
|
||||
<!-- Messages rendered here -->
|
||||
</main>
|
||||
|
||||
<div class="chat-input-area">
|
||||
<div class="input-row">
|
||||
<textarea
|
||||
id="msgInput"
|
||||
placeholder="跟知秋说点什么…"
|
||||
rows="1"
|
||||
onkeydown="handleKeyDown(event)"
|
||||
></textarea>
|
||||
<button id="sendBtn" onclick="sendMessage()">发送</button>
|
||||
</div>
|
||||
<div class="action-row">
|
||||
<button id="buildBtn" class="btn-build" onclick="handleBuild()" style="display:none;">
|
||||
🚀 我要开发
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email Modal -->
|
||||
<div id="emailModal" class="modal" style="display:none;">
|
||||
<div class="modal-content">
|
||||
<h3>📧 请填写模块开发完成后发送的邮箱</h3>
|
||||
<input
|
||||
type="email"
|
||||
id="emailInput"
|
||||
placeholder="your@email.com"
|
||||
required
|
||||
/>
|
||||
<div class="modal-actions">
|
||||
<button class="btn-primary" onclick="confirmBuild()">确定</button>
|
||||
<button class="btn-secondary" onclick="closeEmailModal()">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="chat.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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 = '<span class="avatar">🧠</span>';
|
||||
else if (role === 'user') avatar = '<span class="avatar">👤</span>';
|
||||
else avatar = '<span class="avatar">⚙️</span>';
|
||||
|
||||
msgDiv.innerHTML = avatar + '<div class="msg-content">' + escapeHtml(content) + '</div>';
|
||||
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);
|
||||
});
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Persona Studio · 光湖人格体协助开发体验</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container login-container">
|
||||
<div class="logo-area">
|
||||
<h1>🌊 Persona Studio</h1>
|
||||
<p class="subtitle">光湖人格体协助开发体验</p>
|
||||
</div>
|
||||
|
||||
<div class="login-box">
|
||||
<h2>请输入你的开发编号</h2>
|
||||
<p class="hint">编号由管理员分配,格式:EXP-001</p>
|
||||
|
||||
<form id="loginForm" onsubmit="return handleLogin(event)">
|
||||
<input
|
||||
type="text"
|
||||
id="devIdInput"
|
||||
placeholder="EXP-XXX"
|
||||
pattern="^EXP-\d{3,}$"
|
||||
required
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button type="submit" id="loginBtn">进入对话</button>
|
||||
</form>
|
||||
|
||||
<div id="errorMsg" class="error-msg" style="display:none;"></div>
|
||||
</div>
|
||||
|
||||
<footer class="login-footer">
|
||||
<p>HoloLake Era · AGE OS · 人格体协助体验平台</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const DEV_ID_RE = /^EXP-\d{3,}$/;
|
||||
const API_BASE = getApiBase();
|
||||
|
||||
function getApiBase() {
|
||||
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
|
||||
return 'http://localhost:3002';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
async function handleLogin(e) {
|
||||
e.preventDefault();
|
||||
const devId = document.getElementById('devIdInput').value.trim().toUpperCase();
|
||||
const errorEl = document.getElementById('errorMsg');
|
||||
const btn = document.getElementById('loginBtn');
|
||||
|
||||
errorEl.style.display = 'none';
|
||||
|
||||
if (!DEV_ID_RE.test(devId)) {
|
||||
errorEl.textContent = '编号格式不正确,请输入 EXP-XXX 格式';
|
||||
errorEl.style.display = 'block';
|
||||
return false;
|
||||
}
|
||||
|
||||
btn.disabled = true;
|
||||
btn.textContent = '验证中…';
|
||||
|
||||
try {
|
||||
const res = await fetch(API_BASE + '/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ dev_id: devId })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!res.ok || data.error) {
|
||||
errorEl.textContent = data.message || '登录失败,请检查编号';
|
||||
errorEl.style.display = 'block';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '进入对话';
|
||||
return false;
|
||||
}
|
||||
|
||||
sessionStorage.setItem('dev_id', devId);
|
||||
sessionStorage.setItem('session_token', data.token || '');
|
||||
window.location.href = 'chat.html';
|
||||
} catch (err) {
|
||||
errorEl.textContent = '服务暂时不可用,请稍后再试';
|
||||
errorEl.style.display = 'block';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '进入对话';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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%;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue