monkey patch koboldai lite on unpack to make it look better, minor improvements

This commit is contained in:
lone-cloud 2025-09-04 17:49:20 -07:00
parent 94f38d2868
commit d185d8e9e6
7 changed files with 187 additions and 69 deletions

2
.nvmrc
View file

@ -1 +1 @@
22.18.0 22.19.0

View file

@ -1,7 +1,7 @@
{ {
"name": "gerbil", "name": "gerbil",
"productName": "Gerbil", "productName": "Gerbil",
"version": "0.9.10", "version": "0.9.11",
"description": "Run Large Language Models locally", "description": "Run Large Language Models locally",
"main": "out/main/index.js", "main": "out/main/index.js",
"homepage": "./", "homepage": "./",
@ -39,7 +39,7 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.34.0", "@eslint/js": "^9.34.0",
"@types/node": "^24.3.0", "@types/node": "^24.3.1",
"@types/react": "^19.1.12", "@types/react": "^19.1.12",
"@types/react-dom": "^19.1.9", "@types/react-dom": "^19.1.9",
"@typescript-eslint/eslint-plugin": "^8.42.0", "@typescript-eslint/eslint-plugin": "^8.42.0",

View file

@ -177,7 +177,10 @@ export const DownloadCard = ({
radius="xl" radius="xl"
/> />
<Text size="xs" c="dimmed" ta="center"> <Text size="xs" c="dimmed" ta="center">
{Math.min(downloadProgress, 100).toFixed(1)}% complete {Math.min(downloadProgress, 100) === 100
? '100%'
: `${Math.min(downloadProgress, 100).toFixed(1)}%`}{' '}
complete
</Text> </Text>
</Stack> </Stack>
)} )}

View file

@ -77,8 +77,6 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
<Text c="dimmed">Preparing download options...</Text> <Text c="dimmed">Preparing download options...</Text>
</Stack> </Stack>
) : ( ) : (
<>
{availableDownloads.length > 0 && (
<> <>
{availableDownloads.length > 0 ? ( {availableDownloads.length > 0 ? (
<Stack gap="sm"> <Stack gap="sm">
@ -120,20 +118,19 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
})} })}
</Stack> </Stack>
) : ( ) : (
<Card withBorder p="md" bg="yellow.0" c="yellow.9"> <Card withBorder p="md" bg="red.0" c="red.9">
<Stack gap="xs"> <Stack gap="xs">
<Text fw={500}>No downloads available</Text> <Text fw={500}>No downloads available</Text>
<Text size="sm"> <Text size="sm">
No downloads available for your platform ( Unable to fetch downloads for your platform (
{getPlatformDisplayName(platform)}). {getPlatformDisplayName(platform)}). Please check your
internet connection and try again.
</Text> </Text>
</Stack> </Stack>
</Card> </Card>
)} )}
</> </>
)} )}
</>
)}
</Stack> </Stack>
</Card> </Card>
</Stack> </Stack>

View file

