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

Tauri v2 and mobile platforms #5927

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ For enterprise inquiries, please contact: **[email protected]**
## Features

- **Deploy for free with one-click** on Vercel in under 1 minute
- Compact client (~5MB) on Linux/Windows/MacOS, [download it now](https://github.com/Yidadaa/ChatGPT-Next-Web/releases)
- Compact client (~5MB) on Linux/Windows/MacOS/IOS/Android, [download it now](https://github.com/Yidadaa/ChatGPT-Next-Web/releases)
- Fully compatible with self-deployed LLMs, recommended for use with [RWKV-Runner](https://github.com/josStorer/RWKV-Runner) or [LocalAI](https://github.com/go-skynet/LocalAI)
- Privacy first, all data is stored locally in the browser
- Markdown support: LaTex, mermaid, code highlight, etc.
Expand Down Expand Up @@ -113,7 +113,7 @@ For enterprise inquiries, please contact: **[email protected]**
## 主要功能

- 在 1 分钟内使用 Vercel **免费一键部署**
- 提供体积极小(~5MB)的跨平台客户端(Linux/Windows/MacOS), [下载地址](https://github.com/Yidadaa/ChatGPT-Next-Web/releases)
- 提供体积极小(~5MB)的跨平台客户端(Linux/Windows/MacOS/IOS/Android), [下载地址](https://github.com/Yidadaa/ChatGPT-Next-Web/releases)
- 完整的 Markdown 支持:LaTex 公式、Mermaid 流程图、代码高亮等等
- 精心设计的 UI,响应式设计,支持深色模式,支持 PWA
- 极快的首屏加载速度(~100kb),支持流式响应
Expand Down
4 changes: 2 additions & 2 deletions app/components/exporter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ export function ImagePreviewer(props: {

if (isMobile || (isApp && window.__TAURI__)) {
if (isApp && window.__TAURI__) {
const result = await window.__TAURI__.dialog.save({
const result = await window.__TAURI__.core.dialog.save({
defaultPath: `${props.topic}.png`,
filters: [
{
Expand All @@ -491,7 +491,7 @@ export function ImagePreviewer(props: {
const response = await fetch(blob);
const buffer = await response.arrayBuffer();
const uint8Array = new Uint8Array(buffer);
await window.__TAURI__.fs.writeBinaryFile(result, uint8Array);
await window.__TAURI__.core.fs.writeBinaryFile(result, uint8Array);
showToast(Locale.Download.Success);
} else {
showToast(Locale.Download.Failed);
Expand Down
2 changes: 1 addition & 1 deletion app/config/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const getBuildConfig = () => {

const buildMode = process.env.BUILD_MODE ?? "standalone";
const isApp = !!process.env.BUILD_APP;
const version = "v" + tauriConfig.package.version;
const version = "v" + tauriConfig.version;

const commitInfo = (() => {
try {
Expand Down
54 changes: 28 additions & 26 deletions app/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,34 @@ declare module "*.svg";

declare interface Window {
__TAURI__?: {
writeText(text: string): Promise<void>;
invoke(command: string, payload?: Record<string, unknown>): Promise<any>;
dialog: {
save(options?: Record<string, unknown>): Promise<string | null>;
};
fs: {
writeBinaryFile(path: string, data: Uint8Array): Promise<void>;
writeTextFile(path: string, data: string): Promise<void>;
};
notification: {
requestPermission(): Promise<Permission>;
isPermissionGranted(): Promise<boolean>;
sendNotification(options: string | Options): void;
};
updater: {
checkUpdate(): Promise<UpdateResult>;
installUpdate(): Promise<void>;
onUpdaterEvent(
handler: (status: UpdateStatusResult) => void,
): Promise<UnlistenFn>;
};
http: {
fetch<T>(
url: string,
options?: Record<string, unknown>,
): Promise<Response<T>>;
core: {
writeText(text: string): Promise<void>;
invoke(command: string, payload?: Record<string, unknown>): Promise<any>;
dialog: {
save(options?: Record<string, unknown>): Promise<string | null>;
};
fs: {
writeBinaryFile(path: string, data: Uint8Array): Promise<void>;
writeTextFile(path: string, data: string): Promise<void>;
};
notification: {
requestPermission(): Promise<Permission>;
isPermissionGranted(): Promise<boolean>;
sendNotification(options: string | Options): void;
};
updater: {
checkUpdate(): Promise<UpdateResult>;
installUpdate(): Promise<void>;
onUpdaterEvent(
handler: (status: UpdateStatusResult) => void,
): Promise<UnlistenFn>;
};
http: {
fetch<T>(
url: string,
options?: Record<string, unknown>,
): Promise<Response<T>>;
};
};
};
}
10 changes: 5 additions & 5 deletions app/store/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,22 +89,22 @@ export const useUpdateStore = createPersistStore(
set(() => ({
remoteVersion: remoteId,
}));
if (window.__TAURI__?.notification && isApp) {
if (window.__TAURI__?.core.notification && isApp) {
// Check if notification permission is granted
await window.__TAURI__?.notification
await window.__TAURI__?.core.notification
.isPermissionGranted()
.then((granted) => {
if (!granted) {
return;
} else {
// Request permission to show notifications
window.__TAURI__?.notification
window.__TAURI__?.core.notification
.requestPermission()
.then((permission) => {
if (permission === "granted") {
if (version === remoteId) {
// Show a notification using Tauri
window.__TAURI__?.notification.sendNotification({
window.__TAURI__?.core.notification.sendNotification({
title: "NextChat",
body: `${Locale.Settings.Update.IsLatest}`,
icon: `${ChatGptIcon.src}`,
Expand All @@ -114,7 +114,7 @@ export const useUpdateStore = createPersistStore(
const updateMessage =
Locale.Settings.Update.FoundUpdate(`${remoteId}`);
// Show a notification for the new version using Tauri
window.__TAURI__?.notification.sendNotification({
window.__TAURI__?.core.notification.sendNotification({
title: "NextChat",
body: updateMessage,
icon: `${ChatGptIcon.src}`,
Expand Down
10 changes: 5 additions & 5 deletions app/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function trimTopic(topic: string) {
export async function copyToClipboard(text: string) {
try {
if (window.__TAURI__) {
window.__TAURI__.writeText(text);
window.__TAURI__.core.writeText(text);
} else {
await navigator.clipboard.writeText(text);
}
Expand All @@ -45,7 +45,7 @@ export async function copyToClipboard(text: string) {

export async function downloadAs(text: string, filename: string) {
if (window.__TAURI__) {
const result = await window.__TAURI__.dialog.save({
const result = await window.__TAURI__.core.dialog.save({
defaultPath: `${filename}`,
filters: [
{
Expand All @@ -61,7 +61,7 @@ export async function downloadAs(text: string, filename: string) {

if (result !== null) {
try {
await window.__TAURI__.fs.writeTextFile(result, text);
await window.__TAURI__.core.fs.writeTextFile(result, text);
showToast(Locale.Download.Success);
} catch (error) {
showToast(Locale.Download.Failed);
Expand Down Expand Up @@ -396,11 +396,11 @@ export function getOperationId(operation: {

export function clientUpdate() {
// this a wild for updating client app
return window.__TAURI__?.updater
return window.__TAURI__?.core.updater
.checkUpdate()
.then((updateResult) => {
if (updateResult.shouldUpdate) {
window.__TAURI__?.updater
window.__TAURI__?.core.updater
.installUpdate()
.then((result) => {
showToast(Locale.Settings.Update.Success);
Expand Down
2 changes: 1 addition & 1 deletion app/utils/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function fetch(url: string, options?: RequestInit): Promise<Response> {
for (const item of new Headers(_headers || {})) {
headers[item[0]] = item[1];
}
return window.__TAURI__
return window.__TAURI__.core
.invoke("stream_fetch", {
method: method.toUpperCase(),
url,
Expand Down
15 changes: 15 additions & 0 deletions docs/mobile-build-instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Build Instruction for IOS and Android
## Android
Run command
```
yarn
yarn tauri android build
```
## IOS
IOS build requires Mac and a developer account or ios certificate.
See [here](https://tauri.app/distribute/sign/ios/) for detail.\
After you have the signing requirement. Run command to build
```
yarn
yarn tauri ios build
```
16 changes: 12 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@
"@hello-pangea/dnd": "^16.5.0",
"@next/third-parties": "^14.1.0",
"@svgr/webpack": "^6.5.1",
"@tauri-apps/plugin-clipboard-manager": "^2.2.0",
"@tauri-apps/plugin-dialog": "~2",
"@tauri-apps/plugin-fs": "~2",
"@tauri-apps/plugin-http": "~2",
"@tauri-apps/plugin-notification": "~2",
"@tauri-apps/plugin-shell": "~2",
"@tauri-apps/plugin-updater": "~2",
"@tauri-apps/plugin-window-state": "^2.2.0",
"@vercel/analytics": "^0.1.11",
"@vercel/speed-insights": "^1.0.2",
"axios": "^1.7.5",
Expand All @@ -49,15 +57,15 @@
"remark-breaks": "^3.0.2",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"rt-client": "https://github.com/Azure-Samples/aoai-realtime-audio-sdk/releases/download/js/v0.5.0/rt-client-0.5.0.tgz",
"sass": "^1.59.2",
"spark-md5": "^3.0.2",
"use-debounce": "^9.0.4",
"zustand": "^4.3.8",
"rt-client": "https://github.com/Azure-Samples/aoai-realtime-audio-sdk/releases/download/js/v0.5.0/rt-client-0.5.0.tgz"
"zustand": "^4.3.8"
},
"devDependencies": {
"@tauri-apps/api": "^1.6.0",
"@tauri-apps/cli": "1.5.11",
"@tauri-apps/api": "^2.1.1",
"@tauri-apps/cli": "^2.1.0",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
Expand Down
Loading
Loading