improve history

This commit is contained in:
end-4 2024-03-24 09:14:50 +07:00
parent 31a2d4f379
commit 6eba7707ed
3 changed files with 105 additions and 29 deletions

View file

@ -7,6 +7,8 @@ let configOptions = {
'ai': {
'defaultGPTProvider': "openai",
'defaultTemperature': 0.9,
'enhancements': true,
'useHistory': true,
'writingCursor': " ...", // Warning: Using weird characters can mess up Markdown rendering
},
'animations': {

View file

@ -89,7 +89,7 @@ export const GeminiSettings = () => MarginRevealer({
GeminiService.temperature = value;
},
}),
ConfigGap({ vertical: true, size: 10 }), // Note: size can only be 5, 10, or 15
ConfigGap({ vertical: true, size: 10 }), // Note: size can only be 5, 10, or 15
Box({
vertical: true,
hpack: 'fill',
@ -104,6 +104,15 @@ export const GeminiSettings = () => MarginRevealer({
GeminiService.assistantPrompt = newValue;
},
}),
ConfigToggle({
icon: 'history',
name: 'History',
desc: 'Saves chat history',
initValue: GeminiService.useHistory,
onChange: (self, newValue) => {
GeminiService.useHistory = newValue;
},
}),
]
})
]
@ -201,6 +210,10 @@ export const sendMessage = (text) => {
// Commands
if (text.startsWith('/')) {
if (text.startsWith('/clear')) clearChat();
else if (text.startsWith('/load')) {
clearChat();
GeminiService.loadHistory();
}
else if (text.startsWith('/model')) chatContent.add(SystemMessage(`Currently using \`${GeminiService.modelName}\``, '/model', geminiView))
else if (text.startsWith('/prompt')) {
const firstSpaceIndex = text.indexOf(' ');
@ -257,10 +270,10 @@ export const geminiView = Box({
})
// Always scroll to bottom with new content
const adjustment = scrolledWindow.get_vadjustment();
adjustment.connect("changed", () => {
adjustment.connect("changed", () => Utils.timeout(1, () => {
if(!chatEntry.hasFocus) return;
adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
})
}))
}
})]
});

View file

