feat: handle open Jan on HF GGUF repo (#5173)
* feat: handle open Jan on HF GGUF repo * chore: reset retry attempts
This commit is contained in:
parent
817e3175f3
commit
ecef9d7df6
@ -90,7 +90,7 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
|
|||||||
Authorization: `Bearer ${apiKey}`,
|
Authorization: `Bearer ${apiKey}`,
|
||||||
}
|
}
|
||||||
: {},
|
: {},
|
||||||
retry: 4,
|
retry: 10,
|
||||||
})
|
})
|
||||||
return this.api
|
return this.api
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ dirs = "6.0.0"
|
|||||||
sysinfo = "0.34.2"
|
sysinfo = "0.34.2"
|
||||||
ash = "0.38.0"
|
ash = "0.38.0"
|
||||||
nvml-wrapper = "0.10.0"
|
nvml-wrapper = "0.10.0"
|
||||||
|
tauri-plugin-deep-link = "2"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
libloading = "0.8.7"
|
libloading = "0.8.7"
|
||||||
@ -59,3 +60,4 @@ libc = "0.2.172"
|
|||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
tauri-plugin-updater = "2"
|
tauri-plugin-updater = "2"
|
||||||
once_cell = "1.18"
|
once_cell = "1.18"
|
||||||
|
tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] }
|
||||||
|
|||||||
19
src-tauri/Info.plist
Normal file
19
src-tauri/Info.plist
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>jan.ai.app</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>jan.ai.app</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>jan</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -19,6 +19,7 @@
|
|||||||
"log:default",
|
"log:default",
|
||||||
"updater:default",
|
"updater:default",
|
||||||
"dialog:default",
|
"dialog:default",
|
||||||
|
"deep-link:default",
|
||||||
"core:webview:allow-create-webview-window",
|
"core:webview:allow-create-webview-window",
|
||||||
{
|
{
|
||||||
"identifier": "http:default",
|
"identifier": "http:default",
|
||||||
|
|||||||
@ -14,8 +14,16 @@ use reqwest::blocking::Client;
|
|||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
let mut builder = tauri::Builder::default();
|
||||||
.plugin(tauri_plugin_os::init())
|
#[cfg(desktop)]
|
||||||
|
{
|
||||||
|
builder = builder.plugin(tauri_plugin_single_instance::init(|_app, argv, _cwd| {
|
||||||
|
println!("a new app instance was opened with {argv:?} and the deep link event was already triggered");
|
||||||
|
// when defining deep link schemes at runtime, you must also check `argv` here
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
builder.plugin(tauri_plugin_os::init())
|
||||||
|
.plugin(tauri_plugin_deep_link::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_http::init())
|
.plugin(tauri_plugin_http::init())
|
||||||
|
|||||||
@ -68,7 +68,8 @@
|
|||||||
"windows": {
|
"windows": {
|
||||||
"installMode": "passive"
|
"installMode": "passive"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"deep-link": { "schemes": ["jan"] }
|
||||||
},
|
},
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
"@tanstack/react-router": "^1.116.0",
|
"@tanstack/react-router": "^1.116.0",
|
||||||
"@tanstack/react-router-devtools": "^1.116.0",
|
"@tanstack/react-router-devtools": "^1.116.0",
|
||||||
"@tauri-apps/api": "^2.5.0",
|
"@tauri-apps/api": "^2.5.0",
|
||||||
|
"@tauri-apps/plugin-deep-link": "~2",
|
||||||
"@tauri-apps/plugin-dialog": "^2.2.1",
|
"@tauri-apps/plugin-dialog": "^2.2.1",
|
||||||
"@tauri-apps/plugin-opener": "^2.2.7",
|
"@tauri-apps/plugin-opener": "^2.2.7",
|
||||||
"@tauri-apps/plugin-os": "^2.2.1",
|
"@tauri-apps/plugin-os": "^2.2.1",
|
||||||
|
|||||||
@ -13,6 +13,12 @@ import { getMCPConfig } from '@/services/mcp'
|
|||||||
import { useAssistant } from '@/hooks/useAssistant'
|
import { useAssistant } from '@/hooks/useAssistant'
|
||||||
import { getAssistants } from '@/services/assistants'
|
import { getAssistants } from '@/services/assistants'
|
||||||
import { migrateData } from '@/utils/migration'
|
import { migrateData } from '@/utils/migration'
|
||||||
|
import {
|
||||||
|
onOpenUrl,
|
||||||
|
getCurrent as getCurrentDeepLinkUrls,
|
||||||
|
} from '@tauri-apps/plugin-deep-link'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
|
import { route } from '@/constants/routes'
|
||||||
|
|
||||||
export function DataProvider() {
|
export function DataProvider() {
|
||||||
const { setProviders } = useModelProvider()
|
const { setProviders } = useModelProvider()
|
||||||
@ -21,6 +27,7 @@ export function DataProvider() {
|
|||||||
const { checkForUpdate } = useAppUpdater()
|
const { checkForUpdate } = useAppUpdater()
|
||||||
const { setServers } = useMCPServers()
|
const { setServers } = useMCPServers()
|
||||||
const { setAssistants } = useAssistant()
|
const { setAssistants } = useAssistant()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchModels().then((models) => {
|
fetchModels().then((models) => {
|
||||||
@ -39,6 +46,8 @@ export function DataProvider() {
|
|||||||
console.warn('Failed to load assistants, keeping default:', error)
|
console.warn('Failed to load assistants, keeping default:', error)
|
||||||
})
|
})
|
||||||
migrateData()
|
migrateData()
|
||||||
|
getCurrentDeepLinkUrls().then(handleDeepLink)
|
||||||
|
onOpenUrl(handleDeepLink)
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -58,5 +67,27 @@ export function DataProvider() {
|
|||||||
checkForUpdate()
|
checkForUpdate()
|
||||||
}, [checkForUpdate])
|
}, [checkForUpdate])
|
||||||
|
|
||||||
|
const handleDeepLink = (urls: string[] | null) => {
|
||||||
|
if (!urls) return
|
||||||
|
console.log('Received deeplink:', urls)
|
||||||
|
const deeplink = urls[0]
|
||||||
|
if (deeplink) {
|
||||||
|
const url = new URL(deeplink)
|
||||||
|
const params = url.pathname.split('/').filter((str) => str.length > 0)
|
||||||
|
|
||||||
|
if (params.length < 3) return undefined
|
||||||
|
// const action = params[0]
|
||||||
|
// const provider = params[1]
|
||||||
|
const resource = params.slice(1).join('/')
|
||||||
|
// return { action, provider, resource }
|
||||||
|
navigate({
|
||||||
|
to: route.hub,
|
||||||
|
search: {
|
||||||
|
repo: resource,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router'
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
import {
|
||||||
|
createFileRoute,
|
||||||
|
Link,
|
||||||
|
useNavigate,
|
||||||
|
useSearch,
|
||||||
|
} from '@tanstack/react-router'
|
||||||
import { route } from '@/constants/routes'
|
import { route } from '@/constants/routes'
|
||||||
import { useModelSources } from '@/hooks/useModelSources'
|
import { useModelSources } from '@/hooks/useModelSources'
|
||||||
import { cn, fuzzySearch, toGigabytes } from '@/lib/utils'
|
import { cn, fuzzySearch, toGigabytes } from '@/lib/utils'
|
||||||
@ -37,10 +43,15 @@ type ModelProps = {
|
|||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
type SearchParams = {
|
||||||
|
repo: string
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export const Route = createFileRoute(route.hub as any)({
|
export const Route = createFileRoute(route.hub as any)({
|
||||||
component: Hub,
|
component: Hub,
|
||||||
|
validateSearch: (search: Record<string, unknown>): SearchParams => ({
|
||||||
|
repo: search.repo as SearchParams['repo'],
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
const sortOptions = [
|
const sortOptions = [
|
||||||
@ -50,6 +61,7 @@ const sortOptions = [
|
|||||||
|
|
||||||
function Hub() {
|
function Hub() {
|
||||||
const { sources, fetchSources, loading } = useModelSources()
|
const { sources, fetchSources, loading } = useModelSources()
|
||||||
|
const search = useSearch({ from: route.hub as any })
|
||||||
const [searchValue, setSearchValue] = useState('')
|
const [searchValue, setSearchValue] = useState('')
|
||||||
const [sortSelected, setSortSelected] = useState('newest')
|
const [sortSelected, setSortSelected] = useState('newest')
|
||||||
const [expandedModels, setExpandedModels] = useState<Record<string, boolean>>(
|
const [expandedModels, setExpandedModels] = useState<Record<string, boolean>>(
|
||||||
@ -71,6 +83,22 @@ function Hub() {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (search.repo) {
|
||||||
|
setSearchValue(search.repo || '')
|
||||||
|
setIsSearching(true)
|
||||||
|
addModelSourceTimeoutRef.current = setTimeout(() => {
|
||||||
|
addModelSource(search.repo)
|
||||||
|
.then(() => {
|
||||||
|
fetchSources()
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsSearching(false)
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
}, [fetchSources, search])
|
||||||
|
|
||||||
// Sorting functionality
|
// Sorting functionality
|
||||||
const sortedModels = useMemo(() => {
|
const sortedModels = useMemo(() => {
|
||||||
return [...sources].sort((a, b) => {
|
return [...sources].sort((a, b) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user