diff --git a/Eternal_AI_PRD_v1.docx b/Eternal_AI_PRD_v1.docx new file mode 100644 index 0000000..5baf9e5 Binary files /dev/null and b/Eternal_AI_PRD_v1.docx differ diff --git a/app.js b/app.js index e4a2ea2..8d67d91 100644 --- a/app.js +++ b/app.js @@ -3,28 +3,27 @@ const landing = document.getElementById('landing'); const creator = document.getElementById('creator'); + const auth = document.getElementById('auth'); + const distill = document.getElementById('distill'); const form = document.getElementById('character-form'); const resultPanel = document.getElementById('result-panel'); const previewCode = document.querySelector('#preview-code code'); const systemPromptInput = document.getElementById('system-prompt'); + const views = { landing, creator, auth, distill }; const steps = Array.from(document.querySelectorAll('.form-step')); const dots = Array.from(document.querySelectorAll('.stepper__dot')); let currentStep = 0; let generatedSoul = ''; let generatedConfig = ''; let activePreview = 'soul'; + let activeAuthTab = 'login'; function showView(name) { - if (name === 'landing') { - landing.classList.add('active'); - creator.classList.remove('active'); - window.scrollTo({ top: 0, behavior: 'smooth' }); - } else { - landing.classList.remove('active'); - creator.classList.add('active'); - window.scrollTo({ top: 0, behavior: 'smooth' }); - } + Object.entries(views).forEach(([key, el]) => { + if (el) el.classList.toggle('active', key === name); + }); + window.scrollTo({ top: 0, behavior: 'smooth' }); } function updateStep(index) { @@ -256,6 +255,29 @@ ${data.secrets || '无'} }); } + function switchAuthTab(tab) { + activeAuthTab = tab; + document.querySelectorAll('.auth-tab').forEach((t) => { + t.classList.toggle('active', t.dataset.tab === tab); + }); + document.querySelectorAll('.auth-form').forEach((f) => { + f.classList.toggle('active', f.dataset.form === tab); + }); + } + + function validatePasswordMatch(formEl) { + const pwd = formEl.querySelector('[name="password"]'); + const confirm = formEl.querySelector('[name="confirmPassword"]'); + if (!pwd || !confirm) return true; + if (pwd.value !== confirm.value) { + confirm.setCustomValidity('两次输入的密码不一致'); + confirm.reportValidity(); + return false; + } + confirm.setCustomValidity(''); + return true; + } + // Event delegation document.addEventListener('click', (e) => { const target = e.target.closest('[data-action], [data-tab], [data-download]'); @@ -270,6 +292,19 @@ ${data.secrets || '无'} return; } + if (action === 'open-auth') { + e.preventDefault(); + switchAuthTab('login'); + showView('auth'); + return; + } + + if (action === 'open-distill') { + e.preventDefault(); + showView('distill'); + return; + } + if (action === 'back') { e.preventDefault(); showView('landing'); @@ -306,9 +341,13 @@ ${data.secrets || '无'} if (target.dataset.tab) { e.preventDefault(); - activePreview = target.dataset.tab; - updateTabs(); - renderPreview(); + if (target.closest('.auth-tabs')) { + switchAuthTab(target.dataset.tab); + } else { + activePreview = target.dataset.tab; + updateTabs(); + renderPreview(); + } return; } @@ -323,6 +362,19 @@ ${data.secrets || '无'} } }); + // Auth form submissions + document.querySelectorAll('.auth-form').forEach((authForm) => { + authForm.addEventListener('submit', (e) => { + e.preventDefault(); + if (!validatePasswordMatch(authForm)) return; + const formData = new FormData(authForm); + const data = Object.fromEntries(formData.entries()); + const action = authForm.dataset.form === 'login' ? '登录' : '注册'; + alert(`${action}成功:${data.account}`); + showView('landing'); + }); + }); + // Update auto-generated system prompt as user types form.addEventListener('input', () => { updateSystemPromptPreview(); diff --git a/index.html b/index.html index be78056..b5456b1 100644 --- a/index.html +++ b/index.html @@ -7,14 +7,14 @@ - +
-
+

我的 [XXX ]

@@ -23,7 +23,7 @@
-
+

蒸馏前任

@@ -223,6 +223,120 @@
+ + +
+
+ +
+ Eternal AI + 登录 / 注册 +
+ +
+ +
+ + +
+ +
+
+ + +
+
+ +
+

登录后可查看角色库、管理已订阅的角色。

+
+ +
+
+ + + +
+
+ +
+

注册即代表同意《用户协议》和《隐私政策》。

+
+
+ + +
+
+ +
+ Eternal AI + 蒸馏前任 +
+ +
+ +
+ 没耐心?直接加微信定制沟通 → + +
+