@ -54,7 +54,7 @@ export const AboutTab = () => {
const copyVersionInfo = async () => { const copyVersionInfo = async () => {
const info = [ const info = [
`${PRODUCT_NAME}: v${versionInfo.appVersion}`, `${PRODUCT_NAME}: ${versionInfo.appVersion}`,
`Electron: ${versionInfo.electronVersion}`, `Electron: ${versionInfo.electronVersion}`,
`Node.js: ${versionInfo.nodeVersion}`, `Node.js: ${versionInfo.nodeVersion}`,
`Chromium: ${versionInfo.chromeVersion}`, `Chromium: ${versionInfo.chromeVersion}`,

View file

@ -1,7 +1,17 @@
import { spawn, ChildProcess } from 'child_process'; import { spawn, ChildProcess } from 'child_process';
import { createWriteStream } from 'fs'; import { createWriteStream } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { rm, readdir, stat, unlink, rename, mkdir, chmod } from 'fs/promises'; import {
rm,
readdir,
stat,
unlink,
rename,
mkdir,
chmod,
readFile,
writeFile,
} from 'fs/promises';
import { dialog } from 'electron'; import { dialog } from 'electron';
import axios from 'axios'; import axios from 'axios';
@ -210,6 +220,7 @@ export class KoboldCppManager {
await this.downloadFile(asset, tempPackedFilePath); await this.downloadFile(asset, tempPackedFilePath);
await mkdir(unpackedDirPath, { recursive: true }); await mkdir(unpackedDirPath, { recursive: true });
await this.unpackKoboldCpp(tempPackedFilePath, unpackedDirPath); await this.unpackKoboldCpp(tempPackedFilePath, unpackedDirPath);
await this.patchKliteEmbd(unpackedDirPath);
const launcherPath = await this.setupLauncher( const launcherPath = await this.setupLauncher(
tempPackedFilePath, tempPackedFilePath,
unpackedDirPath unpackedDirPath
@ -254,6 +265,113 @@ export class KoboldCppManager {
} }
} }
private async patchKliteEmbd(unpackedDir: string): Promise<void> {
try {
const possiblePaths = [
join(unpackedDir, '_internal', 'klite.embd'),
join(unpackedDir, 'klite.embd'),
];
let kliteEmbdPath: string | null = null;
for (const path of possiblePaths) {
if (await pathExists(path)) {
kliteEmbdPath = path;
break;
}
}
if (!kliteEmbdPath) {
this.logManager.logError(
'klite.embd file not found in unpacked directory',
new Error('File not found')
);
return;
}
this.windowManager.sendKoboldOutput(
'Injecting CSS override for better iframe display...'
);
const content = await readFile(kliteEmbdPath, 'utf8');
const customCssOverride = `
<style id="gerbil-css-override">
* {
transition: 100ms ease all;
}
.maincontainer {
padding-right: 0 !important;
padding-left: 0 !important;
}
.adaptivecontainer {
width: 100% !important;
}
#lastreq1 {
margin: 0 10px;
}
#inputrow {
padding: 0 10px;
}
#actionmenuitems {
margin-left: 10px;
}
.topmenu {
padding: 10px;
}
#navbarNavDropdown {
padding: 0;
}
#inputrow > :nth-child(1) {
padding-right: 0 !important;
}
#inputrow.show_mode > :nth-child(1) {
flex: 0 0 70px;
margin-right: 4px;
}
#inputrow > :nth-child(3) {
flex: 0 0 70px;
padding-right: 0 !important;
}
#inputrow.show_mode > :nth-child(3) button {
background-color: #129c00;
font-size: 14px;
}
#inputrow.show_mode > :nth-child(3) button:hover {
background-color: #058105;
}
#actionmenuitems + div {
margin-right: 10px;
}
#actionmenuitems button, #actionmenuitems2 button {
background-color: #337ab7 !important;
}
#actionmenuitems button:hover, #actionmenuitems2 button:hover {
background-color: #286090 !important;
}
</style>`;
if (content.includes('</head>')) {
const patchedContent = content.replace(
'</head>',
`${customCssOverride}\n</head>`
);
await writeFile(kliteEmbdPath, patchedContent, 'utf8');
this.windowManager.sendKoboldOutput(
'Successfully injected CSS override to klite.embd'
);
} else {
this.windowManager.sendKoboldOutput(
'Warning: Could not find </head> tag in klite.embd, skipping CSS injection'
);
}
} catch (error) {
this.logManager.logError('Failed to patch klite.embd:', error as Error);
this.windowManager.sendKoboldOutput(
'Warning: Failed to patch klite.embd CSS, but continuing with installation...'
);
}
}
private async getLauncherPath(unpackedDir: string): Promise<string | null> { private async getLauncherPath(unpackedDir: string): Promise<string | null> {
const extensions = const extensions =
process.platform === 'win32' ? ['.exe', ''] : ['', '.exe']; process.platform === 'win32' ? ['.exe', ''] : ['', '.exe'];
@ -604,15 +722,6 @@ export class KoboldCppManager {
} }
} }
isRunning() {
return this.koboldProcess !== null && !this.koboldProcess.killed;
}
async getInstalledVersion(): Promise<string | undefined> {
const currentVersion = await this.getCurrentVersion();
return currentVersion?.version;
}
async launchKoboldCpp( async launchKoboldCpp(
args: string[] = [] args: string[] = []
): Promise<{ success: boolean; pid?: number; error?: string }> { ): Promise<{ success: boolean; pid?: number; error?: string }> {

View file

@ -1280,7 +1280,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:*, @types/node@npm:^24.3.0": "@types/node@npm:*":
version: 24.3.0 version: 24.3.0
resolution: "@types/node@npm:24.3.0" resolution: "@types/node@npm:24.3.0"
dependencies: dependencies:
@ -1298,6 +1298,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^24.3.1":
version: 24.3.1
resolution: "@types/node@npm:24.3.1"
dependencies:
undici-types: "npm:~7.10.0"
checksum: 10c0/99b86fc32294fcd61136ca1f771026443a1e370e9f284f75e243b29299dd878e18c193deba1ce29a374932db4e30eb80826e1049b9aad02d36f5c30b94b6f928
languageName: node
linkType: hard
"@types/plist@npm:^3.0.1": "@types/plist@npm:^3.0.1":
version: 3.0.5 version: 3.0.5
resolution: "@types/plist@npm:3.0.5" resolution: "@types/plist@npm:3.0.5"
@ -3638,7 +3647,7 @@ __metadata:
"@eslint/js": "npm:^9.34.0" "@eslint/js": "npm:^9.34.0"
"@mantine/core": "npm:^8.2.8" "@mantine/core": "npm:^8.2.8"
"@mantine/hooks": "npm:^8.2.8" "@mantine/hooks": "npm:^8.2.8"
"@types/node": "npm:^24.3.0" "@types/node": "npm:^24.3.1"
"@types/react": "npm:^19.1.12" "@types/react": "npm:^19.1.12"
"@types/react-dom": "npm:^19.1.9" "@types/react-dom": "npm:^19.1.9"
"@typescript-eslint/eslint-plugin": "npm:^8.42.0" "@typescript-eslint/eslint-plugin": "npm:^8.42.0"