feat: Add streaming chat + scroll persistence; improve markdown & links
Backend
- /chat: support streaming via StreamingResponse; save full reply after stream ends. Non-stream path unchanged.
- ChatRequest: add stream flag (default false).
- GenerateTitleRequest: add model and use it instead of hardcoded llama3.
- ollama_client.chat_stream(): new async generator parsing Ollama streaming JSON (both formats).
- Remove response_model from /chat to allow streaming; non-stream still returns { reply }.
Electron
- Open external links in system browser (setWindowOpenHandler, shell.openExternal).
- New IPC: update-settings, open-external-link.
- Set minimum window size; preload exposes updateSettings and openExternalLink.
Frontend (React)
- Streaming UI with live chunking; sticky-bottom only when user at bottom.
- Per-session scroll persistence and robust restore.
- New message tip to jump to latest reply when scrolled up.
- Disable Send while sending; spinner.
- General Settings: stream output toggle; propagate model/stream changes.
- Apply color scheme at boot; extract colorSchemes helper.
- Sidebar UX tweaks and unread badges.
Markdown/rendering
- Code blocks: language title bar and wrapper.
- Tables: GitHub-style parsing, per-cell borders, rounded wrapper, spacing, alignment.
- Headings: remove blank line after h1-h4.
- <hr>: handle after tables; strip following whitespace.
- Links: target=_blank with icon and URL tooltip.
Styles
- Add styles for code/table wrappers, new-message tip, toggle, spinner; hover/active vars; narrower sidebar.
API notes / breaking changes
- /chat accepts stream=true and returns text/plain streamed chunks.
- generate-title now requires a model.
- Non-stream /chat response shape unchanged.
This commit is contained in:
@@ -1,52 +1,8 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { colorSchemes, applyColorScheme } from './colorSchemes';
|
||||
|
||||
const COLOR_SCHEME_KEY = 'colorScheme';
|
||||
|
||||
const colorSchemes = {
|
||||
'Default': {
|
||||
'--bg': '#0b1020',
|
||||
'--panel': '#141b34',
|
||||
'--text': '#e6e8ef',
|
||||
'--muted': '#9aa3b2',
|
||||
'--accent': '#6ea8fe',
|
||||
'--border': '#24304f',
|
||||
'--input-bg': '#0e1530',
|
||||
'--user-msg-bg': '#111933',
|
||||
'--assistant-msg-bg': '#101927',
|
||||
},
|
||||
'Grayscale': {
|
||||
'--bg': '#1a1a1a',
|
||||
'--panel': '#2a2a2a',
|
||||
'--text': '#f0f0f0',
|
||||
'--muted': '#aaaaaa',
|
||||
'--accent': '#888888',
|
||||
'--border': '#4a4a4a',
|
||||
'--input-bg': '#202020',
|
||||
'--user-msg-bg': '#333333',
|
||||
'--assistant-msg-bg': '#252525',
|
||||
},
|
||||
'Rose': {
|
||||
'--bg': '#200a10',
|
||||
'--panel': '#301a20',
|
||||
'--text': '#ffe0e0',
|
||||
'--muted': '#a09090',
|
||||
'--accent': '#E91E63',
|
||||
'--border': '#402025',
|
||||
'--input-bg': '#2a1015',
|
||||
'--user-msg-bg': '#331119',
|
||||
'--assistant-msg-bg': '#271019',
|
||||
},
|
||||
};
|
||||
|
||||
function applyColorScheme(schemeName) {
|
||||
const scheme = colorSchemes[schemeName];
|
||||
if (scheme) {
|
||||
for (const [key, value] of Object.entries(scheme)) {
|
||||
document.documentElement.style.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function InterfaceSettings() {
|
||||
const [selectedColorScheme, setSelectedColorScheme] = useState('Default');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user