diff --git a/.config/ags/assets/icons/ai-openai-symbolic.svg b/.config/ags/assets/icons/ai-openai-symbolic.svg
new file mode 120000
index 00000000..c9ee0b32
--- /dev/null
+++ b/.config/ags/assets/icons/ai-openai-symbolic.svg
@@ -0,0 +1 @@
+openai-symbolic.svg
\ No newline at end of file
diff --git a/.config/ags/assets/icons/ai-oxygen-symbolic.svg b/.config/ags/assets/icons/ai-oxygen-symbolic.svg
new file mode 100644
index 00000000..5e1cc193
--- /dev/null
+++ b/.config/ags/assets/icons/ai-oxygen-symbolic.svg
@@ -0,0 +1,54 @@
+
+
diff --git a/.config/ags/assets/icons/ai-zukijourney.png b/.config/ags/assets/icons/ai-zukijourney.png
new file mode 100644
index 00000000..917335e7
Binary files /dev/null and b/.config/ags/assets/icons/ai-zukijourney.png differ
diff --git a/.config/ags/modules/.miscutils/md2pango.js b/.config/ags/modules/.miscutils/md2pango.js
index 8f56e3ae..1c868757 100644
--- a/.config/ags/modules/.miscutils/md2pango.js
+++ b/.config/ags/modules/.miscutils/md2pango.js
@@ -84,6 +84,6 @@ console.log('uwu');
- Random instruction thing
- To update arch lincox, run \`sudo pacman -Syu\`
\`\`\`tex
-\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2}
+\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} hmmmmmm \\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2}
\`\`\`
`;
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js
index d85d5de6..6ea650ad 100644
--- a/.config/ags/modules/sideleft/apis/chatgpt.js
+++ b/.config/ags/modules/sideleft/apis/chatgpt.js
@@ -4,12 +4,13 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
const { Box, Button, Icon, Label, Revealer, Scrollable } = Widget;
-import ChatGPT from '../../../services/chatgpt.js';
+import ChatGPT from '../../../services/gpt.js';
import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js';
import { SystemMessage, ChatMessage } from "./ai_chatmessage.js";
import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.commonwidgets/configwidgets.js';
import { markdownTest } from '../../.miscutils/md2pango.js';
import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js';
+import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`);
@@ -19,6 +20,94 @@ export const chatGPTTabIcon = Icon({
icon: `openai-symbolic`,
});
+const ProviderSwitcher = () => {
+ const ProviderChoice = (id, provider) => {
+ const providerSelected = MaterialIcon('check', 'norm', {
+ setup: (self) => self.hook(ChatGPT, (self) => {
+ self.toggleClassName('invisible', ChatGPT.providerID !== id);
+ }, 'providerChanged')
+ });
+ return Button({
+ tooltipText: provider.description,
+ onClicked: () => {
+ ChatGPT.providerID = id;
+ providerList.revealChild = false;
+ indicatorChevron.label = 'expand_more';
+ },
+ child: Box({
+ className: 'spacing-h-10 txt',
+ children: [
+ Icon({
+ icon: provider['logo_name'],
+ className: 'txt-large'
+ }),
+ Label({
+ hexpand: true,
+ xalign: 0,
+ className: 'txt-small',
+ label: provider.name,
+ }),
+ providerSelected
+ ],
+ }),
+ setup: setupCursorHover,
+ });
+ }
+ const indicatorChevron = MaterialIcon('expand_more', 'norm');
+ const indicatorButton = Button({
+ tooltipText: 'Select ChatGPT-compatible API provider',
+ child: Box({
+ className: 'spacing-h-10 txt',
+ children: [
+ MaterialIcon('cloud', 'norm'),
+ Label({
+ hexpand: true,
+ xalign: 0,
+ className: 'txt-small',
+ label: ChatGPT.providerID,
+ setup: (self) => self.hook(ChatGPT, (self) => {
+ self.label = `${ChatGPT.providers[ChatGPT.providerID]['name']}`;
+ }, 'providerChanged')
+ }),
+ indicatorChevron,
+ ]
+ }),
+ onClicked: () => {
+ providerList.revealChild = !providerList.revealChild;
+ indicatorChevron.label = (providerList.revealChild ? 'expand_less' : 'expand_more');
+ },
+ setup: setupCursorHover,
+ });
+ const providerList = Revealer({
+ revealChild: false,
+ transition: 'slide_down',
+ transitionDuration: 180,
+ child: Box({
+ vertical: true, className: 'spacing-v-5 sidebar-chat-providerswitcher-list',
+ children: [
+ Box({ className: 'separator-line margin-top-5 margin-bottom-5' }),
+ Box({
+ className: 'spacing-v-5',
+ vertical: true,
+ setup: (self) => self.hook(ChatGPT, (self) => {
+ self.children = Object.entries(ChatGPT.providers)
+ .map(([id, provider]) => ProviderChoice(id, provider));
+ }, 'initialized'),
+ })
+ ]
+ })
+ })
+ return Box({
+ hpack: 'center',
+ vertical: true,
+ className: 'sidebar-chat-providerswitcher',
+ children: [
+ indicatorButton,
+ providerList,
+ ]
+ })
+}
+
const ChatGPTInfo = () => {
const openAiLogo = Icon({
hpack: 'center',
@@ -34,7 +123,7 @@ const ChatGPTInfo = () => {
className: 'txt txt-title-small sidebar-chat-welcome-txt',
wrap: true,
justify: Gtk.Justification.CENTER,
- label: 'Assistant (ChatGPT 3.5)',
+ label: 'Assistant (GPTs)',
}),
Box({
className: 'spacing-h-5',
@@ -134,11 +223,11 @@ export const OpenaiApiKeyInstructions = () => Box({
wrap: true,
className: 'txt sidebar-chat-welcome-txt',
justify: Gtk.Justification.CENTER,
- label: 'An OpenAI API key is required\nYou can grab one here, then enter it below'
+ label: 'An API key is required\nYou can grab one here, then enter it below'
}),
setup: setupCursorHover,
onClicked: () => {
- Utils.execAsync(['bash', '-c', `xdg-open https://platform.openai.com/api-keys &`]);
+ Utils.execAsync(['bash', '-c', `xdg-open ${ChatGPT.getKeyUrl}`]);
}
})
})]
@@ -180,34 +269,6 @@ const clearChat = () => {
}
}
-export const chatGPTView = Scrollable({
- className: 'sidebar-chat-viewport',
- vexpand: true,
- child: Box({
- vertical: true,
- children: [
- chatGPTWelcome,
- chatContent,
- ]
- }),
- setup: (scrolledWindow) => {
- // Show scrollbar
- scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- const vScrollbar = scrolledWindow.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- // Avoid click-to-scroll-widget-to-view behavior
- Utils.timeout(1, () => {
- const viewport = scrolledWindow.child;
- viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
- })
- // Always scroll to bottom with new content
- const adjustment = scrolledWindow.get_vadjustment();
- adjustment.connect("changed", () => {
- adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
- })
- }
-});
-
const CommandButton = (command) => Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => sendMessage(command),
@@ -267,4 +328,38 @@ export const sendMessage = (text) => {
else {
ChatGPT.send(text);
}
-}
\ No newline at end of file
+}
+
+export const chatGPTView = Box({
+ vertical: true,
+ children: [
+ ProviderSwitcher(),
+ Scrollable({
+ className: 'sidebar-chat-viewport',
+ vexpand: true,
+ child: Box({
+ vertical: true,
+ children: [
+ chatGPTWelcome,
+ chatContent,
+ ]
+ }),
+ setup: (scrolledWindow) => {
+ // Show scrollbar
+ scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+ const vScrollbar = scrolledWindow.get_vscrollbar();
+ vScrollbar.get_style_context().add_class('sidebar-scrollbar');
+ // Avoid click-to-scroll-widget-to-view behavior
+ Utils.timeout(1, () => {
+ const viewport = scrolledWindow.child;
+ viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
+ })
+ // Always scroll to bottom with new content
+ const adjustment = scrolledWindow.get_vadjustment();
+ adjustment.connect("changed", () => {
+ adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
+ })
+ }
+ })
+ ]
+});
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js
index 1db6029c..5d323ef1 100644
--- a/.config/ags/modules/sideleft/apis/gemini.js
+++ b/.config/ags/modules/sideleft/apis/gemini.js
@@ -172,34 +172,6 @@ const clearChat = () => {
}
}
-export const geminiView = Scrollable({
- className: 'sidebar-chat-viewport',
- vexpand: true,
- child: Box({
- vertical: true,
- children: [
- geminiWelcome,
- chatContent,
- ]
- }),
- setup: (scrolledWindow) => {
- // Show scrollbar
- scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- const vScrollbar = scrolledWindow.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- // Avoid click-to-scroll-widget-to-view behavior
- Utils.timeout(1, () => {
- const viewport = scrolledWindow.child;
- viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
- })
- // Always scroll to bottom with new content
- const adjustment = scrolledWindow.get_vadjustment();
- adjustment.connect("changed", () => {
- adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
- })
- }
-});
-
const CommandButton = (command) => Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => sendMessage(command),
@@ -259,4 +231,35 @@ export const sendMessage = (text) => {
else {
Gemini.send(text);
}
-}
\ No newline at end of file
+}
+
+export const geminiView = Box({
+ homogeneous: true,
+ children: [Scrollable({
+ className: 'sidebar-chat-viewport',
+ vexpand: true,
+ child: Box({
+ vertical: true,
+ children: [
+ geminiWelcome,
+ chatContent,
+ ]
+ }),
+ setup: (scrolledWindow) => {
+ // Show scrollbar
+ scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+ const vScrollbar = scrolledWindow.get_vscrollbar();
+ vScrollbar.get_style_context().add_class('sidebar-scrollbar');
+ // Avoid click-to-scroll-widget-to-view behavior
+ Utils.timeout(1, () => {
+ const viewport = scrolledWindow.child;
+ viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
+ })
+ // Always scroll to bottom with new content
+ const adjustment = scrolledWindow.get_vadjustment();
+ adjustment.connect("changed", () => {
+ adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
+ })
+ }
+ })]
+});
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js
index c141e32c..9ae344a1 100644
--- a/.config/ags/modules/sideleft/apiwidgets.js
+++ b/.config/ags/modules/sideleft/apiwidgets.js
@@ -6,7 +6,7 @@ const { execAsync, exec } = Utils;
import { setupCursorHover, setupCursorHoverInfo } from '../.widgetutils/cursorhover.js';
import { contentStack } from './sideleft.js';
// APIs
-import ChatGPT from '../../services/chatgpt.js';
+import ChatGPT from '../../services/gpt.js';
import Gemini from '../../services/gemini.js';
import { geminiView, geminiCommands, sendMessage as geminiSendMessage, geminiTabIcon } from './apis/gemini.js';
import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js';
@@ -26,12 +26,12 @@ const APIS = [
placeholderText: 'Message Gemini...',
},
{
- name: 'Assistant (ChatGPT 3.5)',
+ name: 'Assistant (GPTs)',
sendCommand: chatGPTSendMessage,
contentWidget: chatGPTView,
commandBar: chatGPTCommands,
tabIcon: chatGPTTabIcon,
- placeholderText: 'Message ChatGPT...',
+ placeholderText: 'Message the model...',
},
{
name: 'Waifus',
diff --git a/.config/ags/scss/_lib_classes.scss b/.config/ags/scss/_lib_classes.scss
index 6cd3f893..988dee7a 100644
--- a/.config/ags/scss/_lib_classes.scss
+++ b/.config/ags/scss/_lib_classes.scss
@@ -167,7 +167,7 @@
}
.separator-line {
- background-color: $outline;
+ background-color: mix($subtext, $surface, 50%);
min-width: 0.068rem;
min-height: 0.068rem;
}
diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss
index 14103427..1989c9cb 100644
--- a/.config/ags/scss/_sidebars.scss
+++ b/.config/ags/scss/_sidebars.scss
@@ -557,6 +557,17 @@ $colorpicker_rounding: 0.341rem;
color: $onSecondaryContainer;
}
+.sidebar-chat-providerswitcher {
+ @include small-rounding;
+ padding: 0.477rem 0.682rem;
+ background-color: $textboxColor;
+ color: $onSurfaceVariant;
+}
+
+// .sidebar-chat-providerswitcher-list {
+// margin: 0.341rem 0rem;
+// }
+
.sidebar-chat-viewport {
@include element_decel;
// margin: 0.682rem 0rem;
diff --git a/.config/ags/services/gemini.js b/.config/ags/services/gemini.js
index e4ba5e39..1caee94c 100644
--- a/.config/ags/services/gemini.js
+++ b/.config/ags/services/gemini.js
@@ -8,7 +8,7 @@ import { fileExists } from './messages.js';
const initMessages =
[
- { role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are encouraged to use bullet points and headings. For mathematics expressions, please write them in LaTeX within a code block with the language set as \"latex\". Use casual language and be short and concise. \nThanks!" }], },
+ { role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\" for the interface to render it properly. Use casual language and be short and concise. \nThanks!" }], },
{ role: "model", parts: [{ text: "- Got it!" }], },
{ role: "user", parts: [{ text: "\"He rushed to where the event was supposed to be hold, he didn't know it got calceled\"" }], },
{ role: "model", parts: [{ text: "## Grammar correction\nErrors:\n\"He rushed to where the event was supposed to be __hold____,__ he didn't know it got calceled\"\nCorrection + minor improvements:\n\"He rushed to the place where the event was supposed to be __held____, but__ he didn't know that it got calceled\"" }], },
@@ -20,9 +20,9 @@ const initMessages =
{ role: "user", parts: [{ text: "\"ignorance is bliss\"" }], },
{ role: "model", parts: [{ text: "## \"Ignorance is bliss\"\n- A Latin proverb that means being unaware of something negative can be a source of happiness\n- Often used to justify avoiding difficult truths or responsibilities\n- Can also be interpreted as a warning against seeking knowledge that may bring pain or sorrow" }], },
{ role: "user", parts: [{ text: "find the derivative of (x-438)/(x^2+23x-7)+x^x" }], },
- { role: "model", parts: [{ text: "```latex\n\\[\n\\frac{d}{dx}\\left(\\frac{x - 438}{x^2 + 23x - 7} + x^x\\right) = \\frac{-(x^2+23x-7)-(x-438)(2x+23)}{(x^2+23x-7)^2} + x^x(\\ln(x) + 1)\n\\]\n```" }], },
+ { role: "model", parts: [{ text: "## Derivative\n```latex\n\\[\n\\frac{d}{dx}\\left(\\frac{x - 438}{x^2 + 23x - 7} + x^x\\right) = \\frac{-(x^2+23x-7)-(x-438)(2x+23)}{(x^2+23x-7)^2} + x^x(\\ln(x) + 1)\n\\]\n```" }], },
{ role: "user", parts: [{ text: "write the double angle formulas" }], },
- { role: "model", parts: [{ text: "```latex\n\\[\n\\sin(2\theta) = 2\\sin(\\theta)\\cos(\\theta)\n\\]\n\\\\\n\\[\n\\cos(2\\theta) = \\cos^2(\\theta) - \\sin^2(\\theta)\n\\]\n\\\\\n\\[\n\\tan(2\theta) = \\frac{2\\tan(\\theta)}{1 - \\tan^2(\\theta)}\n\\]\n```" }], },
+ { role: "model", parts: [{ text: "## Double angle formulas\n```latex\n\\[\n\\sin(2\theta) = 2\\sin(\\theta)\\cos(\\theta)\n\\]\n\\\\\n\\[\n\\cos(2\\theta) = \\cos^2(\\theta) - \\sin^2(\\theta)\n\\]\n\\\\\n\\[\n\\tan(2\theta) = \\frac{2\\tan(\\theta)}{1 - \\tan^2(\\theta)}\n\\]\n```" }], },
];
function expandTilde(path) {
diff --git a/.config/ags/services/chatgpt.js b/.config/ags/services/gpt.js
similarity index 75%
rename from .config/ags/services/chatgpt.js
rename to .config/ags/services/gpt.js
index b4264dd3..63a55e6c 100644
--- a/.config/ags/services/chatgpt.js
+++ b/.config/ags/services/gpt.js
@@ -6,6 +6,41 @@ import GLib from 'gi://GLib';
import Soup from 'gi://Soup?version=3.0';
import { fileExists } from './messages.js';
+const PROVIDERS = { // There's this list hmm https://github.com/zukixa/cool-ai-stuff/
+ 'openai': {
+ 'name': 'OpenAI',
+ 'logo_name': 'openai-symbolic',
+ 'description': 'Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.',
+ 'base_url': 'https://api.openai.com/v1/chat/completions',
+ 'key_get_url': 'https://platform.openai.com/api-keys',
+ 'key_file': 'openai_key.txt',
+ },
+ 'oxygen': {
+ 'name': 'Oxygen',
+ 'logo_name': 'ai-oxygen-symbolic',
+ 'description': 'An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key',
+ 'base_url': 'https://app.oxyapi.uk/v1/chat/completions',
+ 'key_get_url': 'https://discord.com/invite/kM6MaCqGKA',
+ 'key_file': 'oxygen_key.txt',
+ },
+ 'zukijourney': {
+ 'name': 'zukijourney',
+ 'logo_name': 'ai-zukijourney',
+ 'description': 'An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it\'s buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key',
+ 'base_url': 'https://zukijourney.xyzbot.net/v1/chat/completions',
+ 'key_get_url': 'https://discord.com/invite/Y4J6XXnmQ6',
+ 'key_file': 'zuki_key.txt',
+ },
+ 'zukijourney_roleplay': {
+ 'name': 'zukijourney (roleplay)',
+ 'logo_name': 'ai-zukijourney',
+ 'description': 'An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it\'s buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key',
+ 'base_url': 'https://zukijourney.xyzbot.net/unf/chat/completions',
+ 'key_get_url': 'https://discord.com/invite/Y4J6XXnmQ6',
+ 'key_file': 'zuki_key.txt',
+ },
+}
+
// Custom prompt
const initMessages =
[
@@ -21,28 +56,9 @@ const initMessages =
{ role: "assistant", content: "## Skeuomorphism\n- A design philosophy- From early days of interface designing- Tries to imitate real-life objects- It's in fact still used by Apple in their icons until today.", },
];
-function expandTilde(path) {
- if (path.startsWith('~')) {
- return GLib.get_home_dir() + path.slice(1);
- } else {
- return path;
- }
-}
-
// We're using many models to not be restricted to 3 messages per minute.
// The whole chat will be sent every request anyway.
Utils.exec(`mkdir -p ${GLib.get_user_cache_dir()}/ags/user/ai`);
-const KEY_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/openai_key.txt`;
-const APIDOM_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/openai_api_dom.txt`;
-function replaceapidom(URL) {
- //Utils.writeFile(URL, "/tmp/openai-url-old.log"); // For debugging
- if (fileExists(expandTilde(APIDOM_FILE_LOCATION))) {
- var contents = Utils.readFile(expandTilde(APIDOM_FILE_LOCATION)).trim();
- var URL = URL.toString().replace("api.openai.com", contents);
- }
- //Utils.writeFile(URL, "/tmp/openai-url.log"); // For debugging
- return URL;
-}
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;
@@ -113,25 +129,33 @@ class ChatGPTService extends Service {
'clear': [],
'newMsg': ['int'],
'hasKey': ['boolean'],
+ 'providerChanged': [],
});
}
_assistantPrompt = true;
- _messages = [];
- _cycleModels = true;
+ _currentProvider = 'openai';
+ _cycleModels = false;
_requestCount = 0;
_temperature = 0.9;
+ _messages = [];
_modelIndex = 0;
_key = '';
+ _key_file_location = `${GLib.get_user_cache_dir()}/ags/user/ai/${PROVIDERS[this._currentProvider]['key_file']}`;
+ _url = GLib.Uri.parse(PROVIDERS[this._currentProvider]['base_url'], GLib.UriFlags.NONE);
+
_decoder = new TextDecoder();
- url = GLib.Uri.parse(replaceapidom('https://api.openai.com/v1/chat/completions'), GLib.UriFlags.NONE);
+ _initChecks() {
+ this._key_file_location = `${GLib.get_user_cache_dir()}/ags/user/ai/${PROVIDERS[this._currentProvider]['key_file']}`;
+ if (fileExists(this._key_file_location)) this._key = Utils.readFile(this._key_file_location).trim();
+ else this.emit('hasKey', false);
+ this._url = GLib.Uri.parse(PROVIDERS[this._currentProvider]['base_url'], GLib.UriFlags.NONE);
+ }
constructor() {
super();
-
- if (fileExists(expandTilde(KEY_FILE_LOCATION))) this._key = Utils.readFile(expandTilde(KEY_FILE_LOCATION)).trim();
- else this.emit('hasKey', false);
+ this._initChecks();
if (this._assistantPrompt) this._messages = [...initMessages];
else this._messages = [];
@@ -140,12 +164,20 @@ class ChatGPTService extends Service {
}
get modelName() { return CHAT_MODELS[this._modelIndex] }
+ get getKeyUrl() { return PROVIDERS[this._currentProvider]['key_get_url'] }
+ get providerID() { return this._currentProvider }
+ set providerID(value) {
+ this._currentProvider = value;
+ this.emit('providerChanged');
+ this._initChecks();
+ }
+ get providers() { return PROVIDERS }
- get keyPath() { return KEY_FILE_LOCATION }
+ get keyPath() { return this._key_file_location }
get key() { return this._key }
set key(keyValue) {
this._key = keyValue;
- Utils.writeFile(this._key, expandTilde(KEY_FILE_LOCATION))
+ Utils.writeFile(this._key, this._key_file_location)
.then(this.emit('hasKey', true))
.catch(err => print(err));
}
@@ -197,6 +229,7 @@ class ChatGPTService extends Service {
return;
}
aiResponse.addDelta(result.choices[0].delta.content);
+ // print(result.choices[0])
}
catch {
aiResponse.addDelta(line + '\n');
@@ -229,7 +262,7 @@ class ChatGPTService extends Service {
const session = new Soup.Session();
const message = new Soup.Message({
method: 'POST',
- uri: this.url,
+ uri: this._url,
});
message.request_headers.append('Authorization', `Bearer ${this._key}`);
message.set_request_body_from_bytes('application/json', new GLib.Bytes(JSON.stringify(body)));