Skip to content

Commit

Permalink
add remove llama model setting (#71)
Browse files Browse the repository at this point in the history
* use general confirmation dialog instead of just for DeleteConfirm

Signed-off-by: cbh778899 <[email protected]>

* add deleteModel function

Signed-off-by: cbh778899 <[email protected]>

* update styles

Signed-off-by: cbh778899 <[email protected]>

* move to ConfirmationDialog component

Signed-off-by: cbh778899 <[email protected]>

* add ButtonComponent for one-click settings

Signed-off-by: cbh778899 <[email protected]>

* add validation for current selected item

Signed-off-by: cbh778899 <[email protected]>

* implement delete model function

Signed-off-by: cbh778899 <[email protected]>

---------

Signed-off-by: cbh778899 <[email protected]>
  • Loading branch information
cbh778899 authored Oct 22, 2024
1 parent c277541 commit deff2cc
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 83 deletions.
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

0 comments on commit deff2cc

Please sign in to comment.