diff --git a/public/index.html b/public/index.html
index 079f303..4e37aae 100644
--- a/public/index.html
+++ b/public/index.html
@@ -88,6 +88,34 @@
No persona equipped.
+
diff --git a/public/script.js b/public/script.js
index d193919..a174282 100644
--- a/public/script.js
+++ b/public/script.js
@@ -28,10 +28,6 @@ const personaPronounsInput = document.getElementById("personaPronouns");
const personaAppearanceInput = document.getElementById("personaAppearance");
const personaBackgroundInput = document.getElementById("personaBackground");
const personaDetailsInput = document.getElementById("personaDetails");
-const personaModal = document.getElementById("personaModal");
-const personaCloseBtn = document.getElementById("personaClose");
-const addCustomFieldBtn = document.getElementById("addCustomField");
-const customFieldsList = document.getElementById("customFieldsList");
const newPersonaBtn = document.getElementById("newPersona");
const clearPersonaBtn = document.getElementById("clearPersona");
const personaCancelBtn = document.getElementById("personaCancel");
@@ -198,7 +194,7 @@ function setActivePersonaStatus() {
}
function openPersonaForm(persona = null) {
- personaModal.classList.remove('hidden');
+ personaForm.classList.remove('hidden');
if (persona) {
editingPersonaId = persona.id;
personaFormTitle.textContent = 'Edit persona';
@@ -207,7 +203,6 @@ function openPersonaForm(persona = null) {
personaAppearanceInput.value = persona.appearance || '';
personaBackgroundInput.value = persona.background || '';
personaDetailsInput.value = persona.details || '';
- renderCustomFields(persona.customFields || []);
} else {
editingPersonaId = null;
personaFormTitle.textContent = 'Create persona';
@@ -216,60 +211,15 @@ function openPersonaForm(persona = null) {
personaAppearanceInput.value = '';
personaBackgroundInput.value = '';
personaDetailsInput.value = '';
- renderCustomFields([]);
}
personaNameInput.focus();
}
function closePersonaForm() {
- personaModal.classList.add('hidden');
+ personaForm.classList.add('hidden');
editingPersonaId = null;
}
-function renderCustomFields(fields) {
- customFieldsList.innerHTML = '';
- fields.forEach((field, index) => {
- addCustomFieldRow(field.label || '', field.value || '', index);
- });
-}
-
-function addCustomFieldRow(label = '', value = '') {
- const row = document.createElement('div');
- row.className = 'custom-field-row';
-
- const labelInput = document.createElement('input');
- labelInput.type = 'text';
- labelInput.placeholder = 'Label';
- labelInput.value = label;
-
- const valueInput = document.createElement('input');
- valueInput.type = 'text';
- valueInput.placeholder = 'Value';
- valueInput.value = value;
-
- const removeBtn = document.createElement('button');
- removeBtn.type = 'button';
- removeBtn.textContent = 'Remove';
- removeBtn.className = 'secondary-action';
- removeBtn.addEventListener('click', () => row.remove());
-
- row.appendChild(labelInput);
- row.appendChild(valueInput);
- row.appendChild(removeBtn);
- customFieldsList.appendChild(row);
-}
-
-function collectCustomFields() {
- const rows = customFieldsList.querySelectorAll('.custom-field-row');
- return Array.from(rows).map(row => {
- const [labelInput, valueInput] = row.querySelectorAll('input');
- return {
- label: labelInput.value.trim(),
- value: valueInput.value.trim()
- };
- }).filter(field => field.label || field.value);
-}
-
function renderPersonaList() {
personaList.innerHTML = '';
if (!personas.length) {
@@ -321,10 +271,7 @@ function renderPersonaList() {
async function loadPersonas() {
const res = await get('/personas');
if (res.error) return;
- personas = (res.personas || []).map(persona => ({
- ...persona,
- customFields: persona.customFields || []
- }));
+ personas = res.personas || [];
activePersonaId = res.activePersonaId || null;
renderPersonaList();
}
@@ -349,8 +296,7 @@ async function savePersona() {
pronouns: personaPronounsInput.value.trim(),
appearance: personaAppearanceInput.value.trim(),
background: personaBackgroundInput.value.trim(),
- details: personaDetailsInput.value.trim(),
- customFields: collectCustomFields()
+ details: personaDetailsInput.value.trim()
};
if (!payload.name) return;
let res;
@@ -374,12 +320,6 @@ async function deletePersona(personaId) {
await loadPersonas();
}
-document.addEventListener('keydown', (event) => {
- if (event.key === 'Escape' && !personaModal.classList.contains('hidden')) {
- closePersonaForm();
- }
-});
-
function setLoadingState(loading) {
isProcessing = loading;
sendBtn.disabled = loading;
@@ -650,16 +590,6 @@ newPersonaBtn.addEventListener('click', () => openPersonaForm());
personaCancelBtn.addEventListener('click', () => closePersonaForm());
-personaCloseBtn.addEventListener('click', () => closePersonaForm());
-
-personaModal.addEventListener('click', (event) => {
- if (event.target === personaModal) {
- closePersonaForm();
- }
-});
-
-addCustomFieldBtn.addEventListener('click', () => addCustomFieldRow());
-
clearPersonaBtn.addEventListener('click', () => clearPersona());
personaForm.addEventListener('submit', (event) => {
diff --git a/public/style.css b/public/style.css
index 45705bc..1083397 100644
--- a/public/style.css
+++ b/public/style.css
@@ -461,9 +461,14 @@ button:disabled {
.persona-form {
display: grid;
gap: 10px;
- max-height: 65vh;
- overflow-y: auto;
- padding-right: 6px;
+ background: rgba(10, 10, 20, 0.75);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ border-radius: 16px;
+ padding: 12px;
+}
+
+.persona-form.hidden {
+ display: none;
}
.persona-form h3 {
@@ -477,83 +482,6 @@ button:disabled {
flex-wrap: wrap;
}
-.modal-overlay {
- position: fixed;
- inset: 0;
- background: rgba(5, 5, 20, 0.75);
- display: grid;
- place-items: center;
- z-index: 1000;
- padding: 24px;
-}
-
-.modal-overlay.hidden {
- display: none;
-}
-
-.modal-card {
- width: min(520px, 92vw);
- background: rgba(19, 19, 42, 0.96);
- border: 1px solid rgba(255, 255, 255, 0.08);
- border-radius: 22px;
- padding: 18px;
- box-shadow: 0 25px 60px -12px var(--shadow);
- display: grid;
- gap: 14px;
-}
-
-.modal-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
-}
-
-.modal-header h3 {
- margin: 0;
- font-size: 1.2rem;
-}
-
-.custom-fields {
- display: grid;
- gap: 10px;
- background: rgba(10, 10, 20, 0.6);
- border: 1px solid rgba(255, 255, 255, 0.06);
- border-radius: 14px;
- padding: 10px;
-}
-
-.custom-fields-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- font-size: 0.9rem;
- color: var(--text-secondary);
-}
-
-.custom-fields-list {
- display: grid;
- gap: 8px;
-}
-
-.custom-field-row {
- display: grid;
- grid-template-columns: 1fr 1fr auto;
- gap: 8px;
- align-items: center;
-}
-
-.custom-field-row input {
- padding: 10px 12px;
- font-size: 14px;
-}
-
-.custom-field-row button {
- padding: 8px 10px;
- font-size: 12px;
- border-radius: 10px;
-}
-
.chat-main {
display: grid;
grid-template-rows: auto 1fr auto auto;
diff --git a/server.js b/server.js
index e857d43..ec3493c 100644
--- a/server.js
+++ b/server.js
@@ -171,8 +171,6 @@ db.prepare(`
TEXT,
details
TEXT,
- custom_fields
- TEXT,
created_at
DATETIME
DEFAULT
@@ -274,25 +272,25 @@ const deleteChatMessagesStmt = db.prepare(
);
const listPersonasStmt = db.prepare(`
- SELECT id, name, pronouns, appearance, background, details, custom_fields, created_at, updated_at
+ SELECT id, name, pronouns, appearance, background, details, created_at, updated_at
FROM personas
WHERE username = ?
ORDER BY datetime(updated_at) DESC
`);
const getPersonaStmt = db.prepare(`
- SELECT id, name, pronouns, appearance, background, details, custom_fields
+ SELECT id, name, pronouns, appearance, background, details
FROM personas
WHERE id = ? AND username = ?
`);
const insertPersonaStmt = db.prepare(
- "INSERT INTO personas (username, name, pronouns, appearance, background, details, custom_fields) VALUES (?, ?, ?, ?, ?, ?, ?)"
+ "INSERT INTO personas (username, name, pronouns, appearance, background, details) VALUES (?, ?, ?, ?, ?, ?)"
);
const updatePersonaStmt = db.prepare(`
UPDATE personas
- SET name = ?, pronouns = ?, appearance = ?, background = ?, details = ?, custom_fields = ?, updated_at = CURRENT_TIMESTAMP
+ SET name = ?, pronouns = ?, appearance = ?, background = ?, details = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ? AND username = ?
`);
@@ -311,7 +309,7 @@ const setActivePersonaStmt = db.prepare(`
`);
const getActivePersonaStmt = db.prepare(`
- SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details, p.custom_fields
+ SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details
FROM user_settings us
JOIN personas p ON p.id = us.active_persona_id
WHERE us.username = ?
@@ -389,27 +387,6 @@ const normalizePersonaField = (value) => {
return trimmed ? trimmed : null;
};
-const normalizeCustomFields = (fields) => {
- if (!Array.isArray(fields)) return null;
- const cleaned = fields
- .map(field => ({
- label: (field?.label || "").trim(),
- value: (field?.value || "").trim()
- }))
- .filter(field => field.label || field.value);
- return cleaned.length ? JSON.stringify(cleaned) : null;
-};
-
-const parseCustomFields = (value) => {
- if (!value) return [];
- try {
- const parsed = JSON.parse(value);
- return Array.isArray(parsed) ? parsed : [];
- } catch (error) {
- return [];
- }
-};
-
const buildPersonaPrompt = (persona) => {
const lines = [
"You are roleplaying with the following persona. Stay in character, be engaging, and align with these details."
@@ -419,10 +396,6 @@ const buildPersonaPrompt = (persona) => {
if (persona.appearance) lines.push(`Appearance: ${persona.appearance}`);
if (persona.background) lines.push(`Background: ${persona.background}`);
if (persona.details) lines.push(`Details: ${persona.details}`);
- const customFields = parseCustomFields(persona.custom_fields);
- customFields.forEach(field => {
- lines.push(`${field.label || "Custom"}: ${field.value}`);
- });
return lines.join("\n");
};
@@ -511,10 +484,7 @@ app.post("/chats/:id/clear", requireLogin, (req, res) => {
app.get("/personas", requireLogin, (req, res) => {
const user = req.session.user;
- const personas = listPersonasStmt.all(user).map(persona => ({
- ...persona,
- customFields: parseCustomFields(persona.custom_fields)
- }));
+ const personas = listPersonasStmt.all(user);
const activePersonaId = getActivePersonaIdStmt.get(user)?.active_persona_id ?? null;
res.json({personas, activePersonaId});
});
@@ -529,23 +499,16 @@ app.post("/personas", requireLogin, (req, res) => {
const appearance = normalizePersonaField(req.body?.appearance);
const background = normalizePersonaField(req.body?.background);
const details = normalizePersonaField(req.body?.details);
- const customFields = normalizeCustomFields(req.body?.customFields);
const personaId = insertPersonaStmt.run(
user,
name,
pronouns,
appearance,
background,
- details,
- customFields
+ details
).lastInsertRowid;
const persona = getPersonaStmt.get(personaId, user);
- res.json({
- persona: {
- ...persona,
- customFields: parseCustomFields(persona.custom_fields)
- }
- });
+ res.json({persona});
});
app.put("/personas/:id", requireLogin, (req, res) => {
@@ -559,14 +522,12 @@ app.put("/personas/:id", requireLogin, (req, res) => {
const appearance = normalizePersonaField(req.body?.appearance);
const background = normalizePersonaField(req.body?.background);
const details = normalizePersonaField(req.body?.details);
- const customFields = normalizeCustomFields(req.body?.customFields);
const result = updatePersonaStmt.run(
name,
pronouns,
appearance,
background,
details,
- customFields,
personaId,
user
);
@@ -574,12 +535,7 @@ app.put("/personas/:id", requireLogin, (req, res) => {
return res.status(404).json({error: "Persona not found"});
}
const persona = getPersonaStmt.get(personaId, user);
- res.json({
- persona: {
- ...persona,
- customFields: parseCustomFields(persona.custom_fields)
- }
- });
+ res.json({persona});
});
app.delete("/personas/:id", requireLogin, (req, res) => {