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

Chore fix #4671

Merged
merged 6 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,17 @@ To control custom models, use `+` to add a custom model, use `-` to hide a model

User `-all` to disable all default models, `+all` to enable all default models.

### `WHITE_WEBDEV_ENDPOINTS` (可选)
### `WHITE_WEBDEV_ENDPOINTS` (optional)

You can use this option if you want to increase the number of webdav service addresses you are allowed to access, as required by the format:
- Each address must be a complete endpoint
> `https://xxxx/yyy`
- Multiple addresses are connected by ', '

### `DEFAULT_INPUT_TEMPLATE` (optional)

Customize the default template used to initialize the User Input Preprocessing configuration item in Settings.

## Requirements

NodeJS >= 18, Docker >= 20
Expand Down
3 changes: 3 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ anthropic claude Api Url.
用来控制模型列表,使用 `+` 增加一个模型,使用 `-` 来隐藏一个模型,使用 `模型名=展示名` 来自定义模型的展示名,用英文逗号隔开。

### `DEFAULT_INPUT_TEMPLATE` (可选)
自定义默认的 template,用于初始化『设置』中的『用户输入预处理』配置项

## 开发

点击下方按钮,开始二次开发:
Expand Down
3 changes: 2 additions & 1 deletion app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ import {
getMessageTextContent,
getMessageImages,
isVisionModel,
compressImage,
} from "../utils";

import { compressImage } from "@/app/utils/chat";

import dynamic from "next/dynamic";

import { ChatControllerPool } from "../client/controller";
Expand Down
2 changes: 2 additions & 0 deletions app/config/build.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import tauriConfig from "../../src-tauri/tauri.conf.json";
import { DEFAULT_INPUT_TEMPLATE } from "../constant";

export const getBuildConfig = () => {
if (typeof process === "undefined") {
Expand Down Expand Up @@ -38,6 +39,7 @@ export const getBuildConfig = () => {
...commitInfo,
buildMode,
isApp,
template: process.env.DEFAULT_INPUT_TEMPLATE ?? DEFAULT_INPUT_TEMPLATE,
};
};

Expand Down
3 changes: 3 additions & 0 deletions app/config/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ declare global {

// google tag manager
GTM_ID?: string;

// custom template for preprocessing user input
DEFAULT_INPUT_TEMPLATE?: string;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/store/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ export const useChatStore = createPersistStore(
content:
session.memoryPrompt.length > 0
? Locale.Store.Prompt.History(session.memoryPrompt)
: "",
: ";",
date: "",
} as ChatMessage;
},
Expand Down
16 changes: 12 additions & 4 deletions app/store/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LLMModel } from "../client/api";
import { isMacOS } from "../utils";
import { getClientConfig } from "../config/client";
import {
DEFAULT_INPUT_TEMPLATE,
Expand All @@ -25,14 +24,16 @@ export enum Theme {
Light = "light",
}

const config = getClientConfig();

export const DEFAULT_CONFIG = {
lastUpdate: Date.now(), // timestamp, to merge state

submitKey: SubmitKey.Enter,
avatar: "1f603",
fontSize: 14,
theme: Theme.Auto as Theme,
tightBorder: !!getClientConfig()?.isApp,
tightBorder: !!config?.isApp,
sendPreviewBubble: true,
enableAutoGenerateTitle: true,
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
Expand All @@ -56,7 +57,7 @@ export const DEFAULT_CONFIG = {
historyMessageCount: 4,
compressMessageLengthThreshold: 1000,
enableInjectSystemPrompts: true,
template: DEFAULT_INPUT_TEMPLATE,
template: config?.template ?? DEFAULT_INPUT_TEMPLATE,
},
};

Expand Down Expand Up @@ -132,7 +133,7 @@ export const useAppConfig = createPersistStore(
}),
{
name: StoreKey.Config,
version: 3.8,
version: 3.9,
migrate(persistedState, version) {
const state = persistedState as ChatConfig;

Expand Down Expand Up @@ -163,6 +164,13 @@ export const useAppConfig = createPersistStore(
state.lastUpdate = Date.now();
}

if (version < 3.9) {
state.modelConfig.template =
state.modelConfig.template !== DEFAULT_INPUT_TEMPLATE
? state.modelConfig.template
: config?.template ?? DEFAULT_INPUT_TEMPLATE;
}

return state as any;
},
},
Expand Down
56 changes: 6 additions & 50 deletions app/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,48 +83,6 @@ export async function downloadAs(text: string, filename: string) {
}
}

