feat: Avatar Scale (0.5×–3×) + Krea AI Bildgenerierung für Avatare
Backend: - SessionRecord + AgentRecord: neues Feld AvatarScale (double, Default 1.0) - DatabaseService: avatar_scale Migration, in Create/Update/GetWithStats - SessionEndpoint + AgentEndpoint: avatarScale in Create/Update - api.js: apiKreaStatus(), apiKreaGenerate() Frontend: - Session + Agent Templates: Range-Slider (0.5×–3×) in Avatar-Section - Krea AI Generate: Prompt-Input + Magic-Button (nur wenn KreaToken konfiguriert) - Live-Preview: transform: scale() auf Avatar-Vorschau - Dashboard: scale() auf Session- und Agent-Card-Images - form.css: avatar-scale-row + avatar-ai-section Styling
This commit is contained in:
1 parent
4ebbeaa818
commit
057d37d76f
11 files changed
+220
-15
No files matched your search
@@ -64,7 +64,8 @@ public static class AgentEndpoint
|
||||
UseUserInfo = !body.TryGetProperty("useUserInfo", out var uu) || uu.GetBoolean(),
|
||||
UseMemory = !body.TryGetProperty("useMemory", out var um) || um.GetBoolean(),
|
||||
UseWebSearch = body.TryGetProperty("webSearchVersion", out var wsv) && !string.IsNullOrEmpty(wsv.GetString()),
|
||||
WebSearchVersion = body.TryGetProperty("webSearchVersion", out var wsv2) ? wsv2.GetString() ?? "" : ""
|
||||
WebSearchVersion = body.TryGetProperty("webSearchVersion", out var wsv2) ? wsv2.GetString() ?? "" : "",
|
||||
AvatarScale = body.TryGetProperty("avatarScale", out var asc) ? asc.GetDouble() : 1.0
|
||||
};
|
||||
|
||||
agent = await db.CreateAgent(agent);
|
||||
@@ -100,6 +101,7 @@ public static class AgentEndpoint
|
||||
agent.WebSearchVersion = wsv.GetString() ?? "";
|
||||
agent.UseWebSearch = !string.IsNullOrEmpty(agent.WebSearchVersion);
|
||||
}
|
||||
if (body.TryGetProperty("avatarScale", out var asc)) agent.AvatarScale = asc.GetDouble();
|
||||
|
||||
await db.UpdateAgent(agent);
|
||||
memoryService.InitializeAgentFiles(agentId, agent.Name);
|
||||
|
||||
@@ -76,8 +76,9 @@ public static class SessionEndpoint
|
||||
}
|
||||
var context = body.TryGetProperty("context", out var ctxEl) ? ctxEl.GetString() : null;
|
||||
var customCommands = body.TryGetProperty("customCommands", out var cc) && cc.ValueKind != JsonValueKind.Null ? cc.GetRawText() : null;
|
||||
var avatarScale = body.TryGetProperty("avatarScale", out var asc) ? asc.GetDouble() : 1.0;
|
||||
|
||||
var session = await db.CreateSession(userId, name, description, image, agentId, workspace, context, customCommands);
|
||||
var session = await db.CreateSession(userId, name, description, image, agentId, workspace, context, customCommands, avatarScale);
|
||||
await ctx.Response.WriteAsJsonAsync(session);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ public class AgentRecord
|
||||
public bool UseMemory { get; set; } = true;
|
||||
public bool UseWebSearch { get; set; }
|
||||
public string WebSearchVersion { get; set; } = "";
|
||||
public double AvatarScale { get; set; } = 1.0;
|
||||
public string UserId { get; set; }
|
||||
public bool IsDeleted { get; set; }
|
||||
public string CreatedAt { get; set; }
|
||||
|
||||
@@ -16,6 +16,7 @@ public class SessionRecord
|
||||
public string TelegramBotToken { get; set; }
|
||||
public string TelegramWebhookSecret { get; set; }
|
||||
public string TelegramChatId { get; set; }
|
||||
public double AvatarScale { get; set; } = 1.0;
|
||||
public string CreatedAt { get; set; }
|
||||
public string UpdatedAt { get; set; }
|
||||
}
|
||||
@@ -167,6 +167,8 @@ public class DatabaseService
|
||||
TryAddColumn(conn, "users", "persona", "TEXT");
|
||||
TryAddColumn(conn, "users", "settings", "TEXT");
|
||||
TryAddColumn(conn, "users", "default_path", "TEXT");
|
||||
TryAddColumn(conn, "sessions", "avatar_scale", "REAL NOT NULL DEFAULT 1.0");
|
||||
TryAddColumn(conn, "agents", "avatar_scale", "REAL NOT NULL DEFAULT 1.0");
|
||||
TryAddColumn(conn, "cronjobs", "notify_session_id", "TEXT");
|
||||
|
||||
conn.Execute(@"
|
||||
@@ -320,8 +322,8 @@ public class DatabaseService
|
||||
agent.CreatedAt = now;
|
||||
agent.UpdatedAt = now;
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT INTO agents (agent_id, user_id, name, avatar, description, model, tool_choice, custom_commands, auto_commit, use_soul, use_identity, use_user_info, use_memory, use_web_search, web_search_version, is_deleted, created_at, updated_at)
|
||||
VALUES (@AgentId, @UserId, @Name, @Avatar, @Description, @Model, @ToolChoice, @CustomCommands, @AutoCommit, @UseSoul, @UseIdentity, @UseUserInfo, @UseMemory, @UseWebSearch, @WebSearchVersion, 0, @CreatedAt, @UpdatedAt)
|
||||
INSERT INTO agents (agent_id, user_id, name, avatar, description, model, tool_choice, custom_commands, auto_commit, use_soul, use_identity, use_user_info, use_memory, use_web_search, web_search_version, avatar_scale, is_deleted, created_at, updated_at)
|
||||
VALUES (@AgentId, @UserId, @Name, @Avatar, @Description, @Model, @ToolChoice, @CustomCommands, @AutoCommit, @UseSoul, @UseIdentity, @UseUserInfo, @UseMemory, @UseWebSearch, @WebSearchVersion, @AvatarScale, 0, @CreatedAt, @UpdatedAt)
|
||||
", agent);
|
||||
return agent;
|
||||
}
|
||||
@@ -349,7 +351,7 @@ public class DatabaseService
|
||||
model = @Model, tool_choice = @ToolChoice,
|
||||
custom_commands = @CustomCommands, auto_commit = @AutoCommit,
|
||||
use_soul = @UseSoul, use_identity = @UseIdentity, use_user_info = @UseUserInfo, use_memory = @UseMemory, use_web_search = @UseWebSearch, web_search_version = @WebSearchVersion,
|
||||
updated_at = @UpdatedAt
|
||||
avatar_scale = @AvatarScale, updated_at = @UpdatedAt
|
||||
WHERE agent_id = @AgentId AND user_id = @UserId
|
||||
", agent);
|
||||
}
|
||||
@@ -364,7 +366,7 @@ public class DatabaseService
|
||||
|
||||
// ── Sessions ──
|
||||
|
||||
public async Task<SessionRecord> CreateSession(string userId, string name = null, string description = null, string image = null, string agentId = null, string workspace = null, string context = null, string customCommands = null)
|
||||
public async Task<SessionRecord> CreateSession(string userId, string name = null, string description = null, string image = null, string agentId = null, string workspace = null, string context = null, string customCommands = null, double avatarScale = 1.0)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var now = DateTime.UtcNow.ToString("o");
|
||||
@@ -379,12 +381,13 @@ public class DatabaseService
|
||||
Workspace = workspace,
|
||||
Context = context,
|
||||
CustomCommands = customCommands,
|
||||
AvatarScale = avatarScale,
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
};
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT INTO sessions (session_id, user_id, name, description, image, agent_id, workspace, context, custom_commands, created_at, updated_at)
|
||||
VALUES (@SessionId, @UserId, @Name, @Description, @Image, @AgentId, @Workspace, @Context, @CustomCommands, @CreatedAt, @UpdatedAt)
|
||||
INSERT INTO sessions (session_id, user_id, name, description, image, agent_id, workspace, context, custom_commands, avatar_scale, created_at, updated_at)
|
||||
VALUES (@SessionId, @UserId, @Name, @Description, @Image, @AgentId, @Workspace, @Context, @CustomCommands, @AvatarScale, @CreatedAt, @UpdatedAt)
|
||||
", session);
|
||||
return session;
|
||||
}
|
||||
@@ -427,6 +430,7 @@ public class DatabaseService
|
||||
s.Workspace,
|
||||
s.Context,
|
||||
s.CustomCommands,
|
||||
s.AvatarScale,
|
||||
s.IsDeleted,
|
||||
s.CreatedAt,
|
||||
s.UpdatedAt,
|
||||
@@ -476,6 +480,7 @@ public class DatabaseService
|
||||
if (body.TryGetProperty("workspace", out var w)) { sets.Add("workspace = @workspace"); p.Add("workspace", w.GetString()); }
|
||||
if (body.TryGetProperty("context", out var ctx)) { sets.Add("context = @context"); p.Add("context", ctx.GetString()); }
|
||||
if (body.TryGetProperty("customCommands", out var cc)) { sets.Add("custom_commands = @customCommands"); p.Add("customCommands", cc.ValueKind == System.Text.Json.JsonValueKind.Null ? null : cc.GetRawText()); }
|
||||
if (body.TryGetProperty("avatarScale", out var asc)) { sets.Add("avatar_scale = @avatarScale"); p.Add("avatarScale", asc.GetDouble()); }
|
||||
|
||||
await conn.ExecuteAsync($"UPDATE sessions SET {string.Join(", ", sets)} WHERE session_id = @sessionId", p);
|
||||
}
|
||||
|
||||
+28
-2
@@ -22,8 +22,8 @@
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
width: 8em;
|
||||
height: 8em;
|
||||
background: var(--f2-bg);
|
||||
border: var(--border-width) solid var(--f2-border);
|
||||
display: flex;
|
||||
@@ -38,6 +38,32 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: scale var(--transition-duration);
|
||||
}
|
||||
|
||||
.avatar-scale-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--badge-spacing);
|
||||
flex: 1;
|
||||
padding: var(--box-padding);
|
||||
}
|
||||
.avatar-scale-row label {
|
||||
margin: 0;
|
||||
}
|
||||
.avatar-scale-row input[type="range"] {
|
||||
flex: 1;
|
||||
accent-color: var(--primary);
|
||||
}
|
||||
.avatar-scale-row span {
|
||||
font-size: 0.85em;
|
||||
min-width: 2.5em;
|
||||
text-align: right;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.avatar-ai-section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.input-with-btn {
|
||||
|
||||
@@ -106,6 +106,17 @@
|
||||
<button id="sessionImageBtn">Bild ändern</button>
|
||||
<button id="sessionImageClearBtn">Entfernen</button>
|
||||
</div>
|
||||
<div class="avatar-scale-row" id="sessionScaleRow" hidden>
|
||||
<label>Zoom</label>
|
||||
<input type="range" id="sessionAvatarScale" min="0.5" max="3" step="0.1" value="1">
|
||||
<span id="sessionScaleValue">1×</span>
|
||||
</div>
|
||||
<div class="avatar-ai-section" id="sessionAiSection" hidden>
|
||||
<div class="input-with-btn">
|
||||
<input type="text" id="sessionAiPrompt" placeholder="Bildbeschreibung eingeben...">
|
||||
<button type="button" id="sessionAiGenerateBtn" class="icon-btn" title="Bild generieren"><i class="fa fa-magic"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<label>Name</label>
|
||||
<input type="text" id="sessionName" placeholder="Name der Session">
|
||||
<label>Agent</label>
|
||||
@@ -164,6 +175,17 @@
|
||||
<button id="avatarBtn">Avatar ändern</button>
|
||||
<button id="avatarClearBtn">Entfernen</button>
|
||||
</div>
|
||||
<div class="avatar-scale-row" id="agentScaleRow" hidden>
|
||||
<label>Zoom</label>
|
||||
<input type="range" id="agentAvatarScale" min="0.5" max="3" step="0.1" value="1">
|
||||
<span id="agentScaleValue">1×</span>
|
||||
</div>
|
||||
<div class="avatar-ai-section" id="agentAiSection" hidden>
|
||||
<div class="input-with-btn">
|
||||
<input type="text" id="agentAiPrompt" placeholder="Bildbeschreibung eingeben...">
|
||||
<button type="button" id="agentAiGenerateBtn" class="icon-btn" title="Bild generieren"><i class="fa fa-magic"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<label>Name</label>
|
||||
<input type="text" id="agentName" placeholder="Name des Agents">
|
||||
<label>Model</label>
|
||||
|
||||
@@ -472,6 +472,27 @@ async function apiAdminImpersonate(userId) {
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
// ── Krea Image API ──
|
||||
|
||||
async function apiKreaStatus() {
|
||||
const resp = await fetch('/api/images/status');
|
||||
if (!resp.ok) return { configured: false };
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
async function apiKreaGenerate(prompt, model, width, height) {
|
||||
const resp = await fetch('/api/images/generate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ prompt, model: model || 'flux', width: width || 512, height: height || 512, batchSize: 1 })
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json().catch(() => ({}));
|
||||
throw new Error(err.error || 'Bildgenerierung fehlgeschlagen');
|
||||
}
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
// ── Backup API ──
|
||||
|
||||
async function apiBackupDb() {
|
||||
|
||||
@@ -38,8 +38,19 @@ registerPage('agent', {
|
||||
const skillList = document.getElementById('agentSkillList');
|
||||
const more = document.querySelector('.more');
|
||||
|
||||
const scaleRow = document.getElementById('agentScaleRow');
|
||||
const scaleInput = document.getElementById('agentAvatarScale');
|
||||
const scaleValue = document.getElementById('agentScaleValue');
|
||||
|
||||
_agentAvatarData = null;
|
||||
|
||||
function updatePreviewScale() {
|
||||
var img = avatarPreview.querySelector('img');
|
||||
if (img) img.style.scale = scaleInput.value;
|
||||
scaleValue.textContent = scaleInput.value + '×';
|
||||
}
|
||||
scaleInput.addEventListener('input', updatePreviewScale);
|
||||
|
||||
if (agent) {
|
||||
title.textContent = agent.name;
|
||||
nameEl.value = agent.name || '';
|
||||
@@ -55,8 +66,14 @@ registerPage('agent', {
|
||||
_agentAvatarData = agent.avatar || null;
|
||||
deleteBtn.hidden = false;
|
||||
|
||||
if (agent.avatarScale && agent.avatarScale !== 1) {
|
||||
scaleInput.value = agent.avatarScale;
|
||||
scaleValue.textContent = agent.avatarScale + '×';
|
||||
}
|
||||
|
||||
if (agent.avatar) {
|
||||
avatarPreview.innerHTML = `<img src="${agent.avatar}" alt="Avatar">`;
|
||||
avatarPreview.innerHTML = `<img src="${agent.avatar}" alt="Avatar" style="scale: ${agent.avatarScale || 1}">`;
|
||||
scaleRow.hidden = false;
|
||||
}
|
||||
|
||||
// Custom Commands laden
|
||||
@@ -82,6 +99,43 @@ registerPage('agent', {
|
||||
// Befehl hinzufügen
|
||||
addCommandBtn.addEventListener('click', () => createCommandRow(commandsList));
|
||||
|
||||
// AI Bild-Generierung (nur wenn Krea konfiguriert)
|
||||
const aiSection = document.getElementById('agentAiSection');
|
||||
const aiPrompt = document.getElementById('agentAiPrompt');
|
||||
const aiGenerateBtn = document.getElementById('agentAiGenerateBtn');
|
||||
apiKreaStatus().then(status => {
|
||||
if (status.configured) aiSection.hidden = false;
|
||||
});
|
||||
aiGenerateBtn.addEventListener('click', async () => {
|
||||
const prompt = aiPrompt.value.trim();
|
||||
if (!prompt) return;
|
||||
aiGenerateBtn.disabled = true;
|
||||
aiGenerateBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||
try {
|
||||
const result = await apiKreaGenerate(prompt);
|
||||
if (result.files && result.files.length > 0) {
|
||||
const imgResp = await fetch('/api/images/file/' + result.files[0]);
|
||||
const blob = await imgResp.blob();
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
_agentAvatarData = reader.result;
|
||||
avatarPreview.innerHTML = `<img src="${reader.result}" alt="Avatar">`;
|
||||
scaleRow.hidden = false;
|
||||
updatePreviewScale();
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
}
|
||||
} catch (e) {
|
||||
showToast('Fehler: ' + e.message, 'error');
|
||||
} finally {
|
||||
aiGenerateBtn.disabled = false;
|
||||
aiGenerateBtn.innerHTML = '<i class="fa fa-magic"></i>';
|
||||
}
|
||||
});
|
||||
aiPrompt.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') { e.preventDefault(); aiGenerateBtn.click(); }
|
||||
});
|
||||
|
||||
// Avatar Upload
|
||||
avatarBtn.addEventListener('click', () => avatarInput.click());
|
||||
avatarInput.addEventListener('change', () => {
|
||||
@@ -91,6 +145,8 @@ registerPage('agent', {
|
||||
reader.onload = () => {
|
||||
_agentAvatarData = reader.result;
|
||||
avatarPreview.innerHTML = `<img src="${reader.result}" alt="Avatar">`;
|
||||
scaleRow.hidden = false;
|
||||
updatePreviewScale();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
@@ -99,6 +155,9 @@ registerPage('agent', {
|
||||
_agentAvatarData = null;
|
||||
avatarPreview.innerHTML = '?';
|
||||
avatarInput.value = '';
|
||||
scaleRow.hidden = true;
|
||||
scaleInput.value = 1;
|
||||
scaleValue.textContent = '1×';
|
||||
});
|
||||
|
||||
// Avatar Paste (Ctrl+V)
|
||||
@@ -114,6 +173,8 @@ registerPage('agent', {
|
||||
reader.onload = () => {
|
||||
_agentAvatarData = reader.result;
|
||||
avatarPreview.innerHTML = `<img src="${reader.result}" alt="Avatar">`;
|
||||
scaleRow.hidden = false;
|
||||
updatePreviewScale();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
return;
|
||||
@@ -142,6 +203,7 @@ registerPage('agent', {
|
||||
useMemory: useMemoryEl.checked,
|
||||
webSearchVersion: webSearchVersionEl.value,
|
||||
avatar: _agentAvatarData,
|
||||
avatarScale: parseFloat(scaleInput.value) || 1,
|
||||
customCommands: getCommandsFromUI(commandsList)
|
||||
};
|
||||
|
||||
|
||||
@@ -51,8 +51,9 @@ registerPage('dashboard', {
|
||||
if (s.context) sessionBadges.push(`<span class="badge badge-feature" title="${esc(s.context)}"><i class="fa fa-file-text-o"></i></span>`);
|
||||
if (s.telegramConfigured) sessionBadges.push(`<span class="badge ${s.telegramLinked ? 'badge-feature' : 'badge-off'}" title="Telegram ${s.telegramLinked ? 'verbunden' : 'konfiguriert'}"><i class="fa fa-paper-plane"></i></span>`);
|
||||
|
||||
const scaleStyle = s.avatarScale && s.avatarScale !== 1 ? ` style="scale: ${s.avatarScale}"` : '';
|
||||
card.innerHTML = `
|
||||
<div class="card-image">${s.image ? `<img src="${s.image}" alt="">` : ''}</div>
|
||||
<div class="card-image">${s.image ? `<img src="${s.image}" alt=""${scaleStyle}>` : ''}</div>
|
||||
<div class="card-body">
|
||||
<div class="card-title-row">
|
||||
<span class="card-title">${esc(s.name || 'Unbenannt')}</span>
|
||||
@@ -197,8 +198,9 @@ registerPage('dashboard', {
|
||||
badges.push(`<span class="badge badge-skill" title="${esc(skill.description || skill.slug)}"><i class="fa fa-puzzle-piece"></i> ${esc(skill.name)}</span>`);
|
||||
}
|
||||
|
||||
const agentScaleStyle = a.avatarScale && a.avatarScale !== 1 ? ` style="transform: scale(${a.avatarScale})"` : '';
|
||||
card.innerHTML = `
|
||||
<div class="card-image">${a.avatar ? `<img src="${a.avatar}" alt="">` : ''}</div>
|
||||
<div class="card-image">${a.avatar ? `<img src="${a.avatar}" alt=""${agentScaleStyle}>` : ''}</div>
|
||||
<div class="card-body">
|
||||
<div class="card-title-row">
|
||||
<span class="card-title">${esc(a.name)}</span>
|
||||
|
||||
@@ -32,8 +32,19 @@ registerPage('session', {
|
||||
const addCommandBtn = document.getElementById('addCommandBtn');
|
||||
const more = document.querySelector('.more');
|
||||
|
||||
const scaleRow = document.getElementById('sessionScaleRow');
|
||||
const scaleInput = document.getElementById('sessionAvatarScale');
|
||||
const scaleValue = document.getElementById('sessionScaleValue');
|
||||
|
||||
_sessionImageData = null;
|
||||
|
||||
function updatePreviewScale() {
|
||||
var img = imagePreview.querySelector('img');
|
||||
if (img) img.style.scale = scaleInput.value;
|
||||
scaleValue.textContent = scaleInput.value + '×';
|
||||
}
|
||||
scaleInput.addEventListener('input', updatePreviewScale);
|
||||
|
||||
if (session) {
|
||||
titleEl.textContent = session.name || 'Unbenannt';
|
||||
nameEl.value = session.name || '';
|
||||
@@ -42,8 +53,14 @@ registerPage('session', {
|
||||
_sessionImageData = session.image || null;
|
||||
deleteBtn.hidden = false;
|
||||
|
||||
if (session.avatarScale && session.avatarScale !== 1) {
|
||||
scaleInput.value = session.avatarScale;
|
||||
scaleValue.textContent = session.avatarScale + '×';
|
||||
}
|
||||
|
||||
if (session.image) {
|
||||
imagePreview.innerHTML = `<img src="${session.image}" alt="">`;
|
||||
imagePreview.innerHTML = `<img src="${session.image}" alt="" style="scale: ${session.avatarScale || 1}">`;
|
||||
scaleRow.hidden = false;
|
||||
}
|
||||
|
||||
// Custom Commands laden
|
||||
@@ -87,6 +104,43 @@ registerPage('session', {
|
||||
}
|
||||
if (session && session.agentId) agentSelect.value = session.agentId;
|
||||
|
||||
// AI Bild-Generierung (nur wenn Krea konfiguriert)
|
||||
const aiSection = document.getElementById('sessionAiSection');
|
||||
const aiPrompt = document.getElementById('sessionAiPrompt');
|
||||
const aiGenerateBtn = document.getElementById('sessionAiGenerateBtn');
|
||||
apiKreaStatus().then(status => {
|
||||
if (status.configured) aiSection.hidden = false;
|
||||
});
|
||||
aiGenerateBtn.addEventListener('click', async () => {
|
||||
const prompt = aiPrompt.value.trim();
|
||||
if (!prompt) return;
|
||||
aiGenerateBtn.disabled = true;
|
||||
aiGenerateBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||
try {
|
||||
const result = await apiKreaGenerate(prompt);
|
||||
if (result.files && result.files.length > 0) {
|
||||
const imgResp = await fetch('/api/images/file/' + result.files[0]);
|
||||
const blob = await imgResp.blob();
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
_sessionImageData = reader.result;
|
||||
imagePreview.innerHTML = `<img src="${reader.result}" alt="">`;
|
||||
scaleRow.hidden = false;
|
||||
updatePreviewScale();
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
}
|
||||
} catch (e) {
|
||||
showToast('Fehler: ' + e.message, 'error');
|
||||
} finally {
|
||||
aiGenerateBtn.disabled = false;
|
||||
aiGenerateBtn.innerHTML = '<i class="fa fa-magic"></i>';
|
||||
}
|
||||
});
|
||||
aiPrompt.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') { e.preventDefault(); aiGenerateBtn.click(); }
|
||||
});
|
||||
|
||||
// Bild Upload
|
||||
imageBtn.addEventListener('click', () => imageInput.click());
|
||||
imageInput.addEventListener('change', () => {
|
||||
@@ -96,6 +150,8 @@ registerPage('session', {
|
||||
reader.onload = () => {
|
||||
_sessionImageData = reader.result;
|
||||
imagePreview.innerHTML = `<img src="${reader.result}" alt="">`;
|
||||
scaleRow.hidden = false;
|
||||
updatePreviewScale();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
@@ -104,6 +160,9 @@ registerPage('session', {
|
||||
_sessionImageData = null;
|
||||
imagePreview.innerHTML = '?';
|
||||
imageInput.value = '';
|
||||
scaleRow.hidden = true;
|
||||
scaleInput.value = 1;
|
||||
scaleValue.textContent = '1×';
|
||||
});
|
||||
|
||||
// Bild Paste (Ctrl+V)
|
||||
@@ -119,6 +178,8 @@ registerPage('session', {
|
||||
reader.onload = () => {
|
||||
_sessionImageData = reader.result;
|
||||
imagePreview.innerHTML = `<img src="${reader.result}" alt="">`;
|
||||
scaleRow.hidden = false;
|
||||
updatePreviewScale();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
return;
|
||||
@@ -175,7 +236,8 @@ registerPage('session', {
|
||||
agentId: agentSelect.value || null,
|
||||
context: _sessionContextMde.value().trim() || null,
|
||||
workspace: workspaceEl.value.trim() || null,
|
||||
customCommands: commands
|
||||
customCommands: commands,
|
||||
avatarScale: parseFloat(scaleInput.value) || 1
|
||||
};
|
||||
|
||||
if (isNew) {
|
||||
|
||||
Reference in new issue
Block a user