Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add remove llama model setting #71

Merged
merged 7 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions preloader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const {
setClient,
downloadModel,
updateModelSettings,
formator
formator, deleteModel
} = require("./node-llama-cpp-preloader.js")

const {
Expand All @@ -15,7 +15,8 @@ const {

contextBridge.exposeInMainWorld('node-llama-cpp', {
loadModel, chatCompletions, updateModelSettings,
abortCompletion, setClient, downloadModel, formator
abortCompletion, setClient, downloadModel, formator,
deleteModel
})

contextBridge.exposeInMainWorld('file-handler', {
Expand Down
18 changes: 16 additions & 2 deletions preloader/node-llama-cpp-preloader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { ipcRenderer } = require("electron");
const { createWriteStream, existsSync, statSync, mkdirSync } = require("fs");
const { createWriteStream, existsSync, statSync, mkdirSync, rmSync } = require("fs");
const path = require("path");

let llama, getLlama, LlamaChatSession, current_model;
Expand Down Expand Up @@ -216,6 +216,19 @@ function downloadModel(url, cb=null) {
})
}

/**
* Delete a model from disk
* @param {String} model_name the model name on disk
* @returns {Boolean}
*/
function deleteModel(model_name) {
const model = path.join(model_path, model_name);
if(existsSync(model)){
rmSync(model);
}
return true;
}

/**
* format messages, reset history if needed
* @param {Message[]} messages
Expand All @@ -239,5 +252,6 @@ module.exports = {
setClient,
downloadModel,
updateModelSettings,
formator
formator,
deleteModel
}
26 changes: 26 additions & 0 deletions src/components/ConfirmationDialog.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useEffect, useRef } from "react";

export default function ConfirmationDialog({children, open_status, setOpenStatus, callback}) {
const dialogRef = useRef(null);

useEffect(()=>{
if(dialogRef.current) {
if(open_status) dialogRef.current.showModal();
else dialogRef.current.close();
}
}, [open_status])

return (
<dialog className="confirmation-dialog" ref={dialogRef} onClose={()=>setOpenStatus(false)}>
{ children }
<div
className="button clickable"
onClick={()=>callback(true)}
>Yes, Continue</div>
<div
className="button clickable"
onClick={()=>callback(false)}
>No, Go Back</div>
</dialog>
)
}
29 changes: 0 additions & 29 deletions src/components/chat/DeleteConfirm.jsx

This file was deleted.

19 changes: 10 additions & 9 deletions src/components/chat/index.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useEffect, useRef, useState } from "react";
import Tickets from "./Tickets";
// import Conversation from "./Conversation";
import useIDB from "../../utils/idb";
import DeleteConfirm from "./DeleteConfirm";
import ChatPage from "./ChatPage";
import { getCompletionFunctions } from "../../utils/workers";
import { getPlatformSettings } from "../../utils/general_settings";
import { exportChatHistory } from "../../utils/chat-history-handler";
import ConfirmationDialog from "../ConfirmationDialog";

export default function Chat() {

Expand Down Expand Up @@ -184,13 +183,15 @@ export default function Chat() {
pending_message={pending_message} abort={session_setting.abort}
sendMessage={sendMessage} updateSystemInstruction={updateSystemInstruction}
/>
<DeleteConfirm
showConfirm={show_delete_confirm}
closeDialog={()=>toggleConfirm(false)}
deleteHistory={deleteHistory}
resetRequestDelete={resetRequestDelete}
conv_to_delete={conv_to_delete}
/>
<ConfirmationDialog
open_status={show_delete_confirm}
setOpenStatus={toggleConfirm}
callback={cb=>{
cb ? deleteHistory() : resetRequestDelete();
}}
>
<div>Delete <strong>{ conv_to_delete && conv_to_delete.title }</strong>?</div>
</ConfirmationDialog>
</div> :
<></>
)
Expand Down
93 changes: 77 additions & 16 deletions src/components/settings/LlamaSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import useIDB from "../../utils/idb";
import { getPlatformSettings, updatePlatformSettings } from "../../utils/general_settings";
import { DEFAULT_LLAMA_CPP_MODEL_URL } from "../../utils/types";
import DropdownComponent from "./components/DropdownComponent";
import ButtonComponent from "./components/ButtonComponent";
import ConfirmationDialog from "../ConfirmationDialog";

export default function LlamaSettings({ trigger, enabled, updateEnabled, openDownloadProtector, updateState }) {

const [model_download_link, setModelDownloadLink] = useState('');
const [selected_model, setSelectedModel] = useState({});
const [reset_everytime, setResetEveryTime] = useState(false);
const [downloaded_models, setDownloadedModels] = useState([])
const [delete_confirm_opened, setDeleteConfirmOpenStatus] = useState(false);
const idb = useIDB();

async function saveSettings() {
Expand Down Expand Up @@ -41,25 +45,58 @@ export default function LlamaSettings({ trigger, enabled, updateEnabled, openDow
platform: 'Llama'
}
await idb.insert("downloaded-models", stored_model)
setDownloadedModels([...downloaded_models, { title: stored_model['model-name'], value: stored_model.url }])
setDownloadedModels([...downloaded_models, { title: stored_model['model-name'], value: JSON.stringify(stored_model) }])
setSelectedModel(stored_model)
}
}
)
}
await openDownloadProtector(
'Loading model...',
`Loading model ${stored_model['model-name']}`,
async callback => {
callback(100, false);
// load model using the model name retrieved
await window['node-llama-cpp'].loadModel(stored_model['model-name'])
updateState();
callback(100, true)
}
)
await loadModel(stored_model);
}
}

async function loadModel(model) {
await openDownloadProtector(
'Loading model...',
`Loading model ${model['model-name']}`,
async callback => {
callback(100, false);
// load model using the model name retrieved
await window['node-llama-cpp'].loadModel(model['model-name'])
updateState();
callback(100, true)
}
)
}

async function deleteModel() {
let load_after_delete = {};
await openDownloadProtector(
'Please wait while we deleteing the model...',
`Loading model ${selected_model['model-name']}`,
async callback => {
window['node-llama-cpp'].deleteModel(selected_model['model-name']);
callback(80, false);
await idb.deleteOne("downloaded-models", [selected_model]);
callback(90, false);

const models = await idb.getAll("downloaded-models", {
where: [{'platform': 'Llama'}]
});
setDownloadedModels(models.map(e=>{return { title: e['model-name'], value: JSON.stringify(e) }}))
load_after_delete = models.pop() || {}
const url = load_after_delete.url || '';
setSelectedModel(load_after_delete);
setModelDownloadLink(url);
updatePlatformSettings({
llama_model_url: url
})
callback(100, true);
}
)
await loadModel(load_after_delete);
}

useEffect(()=>{
trigger && saveSettings();
// eslint-disable-next-line
Expand All @@ -72,10 +109,10 @@ export default function LlamaSettings({ trigger, enabled, updateEnabled, openDow
setResetEveryTime(llama_reset_everytime);

const models = await idb.getAll("downloaded-models", {
where: [{'platform': 'Llama'}],
select: ["model-name", "url"]
where: [{'platform': 'Llama'}]
});
setDownloadedModels(models.map(e=>{return { title: e['model-name'], value: e.url }}))
setDownloadedModels(models.map(e=>{return { title: e['model-name'], value: JSON.stringify(e) }}))
setSelectedModel(models.filter(e=>e.url === llama_model_url).pop())
})()
// eslint-disable-next-line
}, [])
Expand All @@ -90,7 +127,12 @@ export default function LlamaSettings({ trigger, enabled, updateEnabled, openDow
<DropdownComponent
title={"Select a downloaded model to use"}
description={"If there's no models, you might want to download a new one by enter url below."}
value={downloaded_models} cb={setModelDownloadLink}
value={downloaded_models} cb={model=>{
model = JSON.parse(model)
setSelectedModel(model)
setModelDownloadLink(model.url)
}}
selected={JSON.stringify(selected_model)}
/>
<TextComponent
title={"Or enter the link of model you want to use"}
Expand All @@ -103,6 +145,25 @@ export default function LlamaSettings({ trigger, enabled, updateEnabled, openDow
description={"Reset the conversation, only keeps the latest message and the system instruction, this is useful for many one-shot operations."}
value={reset_everytime} cb={setResetEveryTime}
/>
<ButtonComponent
title={"Delete selected model"}
description={"This will delete the downloaded model, make sure before you choose to delete!"}
className="dangerous" disabled={!model_download_link}
value={"Delete Model"} cb={()=>{setDeleteConfirmOpenStatus(true)}}
/>
<ConfirmationDialog
open_status={delete_confirm_opened}
setOpenStatus={setDeleteConfirmOpenStatus}
callback={cb=>{
cb && deleteModel();
setDeleteConfirmOpenStatus(false);
}}
>
<div>
Are you sure you want to delete model<br/>
<strong>{selected_model['model-name']}</strong>?
</div>
</ConfirmationDialog>
</SettingSection>
)
}
9 changes: 9 additions & 0 deletions src/components/settings/components/ButtonComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function ButtonComponent({ cb, value, disabled, title, description, className }) {
return (
<div className="component">
<div className="title">{title}</div>
{ description && <div className="description">{description}</div> }
<div className={`main-part button ${className||''}${disabled ? ' disabled':""}`} onClick={cb}>{ value }</div>
</div>
)
}
19 changes: 17 additions & 2 deletions src/components/settings/components/DropdownComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
export default function DropdownComponent({ cb, value, title, description }) {
import { useEffect } from "react";
import { useState } from "react";

export default function DropdownComponent({ cb, value, selected, title, description }) {

const [selected_option, setSelectedOption] = useState(selected || (value && value.length && value[0].value) || '');

useEffect(()=>{
selected && setSelectedOption(selected);
}, [selected])

return (
<div className="component">
<div className="title">{title}</div>
{ description && <div className="description">{description}</div> }
<select
className="main-part"
value={selected_option}
onClick={evt=>evt.preventDefault()}
onChange={evt=>cb && cb(evt.target.value)}
onChange={evt=>{
const v = evt.target.value
setSelectedOption(v);
cb && cb(v);
}}
>
{ value.map((e, i)=>{
let title, value;
Expand Down
1 change: 1 addition & 0 deletions src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import './styles/sidebar.css';
import './styles/chat.css';
import './styles/entry.css';
import './styles/settings.css';
import './styles/confirmation-dialog.css';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
Expand Down
22 changes: 0 additions & 22 deletions src/styles/chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,28 +78,6 @@
color: black;
}

.chat > dialog {
border: 2px solid black;
padding: 30px;
border-radius: 10px;
text-align: center;
}
.chat > dialog:focus {
outline: none;
}

.chat > dialog > .button {
border-bottom: 1px solid;
width: fit-content;
margin: auto;
margin-top: 7px;
padding: 0px 7px;
color: rgb(70, 70, 70);
}
.chat > dialog > .button:hover {
color: black;
}

.chat > .conversation-main {
width: calc(100% - var(--tickets-width));
position: absolute;
Expand Down
20 changes: 20 additions & 0 deletions src/styles/confirmation-dialog.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.confirmation-dialog {
border: 2px solid black;
padding: 30px;
border-radius: 10px;
text-align: center;
max-width: 60%;
}

.confirmation-dialog > .button {
border-bottom: 1px solid;
width: fit-content;
margin: auto;
margin-top: 7px;
padding: 0px 7px;
color: rgb(70, 70, 70);
}

.confirmation-dialog > .button:hover {
color: black;
}
Loading