mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-04 04:04:44 -07:00
monkey patch koboldai lite on unpack to make it look better, minor improvements
This commit is contained in:
parent
94f38d2868
commit
d185d8e9e6
7 changed files with 187 additions and 69 deletions
2
.nvmrc
2
.nvmrc
|
|
@ -1 +1 @@
|
||||||
22.18.0
|
22.19.0
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -78,59 +78,56 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
|
||||||
</Stack>
|
</Stack>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{availableDownloads.length > 0 && (
|
{availableDownloads.length > 0 ? (
|
||||||
<>
|
<Stack gap="sm">
|
||||||
{availableDownloads.length > 0 ? (
|
{sortedDownloads.map((download) => {
|
||||||
<Stack gap="sm">
|
const isDownloading =
|
||||||
{sortedDownloads.map((download) => {
|
Boolean(downloading) &&
|
||||||
const isDownloading =
|
downloadingAsset === download.name;
|
||||||
Boolean(downloading) &&
|
|
||||||
downloadingAsset === download.name;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={download.name}
|
key={download.name}
|
||||||
ref={isDownloading ? downloadingItemRef : null}
|
ref={isDownloading ? downloadingItemRef : null}
|
||||||
>
|
>
|
||||||
<DownloadCard
|
<DownloadCard
|
||||||
name={download.name}
|
name={download.name}
|
||||||
size={formatDownloadSize(
|
size={formatDownloadSize(
|
||||||
download.size,
|
download.size,
|
||||||
download.url
|
download.url
|
||||||
)}
|
)}
|
||||||
version={download.version}
|
version={download.version}
|
||||||
description={getAssetDescription(download.name)}
|
description={getAssetDescription(download.name)}
|
||||||
isDownloading={isDownloading}
|
isDownloading={isDownloading}
|
||||||
downloadProgress={
|
downloadProgress={
|
||||||
isDownloading
|
isDownloading
|
||||||
? downloadProgress[download.name] || 0
|
? downloadProgress[download.name] || 0
|
||||||
: 0
|
: 0
|
||||||
}
|
}
|
||||||
disabled={
|
disabled={
|
||||||
Boolean(downloading) &&
|
Boolean(downloading) &&
|
||||||
downloadingAsset !== download.name
|
downloadingAsset !== download.name
|
||||||
}
|
}
|
||||||
onDownload={(e) => {
|
onDownload={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleDownload(download);
|
handleDownload(download);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</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
|
||||||
</Text>
|
internet connection and try again.
|
||||||
</Stack>
|
</Text>
|
||||||
</Card>
|
</Stack>
|
||||||
)}
|
</Card>
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -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}`,
|
||||||
|
|
|
||||||
|
|
@ -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 }> {
|
||||||
|
|
|
||||||
13
yarn.lock
13
yarn.lock
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue