moved js files in public into js and css into css folder
This commit is contained in:
+33
-14
@@ -1,17 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Sign in · Elsewhere</title>
|
||||
<link rel="icon" href="/favicon.svg">
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls">
|
||||
<link rel="icon" href="img/favicon.svg">
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls">
|
||||
</script>
|
||||
<link rel="stylesheet" href="/style.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="site-page account-page">
|
||||
<!-- site-header -->
|
||||
<main id="main" class="account-layout page-content">
|
||||
@@ -32,9 +36,17 @@
|
||||
<div class="field">
|
||||
<label for="accountPassword">Password</label>
|
||||
<div class="password-input">
|
||||
<input id="accountPassword" name="password" type="password" autocomplete="current-password" required minlength="6">
|
||||
<button type="button" id="showPassword" class="icon-button password-toggle" aria-label="Show password" title="Show password" aria-controls="accountPassword" aria-pressed="false">
|
||||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/><path class="eye-slash" d="m3 3 18 18"/></svg>
|
||||
<input id="accountPassword" name="password" type="password" autocomplete="current-password"
|
||||
required minlength="6">
|
||||
<button type="button" id="showPassword" class="icon-button password-toggle"
|
||||
aria-label="Show password" title="Show password" aria-controls="accountPassword"
|
||||
aria-pressed="false">
|
||||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor"
|
||||
stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z" />
|
||||
<circle cx="12" cy="12" r="3" />
|
||||
<path class="eye-slash" d="m3 3 18 18" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -44,10 +56,16 @@
|
||||
</label>
|
||||
<label id="consentField" class="consent-container hidden">
|
||||
<input name="consent" type="checkbox">
|
||||
<span>I agree to the <a href="/tos.html" target="_blank" rel="noopener">Terms</a> and <a href="/privacy.html" target="_blank" rel="noopener">Privacy Policy</a>.</span>
|
||||
<span>I agree to the <a href="/tos.html" target="_blank" rel="noopener">Terms</a> and <a
|
||||
href="/privacy.html" target="_blank" rel="noopener">Privacy Policy</a>.</span>
|
||||
</label>
|
||||
<div id="accountStatus" class="account-status hidden" role="status" aria-live="polite" aria-atomic="true" tabindex="-1">
|
||||
<svg class="account-error-icon" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v6m0 3v1"/></svg>
|
||||
<div id="accountStatus" class="account-status hidden" role="status" aria-live="polite"
|
||||
aria-atomic="true" tabindex="-1">
|
||||
<svg class="account-error-icon" viewBox="0 0 24 24" width="20" height="20" fill="none"
|
||||
stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<path d="M12 7v6m0 3v1" />
|
||||
</svg>
|
||||
<span id="accountStatusText"></span>
|
||||
</div>
|
||||
<button id="accountSubmit" class="primary-action" type="submit">Sign in</button>
|
||||
@@ -62,8 +80,9 @@
|
||||
<a href="/privacy.html">Privacy</a>
|
||||
<a href="/tos.html">Terms</a>
|
||||
</footer>
|
||||
<script type="module" src="/pages.js?v=20260909-account-controls">
|
||||
<script type="module" src="js/pages.js?v=20260909-account-controls">
|
||||
</script>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+159
-61
@@ -1,17 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="icon" type="image/svg+xml" href="img/favicon.svg">
|
||||
<title>Elsewhere</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/style.css?v=20260920-web-search-composer"/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260920-web-search-composer" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/pages.css?v=20260909-account-controls"><link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
</head>
|
||||
|
||||
<body class="site-page chat-page" data-theme="fakegpt" data-theme-mode="light">
|
||||
<!-- site-header -->
|
||||
<div class="app-shell">
|
||||
@@ -19,7 +24,10 @@
|
||||
<div class="chat-layout chat-layout-focus">
|
||||
<aside id="chatSidebar" class="chat-sidebar" aria-label="Conversation history">
|
||||
<div class="sidebar-top">
|
||||
<div class="sidebar-workspace-card"><h2>Conversations</h2><button id="newChat" class="primary-action" type="button">New chat</button></div>
|
||||
<div class="sidebar-workspace-card">
|
||||
<h2>Conversations</h2><button id="newChat" class="primary-action" type="button">New
|
||||
chat</button>
|
||||
</div>
|
||||
<label class="field compact-field">
|
||||
<span>Search</span>
|
||||
<input id="chatSearch" type="search" placeholder="Search chats" />
|
||||
@@ -35,39 +43,55 @@
|
||||
</aside>
|
||||
|
||||
<section id="main" class="chat-main chat-main-focus" aria-label="Active conversation">
|
||||
<div class="chat-heading"><p id="workspaceNotice" class="status error hidden" role="status" aria-live="polite"></p><header class="chat-header chat-header-focus">
|
||||
<button id="chatSidebarToggle" class="icon-button sidebar-toggle" type="button" aria-controls="chatSidebar" aria-expanded="false" aria-label="Open conversation history">History</button>
|
||||
<div class="chat-heading">
|
||||
<p id="workspaceNotice" class="status error hidden" role="status" aria-live="polite"></p>
|
||||
<header class="chat-header chat-header-focus">
|
||||
<button id="chatSidebarToggle" class="icon-button sidebar-toggle" type="button"
|
||||
aria-controls="chatSidebar" aria-expanded="false"
|
||||
aria-label="Open conversation history">History</button>
|
||||
<div class="chat-title-block">
|
||||
<div class="chat-title">
|
||||
<h2 id="activeChatTitle">New chat</h2>
|
||||
</div>
|
||||
<div class="chat-header-context" aria-label="Current chat setup">
|
||||
<button id="headerModelButton" class="chat-context-item chat-context-button secondary-action" type="button" aria-controls="chatDrawer" aria-label="Change AI model"><span>Model</span><strong id="headerModelName">Loading...</strong></button>
|
||||
<span class="chat-context-item"><span>Persona</span><strong id="headerPersonaName">None</strong></span>
|
||||
<button id="headerModelButton"
|
||||
class="chat-context-item chat-context-button secondary-action" type="button"
|
||||
aria-controls="chatDrawer"
|
||||
aria-label="Change AI model"><span>Model</span><strong
|
||||
id="headerModelName">Loading...</strong></button>
|
||||
<span class="chat-context-item"><span>Persona</span><strong
|
||||
id="headerPersonaName">None</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-header-actions">
|
||||
<div class="chat-actions-menu">
|
||||
<button id="chatDrawerButton" class="secondary-action overflow-trigger" type="button" aria-expanded="false" aria-controls="chatDrawer">
|
||||
<button id="chatDrawerButton" class="secondary-action overflow-trigger"
|
||||
type="button" aria-expanded="false" aria-controls="chatDrawer">
|
||||
<span class="overflow-trigger-label">Chat settings</span>
|
||||
</button>
|
||||
<div id="chatDrawer" class="chat-drawer hidden" role="dialog" aria-modal="true" aria-labelledby="chatDrawerTitle">
|
||||
<div id="chatDrawer" class="chat-drawer hidden" role="dialog" aria-modal="true"
|
||||
aria-labelledby="chatDrawerTitle">
|
||||
<div class="chat-drawer-panel">
|
||||
<div class="chat-drawer-header">
|
||||
<div>
|
||||
<p class="eyebrow">Conversation</p>
|
||||
<h2 id="chatDrawerTitle">Settings</h2>
|
||||
</div>
|
||||
<button id="chatDrawerClose" class="icon-button" type="button" aria-label="Close chat settings">×</button>
|
||||
<button id="chatDrawerClose" class="icon-button" type="button"
|
||||
aria-label="Close chat settings">×</button>
|
||||
</div>
|
||||
<div class="chat-drawer-body">
|
||||
<div class="chat-drawer-summary">
|
||||
<div class="chat-drawer-pills">
|
||||
<span id="chatCharacterPill" class="context-pill hidden">Character: none</span>
|
||||
<span id="chatUserPersonaPill" class="context-pill hidden">User persona: none</span>
|
||||
<span id="chatCharacterPill"
|
||||
class="context-pill hidden">Character: none</span>
|
||||
<span id="chatUserPersonaPill" class="context-pill hidden">User
|
||||
persona: none</span>
|
||||
</div>
|
||||
</div>
|
||||
<details class="chat-drawer-section chat-drawer-disclosure chat-drawer-section--model" open>
|
||||
<details
|
||||
class="chat-drawer-section chat-drawer-disclosure chat-drawer-section--model"
|
||||
open>
|
||||
<summary class="chat-drawer-row">
|
||||
<span class="chat-drawer-row-label">
|
||||
<span class="eyebrow">AI model</span>
|
||||
@@ -78,7 +102,9 @@
|
||||
<span class="chat-drawer-row-hint">Change</span>
|
||||
</span>
|
||||
</summary>
|
||||
<div id="modelPanel" class="model-panel chat-drawer-disclosure-panel" data-static-panel="true">
|
||||
<div id="modelPanel"
|
||||
class="model-panel chat-drawer-disclosure-panel"
|
||||
data-static-panel="true">
|
||||
<div class="model-select">
|
||||
<div class="model-select-header">
|
||||
<label for="model">Model</label>
|
||||
@@ -88,26 +114,40 @@
|
||||
<select id="model">
|
||||
<option disabled selected>Loading models...</option>
|
||||
</select>
|
||||
<span class="model-select-chevron" aria-hidden="true"></span>
|
||||
<span class="model-select-chevron"
|
||||
aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modelHelp" class="model-help" aria-live="polite">
|
||||
<div class="model-help-header">
|
||||
<strong id="modelHelpTitle">Choose a model</strong>
|
||||
<span id="modelHelpBadge" class="model-help-badge">Waiting</span>
|
||||
<span id="modelHelpBadge"
|
||||
class="model-help-badge">Waiting</span>
|
||||
</div>
|
||||
<p id="modelHelpSummary" class="model-help-summary">Pick a model to see what it is best suited for.</p>
|
||||
<p id="modelHelpSummary" class="model-help-summary">Pick a
|
||||
model to see what it is best suited for.</p>
|
||||
</div>
|
||||
<div class="generation-settings-grid">
|
||||
<label class="field"><span>Temperature</span><input id="chatTemperature" type="number" min="0" max="2" step="0.1" placeholder="Default"/></label>
|
||||
<label class="field"><span>Context length</span><input id="chatContextLength" type="number" min="256" max="131072" placeholder="Default"/></label>
|
||||
<label class="field"><span>Response length</span><input id="chatResponseLength" type="number" min="1" max="32768" placeholder="Default"/></label>
|
||||
<label class="field field-wide"><span>System instruction</span><textarea id="chatSystemInstruction" rows="4" maxlength="8000" placeholder="Optional instructions for this chat"></textarea></label>
|
||||
<button id="saveGenerationSettings" type="button">Save generation settings</button>
|
||||
<label class="field"><span>Temperature</span><input
|
||||
id="chatTemperature" type="number" min="0" max="2"
|
||||
step="0.1" placeholder="Default" /></label>
|
||||
<label class="field"><span>Context length</span><input
|
||||
id="chatContextLength" type="number" min="256"
|
||||
max="131072" placeholder="Default" /></label>
|
||||
<label class="field"><span>Response length</span><input
|
||||
id="chatResponseLength" type="number" min="1"
|
||||
max="32768" placeholder="Default" /></label>
|
||||
<label class="field field-wide"><span>System
|
||||
instruction</span><textarea
|
||||
id="chatSystemInstruction" rows="4" maxlength="8000"
|
||||
placeholder="Optional instructions for this chat"></textarea></label>
|
||||
<button id="saveGenerationSettings" type="button">Save
|
||||
generation settings</button>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
<details class="chat-drawer-section chat-drawer-disclosure chat-drawer-section--persona">
|
||||
<details
|
||||
class="chat-drawer-section chat-drawer-disclosure chat-drawer-section--persona">
|
||||
<summary class="chat-drawer-row">
|
||||
<span class="chat-drawer-row-label">
|
||||
<span class="eyebrow">Your identity</span>
|
||||
@@ -118,18 +158,25 @@
|
||||
<span class="chat-drawer-row-hint">Change</span>
|
||||
</span>
|
||||
</summary>
|
||||
<div id="personaPanel" class="persona-panel chat-drawer-disclosure-panel" data-static-panel="true">
|
||||
<div id="personaPanel"
|
||||
class="persona-panel chat-drawer-disclosure-panel"
|
||||
data-static-panel="true">
|
||||
<div class="persona-section">
|
||||
<div class="persona-section-header">
|
||||
<div>
|
||||
<h2>Your persona</h2>
|
||||
</div>
|
||||
<div class="persona-section-actions">
|
||||
<button id="clearUserPersona" class="secondary-action" type="button">Clear</button>
|
||||
<a href="/app/personas" class="secondary-action">Manage</a>
|
||||
<button id="clearUserPersona"
|
||||
class="secondary-action"
|
||||
type="button">Clear</button>
|
||||
<a href="/app/personas"
|
||||
class="secondary-action">Manage</a>
|
||||
</div>
|
||||
</div>
|
||||
<p id="activeUserPersonaStatus" class="status persona-status">No default user persona set.</p>
|
||||
<p id="activeUserPersonaStatus"
|
||||
class="status persona-status">No default user persona
|
||||
set.</p>
|
||||
<div id="userPersonaList" class="persona-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -137,10 +184,17 @@
|
||||
<div class="chat-drawer-section">
|
||||
<p class="dropdown-section-label">Chat</p>
|
||||
<div class="chat-drawer-action-list">
|
||||
<button id="renameChat" class="secondary-action chat-drawer-action" type="button" data-chat-action="rename">Rename chat</button>
|
||||
<button id="pinChat" class="secondary-action chat-drawer-action" type="button" data-chat-action="pin">Pin</button>
|
||||
<button id="archiveChat" class="secondary-action chat-drawer-action" type="button" data-chat-action="archive">Archive</button>
|
||||
<button id="exportChat" class="secondary-action chat-drawer-action" type="button" data-chat-action="export">Export</button>
|
||||
<button id="renameChat"
|
||||
class="secondary-action chat-drawer-action" type="button"
|
||||
data-chat-action="rename">Rename chat</button>
|
||||
<button id="pinChat" class="secondary-action chat-drawer-action"
|
||||
type="button" data-chat-action="pin">Pin</button>
|
||||
<button id="archiveChat"
|
||||
class="secondary-action chat-drawer-action" type="button"
|
||||
data-chat-action="archive">Archive</button>
|
||||
<button id="exportChat"
|
||||
class="secondary-action chat-drawer-action" type="button"
|
||||
data-chat-action="export">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
<details class="chat-drawer-section chat-drawer-more">
|
||||
@@ -151,12 +205,23 @@
|
||||
<span class="chat-drawer-row-hint">Show</span>
|
||||
</summary>
|
||||
<div class="chat-drawer-action-list chat-drawer-disclosure-panel">
|
||||
<button id="moveChatFolder" class="secondary-action chat-drawer-action" type="button" data-chat-action="folder">Move to folder</button>
|
||||
<button id="manageChatMemory" class="secondary-action chat-drawer-action" type="button" data-chat-action="memory">Memory facts</button>
|
||||
<button id="managePersonaState" class="secondary-action chat-drawer-action" type="button" data-chat-action="personaState">Roleplay state</button>
|
||||
<button id="backupWorkspace" class="secondary-action chat-drawer-action" type="button">Backup workspace</button>
|
||||
<button id="importWorkspace" class="secondary-action chat-drawer-action" type="button">Import workspace</button>
|
||||
<input id="importWorkspaceFile" class="hidden" type="file" accept="application/json,.json"/>
|
||||
<button id="moveChatFolder"
|
||||
class="secondary-action chat-drawer-action" type="button"
|
||||
data-chat-action="folder">Move to folder</button>
|
||||
<button id="manageChatMemory"
|
||||
class="secondary-action chat-drawer-action" type="button"
|
||||
data-chat-action="memory">Memory facts</button>
|
||||
<button id="managePersonaState"
|
||||
class="secondary-action chat-drawer-action" type="button"
|
||||
data-chat-action="personaState">Roleplay state</button>
|
||||
<button id="backupWorkspace"
|
||||
class="secondary-action chat-drawer-action"
|
||||
type="button">Backup workspace</button>
|
||||
<button id="importWorkspace"
|
||||
class="secondary-action chat-drawer-action"
|
||||
type="button">Import workspace</button>
|
||||
<input id="importWorkspaceFile" class="hidden" type="file"
|
||||
accept="application/json,.json" />
|
||||
</div>
|
||||
</details>
|
||||
<details class="chat-drawer-section chat-drawer-danger">
|
||||
@@ -167,7 +232,9 @@
|
||||
<span class="chat-drawer-row-hint">Show</span>
|
||||
</summary>
|
||||
<div class="chat-drawer-action-list chat-drawer-disclosure-panel">
|
||||
<button id="clearChat" class="secondary-action chat-drawer-action chat-drawer-action-danger" type="button" data-chat-action="clear">Clear chat</button>
|
||||
<button id="clearChat"
|
||||
class="secondary-action chat-drawer-action chat-drawer-action-danger"
|
||||
type="button" data-chat-action="clear">Clear chat</button>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
@@ -175,9 +242,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header></div>
|
||||
</header>
|
||||
</div>
|
||||
|
||||
<div id="chatActivityOverlay" class="chat-activity-overlay hidden" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div id="chatActivityOverlay" class="chat-activity-overlay hidden" role="status" aria-live="polite"
|
||||
aria-atomic="true">
|
||||
<div class="chat-activity-card">
|
||||
<div class="chat-activity-mark" aria-hidden="true">
|
||||
<span></span>
|
||||
@@ -190,7 +259,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="messages" class="messages-panel messages-panel-focus" role="log" aria-live="polite" aria-relevant="additions text"></div>
|
||||
<div id="messages" class="messages-panel messages-panel-focus" role="log" aria-live="polite"
|
||||
aria-relevant="additions text"></div>
|
||||
|
||||
<div class="input-shell input-shell-focus">
|
||||
<div class="input-meta">
|
||||
@@ -198,15 +268,34 @@
|
||||
</div>
|
||||
<div id="uploadPreviews" class="upload-previews" aria-live="polite" hidden></div>
|
||||
<div class="input-container">
|
||||
<input id="imagePicker" type="file" accept="image/png,image/jpeg,image/webp" multiple hidden>
|
||||
<button id="attachImage" class="icon-button" type="button" aria-label="Attach image" title="Attach image">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="3"/><circle cx="8" cy="8" r="1.5"/><path d="m3 17 5-5 4 4 4-6 5 7"/></svg>
|
||||
<input id="imagePicker" type="file" accept="image/png,image/jpeg,image/webp" multiple
|
||||
hidden>
|
||||
<button id="attachImage" class="icon-button" type="button" aria-label="Attach image"
|
||||
title="Attach image">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1.6" aria-hidden="true">
|
||||
<rect x="3" y="3" width="18" height="18" rx="3" />
|
||||
<circle cx="8" cy="8" r="1.5" />
|
||||
<path d="m3 17 5-5 4 4 4-6 5 7" />
|
||||
</svg>
|
||||
</button>
|
||||
<button id="webSearch" class="icon-button" type="button" aria-label="Search the web" title="Search the web" aria-pressed="false">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="9"/><ellipse cx="12" cy="12" rx="4" ry="9"/><path d="M3 12h18"/></svg>
|
||||
<button id="webSearch" class="icon-button" type="button" aria-label="Search the web"
|
||||
title="Search the web" aria-pressed="false">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1.6" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<ellipse cx="12" cy="12" rx="4" ry="9" />
|
||||
<path d="M3 12h18" />
|
||||
</svg>
|
||||
</button>
|
||||
<button id="reasoning" class="icon-button" type="button" aria-label="Enable reasoning" title="Enable reasoning" aria-pressed="false" disabled>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 18V5a3 3 0 0 0-5.8-1A4 4 0 0 0 3 10a4 4 0 0 0 1 7.8A4 4 0 0 0 12 18ZM12 5a3 3 0 0 1 5.8-1A4 4 0 0 1 21 10a4 4 0 0 1-1 7.8A4 4 0 0 1 12 18M8 8a4 4 0 0 1-5 2m13-2a4 4 0 0 0 5 2M8 14a4 4 0 0 0-4 4m12-4a4 4 0 0 1 4 4"/></svg>
|
||||
<button id="reasoning" class="icon-button" type="button" aria-label="Enable reasoning"
|
||||
title="Enable reasoning" aria-pressed="false" disabled>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M12 18V5a3 3 0 0 0-5.8-1A4 4 0 0 0 3 10a4 4 0 0 0 1 7.8A4 4 0 0 0 12 18ZM12 5a3 3 0 0 1 5.8-1A4 4 0 0 1 21 10a4 4 0 0 1-1 7.8A4 4 0 0 1 12 18M8 8a4 4 0 0 1-5 2m13-2a4 4 0 0 0 5 2M8 14a4 4 0 0 0-4 4m12-4a4 4 0 0 1 4 4" />
|
||||
</svg>
|
||||
</button>
|
||||
<label class="visually-hidden" for="msgInput">Message</label>
|
||||
<textarea id="msgInput" rows="1" placeholder="Type your message..."></textarea>
|
||||
@@ -229,7 +318,8 @@
|
||||
</div>
|
||||
<form id="personaForm" class="persona-form">
|
||||
<div class="persona-form-intro">
|
||||
<p class="persona-helper">AI Characters shape who you talk to. User personas add context for who you are in the scene.</p>
|
||||
<p class="persona-helper">AI Characters shape who you talk to. User personas add context for who you
|
||||
are in the scene.</p>
|
||||
</div>
|
||||
<p id="personaFormNotice" class="status hidden"></p>
|
||||
<div class="persona-form-grid">
|
||||
@@ -254,11 +344,13 @@
|
||||
</label>
|
||||
<label class="field field-wide">
|
||||
<span>Background</span>
|
||||
<textarea id="personaBackground" rows="3" placeholder="Backstory, history, role, or origins"></textarea>
|
||||
<textarea id="personaBackground" rows="3"
|
||||
placeholder="Backstory, history, role, or origins"></textarea>
|
||||
</label>
|
||||
<label class="field field-wide">
|
||||
<span>Details</span>
|
||||
<textarea id="personaDetails" rows="4" placeholder="Personality traits, voice, goals, quirks, boundaries, style"></textarea>
|
||||
<textarea id="personaDetails" rows="4"
|
||||
placeholder="Personality traits, voice, goals, quirks, boundaries, style"></textarea>
|
||||
</label>
|
||||
<label id="personaExamplesField" class="field field-wide hidden">
|
||||
<span>Example dialogues</span>
|
||||
@@ -268,7 +360,8 @@
|
||||
{{user}}: Hi, Marc!
|
||||
{{character}}: Nice to meet you</pre>
|
||||
</div>
|
||||
<textarea id="personaExampleDialogues" rows="5" placeholder="Write example exchanges that define the AI's tone, phrasing, pacing, and personality."></textarea>
|
||||
<textarea id="personaExampleDialogues" rows="5"
|
||||
placeholder="Write example exchanges that define the AI's tone, phrasing, pacing, and personality."></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="persona-actions">
|
||||
@@ -288,7 +381,8 @@
|
||||
<button id="roleplayStarterClose" type="button" class="icon-button">Close</button>
|
||||
</div>
|
||||
<div class="roleplay-starter-intro">
|
||||
<p id="roleplayStarterIntroCopy" class="persona-helper">Pick a character and choose who you are before moving on to the opening scene.</p>
|
||||
<p id="roleplayStarterIntroCopy" class="persona-helper">Pick a character and choose who you are before
|
||||
moving on to the opening scene.</p>
|
||||
</div>
|
||||
<p id="roleplayStarterNotice" class="status hidden"></p>
|
||||
<div class="roleplay-starter-actions">
|
||||
@@ -307,9 +401,11 @@
|
||||
<div id="roleplayStarterStepTwo" class="roleplay-starter-page hidden">
|
||||
<label class="field field-wide">
|
||||
<span>Optional opening direction</span>
|
||||
<textarea id="roleplayScenarioInput" rows="4" placeholder="Describe the kind of opening scene you want, such as a setting, conflict, relationship dynamic, or mood. Leave it empty and the AI will invent its own scenario."></textarea>
|
||||
<textarea id="roleplayScenarioInput" rows="4"
|
||||
placeholder="Describe the kind of opening scene you want, such as a setting, conflict, relationship dynamic, or mood. Leave it empty and the AI will invent its own scenario."></textarea>
|
||||
</label>
|
||||
<p class="subtitle">Leave this empty if you want the AI Character to invent the scenario on its own. No character limit.</p>
|
||||
<p class="subtitle">Leave this empty if you want the AI Character to invent the scenario on its own. No
|
||||
character limit.</p>
|
||||
<div id="roleplayStarterSuggestions" class="quick-prompts" aria-label="Scenario suggestions"></div>
|
||||
</div>
|
||||
<div class="popup-actions">
|
||||
@@ -321,7 +417,8 @@
|
||||
</div>
|
||||
|
||||
<div id="popupModal" class="modal-overlay hidden">
|
||||
<div class="modal-card popup-card" role="dialog" aria-modal="true" aria-labelledby="popupTitle" aria-describedby="popupDescription">
|
||||
<div class="modal-card popup-card" role="dialog" aria-modal="true" aria-labelledby="popupTitle"
|
||||
aria-describedby="popupDescription">
|
||||
<div class="modal-header">
|
||||
<div class="persona-modal-heading">
|
||||
<p id="popupEyebrow" class="eyebrow">Action</p>
|
||||
@@ -363,7 +460,8 @@
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js" defer></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js" defer></script>
|
||||
<script type="module" src="/script.js?v=20260921-reasoning-capability"></script>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/script.js?v=20260921-reasoning-capability"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+15
-9
@@ -1,23 +1,28 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Discover personas · Elsewhere</title>
|
||||
<link rel="icon" href="/favicon.svg">
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls">
|
||||
<link rel="icon" href="/img/favicon.svg">
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls">
|
||||
</script>
|
||||
<link rel="stylesheet" href="/style.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="site-page discover-page">
|
||||
<!-- site-header -->
|
||||
<main id="main" class="site-section page-content">
|
||||
<p class="eyebrow">From the community</p>
|
||||
<h1>Find your next conversation.</h1>
|
||||
<p class="hero-copy">Discover characters and personas made by the community. Sign in when you're ready to bring one into your workspace.</p>
|
||||
<p class="hero-copy">Discover characters and personas made by the community. Sign in when you're ready to bring
|
||||
one into your workspace.</p>
|
||||
<label class="field">
|
||||
<span>Search personas</span>
|
||||
<input id="publicSearch" type="search" placeholder="Search by name or description">
|
||||
@@ -30,8 +35,9 @@
|
||||
<a href="/privacy.html">Privacy</a>
|
||||
<a href="/tos.html">Terms</a>
|
||||
</footer>
|
||||
<script type="module" src="/pages.js?v=20260909-account-controls">
|
||||
<script type="module" src="/js/pages.js?v=20260909-account-controls">
|
||||
</script>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+10
-5
@@ -1,17 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Home · Elsewhere</title>
|
||||
<link rel="icon" href="/favicon.svg">
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls">
|
||||
<link rel="icon" href="/img/favicon.svg">
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls">
|
||||
</script>
|
||||
<link rel="stylesheet" href="/style.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="site-page home-page">
|
||||
<!-- site-header -->
|
||||
|
||||
@@ -50,8 +54,9 @@
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script type="module" src="/pages.js?v=20260909-account-controls">
|
||||
<script type="module" src="/js/pages.js?v=20260909-account-controls">
|
||||
</script>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
@@ -1,7 +1,7 @@
|
||||
import {get, post, put} from "./app/api.js?v=20260909-account-controls";
|
||||
import {initializeAppearance} from "./app/themeController.js?v=20260909-account-controls";
|
||||
import {clearStatus, setStatus} from "./app/statusNotice.js?v=20260909-account-controls";
|
||||
import {populatePersonaForm, readPersonaForm} from "./app/personaForm.js?v=20260909-account-controls";
|
||||
import { get, post, put } from "./js/api.js?v=20260909-account-controls";
|
||||
import { initializeAppearance } from "./js/themeController.js?v=20260909-account-controls";
|
||||
import { clearStatus, setStatus } from "./js/statusNotice.js?v=20260909-account-controls";
|
||||
import { populatePersonaForm, readPersonaForm } from "./js/personaForm.js?v=20260909-account-controls";
|
||||
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const marketPersonaList = $("marketPersonaList");
|
||||
@@ -540,7 +540,7 @@ async function startMarketPersonaChat(marketId, userPersonaSelection, scenarioPr
|
||||
return;
|
||||
}
|
||||
if (userPersonaSelection === "create_new") {
|
||||
window.location.href = "/app/personas?view=my-roleplay-companions&create=user";
|
||||
window.location.href = "/js/personas?view=my-roleplay-companions&create=user";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -623,7 +623,7 @@ if (marketCreateAiCharacterBtn) {
|
||||
}
|
||||
if (marketCreateUserPersonaBtn) {
|
||||
marketCreateUserPersonaBtn.addEventListener("click", () => {
|
||||
window.location.href = "/app/personas?view=my-roleplay-companions&create=user";
|
||||
window.location.href = "/js/personas?view=my-roleplay-companions&create=user";
|
||||
});
|
||||
}
|
||||
marketPreviewClose.addEventListener("click", closeMarketPreview);
|
||||
@@ -633,7 +633,7 @@ marketPreviewModal.addEventListener("click", (event) => {
|
||||
marketPreviewUserPersonaSelect.addEventListener("change", () => {
|
||||
if (!pendingMarketPersona || pendingMarketPersona.persona_type !== "assistant") return;
|
||||
if (marketPreviewUserPersonaSelect.value === "create_new") {
|
||||
window.location.href = "/app/personas?view=my-roleplay-companions&create=user";
|
||||
window.location.href = "/js/personas?view=my-roleplay-companions&create=user";
|
||||
return;
|
||||
}
|
||||
marketPreviewConfirm.classList.toggle("hidden", !marketPreviewUserPersonaSelect.value);
|
||||
@@ -1,4 +1,4 @@
|
||||
import {get, post} from "/app/api.js?v=20260909-account-controls";
|
||||
import { get, post } from "/js/api.js?v=20260909-account-controls";
|
||||
|
||||
const params = new URLSearchParams(location.search);
|
||||
function returnPath() {
|
||||
@@ -1,12 +1,12 @@
|
||||
import {del, get, post, put, stream} from "./app/api.js?v=20260909-account-controls";
|
||||
import {regenerateInline} from "./app/regeneration.js";
|
||||
import {appendSources, createWebSearchToggle} from "./app/webSearch.js";
|
||||
import {appendAttachments, createAttachmentComposer} from "./app/attachments.js";
|
||||
import {createReasoningToggle, finishReasoning, updateReasoning} from "./app/reasoning.js?v=20260921-reasoning-capability";
|
||||
import {closeChatDrawer, openChatDrawer} from "./app/chatDrawer.js?v=20260909-account-controls";
|
||||
import {onboardingPrompts, requestedChatId} from "./app/constants.js?v=20260909-account-controls";
|
||||
import {getModelProfile} from "./app/modelProfiles.js?v=20260909-account-controls";
|
||||
import {applyTheme as applySharedTheme, applyThemeMode as applySharedThemeMode, readStoredAppearance} from "./app/themeController.js?v=20260909-account-controls";
|
||||
import { del, get, post, put, stream } from "./js/api.js?v=20260909-account-controls";
|
||||
import { regenerateInline } from "./js/regeneration.js";
|
||||
import { appendSources, createWebSearchToggle } from "./js/webSearch.js";
|
||||
import { appendAttachments, createAttachmentComposer } from "./js/attachments.js";
|
||||
import { createReasoningToggle, finishReasoning, updateReasoning } from "./js/reasoning.js?v=20260921-reasoning-capability";
|
||||
import { closeChatDrawer, openChatDrawer } from "./js/chatDrawer.js?v=20260909-account-controls";
|
||||
import { onboardingPrompts, requestedChatId } from "./js/constants.js?v=20260909-account-controls";
|
||||
import { getModelProfile } from "./js/modelProfiles.js?v=20260909-account-controls";
|
||||
import { applyTheme as applySharedTheme, applyThemeMode as applySharedThemeMode, readStoredAppearance } from "./js/themeController.js?v=20260909-account-controls";
|
||||
import {
|
||||
activeChatTitle,
|
||||
activeUserPersonaStatus,
|
||||
@@ -103,7 +103,7 @@ import {
|
||||
brandLogoTargets,
|
||||
brandNameTargets,
|
||||
userPersonaList
|
||||
} from "./app/dom.js?v=20260909-account-controls";
|
||||
} from "./js/dom.js?v=20260909-account-controls";
|
||||
|
||||
const headerModelButton = document.getElementById("headerModelButton");
|
||||
const webSearchButton = document.getElementById("webSearch");
|
||||
@@ -1,11 +1,11 @@
|
||||
import {del, get, post, put} from "./app/api.js?v=20260909-account-controls";
|
||||
import { del, get, post, put } from "./js/api.js?v=20260909-account-controls";
|
||||
import {
|
||||
applyTheme as applySharedTheme,
|
||||
applyThemeMode as applySharedThemeMode,
|
||||
initializeAppearance
|
||||
} from "./app/themeController.js?v=20260909-account-controls";
|
||||
import {clearStatus, setStatus} from "./app/statusNotice.js?v=20260909-account-controls";
|
||||
import {populatePersonaForm, readPersonaForm} from "./app/personaForm.js?v=20260909-account-controls";
|
||||
} from "./js/themeController.js?v=20260909-account-controls";
|
||||
import { clearStatus, setStatus } from "./js/statusNotice.js?v=20260909-account-controls";
|
||||
import { populatePersonaForm, readPersonaForm } from "./js/personaForm.js?v=20260909-account-controls";
|
||||
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const settingsNotice = $("settingsNotice");
|
||||
+17
-10
@@ -1,16 +1,20 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Elsewhere</title>
|
||||
<link rel="icon" href="/favicon.svg">
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/style.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="icon" href="/img/favicon.svg">
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/pages.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="site-page landing-page">
|
||||
<!-- site-header -->
|
||||
<main id="main" class="landing-entry">
|
||||
@@ -20,13 +24,16 @@
|
||||
<h1>Take a thought<br>somewhere.</h1>
|
||||
<p>Talk it through. Make something up.<br>Meet a character and see where it goes.</p>
|
||||
<div class="site-actions">
|
||||
<a data-start-link class="primary-action" href="/register">Step inside <span aria-hidden="true">→</span></a>
|
||||
<a data-start-link class="primary-action" href="/register">Step inside <span
|
||||
aria-hidden="true">→</span></a>
|
||||
<a href="/market">Meet the personas</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="site-footer"><span>elsewhere / a little room for imagination</span><a href="/privacy.html">Privacy</a><a href="/tos.html">Terms</a></footer>
|
||||
<script type="module" src="/pages.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
<footer class="site-footer"><span>elsewhere / a little room for imagination</span><a
|
||||
href="/privacy.html">Privacy</a><a href="/tos.html">Terms</a></footer>
|
||||
<script type="module" src="/js/pages.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+41
-21
@@ -1,17 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
|
||||
<title>Elsewhere Discover</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/style.css?v=20260909-account-controls"/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
</head>
|
||||
|
||||
<body class="site-page market-page" data-theme="fakegpt" data-theme-mode="light">
|
||||
<!-- site-header -->
|
||||
<main id="main" class="market-shell page-content">
|
||||
@@ -20,7 +24,8 @@
|
||||
<p class="eyebrow">Shared personas</p>
|
||||
<h1>Discover</h1>
|
||||
</div>
|
||||
<div class="market-header-actions"><button id="refreshMarket" class="secondary-action" type="button">Refresh</button></div>
|
||||
<div class="market-header-actions"><button id="refreshMarket" class="secondary-action"
|
||||
type="button">Refresh</button></div>
|
||||
</header>
|
||||
|
||||
<div class="market-search">
|
||||
@@ -32,8 +37,10 @@
|
||||
|
||||
<section class="settings-layout market-settings-layout">
|
||||
<aside class="settings-nav" aria-label="Market sections" role="tablist">
|
||||
<button class="settings-nav-item active" type="button" role="tab" aria-selected="true" data-market-view="ai-characters">Characters</button>
|
||||
<button class="settings-nav-item" type="button" role="tab" aria-selected="false" data-market-view="user-personas">User personas</button>
|
||||
<button class="settings-nav-item active" type="button" role="tab" aria-selected="true"
|
||||
data-market-view="ai-characters">Characters</button>
|
||||
<button class="settings-nav-item" type="button" role="tab" aria-selected="false"
|
||||
data-market-view="user-personas">User personas</button>
|
||||
</aside>
|
||||
|
||||
<div class="settings-content">
|
||||
@@ -56,7 +63,8 @@
|
||||
<option value="alphabetical">A-Z</option>
|
||||
</select>
|
||||
</label>
|
||||
<button id="marketCreateAiCharacter" type="button" class="secondary-action">Create AI Character</button>
|
||||
<button id="marketCreateAiCharacter" type="button" class="secondary-action">Create AI
|
||||
Character</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="marketPersonaList" class="persona-list"></div>
|
||||
@@ -82,7 +90,8 @@
|
||||
<option value="alphabetical">A-Z</option>
|
||||
</select>
|
||||
</label>
|
||||
<button id="marketCreateUserPersona" type="button" class="secondary-action">Create User Persona</button>
|
||||
<button id="marketCreateUserPersona" type="button" class="secondary-action">Create User
|
||||
Persona</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="marketUserPersonaList" class="persona-list"></div>
|
||||
@@ -99,7 +108,8 @@
|
||||
<p class="eyebrow">Persona preview</p>
|
||||
<h3 id="marketPreviewTitle">Persona details</h3>
|
||||
<h4 id="marketPreviewName" class="market-preview-name">Persona details</h4>
|
||||
<p id="marketPreviewIntro" class="subtitle">Review this persona and choose how you want to use it.</p>
|
||||
<p id="marketPreviewIntro" class="subtitle">Review this persona and choose how you want to use it.
|
||||
</p>
|
||||
</div>
|
||||
<button id="marketPreviewClose" type="button" class="icon-button">Close</button>
|
||||
</div>
|
||||
@@ -138,9 +148,11 @@
|
||||
<div id="marketPreviewStepTwo" class="roleplay-starter-page hidden">
|
||||
<label id="marketPreviewScenarioField" class="field market-preview-scenario-field">
|
||||
<span>Scenario (optional)</span>
|
||||
<textarea id="marketPreviewScenario" rows="4" placeholder="Describe the opening scene you want. Leave it empty and the AI Character will invent its own scenario."></textarea>
|
||||
<textarea id="marketPreviewScenario" rows="4"
|
||||
placeholder="Describe the opening scene you want. Leave it empty and the AI Character will invent its own scenario."></textarea>
|
||||
</label>
|
||||
<p class="subtitle">Leave this empty if you want the AI Character to invent the scenario on its own. No character limit.</p>
|
||||
<p class="subtitle">Leave this empty if you want the AI Character to invent the scenario on its own.
|
||||
No character limit.</p>
|
||||
</div>
|
||||
<div class="market-preview-footer">
|
||||
<button id="marketPreviewConfirm" type="button" class="primary-action">Take persona</button>
|
||||
@@ -160,7 +172,8 @@
|
||||
</div>
|
||||
<form id="marketPersonaForm" class="persona-form">
|
||||
<div class="persona-form-intro">
|
||||
<p class="persona-helper">Create or update your AI Characters for roleplay chats and marketplace publishing.</p>
|
||||
<p class="persona-helper">Create or update your AI Characters for roleplay chats and marketplace
|
||||
publishing.</p>
|
||||
</div>
|
||||
<p id="marketPersonaFormNotice" class="status hidden"></p>
|
||||
<div class="persona-form-grid">
|
||||
@@ -178,11 +191,13 @@
|
||||
</label>
|
||||
<label class="field field-wide">
|
||||
<span>Background</span>
|
||||
<textarea id="marketPersonaBackground" rows="3" placeholder="Backstory, history, role, or origins"></textarea>
|
||||
<textarea id="marketPersonaBackground" rows="3"
|
||||
placeholder="Backstory, history, role, or origins"></textarea>
|
||||
</label>
|
||||
<label class="field field-wide">
|
||||
<span>Details</span>
|
||||
<textarea id="marketPersonaDetails" rows="4" placeholder="Personality traits, voice, goals, quirks, boundaries, style"></textarea>
|
||||
<textarea id="marketPersonaDetails" rows="4"
|
||||
placeholder="Personality traits, voice, goals, quirks, boundaries, style"></textarea>
|
||||
</label>
|
||||
<label class="field field-wide">
|
||||
<span>Example dialogues</span>
|
||||
@@ -192,7 +207,8 @@
|
||||
{{user}}: Hi, Marc!
|
||||
{{character}}: Nice to meet you</pre>
|
||||
</div>
|
||||
<textarea id="marketPersonaExampleDialogues" rows="5" placeholder="Write example exchanges that define the character's tone, phrasing, pacing, and personality."></textarea>
|
||||
<textarea id="marketPersonaExampleDialogues" rows="5"
|
||||
placeholder="Write example exchanges that define the character's tone, phrasing, pacing, and personality."></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="persona-actions">
|
||||
@@ -202,7 +218,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="marketActivityOverlay" class="chat-activity-overlay hidden" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div id="marketActivityOverlay" class="chat-activity-overlay hidden" role="status" aria-live="polite"
|
||||
aria-atomic="true">
|
||||
<div class="chat-activity-card">
|
||||
<div class="chat-activity-mark" aria-hidden="true">
|
||||
<span></span>
|
||||
@@ -216,7 +233,8 @@
|
||||
</div>
|
||||
|
||||
<div id="marketPopupModal" class="modal-overlay hidden">
|
||||
<div class="modal-card popup-card" role="dialog" aria-modal="true" aria-labelledby="marketPopupTitle" aria-describedby="marketPopupDescription">
|
||||
<div class="modal-card popup-card" role="dialog" aria-modal="true" aria-labelledby="marketPopupTitle"
|
||||
aria-describedby="marketPopupDescription">
|
||||
<div class="modal-header">
|
||||
<div class="persona-modal-heading">
|
||||
<p id="marketPopupEyebrow" class="eyebrow">Action</p>
|
||||
@@ -237,6 +255,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/market.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script></body>
|
||||
<script type="module" src="/js/market.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+17
-9
@@ -1,16 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Privacy Policy – DeepFake</title>
|
||||
<link rel="stylesheet" href="style.css?v=20260909-account-controls" />
|
||||
<link rel="stylesheet" href="legal.css?v=20260909-account-controls" />
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls" />
|
||||
<link rel="stylesheet" href="/css/legal.css?v=20260909-account-controls" />
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="site-page legal-page">
|
||||
<!-- site-header -->
|
||||
<main id="main" class="legal-content">
|
||||
@@ -58,12 +62,14 @@
|
||||
|
||||
<section>
|
||||
<h2>5. Data Retention</h2>
|
||||
<p>We retain data as long as your account is active. If you request deletion, your data will be deleted unless we must retain it for legal reasons.</p>
|
||||
<p>We retain data as long as your account is active. If you request deletion, your data will be deleted
|
||||
unless we must retain it for legal reasons.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>6. Data Transfers</h2>
|
||||
<p>Your data may be stored or processed where our servers reside. Switzerland has an adequacy decision with the EU, meaning transfers can occur without additional safeguards.</p>
|
||||
<p>Your data may be stored or processed where our servers reside. Switzerland has an adequacy decision with
|
||||
the EU, meaning transfers can occur without additional safeguards.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -81,7 +87,8 @@
|
||||
|
||||
<section>
|
||||
<h2>8. Data Security</h2>
|
||||
<p>We implement reasonable technical and organizational measures to protect your data — encryption for passwords and secure database access.</p>
|
||||
<p>We implement reasonable technical and organizational measures to protect your data — encryption for
|
||||
passwords and secure database access.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -89,6 +96,7 @@
|
||||
<p>We may update this document. Changes will be posted with a “Last updated” date.</p>
|
||||
</section>
|
||||
</main>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+43
-22
@@ -1,17 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
|
||||
<meta charset="UTF-8" />
|
||||
<title>Elsewhere Settings</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/style.css?v=20260909-account-controls"/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
</head>
|
||||
|
||||
<body class="site-page settings-page" data-theme="fakegpt" data-theme-mode="light">
|
||||
<!-- site-header -->
|
||||
<main id="main" class="settings-shell page-content">
|
||||
@@ -26,10 +30,13 @@
|
||||
|
||||
<section class="settings-layout">
|
||||
<aside class="settings-nav" aria-label="Settings sections" role="tablist">
|
||||
<button class="settings-nav-item active" type="button" role="tab" aria-selected="true" data-settings-view="personal">Account</button>
|
||||
<button class="settings-nav-item active" type="button" role="tab" aria-selected="true"
|
||||
data-settings-view="personal">Account</button>
|
||||
|
||||
<button class="settings-nav-item" type="button" role="tab" aria-selected="false" data-settings-view="design">Appearance</button>
|
||||
<button id="diagnosticsNavItem" class="settings-nav-item hidden" type="button" role="tab" aria-selected="false" data-settings-view="diagnostics">Diagnostics</button>
|
||||
<button class="settings-nav-item" type="button" role="tab" aria-selected="false"
|
||||
data-settings-view="design">Appearance</button>
|
||||
<button id="diagnosticsNavItem" class="settings-nav-item hidden" type="button" role="tab"
|
||||
aria-selected="false" data-settings-view="diagnostics">Diagnostics</button>
|
||||
</aside>
|
||||
|
||||
<div class="settings-content">
|
||||
@@ -87,12 +94,14 @@
|
||||
<div>
|
||||
<p class="eyebrow">Account data</p>
|
||||
<h2>Export and sessions</h2>
|
||||
<p class="subtitle">Download your account data or sign out every active browser session.</p>
|
||||
<p class="subtitle">Download your account data or sign out every active browser session.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="persona-actions">
|
||||
<button id="exportAccount" type="button" class="secondary-action">Export account</button>
|
||||
<button id="logoutAllSessions" type="button" class="secondary-action">Logout all sessions</button>
|
||||
<button id="logoutAllSessions" type="button" class="secondary-action">Logout all
|
||||
sessions</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,16 +110,19 @@
|
||||
<div>
|
||||
<p class="eyebrow">Danger zone</p>
|
||||
<h2>Delete account</h2>
|
||||
<p class="subtitle">This permanently removes your account, chats, personas, templates, and market activity.</p>
|
||||
<p class="subtitle">This permanently removes your account, chats, personas, templates,
|
||||
and market activity.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="persona-actions">
|
||||
<button id="deleteAccount" type="button" class="secondary-action danger">Delete account</button>
|
||||
<button id="deleteAccount" type="button" class="secondary-action danger">Delete
|
||||
account</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="settings-view" role="tabpanel" aria-hidden="true" data-settings-panel="my-roleplay-companions">
|
||||
<section class="settings-view" role="tabpanel" aria-hidden="true"
|
||||
data-settings-panel="my-roleplay-companions">
|
||||
<div class="settings-panel">
|
||||
<div class="settings-section-header">
|
||||
<div>
|
||||
@@ -118,8 +130,10 @@
|
||||
<h2>My personas</h2>
|
||||
</div>
|
||||
<div class="market-header-actions action-pair">
|
||||
<button id="createAiCharacter" type="button" class="secondary-action">Create AI Character</button>
|
||||
<button id="createUserPersona" type="button" class="secondary-action">Create User Persona</button>
|
||||
<button id="createAiCharacter" type="button" class="secondary-action">Create AI
|
||||
Character</button>
|
||||
<button id="createUserPersona" type="button" class="secondary-action">Create User
|
||||
Persona</button>
|
||||
</div>
|
||||
</div>
|
||||
<h3>AI Characters</h3>
|
||||
@@ -174,7 +188,8 @@
|
||||
<div>
|
||||
<p class="eyebrow">Admin</p>
|
||||
<h2>Model diagnostics</h2>
|
||||
<p class="subtitle">Backend status, model inventory, latency, and configuration warnings.</p>
|
||||
<p class="subtitle">Backend status, model inventory, latency, and configuration
|
||||
warnings.</p>
|
||||
</div>
|
||||
<button id="refreshDiagnostics" type="button" class="secondary-action">Refresh</button>
|
||||
</div>
|
||||
@@ -252,11 +267,13 @@
|
||||
</label>
|
||||
<label class="field field-wide">
|
||||
<span>Background</span>
|
||||
<textarea id="settingsPersonaBackground" rows="3" placeholder="Backstory, history, role, or origins"></textarea>
|
||||
<textarea id="settingsPersonaBackground" rows="3"
|
||||
placeholder="Backstory, history, role, or origins"></textarea>
|
||||
</label>
|
||||
<label class="field field-wide">
|
||||
<span>Details</span>
|
||||
<textarea id="settingsPersonaDetails" rows="4" placeholder="Personality traits, voice, goals, quirks, boundaries, style"></textarea>
|
||||
<textarea id="settingsPersonaDetails" rows="4"
|
||||
placeholder="Personality traits, voice, goals, quirks, boundaries, style"></textarea>
|
||||
</label>
|
||||
<label id="settingsPersonaExamplesField" class="field field-wide hidden">
|
||||
<span>Example dialogues</span>
|
||||
@@ -266,7 +283,8 @@
|
||||
{{user}}: Hi, Marc!
|
||||
{{character}}: Nice to meet you</pre>
|
||||
</div>
|
||||
<textarea id="settingsPersonaExampleDialogues" rows="5" placeholder="Write example exchanges that define the character's tone, phrasing, pacing, and personality."></textarea>
|
||||
<textarea id="settingsPersonaExampleDialogues" rows="5"
|
||||
placeholder="Write example exchanges that define the character's tone, phrasing, pacing, and personality."></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="persona-actions">
|
||||
@@ -277,7 +295,8 @@
|
||||
</div>
|
||||
|
||||
<div id="settingsPopupModal" class="modal-overlay hidden">
|
||||
<div class="modal-card popup-card" role="dialog" aria-modal="true" aria-labelledby="settingsPopupTitle" aria-describedby="settingsPopupDescription">
|
||||
<div class="modal-card popup-card" role="dialog" aria-modal="true" aria-labelledby="settingsPopupTitle"
|
||||
aria-describedby="settingsPopupDescription">
|
||||
<div class="modal-header">
|
||||
<div class="persona-modal-heading">
|
||||
<p id="settingsPopupEyebrow" class="eyebrow">Action</p>
|
||||
@@ -298,6 +317,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/settings.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script></body>
|
||||
<script type="module" src="/js/settings.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+20
-11
@@ -1,16 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Terms of Service – DeepFake</title>
|
||||
<link rel="stylesheet" href="style.css?v=20260909-account-controls" />
|
||||
<link rel="stylesheet" href="legal.css?v=20260909-account-controls" />
|
||||
<script src="/app/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/shell.css?v=20260909-account-controls">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260909-account-controls" />
|
||||
<link rel="stylesheet" href="/css/legal.css?v=20260909-account-controls" />
|
||||
<script src="/js/theme-bootstrap.js?v=20260909-account-controls"></script>
|
||||
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="site-page legal-page">
|
||||
<!-- site-header -->
|
||||
<main id="main" class="legal-content">
|
||||
@@ -24,22 +28,26 @@
|
||||
|
||||
<section>
|
||||
<h2>User Conduct</h2>
|
||||
<p>You are responsible for content you submit and for maintaining secure account credentials. Do not use DeepFake for unlawful purposes.</p>
|
||||
<p>You are responsible for content you submit and for maintaining secure account credentials. Do not use
|
||||
DeepFake for unlawful purposes.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Data Processing</h2>
|
||||
<p>By using the service, you consent to storing and processing your data as described in the <a href="/privacy.html">Privacy Policy</a>.</p>
|
||||
<p>By using the service, you consent to storing and processing your data as described in the <a
|
||||
href="/privacy.html">Privacy Policy</a>.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Limitation of Liability</h2>
|
||||
<p>We are not liable for service interruptions, data loss, or any indirect damages arising from your use of DeepFake AI.</p>
|
||||
<p>We are not liable for service interruptions, data loss, or any indirect damages arising from your use of
|
||||
DeepFake AI.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Governing Law</h2>
|
||||
<p>These Terms are governed by applicable laws in your jurisdiction (e.g., Switzerland or EU Member States).</p>
|
||||
<p>These Terms are governed by applicable laws in your jurisdiction (e.g., Switzerland or EU Member States).
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -47,6 +55,7 @@
|
||||
<p>We may modify these Terms at any time. Updates will be reflected with a new “Last updated” date.</p>
|
||||
</section>
|
||||
</main>
|
||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+11
-11
@@ -6,7 +6,7 @@ const files = [
|
||||
"src/services/attachmentService.js",
|
||||
"src/services/visionAnalysis.js",
|
||||
"src/routes/uploads.js",
|
||||
"public/app/attachments.js",
|
||||
"public/js/attachments.js",
|
||||
"server.js",
|
||||
"src/app.js",
|
||||
"src/pageLayout.js",
|
||||
@@ -32,18 +32,18 @@ const files = [
|
||||
"src/services/personaService.js",
|
||||
"public/script.js",
|
||||
"public/pages.js",
|
||||
"public/app/workspaceNavigation.js",
|
||||
"public/js/workspaceNavigation.js",
|
||||
"public/settings.js",
|
||||
"public/market.js",
|
||||
"public/app/api.js",
|
||||
"public/app/regeneration.js",
|
||||
"public/app/webSearch.js",
|
||||
"public/app/reasoning.js",
|
||||
"public/app/modelCapabilities.js",
|
||||
"public/app/chatDrawer.js",
|
||||
"public/app/constants.js",
|
||||
"public/app/dom.js",
|
||||
"public/app/modelProfiles.js"
|
||||
"public/js/api.js",
|
||||
"public/js/regeneration.js",
|
||||
"public/js/webSearch.js",
|
||||
"public/js/reasoning.js",
|
||||
"public/js/modelCapabilities.js",
|
||||
"public/js/chatDrawer.js",
|
||||
"public/js/constants.js",
|
||||
"public/js/dom.js",
|
||||
"public/js/modelProfiles.js"
|
||||
];
|
||||
|
||||
for (const file of files) {
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
} from "./chatMessageHelpers.js";
|
||||
|
||||
import { SearXNGSearchProvider, WebSearchError, buildWebSearchContext, retrieveWebSearch } from "./webSearchService.js";
|
||||
import {supportsReasoning} from "../../public/app/modelCapabilities.js";
|
||||
import { supportsReasoning } from "../../public/js/modelCapabilities.js";
|
||||
|
||||
export function createChatService(repositories, modelService, config, webSearchProvider = new SearXNGSearchProvider(config), attachmentService = null) {
|
||||
const formatChatMessage = row => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {supportsReasoning} from "../../public/app/modelCapabilities.js";
|
||||
import { supportsReasoning } from "../../public/js/modelCapabilities.js";
|
||||
import { AttachmentError } from "./attachmentService.js";
|
||||
|
||||
class ModelServiceError extends Error {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {appendAttachments, createAttachmentComposer} from "../public/app/attachments.js";
|
||||
import { appendAttachments, createAttachmentComposer } from "../public/js/attachments.js";
|
||||
|
||||
class Element {
|
||||
constructor() { this.children = []; this.listeners = {}; this.classList = { add() { }, remove() { } }; }
|
||||
|
||||
+20
-10
@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
|
||||
import { createServer } from "node:http";
|
||||
import { createModelService } from "../src/services/modelService.js";
|
||||
import { createApp } from "../src/app.js";
|
||||
import {stream} from "../public/app/api.js";
|
||||
import { stream } from "../public/js/api.js";
|
||||
|
||||
const config = {
|
||||
modelApiBaseUrl: "http://fixture", modelRequestTimeoutMs: 20,
|
||||
@@ -17,13 +17,15 @@ test("active tokens outlive the legacy total timeout and arrive before completio
|
||||
let first;
|
||||
const firstChunk = new Promise(resolve => { first = resolve; });
|
||||
let interval;
|
||||
const service = createModelService(config, {fetch: async () => new Response(new ReadableStream({
|
||||
const service = createModelService(config, {
|
||||
fetch: async () => new Response(new ReadableStream({
|
||||
start(controller) {
|
||||
interval = setInterval(() => controller.enqueue(line({ message: { content: "x" } })), 15);
|
||||
finish = () => { clearInterval(interval); controller.enqueue(line({ done: true })); controller.close(); };
|
||||
},
|
||||
cancel() { clearInterval(interval); }
|
||||
}))});
|
||||
}))
|
||||
});
|
||||
let completed = false;
|
||||
const pending = service.streamReply("qwen3:14b", [], () => first()).then(reply => { completed = true; return reply; });
|
||||
try {
|
||||
@@ -45,7 +47,8 @@ test("connection, inactivity and overall deadlines abort generation", async (t)
|
||||
modelConnectTimeoutMs: kind === "connection" ? 25 : 1000,
|
||||
modelInactivityTimeoutMs: kind === "inactivity" ? 25 : 1000,
|
||||
modelMaxGenerationMs: kind === "overall" ? 70 : 1000
|
||||
}, {fetch: async (_url, {signal}) => {
|
||||
}, {
|
||||
fetch: async (_url, { signal }) => {
|
||||
if (kind === "connection") return new Promise((_resolve, reject) => {
|
||||
signal.addEventListener("abort", () => { cancelled = true; reject(new DOMException("Aborted", "AbortError")); });
|
||||
});
|
||||
@@ -55,7 +58,8 @@ test("connection, inactivity and overall deadlines abort generation", async (t)
|
||||
},
|
||||
cancel() { cancelled = true; clearInterval(interval); }
|
||||
}));
|
||||
}});
|
||||
}
|
||||
});
|
||||
await assert.rejects(service.streamReply("qwen3:14b", [], () => { }), { code: "MODEL_TIMEOUT" });
|
||||
assert.equal(cancelled, true);
|
||||
});
|
||||
@@ -88,17 +92,23 @@ test("browser disconnect aborts Ollama and incomplete output is not persisted",
|
||||
let signal;
|
||||
let releaseAbort;
|
||||
const aborted = new Promise(resolve => { releaseAbort = resolve; });
|
||||
const app = createApp({config: {
|
||||
const app = createApp({
|
||||
config: {
|
||||
dbPath: ":memory:", testMode: true, sessionSecret: "test-only",
|
||||
chatSummaryUpdateEveryMessages: 0, structuredRequestLoggingEnabled: false,
|
||||
eventLoopLagMonitorEnabled: false, slowRequestLoggingEnabled: false
|
||||
}, modelOverrides: {fetch: async (_url, options) => {
|
||||
}, modelOverrides: {
|
||||
fetch: async (_url, options) => {
|
||||
signal = options.signal;
|
||||
signal.addEventListener("abort", releaseAbort, { once: true });
|
||||
return new Response(new ReadableStream({start(controller) {
|
||||
return new Response(new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(line({ message: { content: "partial" } }));
|
||||
}}));
|
||||
}}});
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
const server = createServer(app);
|
||||
await new Promise(resolve => server.listen(0, "127.0.0.1", resolve));
|
||||
t.after(async () => {
|
||||
|
||||
+15
-9
@@ -3,9 +3,9 @@ import assert from "node:assert/strict";
|
||||
import { createServer } from "node:http";
|
||||
import { createApp } from "../src/app.js";
|
||||
import { createModelService } from "../src/services/modelService.js";
|
||||
import {stream} from "../public/app/api.js";
|
||||
import {createReasoningToggle, finishReasoning, updateReasoning} from "../public/app/reasoning.js";
|
||||
import {getModelFamily, supportsReasoning} from "../public/app/modelCapabilities.js";
|
||||
import { stream } from "../public/js/api.js";
|
||||
import { createReasoningToggle, finishReasoning, updateReasoning } from "../public/js/reasoning.js";
|
||||
import { getModelFamily, supportsReasoning } from "../public/js/modelCapabilities.js";
|
||||
|
||||
test("thinking streams separately and survives reload, retry, branch and import", async (t) => {
|
||||
const requests = [];
|
||||
@@ -19,24 +19,30 @@ test("thinking streams separately and survives reload, retry, branch and import"
|
||||
t.after(() => new Promise(resolve => { searchServer.closeAllConnections(); searchServer.close(resolve); }));
|
||||
const modelService = createModelService({
|
||||
modelApiBaseUrl: "http://fixture", modelRequestTimeoutMs: 1000, modelUnloadAfterMs: 60000
|
||||
}, {fetch: async (_url, options) => {
|
||||
}, {
|
||||
fetch: async (_url, options) => {
|
||||
requests.push(JSON.parse(options.body));
|
||||
const chunks = [
|
||||
'{"message":{"thinking":"Consider "}}\n{"message":{"thi',
|
||||
'nking":"carefully.","content":""}}\n',
|
||||
'{"message":{"content":"Answer"},"done":true}'
|
||||
];
|
||||
return new Response(new ReadableStream({start(controller) {
|
||||
return new Response(new ReadableStream({
|
||||
start(controller) {
|
||||
for (const chunk of chunks) controller.enqueue(new TextEncoder().encode(chunk));
|
||||
controller.close();
|
||||
}}));
|
||||
}});
|
||||
const app = createApp({modelService, config: {
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
const app = createApp({
|
||||
modelService, config: {
|
||||
dbPath: ":memory:", testMode: true, sessionSecret: "test-only",
|
||||
searxngUrl: `http://127.0.0.1:${searchServer.address().port}`,
|
||||
chatSummaryUpdateEveryMessages: 0, eventLoopLagMonitorEnabled: false,
|
||||
structuredRequestLoggingEnabled: false, slowRequestLoggingEnabled: false
|
||||
}});
|
||||
}
|
||||
});
|
||||
const server = createServer(app);
|
||||
await new Promise(resolve => server.listen(0, "127.0.0.1", resolve));
|
||||
t.after(async () => {
|
||||
|
||||
+18
-10
@@ -7,8 +7,8 @@ import {runMigrations} from "../src/db/schema.js";
|
||||
import { SearXNGSearchProvider, WebSearchError, buildWebSearchContext, buildWebSearchQuery, decideWebSearch, selectSearchResults, retrieveWebSearch } from "../src/services/webSearchService.js";
|
||||
import { createModelService } from "../src/services/modelService.js";
|
||||
import { formatChatMessage } from "../src/services/chatMessageHelpers.js";
|
||||
import {appendSources, createWebSearchToggle} from "../public/app/webSearch.js";
|
||||
import {stream} from "../public/app/api.js";
|
||||
import { appendSources, createWebSearchToggle } from "../public/js/webSearch.js";
|
||||
import { stream } from "../public/js/api.js";
|
||||
|
||||
// Local protocol fixtures are test-only; production always uses the configured provider.
|
||||
const result = { title: "Major events on September 10, 2025", url: "https://example.org/news", content: "A news report covering major events on September 10, 2025." };
|
||||
@@ -26,10 +26,12 @@ test("SearXNG encodes queries, limits results and treats result data as untruste
|
||||
const upstream = await listen(t, (req, res) => {
|
||||
received = new URL(req.url, "http://localhost");
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.end(JSON.stringify({results: [
|
||||
res.end(JSON.stringify({
|
||||
results: [
|
||||
{ title: "bad", url: "javascript:alert(1)" },
|
||||
...Array.from({ length: 9 }, (_, index) => ({ title: `${"T".repeat(290)} ${index} ${"T".repeat(100)}`, url: `https://example.org/${index}`, content: "S".repeat(2000) }))
|
||||
]}));
|
||||
]
|
||||
}));
|
||||
});
|
||||
const provider = new SearXNGSearchProvider({ searxngUrl: `${upstream.url}/base`, webSearchTimeoutMs: 1000 });
|
||||
const query = `NVIDIA & heute? # ü ${"long ".repeat(200)}`;
|
||||
@@ -151,12 +153,14 @@ test("chat search integrates with streaming, persistence, personas, settings, re
|
||||
},
|
||||
mapError(error) { return { status: 500, body: { error: error.message } }; }
|
||||
};
|
||||
const app = createApp({modelService, config: {
|
||||
const app = createApp({
|
||||
modelService, config: {
|
||||
dbPath: ":memory:", testMode: true, sessionSecret: "test-only", searxngUrl: upstream.url,
|
||||
webSearchTimeoutMs: 1000, chatSummaryUpdateEveryMessages: 0, eventLoopLagMonitorEnabled: false,
|
||||
structuredRequestLoggingEnabled: false, slowRequestLoggingEnabled: false,
|
||||
now: () => new Date("2026-09-21T12:00:00.000Z")
|
||||
}});
|
||||
}
|
||||
});
|
||||
t.after(() => app.locals.close());
|
||||
const backend = await listen(t, app);
|
||||
let cookie;
|
||||
@@ -329,22 +333,26 @@ test("date evidence admits individual events, rejects empty/wrong dates, and bou
|
||||
assert.equal(selected.length, 2);
|
||||
assert.deepEqual(selected.map(source => source.snippet), useful.map(item => item.content));
|
||||
const queries = [];
|
||||
const search = await retrieveWebSearch(question, {async search(query, options) {
|
||||
const search = await retrieveWebSearch(question, {
|
||||
async search(query, options) {
|
||||
queries.push(query);
|
||||
assert.equal(options.category, undefined);
|
||||
return queries.length === 1 ? weak : [...useful, useful[0]];
|
||||
}});
|
||||
}
|
||||
});
|
||||
assert.equal(search.state, "succeeded");
|
||||
assert.equal(queries.length, 2);
|
||||
assert.ok(queries.every(query => query.includes("2025")));
|
||||
assert.deepEqual(search.sources, selected);
|
||||
let duplicateCalls = 0;
|
||||
const refreshed = await retrieveWebSearch(question, {async search() {
|
||||
const refreshed = await retrieveWebSearch(question, {
|
||||
async search() {
|
||||
duplicateCalls++;
|
||||
return duplicateCalls === 1
|
||||
? [{ ...useful[0], content: "Browse the latest headlines and on this day pages." }]
|
||||
: [useful[0]];
|
||||
}});
|
||||
}
|
||||
});
|
||||
assert.equal(refreshed.sources[0].snippet, useful[0].content);
|
||||
let calls = 0;
|
||||
await retrieveWebSearch(question, { async search() { calls++; return useful; } });
|
||||
|
||||
Reference in New Issue
Block a user