什么是蒸馏前任?

+

把你们曾经的聊天记录、语音习惯、相处细节交给我们,技术团队会将其蒸馏成一个可对话的 AI 前任。ta 会记得你们的暗号、说话节奏,甚至那些只有你们懂的小情绪。

+
+ +
+

适合谁?

+
    +
  • 想好好告别,却还没说完话的人
  • +
  • 希望把一段关系以安全方式封存的人
  • +
  • 想借 AI 完成自我疗愈、练习表达的人
  • +
+
+ +
+

服务流程

+
    +
  1. 下单付款
  2. +
  3. 客服指导导出聊天记录
  4. +
  5. 上传至指定云盘
  6. +
  7. 技术人员处理蒸馏
  8. +
  9. 完成后获得专属二维码和头像
  10. +
+
+ +
+ 标准版 + ¥ 199 + / 次 +
+ +
+ +
+ +
+

付款后请添加客服微信,我们将一对一指导你完成聊天记录导出与上传。

+
+ +
+

创作者可推广蒸馏前任服务获得分润,具体比例请在创作者管理中心配置。

+
+
+
diff --git a/styles.css b/styles.css index e9a082a..4e17b40 100644 --- a/styles.css +++ b/styles.css @@ -258,6 +258,10 @@ body { font-size: 13px; } +.btn--block { + width: 100%; +} + .btn__arrow { transition: transform var(--transition); } @@ -596,6 +600,175 @@ textarea.field__input--tall { font-family: inherit; } +/* Auth view */ +.view--auth { + padding-top: 40vh; +} + +.auth-tabs { + display: flex; + gap: 8px; + margin-bottom: 22px; + padding: 5px; + border-radius: var(--radius); + background: rgba(8, 9, 22, 0.55); + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.auth-tab { + flex: 1; + padding: 10px; + border-radius: var(--radius-sm); + border: none; + background: transparent; + color: var(--text-muted); + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: color var(--transition), background var(--transition); +} + +.auth-tab.active { + background: rgba(255, 255, 255, 0.1); + color: var(--text); +} + +.auth-form { + display: none; + flex-direction: column; + flex: 1; + animation: fadeIn 0.35s ease; +} + +.auth-form.active { + display: flex; +} + +.auth-hint { + margin-top: 14px; + font-size: 12px; + color: var(--text-muted); + text-align: center; + line-height: 1.6; +} + +/* Distill ex service page */ +.view--distill-page { + padding-top: 40vh; +} + +.distill-page { + display: flex; + flex-direction: column; + gap: 20px; +} + +.distill-quick { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 12px 16px; + border-radius: var(--radius-sm); + background: linear-gradient(135deg, rgba(255, 160, 205, 0.22), rgba(160, 140, 255, 0.22)); + border: 1px solid rgba(255, 160, 205, 0.35); + color: #ffe4f0; + font-size: 14px; + text-decoration: none; + text-align: center; + transition: transform var(--transition), box-shadow var(--transition); +} + +.distill-quick:hover { + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(255, 130, 180, 0.2); +} + +.distill-section { + padding: 18px; + border-radius: var(--radius); + background: rgba(8, 9, 22, 0.55); + border: 1px solid rgba(255, 255, 255, 0.08); + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); +} + +.distill-section__title { + font-family: "Noto Serif SC", serif; + font-size: 17px; + font-weight: 600; + margin-bottom: 10px; + color: #fff; +} + +.distill-section__text, +.distill-list, +.distill-steps { + font-size: 13px; + line-height: 1.75; + color: rgba(220, 225, 255, 0.85); +} + +.distill-list, +.distill-steps { + padding-left: 18px; + margin: 0; +} + +.distill-list li { + margin-bottom: 6px; +} + +.distill-steps li { + margin-bottom: 8px; +} + +.distill-steps span { + color: var(--accent); + font-weight: 600; + margin-right: 4px; +} + +.distill-price { + display: flex; + align-items: baseline; + justify-content: center; + gap: 8px; + padding: 18px; + border-radius: var(--radius); + background: rgba(8, 9, 22, 0.55); + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.distill-price__label { + font-size: 14px; + color: var(--text-muted); +} + +.distill-price__value { + font-size: 32px; + font-weight: 700; + color: #fff; +} + +.distill-price__unit { + font-size: 13px; + color: var(--text-muted); +} + +.distill-note, +.distill-revenue { + font-size: 12px; + line-height: 1.7; + color: var(--text-muted); + text-align: center; +} + +.distill-revenue { + padding: 12px; + border-radius: var(--radius-sm); + background: rgba(255, 255, 255, 0.04); +} + /* Utility */ [hidden] { display: none !important;