@ -5,16 +5,35 @@ import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import Soup from 'gi://Soup?version=3.0';
import { fileExists } from '../modules/.miscutils/files.js';
if(!fileExists(`${GLib.get_user_config_dir()}/gemini_history.json`))
{
Utils.execAsync([`bash`, `-c`,`touch ${GLib.get_user_config_dir()}/gemini_history.json`]).catch(print);
Utils.writeFile('[ ]', `${GLib.get_user_config_dir()}/gemini_history.json`).catch(print);
const HISTORY_DIR = `${GLib.get_user_cache_dir()}/ags/user/ai/chats/`;
const HISTORY_FILENAME = `gemini.txt`;
const HISTORY_PATH = HISTORY_DIR + HISTORY_FILENAME;
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 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\"" }], },
{ role: "user", parts: [{ text: "raise volume by 5%" }], },
{ role: "model", parts: [{ text: "## Volume +5```bash\nwpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+\n```\nThis command uses the `wpctl` utility to adjust the volume of the default sink." }], }, { role: "user", parts: [{ text: "main advantages of the nixos operating system" }], },
{ role: "model", parts: [{ text: "## NixOS advantages\n- **Reproducible**: A config working on one device will also work on another\n- **Declarative**: One config language to rule them all. Effortlessly share them with others.\n- **Reliable**: Per-program software versioning. Mitigates the impact of software breakage" }], },
{ role: "user", parts: [{ text: "whats skeumorphism" }], },
{ role: "model", parts: [{ text: "## 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." }], },
{ 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: "## 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: "## 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```" }], },
];
if (!fileExists(`${GLib.get_user_config_dir()}/gemini_history.json`)) {
Utils.execAsync([`bash`, `-c`, `touch ${GLib.get_user_config_dir()}/gemini_history.json`]).catch(print);
Utils.writeFile('[ ]', `${GLib.get_user_config_dir()}/gemini_history.json`).catch(print);
}
// read gemini_history.json
const readfile = Utils.readFile(`${GLib.get_user_config_dir()}/gemini_history.json`)
const history_chat = JSON.parse(readfile)
const initMessages = history_chat
// api key
Utils.exec(`mkdir -p ${GLib.get_user_cache_dir()}/ags/user/ai`);
const KEY_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/google_key.txt`;
const APIDOM_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/google_api_dom.txt`;
@ -96,13 +115,17 @@ class GeminiMessage extends Service {
}
parseSection() {
if(this._thinking) {
if (this._thinking) {
this._thinking = false;
this._parts[0].text= '';
this._parts[0].text = '';
}
const parsedData = JSON.parse(this._rawData);
const delta = parsedData.candidates[0].content.parts[0].text;
this._parts[0].text += delta;
if (!parsedData.candidates)
this._parts[0].text += `Blocked: ${parsedData.promptFeedback.blockReason}`;
else {
const delta = parsedData.candidates[0].content.parts[0].text;
this._parts[0].text += delta;
}
// this.emit('delta', delta);
this.notify('content');
this._rawData = '';
@ -119,13 +142,15 @@ class GeminiService extends Service {
});
}
_assistantPrompt = true;
_messages = [];
_assistantPrompt = userOptions.ai.enhancements;
_cycleModels = true;
_requestCount = 0;
_temperature = userOptions.ai.defaultTemperature;
_modelIndex = 0;
_usingHistory = userOptions.ai.useHistory;
_key = '';
_requestCount = 0;
_safe = true;
_temperature = userOptions.ai.defaultTemperature;
_messages = [];
_modelIndex = 0;
_decoder = new TextDecoder();
constructor() {
@ -134,8 +159,9 @@ class GeminiService extends Service {
if (fileExists(KEY_FILE_LOCATION)) this._key = Utils.readFile(KEY_FILE_LOCATION).trim();
else this.emit('hasKey', false);
if (this._assistantPrompt) this._messages = [...initMessages];
else this._messages = [];
// if (this._usingHistory) Utils.timeout(1000, () => this.loadHistory());
if (this._usingHistory) this.loadHistory();
else this._messages = this._assistantPrompt ? [...initMessages] : [];
this.emit('initialized');
}
@ -160,17 +186,52 @@ class GeminiService extends Service {
}
}
get useHistory() { return this._usingHistory; }
set useHistory(value) {
if (value && !this._usingHistory) this.loadHistory();
this._usingHistory = value;
}
get temperature() { return this._temperature }
set temperature(value) { this._temperature = value; }
get messages() { return this._messages }
get lastMessage() { return this._messages[this._messages.length - 1] }
saveHistory() {
Utils.writeFile(JSON.stringify(this._messages.map(msg => {
let m = { role: msg.role, parts: msg.parts }; return m;
})), HISTORY_PATH);
}
loadHistory() {
this._messages = [];
this.appendHistory();
this._usingHistory = true;
}
appendHistory() {
if (fileExists(HISTORY_PATH)) {
const readfile = Utils.readFile(HISTORY_PATH);
JSON.parse(readfile).forEach(element => {
// this._messages.push(element);
this.addMessage(element.role, element.parts[0].text);
});
// console.log(this._messages)
// this._messages = this._messages.concat(JSON.parse(readfile));
// for (let index = 0; index < this._messages.length; index++) {
// this.emit('newMsg', index);
// }
}
else {
this._messages = this._assistantPrompt ? [...initMessages] : []
Utils.exec(`bash -c 'mkdir -p ${HISTORY_DIR} && touch ${HISTORY_PATH}'`)
}
}
clear() {
if (this._assistantPrompt)
this._messages = [...initMessages];
else
this._messages = [];
this._messages = this._assistantPrompt ? [...initMessages] : [];
if (this._usingHistory) this.saveHistory();
this.emit('clear');
}
@ -188,6 +249,7 @@ class GeminiService extends Service {
try {
const [bytes] = stream.read_line_finish(res);
const line = this._decoder.decode(bytes);
// console.log(line);
if (line == '[{') { // beginning of response
aiResponse._rawData += '{';
this.thinking = false;
@ -201,8 +263,7 @@ class GeminiService extends Service {
this.readResponse(stream, aiResponse);
} catch {
aiResponse.done = true;
// the way to save all the history messages for gemini
Utils.writeFile(JSON.stringify(this._messages.map(msg => { let m = { role: msg.role, parts: msg.parts }; return m; })),`${GLib.get_user_config_dir()}/gemini_history.json`);
if (this._usingHistory) this.saveHistory();
return;
}
});