export function compressImage(file: File, maxSize: number): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (readerEvent: any) => {
const image = new Image();
image.onload = () => {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let width = image.width;
let height = image.height;
let quality = 0.9;
let dataUrl;

do {
canvas.width = width;
canvas.height = height;
ctx?.clearRect(0, 0, canvas.width, canvas.height);
ctx?.drawImage(image, 0, 0, width, height);
dataUrl = canvas.toDataURL("image/jpeg", quality);

if (dataUrl.length < maxSize) break;

if (quality > 0.5) {
// Prioritize quality reduction
quality -= 0.1;
} else {
// Then reduce the size
width *= 0.9;
height *= 0.9;
}
} while (dataUrl.length > maxSize);

resolve(dataUrl);
};
image.onerror = reject;
image.src = readerEvent.target.result;
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
}

export function readFromFile() {
return new Promise<string>((res, rej) => {
const fileInput = document.createElement("input");
Expand Down Expand Up @@ -290,16 +248,14 @@ export function getMessageImages(message: RequestMessage): string[] {
}

export function isVisionModel(model: string) {

// Note: This is a better way using the TypeScript feature instead of `&&` or `||` (ts v5.5.0-dev.20240314 I've been using)

const visionKeywords = [
"vision",
"claude-3",
"gemini-1.5-pro",
];
const visionKeywords = ["vision", "claude-3", "gemini-1.5-pro"];

const isGpt4Turbo = model.includes("gpt-4-turbo") && !model.includes("preview");
const isGpt4Turbo =
model.includes("gpt-4-turbo") && !model.includes("preview");

return visionKeywords.some((keyword) => model.includes(keyword)) || isGpt4Turbo;
return (
visionKeywords.some((keyword) => model.includes(keyword)) || isGpt4Turbo
);
}
54 changes: 54 additions & 0 deletions app/utils/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import heic2any from "heic2any";

export function compressImage(file: File, maxSize: number): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (readerEvent: any) => {
const image = new Image();
image.onload = () => {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let width = image.width;
let height = image.height;
let quality = 0.9;
let dataUrl;

do {
canvas.width = width;
canvas.height = height;
ctx?.clearRect(0, 0, canvas.width, canvas.height);
ctx?.drawImage(image, 0, 0, width, height);
dataUrl = canvas.toDataURL("image/jpeg", quality);

if (dataUrl.length < maxSize) break;

if (quality > 0.5) {
// Prioritize quality reduction
quality -= 0.1;
} else {
// Then reduce the size
width *= 0.9;
height *= 0.9;
}
} while (dataUrl.length > maxSize);

resolve(dataUrl);
};
image.onerror = reject;
image.src = readerEvent.target.result;
};
reader.onerror = reject;

if (file.type.includes("heic")) {
heic2any({ blob: file, toType: "image/jpeg" })
.then((blob) => {
reader.readAsDataURL(blob as Blob);
})
.catch((e) => {
reject(e);
});
}

reader.readAsDataURL(file);
});
}
11 changes: 7 additions & 4 deletions app/utils/cloud/upstash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,17 @@ export function createUpstashClient(store: SyncStore) {
}

let url;
if (proxyUrl.length > 0 || proxyUrl === "/") {
let u = new URL(proxyUrl + "/api/upstash/" + path);
const pathPrefix = "/api/upstash/";

try {
let u = new URL(proxyUrl + pathPrefix + path);
// add query params
u.searchParams.append("endpoint", config.endpoint);
url = u.toString();
} else {
url = "/api/upstash/" + path + "?endpoint=" + config.endpoint;
} catch (e) {
url = pathPrefix + path + "?endpoint=" + config.endpoint;
}

return url;
},
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@vercel/speed-insights": "^1.0.2",
"emoji-picker-react": "^4.9.2",
"fuse.js": "^7.0.0",
"heic2any": "^0.0.4",
"html-to-image": "^1.11.11",
"mermaid": "^10.6.1",
"nanoid": "^5.0.3",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3669,6 +3669,11 @@ heap@^0.2.6:
resolved "https://registry.npmmirror.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc"
integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==

heic2any@^0.0.4:
version "0.0.4"
resolved "https://registry.npmmirror.com/heic2any/-/heic2any-0.0.4.tgz#eddb8e6fec53c8583a6e18b65069bb5e8d19028a"
integrity sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA==

highlight.js@~11.7.0:
version "11.7.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.7.0.tgz#3ff0165bc843f8c9bce1fd89e2fda9143d24b11e"
Expand Down
Loading