forked from Shinonome/dots-hyprland
ai: add <think> support
This commit is contained in:
@@ -3,11 +3,12 @@ import GtkSource from "gi://GtkSource?version=3.0";
|
|||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
const { Box, Button, Label, Icon, Scrollable, Stack } = Widget;
|
const { Box, Button, Label, Icon, Revealer, Scrollable, Stack } = Widget;
|
||||||
const { execAsync, exec } = Utils;
|
const { execAsync, exec } = Utils;
|
||||||
import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
|
import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
|
||||||
import md2pango, { replaceInlineLatexWithCodeBlocks } from '../../.miscutils/md2pango.js';
|
import md2pango, { replaceInlineLatexWithCodeBlocks } from '../../.miscutils/md2pango.js';
|
||||||
import { darkMode } from "../../.miscutils/system.js";
|
import { darkMode } from "../../.miscutils/system.js";
|
||||||
|
import { setupCursorHover } from "../../.widgetutils/cursorhover.js";
|
||||||
|
|
||||||
const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`;
|
const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`;
|
||||||
const USERNAME = GLib.get_user_name();
|
const USERNAME = GLib.get_user_name();
|
||||||
@@ -45,20 +46,104 @@ const HighlightedCode = (content, lang) => {
|
|||||||
return sourceView;
|
return sourceView;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TextBlock = (content = '') => Label({
|
const TextBlock = (content = '') => {
|
||||||
hpack: 'fill',
|
const widget = Label({
|
||||||
className: 'txt sidebar-chat-txtblock sidebar-chat-txt',
|
attribute: {
|
||||||
useMarkup: true,
|
'updateTextPlain': (text) => {
|
||||||
xalign: 0,
|
widget.label = text;
|
||||||
wrap: true,
|
},
|
||||||
selectable: true,
|
'updateText': (text) => {
|
||||||
label: content,
|
widget.attribute.updateTextPlain(md2pango(text));
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
hpack: 'fill',
|
||||||
|
className: 'txt sidebar-chat-txtblock sidebar-chat-txt',
|
||||||
|
useMarkup: true,
|
||||||
|
xalign: 0,
|
||||||
|
wrap: true,
|
||||||
|
selectable: true,
|
||||||
|
label: content,
|
||||||
|
});
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThinkBlock = (content = '', revealChild = true) => {
|
||||||
|
const revealThought = Variable(revealChild);
|
||||||
|
const mainText = Label({
|
||||||
|
hpack: 'fill',
|
||||||
|
className: `txt sidebar-chat-txtblock-think sidebar-chat-txt`,
|
||||||
|
useMarkup: true,
|
||||||
|
xalign: 0,
|
||||||
|
wrap: true,
|
||||||
|
selectable: true,
|
||||||
|
label: content,
|
||||||
|
});
|
||||||
|
const mainTextRevealer = Revealer({
|
||||||
|
transition: 'slide_down',
|
||||||
|
revealChild: revealThought.value,
|
||||||
|
child: mainText,
|
||||||
|
setup: (self) => self.hook(revealThought, (self) => {
|
||||||
|
self.revealChild = revealThought.value;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const expandIcon = MaterialIcon(revealThought.value ? 'expand_less' : 'expand_more', 'norm', {
|
||||||
|
setup: (self) => self.hook(revealThought, (self) => {
|
||||||
|
self.label = revealThought.value ? 'expand_less' : 'expand_more';
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const widget = Box({
|
||||||
|
attribute: {
|
||||||
|
'updateTextPlain': (text) => {
|
||||||
|
mainText.label = text;
|
||||||
|
},
|
||||||
|
'updateText': (text) => {
|
||||||
|
widget.attribute.updateTextPlain(md2pango(text));
|
||||||
|
},
|
||||||
|
'done': () => {
|
||||||
|
revealThought.value = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
className: 'sidebar-chat-thinkblock',
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Button({
|
||||||
|
onClicked: (self) => {
|
||||||
|
revealThought.value = !revealThought.value;
|
||||||
|
},
|
||||||
|
child: Box({
|
||||||
|
className: 'spacing-h-10 padding-10',
|
||||||
|
children: [
|
||||||
|
Box({
|
||||||
|
homogeneous: true,
|
||||||
|
valign: 'center',
|
||||||
|
className: 'sidebar-chat-thinkblock-icon',
|
||||||
|
children: [MaterialIcon('neurology', 'large')]
|
||||||
|
}),
|
||||||
|
Label({
|
||||||
|
valign: 'center',
|
||||||
|
hexpand: true,
|
||||||
|
label: 'Chain of Thought',
|
||||||
|
className: 'txt sidebar-chat-thinkblock-txt',
|
||||||
|
}),
|
||||||
|
Box({
|
||||||
|
className: 'sidebar-chat-thinkblock-btn-arrow',
|
||||||
|
homogeneous: true,
|
||||||
|
children: [expandIcon],
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
setup: setupCursorHover,
|
||||||
|
}),
|
||||||
|
mainTextRevealer,
|
||||||
|
]
|
||||||
|
});
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
Utils.execAsync(['bash', '-c', `rm -rf ${LATEX_DIR}`])
|
Utils.execAsync(['bash', '-c', `rm -rf ${LATEX_DIR}`])
|
||||||
.then(() => Utils.execAsync(['bash', '-c', `mkdir -p ${LATEX_DIR}`]))
|
.then(() => Utils.execAsync(['bash', '-c', `mkdir -p ${LATEX_DIR}`]))
|
||||||
.catch(print);
|
.catch(print);
|
||||||
const Latex = (content = '') => {
|
const LatexBlock = (content = '') => {
|
||||||
const latexViewArea = Box({
|
const latexViewArea = Box({
|
||||||
// vscroll: 'never',
|
// vscroll: 'never',
|
||||||
// hscroll: 'automatic',
|
// hscroll: 'automatic',
|
||||||
@@ -122,7 +207,7 @@ sed -i 's/stroke="rgb(0%, 0%, 0%)"/stroke="${darkMode.value ? '#ffffff' : '#0000
|
|||||||
|
|
||||||
const CodeBlock = (content = '', lang = 'txt') => {
|
const CodeBlock = (content = '', lang = 'txt') => {
|
||||||
if (lang == 'tex' || lang == 'latex') {
|
if (lang == 'tex' || lang == 'latex') {
|
||||||
return Latex(content);
|
return LatexBlock(content);
|
||||||
}
|
}
|
||||||
const topBar = Box({
|
const topBar = Box({
|
||||||
className: 'sidebar-chat-codeblock-topbar',
|
className: 'sidebar-chat-codeblock-topbar',
|
||||||
@@ -228,7 +313,8 @@ const MessageContent = (content) => {
|
|||||||
const lastLabel = kids[kids.length - 1];
|
const lastLabel = kids[kids.length - 1];
|
||||||
const blockContent = lines.slice(lastProcessed, index).join('\n');
|
const blockContent = lines.slice(lastProcessed, index).join('\n');
|
||||||
if (!inCode) {
|
if (!inCode) {
|
||||||
lastLabel.label = md2pango(blockContent);
|
lastLabel.attribute.updateText(blockContent);
|
||||||
|
if (lastLabel.label == '') lastLabel.destroy();
|
||||||
contentBox.add(CodeBlock('', codeBlockRegex.exec(line)[1]));
|
contentBox.add(CodeBlock('', codeBlockRegex.exec(line)[1]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -239,13 +325,31 @@ const MessageContent = (content) => {
|
|||||||
lastProcessed = index + 1;
|
lastProcessed = index + 1;
|
||||||
inCode = !inCode;
|
inCode = !inCode;
|
||||||
}
|
}
|
||||||
|
// Think block
|
||||||
|
const thinkBlockStartRegex = /^\s*<think>/; // Start: <think>
|
||||||
|
const thinkBlockEndRegex = /<\/think>\s*$/; // End: </think>
|
||||||
|
if (!inCode && (thinkBlockStartRegex.test(line) || thinkBlockEndRegex.test(line))) {
|
||||||
|
const kids = self.get_children();
|
||||||
|
const lastLabel = kids[kids.length - 1];
|
||||||
|
const blockContent = lines.slice(lastProcessed, index).join('\n');
|
||||||
|
|
||||||
|
lastLabel.attribute.updateTextPlain(blockContent);
|
||||||
|
if (lastLabel.label == '') lastLabel.destroy();
|
||||||
|
if (thinkBlockStartRegex.test(line)) contentBox.add(ThinkBlock());
|
||||||
|
else {
|
||||||
|
// lastLabel.attribute.done();
|
||||||
|
contentBox.add(TextBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
lastProcessed = index + 1;
|
||||||
|
}
|
||||||
// Breaks
|
// Breaks
|
||||||
const dividerRegex = /^\s*---/;
|
const dividerRegex = /^\s*---/;
|
||||||
if (!inCode && dividerRegex.test(line)) {
|
if (!inCode && dividerRegex.test(line)) {
|
||||||
const kids = self.get_children();
|
const kids = self.get_children();
|
||||||
const lastLabel = kids[kids.length - 1];
|
const lastLabel = kids[kids.length - 1];
|
||||||
const blockContent = lines.slice(lastProcessed, index).join('\n');
|
const blockContent = lines.slice(lastProcessed, index).join('\n');
|
||||||
lastLabel.label = md2pango(blockContent);
|
lastLabel.attribute.updateTextPlain(blockContent);
|
||||||
contentBox.add(Divider());
|
contentBox.add(Divider());
|
||||||
contentBox.add(TextBlock());
|
contentBox.add(TextBlock());
|
||||||
lastProcessed = index + 1;
|
lastProcessed = index + 1;
|
||||||
@@ -256,7 +360,7 @@ const MessageContent = (content) => {
|
|||||||
const lastLabel = kids[kids.length - 1];
|
const lastLabel = kids[kids.length - 1];
|
||||||
let blockContent = lines.slice(lastProcessed, lines.length).join('\n');
|
let blockContent = lines.slice(lastProcessed, lines.length).join('\n');
|
||||||
if (!inCode)
|
if (!inCode)
|
||||||
lastLabel.label = `${md2pango(blockContent)}${useCursor ? userOptions.ai.writingCursor : ''}`;
|
lastLabel.attribute.updateTextPlain(`${md2pango(blockContent)}${useCursor ? userOptions.ai.writingCursor : ''}`);
|
||||||
else
|
else
|
||||||
lastLabel.attribute.updateText(blockContent);
|
lastLabel.attribute.updateText(blockContent);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
$hovercolor: $surfaceContainerHigh;
|
$hovercolor: $surfaceContainerHigh;
|
||||||
$activecolor: $surfaceContainerHighest;
|
$activecolor: $surfaceContainerHighest;
|
||||||
$rounding_unsharpen: 0.136rem;
|
$rounding_unsharpen: 0.136rem;
|
||||||
$rounding_verysmall: 0.477rem;
|
$rounding_verysmall: 0.545rem;
|
||||||
$rounding_small: 0.818rem;
|
$rounding_small: 0.818rem;
|
||||||
$rounding_mediumsmall: 0.955rem;
|
$rounding_mediumsmall: 0.955rem;
|
||||||
$rounding_medium: 1.159rem;
|
$rounding_medium: 1.159rem;
|
||||||
|
|||||||
@@ -701,6 +701,43 @@ $skeleton-accent: mix($secondary, $onSecondary, 50%);
|
|||||||
padding-left: 0.818rem;
|
padding-left: 0.818rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-chat-txtblock-think {
|
||||||
|
margin-left: -0.136rem;
|
||||||
|
padding: 0.682rem;
|
||||||
|
padding-left: 1.159rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-chat-thinkblock {
|
||||||
|
@include small-rounding;
|
||||||
|
background-color: $layer2;
|
||||||
|
color: $onLayer3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-chat-thinkblock-icon {
|
||||||
|
@include verysmall-rounding;
|
||||||
|
background-color: $secondaryContainer;
|
||||||
|
color: $onSecondaryContainer;
|
||||||
|
min-width: 2.045rem;
|
||||||
|
min-height: 2.045rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-chat-thinkblock-btn-arrow {
|
||||||
|
@include full-rounding;
|
||||||
|
@include icon-material;
|
||||||
|
min-width: 1.705rem;
|
||||||
|
min-height: 1.705rem;
|
||||||
|
background-color: $layer2;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: $layer2Hover;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: $layer2Active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-chat-txt {
|
.sidebar-chat-txt {
|
||||||
@include readingfont;
|
@include readingfont;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user