add waifu image fetch

This commit is contained in:
end-4 2024-01-01 01:52:25 +07:00
parent 5a7efaa139
commit ff377a5826
14 changed files with 269 additions and 211 deletions

View file

@ -1,5 +1,6 @@
"strict mode";
"use strict";
// Import
const { GLib } = imports.gi;
import { App, Utils } from './imports.js';
// Widgets
import Bar from './widgets/bar/main.js';
@ -16,8 +17,6 @@ import SideRight from './widgets/sideright/main.js';
const CLOSE_ANIM_TIME = 210; // Longer than actual anim time (see styles) to make sure widgets animate fully
// Init cache
Utils.exec(`bash -c 'mkdir -p ~/.cache/ags/user/colorschemes'`);
// SCSS compilation
Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicwal.scss'`); // reset music styles
Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicmaterial.scss'`); // reset music styles
@ -43,8 +42,8 @@ export default {
CornerTopright(),
CornerBottomleft(),
CornerBottomright(),
// DesktopBackground(),
// Dock(), // Buggy
// DesktopBackground(), // If you're going to uncomment these,
// Dock(), // Buggy // uncomment the import statement too.
Overview(),
Indicator(),
Cheatsheet(),

View file

@ -57,7 +57,7 @@ const pad = (lines, start = 1, end = 1) => {
return lines.map((l) => l.padEnd(len + end, ' ').padStart(len + end + start, ' '))
}
export function convert(text) {
export default (text) => {
let lines = text.split('\n')
// Indicates if the current line is within a code block
@ -205,33 +205,6 @@ export function convert(text) {
return output.join('\n')
}
const readFile = (f) => {
// node.js only and when running from the command line
const fs = require('fs')
return fs.readFileSync(f, 'utf8')
}
let __is_nodejs_main = false
try {
// node.js specific checks and exports
__is_nodejs_main = (require.main === module)
exports.convert = convert
} catch (e) { }
if (__is_nodejs_main) {
// running in node.js called from the CLI
let args = process.argv.slice(2)
if (args.length == 0 || args.find((a) => a == '-h')) {
console.log(`Usage: ${process.argv[1]} FILE [FILE...]`)
process.exit(0)
}
for (let i = 0; i < args.length; i++) {
const f = args[i];
process.stdout.write(convert(readFile(f)));
}
}
export const markdownTest = `# Heading 1
## Heading 2
### Heading 3

View file

@ -166,27 +166,27 @@ $onChatgpt: $onPrimary;
padding: 0rem $rounding_medium;
}
.sidebar-navrail-btn>box>label {
.sidebar-navrail-btn > box > label {
@include full-rounding;
@include menu_decel;
}
.sidebar-navrail-btn:hover>box>label:first-child,
.sidebar-navrail-btn:focus>box>label:first-child {
.sidebar-navrail-btn:hover > box > label:first-child,
.sidebar-navrail-btn:focus > box > label:first-child {
background-color: mix($t_surfaceVariant, $onSurfaceVariant, 90%);
}
.sidebar-navrail-btn:active>box>label:first-child {
.sidebar-navrail-btn:active > box > label:first-child {
background-color: mix($surfaceVariant, $onSurfaceVariant, 75%);
}
.sidebar-navrail-btn-active>box>label:first-child {
.sidebar-navrail-btn-active > box > label:first-child {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.sidebar-navrail-btn-active:hover>box>label:first-child,
.sidebar-navrail-btn-active:focus>box>label:first-child {
.sidebar-navrail-btn-active:hover > box > label:first-child,
.sidebar-navrail-btn-active:focus > box > label:first-child {
background-color: mix($secondaryContainer, $hovercolor, 90%);
color: mix($onSecondaryContainer, $hovercolor, 90%);
}
@ -346,7 +346,7 @@ $onChatgpt: $onPrimary;
background-color: mix($surfaceVariant, $onSurfaceVariant, 75%);
}
.sidebar-selector-tab-active>box>label {
.sidebar-selector-tab-active > box > label {
color: $primary;
}
@ -509,7 +509,7 @@ $onChatgpt: $onPrimary;
.sidebar-chat-apiswitcher-icon {
@include menu_decel;
@include full-rounding;
min-width: 2.182rem;
min-width: 2.182rem;
min-height: 2.182rem;
color: $onSurface;
}
@ -548,11 +548,19 @@ $onChatgpt: $onPrimary;
.sidebar-chat-send:hover,
.sidebar-chat-send:focus {
background-color: mix($sidebar_chat_textboxareaColor, $t_onSecondaryContainer, 97%);
background-color: mix(
$sidebar_chat_textboxareaColor,
$t_onSecondaryContainer,
97%
);
}
.sidebar-chat-send:active {
background-color: mix($sidebar_chat_textboxareaColor, $t_onSecondaryContainer, 80%);
background-color: mix(
$sidebar_chat_textboxareaColor,
$t_onSecondaryContainer,
80%
);
}
.sidebar-chat-send-available {
@ -576,6 +584,7 @@ $onChatgpt: $onPrimary;
.sidebar-chat-indicator {
@include full-rounding;
min-width: 0.136rem;
background-color: $onBackground;
}
.sidebar-chat-indicator-user {
@ -594,7 +603,6 @@ $onChatgpt: $onPrimary;
@include titlefont;
padding: 0.341rem;
margin-left: -0.136rem;
padding: 0.341rem;
padding-left: 0.818rem;
}
@ -699,7 +707,11 @@ $onChatgpt: $onPrimary;
}
.sidebar-chat-chip-action:active {
background-color: mix($sidebar_chat_textboxareaColor, $onSurfaceVariant, 70%);
background-color: mix(
$sidebar_chat_textboxareaColor,
$onSurfaceVariant,
70%
);
color: mix($sidebar_chat_textboxareaColor, $surfaceVariant, 70%);
}
@ -741,3 +753,26 @@ $onChatgpt: $onPrimary;
background-color: mix($primary, $onPrimary, 80%);
}
.sidebar-waifu-heading {
@include titlefont;
padding: 0.341rem;
margin-left: -0.136rem;
padding-left: 0.818rem;
}
.sidebar-waifu-content {
margin-left: 0.682rem;
}
.sidebar-waifu-txt {
@include readingfont;
margin-left: 0.682rem;
}
.sidebar-waifu-image {
margin-left: 0.682rem;
@include normal-rounding;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}

View file

@ -44,7 +44,7 @@ function expandTilde(path) {
// We're using many models to not be restricted to 3 messages per minute.
// The whole chat will be sent every request anyway.
const KEY_FILE_LOCATION = `~/.cache/ags/user/openai_api_key.txt`;
const KEY_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/openai_api_key.txt`;
const CHAT_MODELS = ["gpt-3.5-turbo-1106", "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0613"]
const ONE_CYCLE_COUNT = 3;

View file

@ -63,7 +63,7 @@ class TodoService extends Service {
super();
this._todoPath = `${GLib.get_user_cache_dir()}/ags/user/todo.json`;
if (!fileExists(this._todoPath)) { // No? create file with empty array
Utils.exec(`bash -c 'mkdir -p ~/.cache/ags/user'`);
Utils.exec(`bash -c 'mkdir -p ${GLib.get_user_cache_dir()}/ags/user'`);
Utils.exec(`touch ${this._todoPath}`);
Utils.writeFile("[]", this._todoPath).then(() => {
this._todoJson = JSON.parse(Utils.readFile(this._todoPath))

View file

@ -5,64 +5,20 @@ import GLib from 'gi://GLib';
import Soup from 'gi://Soup?version=3.0';
import { fileExists } from './messages.js';
class WaifuResponse extends Service {
static {
Service.register(this,
{
'delta': ['string'],
},
{
'content': ['string'],
'thinking': ['boolean'],
'done': ['boolean'],
});
}
_role = '';
_content = '';
_thinking = false;
_done = false;
constructor(role, content, thinking = false, done = false) {
super();
this._role = role;
this._content = content;
this._thinking = thinking;
this._done = done;
}
get done() { return this._done }
set done(isDone) { this._done = isDone; this.notify('done') }
get role() { return this._role }
set role(role) { this._role = role; this.emit('changed') }
get content() { return this._content }
set content(content) {
this._content = content;
this.notify('content')
this.emit('changed')
}
get label() { return this._parserState.parsed + this._parserState.stack.join('') }
get thinking() { return this._thinking }
set thinking(thinking) {
this._thinking = thinking;
this.notify('thinking')
this.emit('changed')
}
addDelta(delta) {
if (this.thinking) {
this.thinking = false;
this.content = delta;
}
else {
this.content += delta;
}
this.emit('delta', delta);
}
function paramStringFromObj(params) {
return Object.entries(params)
.map(([key, value]) => {
if (Array.isArray(value)) { // If it's an array, repeat
if (value.length == 0) return '';
let thisKey = `${encodeURIComponent(key)}=${encodeURIComponent(value[0])}`
for (let i = 1; i < value.length; i++) {
thisKey += `&${encodeURIComponent(key)}=${encodeURIComponent(value[i])}`;
}
return thisKey;
}
return `${key}=${value}`;
})
.join('&');
}
class WaifuService extends Service {
@ -76,9 +32,10 @@ class WaifuService extends Service {
'nekos': {},
'pics': {},
}
_url = 'https://api.waifu.im/search';
_baseUrl = 'https://api.waifu.im/search';
_mode = 'im'; // Allowed: im
_responses = [];
_queries = [];
_nsfw = false;
_minHeight = 600;
@ -86,7 +43,8 @@ class WaifuService extends Service {
Service.register(this, {
'initialized': [],
'clear': [],
'newResponse': ['string'],
'newResponse': ['int'],
'updateResponse': ['int'],
});
}
@ -97,71 +55,68 @@ class WaifuService extends Service {
clear() {
this._responses = [];
this._queries = [];
this.emit('clear');
}
get mode() { return this._mode }
set mode(value) {
this._mode = value;
this._url = this._endpoints[this._mode];
this._baseUrl = this._endpoints[this._mode];
}
get nsfw() { return this._nsfw }
set nsfw(value) { this._nsfw = value }
get queries() { return this._queries }
get responses() { return this._responses }
readResponseRecursive(stream, response) {
stream.read_line_async(
0, null,
(stream, res) => {
if (!stream) return;
const [bytes] = stream.read_line_finish(res);
const line = this._decoder.decode(bytes);
if (line && line != '') {
let data = line.substr(6);
if (data == '[DONE]') return;
try {
const result = JSON.parse(data);
if (result.choices[0].finish_reason === 'stop') {
response.done = true;
return;
}
response.addDelta(result.choices[0].delta.content);
}
catch {
response.addDelta(line + '\n');
}
}
this.readResponseRecursive(stream, response);
});
}
fetch(msg) {
const newMessageId = this._responses.length;
const taglist = msg.split(' ');
this.emit('newResponse', msg);
this._responses.push(msg);
this._queries.push(taglist);
this.emit('newResponse', newMessageId);
// Construct body/headers
const params = {
'included_tags': taglist,
'height': `>=${this._minHeight}`,
'nsfw': this._nsfw,
};
const session = new Soup.Session();
const message = new Soup.Message({
const paramString = paramStringFromObj(params);
console.log(paramString);
// Fetch
const options = {
method: 'GET',
uri: GLib.Uri.parse(this._url, GLib.UriFlags.NONE),
});
session.send_message(message, (session, message) => {
if (message.status_code === 200) {
const responseBody = message.response_body.data;
const data = JSON.parse(responseBody);
// Process the response data as needed
console.log(data);
log(data);
} else {
logError('Request failed with status code: ' + message.status_code);
}
});
headers: this._headers[this._mode],
};
Utils.fetch(`${this._baseUrl}?${paramString}`, options)
.then(result => result.text()) // Parse
.then((dataString) => { // Store interesting stuff and emit
const parsedData = JSON.parse(dataString);
if (!parsedData.images) this._responses.push({
signature: -1,
url: '',
source: '',
dominant_color: '#383A40',
is_nsfw: false,
width: 0,
height: 0,
tags: [],
});
else {
const imageData = parsedData.images[0];
this._responses.push({
signature: imageData?.signature || -1,
url: imageData?.url || undefined,
source: imageData?.source,
dominant_color: imageData?.dominant_color || '#000000',
is_nsfw: imageData?.is_nsfw || false,
width: imageData?.width || 0,
height: imageData?.height || 0,
tags: imageData?.tags.map(obj => obj["name"]) || [],
});
}
this.emit('updateResponse', newMessageId);
})
.catch(console.error)
}
}

View file

@ -1839,7 +1839,8 @@ tooltip {
.sidebar-chat-indicator {
border-radius: 9999px;
-gtk-outline-radius: 9999px;
min-width: 0.136rem; }
min-width: 0.136rem;
background-color: #eae0e4; }
.sidebar-chat-indicator-user {
background-color: #eae0e4; }
@ -1854,7 +1855,6 @@ tooltip {
font-family: 'Gabarito', 'Poppins', 'Lexend', sans-serif;
padding: 0.341rem;
margin-left: -0.136rem;
padding: 0.341rem;
padding-left: 0.818rem; }
.sidebar-chat-txtblock {
@ -1980,6 +1980,27 @@ tooltip {
.sidebar-pin-enabled:active {
background-color: #dda0d4; }
.sidebar-waifu-heading {
font-family: 'Gabarito', 'Poppins', 'Lexend', sans-serif;
padding: 0.341rem;
margin-left: -0.136rem;
padding-left: 0.818rem; }
.sidebar-waifu-content {
margin-left: 0.682rem; }
.sidebar-waifu-txt {
font-family: 'Lexend', 'Noto Sans', sans-serif;
margin-left: 0.682rem; }
.sidebar-waifu-image {
margin-left: 0.682rem;
border-radius: 1.159rem;
-gtk-outline-radius: 1.159rem;
background-size: cover;
background-repeat: no-repeat;
background-position: center; }
.session-bg {
margin-top: -2.727rem;
background-color: rgba(16, 13, 16, 0.64); }

View file

@ -129,6 +129,7 @@ const Taskbar = () => Widget.Box({
if (!address) return;
const removedButton = box._map.get(address);
if (!removedButton) return;
removedButton.revealChild = false;
Utils.timeout(ANIMATION_TIME, () => {

View file

@ -17,7 +17,7 @@ function expandTilde(path) {
}
}
const LIGHTDARK_FILE_LOCATION = '~/.cache/ags/user/colormode.txt'
const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`;
const lightDark = Utils.readFile(expandTilde(LIGHTDARK_FILE_LOCATION)).trim();
const COVER_COLORSCHEME_SUFFIX = '_colorscheme.css';
const PREFERRED_PLAYER = 'plasma-browser-integration';
@ -165,7 +165,7 @@ const CoverArt = ({ player, ...rest }) => Box({
`${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' > ${App.configDir}/scss/_musicmaterial.scss ${lightDark}`])
.then(() => {
exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`)
exec(`bash -c "cp ~/.cache/wal/colors.scss ${App.configDir}/scss/_musicwal.scss"`)
exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`);
exec(`sassc ${App.configDir}/scss/_music.scss ${stylePath}`);
self.css = `background-image: url('${coverPath}');`;
App.applyCss(`${stylePath}`);

View file

@ -21,12 +21,12 @@ export function launchCustomCommand(command) {
execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchcolor.sh`, `&`]).catch(print);
}
else if (args[0] == '>light') { // Light mode
execAsync([`bash`, `-c`, `mkdir -p ~/.cache/ags/user && echo "-l" > ~/.cache/ags/user/colormode.txt`])
execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "-l" > ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`])
.then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchwall.sh --noswitch`]).catch(print))
.catch(print);
}
else if (args[0] == '>dark') { // Dark mode
execAsync([`bash`, `-c`, `mkdir -p ~/.cache/ags/user && echo "" > ~/.cache/ags/user/colormode.txt`])
execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "" > ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`])
.then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchwall.sh --noswitch`]).catch(print))
.catch(print);
}
@ -34,10 +34,10 @@ export function launchCustomCommand(command) {
execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/applycolor.sh --bad-apple`]).catch(print);
}
else if (args[0] == '>material') { // Light mode
execAsync([`bash`, `-c`, `mkdir -p ~/.cache/ags/user && echo "material" > ~/.cache/ags/user/colorbackend.txt`]).catch(print);
execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "material" > ${GLib.get_user_cache_dir()}/ags/user/colorbackend.txt`]).catch(print);
}
else if (args[0] == '>pywal') { // Dark mode
execAsync([`bash`, `-c`, `mkdir -p ~/.cache/ags/user && echo "pywal" > ~/.cache/ags/user/colorbackend.txt`]).catch(print);
execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "pywal" > ${GLib.get_user_cache_dir()}/ags/user/colorbackend.txt`]).catch(print);
}
else if (args[0] == '>todo') { // Todo
Todo.add(args.slice(1).join(' '));

View file

@ -204,39 +204,24 @@ export const chatGPTView = Scrollable({
}
});
const CommandButton = (command) => Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => sendMessage(command),
setup: setupCursorHover,
label: command,
});
export const chatGPTCommands = Box({
className: 'spacing-h-5',
children: [
Box({ hexpand: true }),
Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => chatContent.add(SystemMessage(
`Key stored in:\n\`${ChatGPT.keyPath}\`\nTo update this key, type \`/key YOUR_API_KEY\``,
'/key',
chatGPTView)),
setup: setupCursorHover,
label: '/key',
}),
Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => chatContent.add(SystemMessage(
`Currently using \`${ChatGPT.modelName}\``,
'/model',
chatGPTView
)),
setup: setupCursorHover,
label: '/model',
}),
Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => clearChat(),
setup: setupCursorHover,
label: '/clear',
}),
CommandButton('/key'),
CommandButton('/model'),
CommandButton('/clear'),
]
});
export const chatGPTSendMessage = (text) => {
export const sendMessage = (text) => {
// Check if text or API key is empty
if (text.length == 0) return;
if (ChatGPT.key.length == 0) {

View file

@ -3,7 +3,7 @@ import { App, Utils, Widget } from '../../../imports.js';
const { Box, Button, Entry, EventBox, Icon, Label, Revealer, Scrollable, Stack } = Widget;
const { execAsync, exec } = Utils;
import { MaterialIcon } from "../../../lib/materialicon.js";
import { convert } from "../../../lib/md2pango.js";
import md2pango from "../../../lib/md2pango.js";
import GtkSource from "gi://GtkSource?version=3.0";
const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/data/sourceviewtheme.xml`;
@ -168,7 +168,7 @@ const MessageContent = (content) => {
const lastLabel = kids[kids.length - 1];
const blockContent = lines.slice(lastProcessed, index).join('\n');
if (!inCode) {
lastLabel.label = convert(blockContent);
lastLabel.label = md2pango(blockContent);
contentBox.add(CodeBlock('', codeBlockRegex.exec(line)[1]));
}
else {
@ -185,7 +185,7 @@ const MessageContent = (content) => {
const kids = self.get_children();
const lastLabel = kids[kids.length - 1];
const blockContent = lines.slice(lastProcessed, index).join('\n');
lastLabel.label = convert(blockContent);
lastLabel.label = md2pango(blockContent);
contentBox.add(Divider());
contentBox.add(TextBlock());
lastProcessed = index + 1;
@ -196,7 +196,7 @@ const MessageContent = (content) => {
const lastLabel = kids[kids.length - 1];
let blockContent = lines.slice(lastProcessed, lines.length).join('\n');
if (!inCode)
lastLabel.label = `${convert(blockContent)}${useCursor ? CHATGPT_CURSOR : ''}`;
lastLabel.label = `${md2pango(blockContent)}${useCursor ? CHATGPT_CURSOR : ''}`;
else
lastLabel._updateText(blockContent);
}
@ -208,7 +208,7 @@ const MessageContent = (content) => {
// xalign: 0,
// wrap: true,
// selectable: true,
// label: '------------------------------\n' + convert(content),
// label: '------------------------------\n' + md2pango(content),
// }))
contentBox.show_all();
}]

View file

@ -6,6 +6,19 @@ import { MaterialIcon } from "../../../lib/materialicon.js";
import { setupCursorHover, setupCursorHoverInfo } from "../../../lib/cursorhover.js";
import WaifuService from '../../../services/waifus.js';
const MESSAGE_SCROLL_DELAY = 13; // In milliseconds, the time before an updated message scrolls to bottom
// Create cache folder and clear pics from previous session
Utils.exec(`bash -c 'mkdir -p ${GLib.get_user_cache_dir()}/ags/media/waifus'`);
Utils.exec(`bash -c 'rm ${GLib.get_user_cache_dir()}/ags/media/waifus/*'`);
const CommandButton = (command) => Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => sendMessage(command),
setup: setupCursorHover,
label: command,
});
export const waifuTabIcon = Box({
hpack: 'center',
className: 'sidebar-chat-apiswitcher-icon',
@ -15,17 +28,90 @@ export const waifuTabIcon = Box({
]
});
const WaifuImage = (taglist) => {
const colorIndicator = Box({
className: `sidebar-chat-indicator`,
});
const downloadIndicator = Label({
className: 'sidebar-waifu-txt txt-smallie txt',
xalign: 0,
label: 'Downloading image...',
});
const blockHeading = Box({
className: 'sidebar-waifu-content',
vertical: true,
children: [
Box({
children: taglist.map((tag) => CommandButton(tag))
}),
downloadIndicator,
]
});
const blockImage = Box({
hpack: 'start',
className: 'sidebar-waifu-image',
})
const thisBlock = Box({
className: 'sidebar-chat-message',
properties: [
['update', (imageData) => {
const { signature, url, source, dominant_color, is_nsfw, width, height, tags } = imageData;
const imagePath = `${GLib.get_user_cache_dir()}/ags/media/waifus/${signature}`;
// Start download
Utils.execAsync(['bash', '-c', `wget -O '${imagePath}' '${url}'`])
.then(() => {
blockImage.css = `background-image:url('${imagePath}');`;
downloadIndicator.destroy();
})
.catch(print);
colorIndicator.css = `background-color: ${dominant_color};`;
// Width allocation
const widgetWidth = Math.floor(waifuContent.get_allocated_width() * 0.75); // idk tbh
blockImage.set_size_request(widgetWidth, Math.ceil(widgetWidth * height / width));
}],
],
children: [
colorIndicator,
Box({
vertical: true,
className: 'spacing-v-10',
children: [
blockHeading,
blockImage,
]
})
],
setup: (self) => Utils.timeout(MESSAGE_SCROLL_DELAY, () => {
var adjustment = waifuView.get_vadjustment();
adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
})
});
return thisBlock;
}
const waifuContent = Box({
className: 'spacing-v-15',
vertical: true,
vexpand: true,
properties: [
['map', new Map()],
],
connections: [
[WaifuService, (box, id) => {
const message = WaifuService.responses[id];
if (!message) return;
box.add(Label({
label: message,
}))
if (id === undefined) return;
console.log('new', WaifuService.queries[id]);
const newImageBlock = WaifuImage(WaifuService.queries[id]);
box.add(newImageBlock);
box.show_all();
box._map.set(id, newImageBlock);
}, 'newResponse'],
[WaifuService, (box, id) => {
if (id === undefined) return;
const data = WaifuService.responses[id];
if (!data) return;
const imageBlock = box._map.get(id);
imageBlock._update(data);
}, 'updateResponse'],
]
});
@ -55,18 +141,21 @@ export const waifuCommands = Box({
className: 'spacing-h-5',
children: [
Box({ hexpand: true }),
Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => {
// command do something
},
setup: setupCursorHover,
label: '/call',
}),
CommandButton('/clear'),
]
});
export const waifuCallAPI = (text) => {
export const sendMessage = (text) => {
// Do something on send
WaifuService.fetch(text);
// Commands
if (text.startsWith('/')) {
if (text.startsWith('/clear')) {
const kids = waifuContent.get_children();
for (let i = 0; i < kids.length; i++) {
const child = kids[i];
child.destroy();
}
}
}
else WaifuService.fetch(text);
}

View file

@ -5,8 +5,8 @@ const { execAsync, exec } = Utils;
import { setupCursorHover, setupCursorHoverInfo } from "../../lib/cursorhover.js";
// APIs
import ChatGPT from '../../services/chatgpt.js';
import { chatGPTView, chatGPTCommands, chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js';
import { waifuView, waifuCommands, waifuCallAPI, waifuTabIcon } from './apis/waifu.js';
import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js';
import { waifuView, waifuCommands, sendMessage as waifuSendMessage, waifuTabIcon } from './apis/waifu.js';
const APIS = [
{
@ -19,7 +19,7 @@ const APIS = [
},
{
name: 'Waifus',
sendCommand: waifuCallAPI,
sendCommand: waifuSendMessage,
contentWidget: waifuView,
commandBar: waifuCommands,
tabIcon: waifuTabIcon,