feat: Nvidia API direkt-Anbindung mit Thinking-Mode Support

Neues Server-Setting NvidiaApiKey – wenn gesetzt, wird direkt
integrate.api.nvidia.com verwendet statt g4f.space Proxy.
Thinking-Modelle (kimi-k2, qwq, deepseek-r1) erhalten automatisch
chat_template_kwargs und reasoning-Output wird als klappbare
Denkprozess-Bubble im Chat angezeigt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.6 committed 2026-03-25 09:09:02 +01:00
1 parent 1101bb83a0
commit 4960b57ec7
6 files changed
+176 -3

No files matched your search

+10
View File
@@ -1126,6 +1126,16 @@
}
}
/* Thinking Box (Nvidia Reasoning) */
.thinking-box .tool-box-header .tool-name {
color: var(--warning);
}
.thinking-box .thinking-content {
padding: var(--box-padding);
}
/* Review Bubbles */
.review-bubble {
+12
View File
@@ -28,6 +28,18 @@ function addChainMetaBubble(d, streamed) {
function handleStreamEvent(eventType, data) {
switch (eventType) {
case 'thinking_start':
startThinkingBubble();
break;
case 'thinking_delta':
appendToThinking(data.text);
break;
case 'thinking_end':
endThinkingBubble();
break;
case 'text_start':
if (!_streamDiv) startStreamBubble();
break;
+18
View File
@@ -259,6 +259,24 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
}
break;
}
case 'thinking': {
if (msg.role === 'assistant' && msg.content) {
var thinkDiv = document.createElement('div');
thinkDiv.className = 'tool-box thinking-box' + (archived ? ' archived' : '');
var thinkHeader = document.createElement('div');
thinkHeader.className = 'tool-box-header clickable';
thinkHeader.innerHTML = '<span class="tool-name">Denkprozess</span>';
var thinkContent = document.createElement('div');
thinkContent.className = 'thinking-content markdown';
thinkContent.innerHTML = renderMarkdown(msg.content);
thinkContent.hidden = true;
thinkHeader.addEventListener('click', function() { thinkContent.hidden = !thinkContent.hidden; });
thinkDiv.appendChild(thinkHeader);
thinkDiv.appendChild(thinkContent);
fragment.appendChild(thinkDiv);
}
break;
}
case 'tool_use':
if (msg.toolName === 'ask_user_choice') {
_renderChoiceBubbleInFragment(fragment, msgs, _msgIdx);
+51
View File
@@ -52,6 +52,57 @@ function endStreamBubble() {
_streamText = '';
}
// ── Thinking Bubble (Nvidia Reasoning) ──
let _thinkingDiv = null;
let _thinkingText = '';
function startThinkingBubble() {
_thinkingDiv = document.createElement('div');
_thinkingDiv.className = 'tool-box thinking-box streamed';
var header = document.createElement('div');
header.className = 'tool-box-header clickable';
header.innerHTML = '<span class="tool-name">Denkprozess</span>';
var content = document.createElement('div');
content.className = 'thinking-content markdown';
content.hidden = true;
content.innerHTML = '<p><span class="cursor"></span></p>';
header.addEventListener('click', function() { content.hidden = !content.hidden; });
_thinkingDiv.appendChild(header);
_thinkingDiv.appendChild(content);
_thinkingText = '';
chatEl().appendChild(_thinkingDiv);
scrollDown();
}
function appendToThinking(text) {
if (!_thinkingDiv) startThinkingBubble();
_thinkingText += text;
var contentEl = _thinkingDiv.querySelector('.thinking-content');
contentEl.innerHTML = renderMarkdown(_thinkingText);
var cursor = document.createElement('span');
cursor.className = 'cursor';
var lastBlock = contentEl.lastElementChild;
if (lastBlock) lastBlock.appendChild(cursor);
else contentEl.appendChild(cursor);
scrollDown();
}
function endThinkingBubble() {
if (_thinkingDiv) {
var cursor = _thinkingDiv.querySelector('.cursor');
if (cursor) cursor.remove();
var contentEl = _thinkingDiv.querySelector('.thinking-content');
if (!_thinkingText.trim()) _thinkingDiv.remove();
else {
contentEl.innerHTML = renderMarkdown(_thinkingText);
contentEl.hidden = true;
}
}
_thinkingDiv = null;
_thinkingText = '';
}
// ── Review Bubbles (Streaming) ──
let _reviewBubble = null;