Merge branch 'docs' into update-api-reference
This commit is contained in:
commit
dd5d4aecc1
6
.github/workflows/jan-docs.yml
vendored
6
.github/workflows/jan-docs.yml
vendored
@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
- docs
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/jan-docs.yml'
|
||||
@ -12,6 +13,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
- docs
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/jan-docs.yml'
|
||||
@ -91,13 +93,13 @@ jobs:
|
||||
Preview URL: ${{ steps.deployCloudflarePages.outputs.url }}
|
||||
|
||||
- name: Add Custome Domain file
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/docs' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
run: echo "${{ vars.DOCUSAURUS_DOMAIN }}" > ./docs/build/CNAME
|
||||
|
||||
# Popular action to deploy to GitHub Pages:
|
||||
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus
|
||||
- name: Deploy to GitHub Pages
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/docs' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@ -16,7 +16,6 @@ on:
|
||||
jobs:
|
||||
set-public-provider:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
outputs:
|
||||
public_provider: ${{ steps.set-public-provider.outputs.public_provider }}
|
||||
ref: ${{ steps.set-public-provider.outputs.ref }}
|
||||
|
||||
10
README.md
10
README.md
@ -76,31 +76,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute
|
||||
<tr style="text-align:center">
|
||||
<td style="text-align:center"><b>Experimental (Nightly Build)</b></td>
|
||||
<td style="text-align:center">
|
||||
<a href='https://delta.jan.ai/latest/jan-win-x64-0.4.4-166.exe'>
|
||||
<a href='https://delta.jan.ai/latest/jan-win-x64-0.4.4-180.exe'>
|
||||
<img src='./docs/static/img/windows.png' style="height:14px; width: 14px" />
|
||||
<b>jan.exe</b>
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align:center">
|
||||
<a href='https://delta.jan.ai/latest/jan-mac-x64-0.4.4-166.dmg'>
|
||||
<a href='https://delta.jan.ai/latest/jan-mac-x64-0.4.4-180.dmg'>
|
||||
<img src='./docs/static/img/mac.png' style="height:15px; width: 15px" />
|
||||
<b>Intel</b>
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align:center">
|
||||
<a href='https://delta.jan.ai/latest/jan-mac-arm64-0.4.4-166.dmg'>
|
||||
<a href='https://delta.jan.ai/latest/jan-mac-arm64-0.4.4-180.dmg'>
|
||||
<img src='./docs/static/img/mac.png' style="height:15px; width: 15px" />
|
||||
<b>M1/M2</b>
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align:center">
|
||||
<a href='https://delta.jan.ai/latest/jan-linux-amd64-0.4.4-166.deb'>
|
||||
<a href='https://delta.jan.ai/latest/jan-linux-amd64-0.4.4-180.deb'>
|
||||
<img src='./docs/static/img/linux.png' style="height:14px; width: 14px" />
|
||||
<b>jan.deb</b>
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align:center">
|
||||
<a href='https://delta.jan.ai/latest/jan-linux-x86_64-0.4.4-166.AppImage'>
|
||||
<a href='https://delta.jan.ai/latest/jan-linux-x86_64-0.4.4-180.AppImage'>
|
||||
<img src='./docs/static/img/linux.png' style="height:14px; width: 14px" />
|
||||
<b>jan.AppImage</b>
|
||||
</a>
|
||||
|
||||
5
core/.prettierignore
Normal file
5
core/.prettierignore
Normal file
@ -0,0 +1,5 @@
|
||||
.next/
|
||||
node_modules/
|
||||
dist/
|
||||
*.hbs
|
||||
*.mdx
|
||||
@ -265,19 +265,22 @@ export const downloadModel = async (
|
||||
const modelBinaryPath = join(directoryPath, modelId)
|
||||
|
||||
const request = require('request')
|
||||
const rq = request({ url: model.source_url, strictSSL, proxy })
|
||||
const progress = require('request-progress')
|
||||
|
||||
for (const source of model.sources) {
|
||||
const rq = request({ url: source, strictSSL, proxy })
|
||||
progress(rq, {})
|
||||
.on('progress', function (state: any) {
|
||||
console.log('progress', JSON.stringify(state, null, 2))
|
||||
console.debug('progress', JSON.stringify(state, null, 2))
|
||||
})
|
||||
.on('error', function (err: Error) {
|
||||
console.error('error', err)
|
||||
})
|
||||
.on('end', function () {
|
||||
console.log('end')
|
||||
console.debug('end')
|
||||
})
|
||||
.pipe(fs.createWriteStream(modelBinaryPath))
|
||||
}
|
||||
|
||||
return {
|
||||
message: `Starting download ${modelId}`,
|
||||
|
||||
@ -21,6 +21,11 @@ export enum InferenceEngine {
|
||||
hf_endpoint = 'hf_endpoint',
|
||||
}
|
||||
|
||||
export type ModelArtifact = {
|
||||
filename: string
|
||||
url: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Model type defines the shape of a model object.
|
||||
* @stored
|
||||
@ -45,7 +50,7 @@ export type Model = {
|
||||
/**
|
||||
* The model download source. It can be an external url or a local filepath.
|
||||
*/
|
||||
source_url: string
|
||||
sources: ModelArtifact[]
|
||||
|
||||
/**
|
||||
* The model identifier, which can be referenced in the API endpoints.
|
||||
@ -107,6 +112,8 @@ export type ModelSettingParams = {
|
||||
system_prompt?: string
|
||||
ai_prompt?: string
|
||||
user_prompt?: string
|
||||
llama_model_path?: string
|
||||
mmproj?: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -56,7 +56,6 @@ jan/ # Jan root folder
|
||||
|
||||
- Each `model` folder contains a `model.json` file, which is a representation of a model.
|
||||
- `model.json` contains metadata and default parameters used to run a model.
|
||||
- The only required field is `source_url`.
|
||||
|
||||
### Example
|
||||
|
||||
@ -64,36 +63,43 @@ Here's a standard example `model.json` for a GGUF model.
|
||||
|
||||
```js
|
||||
{
|
||||
"id": "zephyr-7b", // Defaults to foldername
|
||||
"object": "model", // Defaults to "model"
|
||||
"source_url": "https://huggingface.co/TheBloke/zephyr-7B-beta-GGUF/blob/main/zephyr-7b-beta.Q4_K_M.gguf",
|
||||
"name": "Zephyr 7B", // Defaults to foldername
|
||||
"owned_by": "you", // Defaults to "you"
|
||||
"version": "1", // Defaults to 1
|
||||
"created": 1231231, // Defaults to file creation time
|
||||
"description": null, // Defaults to null
|
||||
"state": enum[null, "ready"]
|
||||
"format": "ggufv3", // Defaults to "ggufv3"
|
||||
"engine": "nitro", // engine_id specified in jan/engine folder
|
||||
"engine_parameters": { // Engine parameters inside model.json can override
|
||||
"ctx_len": 2048, // the value inside the base engine.json
|
||||
"id": "zephyr-7b", // Defaults to foldername
|
||||
"object": "model", // Defaults to "model"
|
||||
"sources": [
|
||||
{
|
||||
"filename": "zephyr-7b-beta.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/zephyr-7B-beta-GGUF/blob/main/zephyr-7b-beta.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"name": "Zephyr 7B", // Defaults to foldername
|
||||
"owned_by": "you", // Defaults to "you"
|
||||
"version": "1", // Defaults to 1
|
||||
"created": 1231231, // Defaults to file creation time
|
||||
"description": null, // Defaults to null
|
||||
"format": "ggufv3", // Defaults to "ggufv3"
|
||||
"engine": "nitro", // engine_id specified in jan/engine folder
|
||||
"engine_parameters": {
|
||||
// Engine parameters inside model.json can override
|
||||
"ctx_len": 4096, // the value inside the base engine.json
|
||||
"ngl": 100,
|
||||
"embedding": true,
|
||||
"n_parallel": 4,
|
||||
},
|
||||
"model_parameters": { // Models are called parameters
|
||||
"n_parallel": 4
|
||||
},
|
||||
"model_parameters": {
|
||||
// Models are called parameters
|
||||
"stream": true,
|
||||
"max_tokens": 2048,
|
||||
"max_tokens": 4096,
|
||||
"stop": ["<endofstring>"], // This usually can be left blank, only used with specific need from model author
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0,
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95
|
||||
},
|
||||
"metadata": {}, // Defaults to {}
|
||||
"assets": [ // Defaults to current dir
|
||||
"file://.../zephyr-7b-q4_k_m.bin",
|
||||
]
|
||||
},
|
||||
"metadata": {}, // Defaults to {}
|
||||
"assets": [
|
||||
// Defaults to current dir
|
||||
"file://.../zephyr-7b-q4_k_m.bin"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -31,7 +31,6 @@ In this section, we will show you how to import a GGUF model from [HuggingFace](
|
||||
|
||||
## Manually Importing a Downloaded Model (nightly versions and v0.4.4+)
|
||||
|
||||
|
||||
### 1. Create a Model Folder
|
||||
|
||||
Navigate to the `~/jan/models` folder. You can find this folder by going to `App Settings` > `Advanced` > `Open App Directory`.
|
||||
@ -190,14 +189,18 @@ Edit `model.json` and include the following configurations:
|
||||
- Ensure the filename must be `model.json`.
|
||||
- Ensure the `id` property matches the folder name you created.
|
||||
- Ensure the GGUF filename should match the `id` property exactly.
|
||||
- Ensure the `source_url` property is the direct binary download link ending in `.gguf`. In HuggingFace, you can find the direct links in the `Files and versions` tab.
|
||||
- Ensure the `source.url` property is the direct binary download link ending in `.gguf`. In HuggingFace, you can find the direct links in the `Files and versions` tab.
|
||||
- Ensure you are using the correct `prompt_template`. This is usually provided in the HuggingFace model's description page.
|
||||
- Ensure the `state` property is set to `ready`.
|
||||
|
||||
```json title="model.json"
|
||||
{
|
||||
// highlight-start
|
||||
"source_url": "https://huggingface.co/janhq/trinity-v1-GGUF/resolve/main/trinity-v1.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "trinity-v1.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/janhq/trinity-v1-GGUF/resolve/main/trinity-v1.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "trinity-v1-7b",
|
||||
// highlight-end
|
||||
"object": "model",
|
||||
@ -208,7 +211,8 @@ Edit `model.json` and include the following configurations:
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
// highlight-next-line
|
||||
"prompt_template": "{system_message}\n### Instruction:\n{prompt}\n### Response:"
|
||||
"prompt_template": "{system_message}\n### Instruction:\n{prompt}\n### Response:",
|
||||
"llama_model_path": "trinity-v1.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"max_tokens": 4096
|
||||
@ -218,9 +222,7 @@ Edit `model.json` and include the following configurations:
|
||||
"tags": ["7B", "Merged"],
|
||||
"size": 4370000000
|
||||
},
|
||||
"engine": "nitro",
|
||||
// highlight-next-line
|
||||
"state": "ready"
|
||||
"engine": "nitro"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -40,7 +40,12 @@ Navigate to the `~/jan/models` folder. Create a folder named `gpt-3.5-turbo-16k`
|
||||
|
||||
```json title="~/jan/models/gpt-3.5-turbo-16k/model.json"
|
||||
{
|
||||
"source_url": "https://openai.com",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "openai",
|
||||
"url": "https://openai.com"
|
||||
}
|
||||
],
|
||||
// highlight-next-line
|
||||
"id": "gpt-3.5-turbo-16k",
|
||||
"object": "model",
|
||||
@ -55,8 +60,7 @@ Navigate to the `~/jan/models` folder. Create a folder named `gpt-3.5-turbo-16k`
|
||||
"author": "OpenAI",
|
||||
"tags": ["General", "Big Context Length"]
|
||||
},
|
||||
"engine": "openai",
|
||||
"state": "ready"
|
||||
"engine": "openai"
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
@ -118,7 +122,12 @@ Navigate to the `~/jan/models` folder. Create a folder named `mistral-ins-7b-q4`
|
||||
|
||||
```json title="~/jan/models/mistral-ins-7b-q4/model.json"
|
||||
{
|
||||
"source_url": "https://jan.ai",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "janai",
|
||||
"url": "https://jan.ai"
|
||||
}
|
||||
],
|
||||
// highlight-next-line
|
||||
"id": "mistral-ins-7b-q4",
|
||||
"object": "model",
|
||||
@ -134,8 +143,7 @@ Navigate to the `~/jan/models` folder. Create a folder named `mistral-ins-7b-q4`
|
||||
"tags": ["remote", "awesome"]
|
||||
},
|
||||
// highlight-start
|
||||
"engine": "openai",
|
||||
"state": "ready"
|
||||
"engine": "openai"
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
@ -49,7 +49,12 @@ Navigate to the `~/jan/models` folder. Create a folder named `<openrouter-modeln
|
||||
|
||||
```json title="~/jan/models/openrouter-dolphin-mixtral-8x7b/model.json"
|
||||
{
|
||||
"source_url": "https://openrouter.ai/",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "openrouter",
|
||||
"url": "https://openrouter.ai/"
|
||||
}
|
||||
],
|
||||
"id": "cognitivecomputations/dolphin-mixtral-8x7b",
|
||||
"object": "model",
|
||||
"name": "Dolphin 2.6 Mixtral 8x7B",
|
||||
@ -63,8 +68,7 @@ Navigate to the `~/jan/models` folder. Create a folder named `<openrouter-modeln
|
||||
"tags": ["General", "Big Context Length"]
|
||||
},
|
||||
// highlight-start
|
||||
"engine": "openai",
|
||||
"state": "ready"
|
||||
"engine": "openai"
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
@ -59,7 +59,12 @@ Navigate to the `~/jan/models` folder. Create a folder named `<your-deployment-n
|
||||
|
||||
```json title="~/jan/models/gpt-35-hieu-jan/model.json"
|
||||
{
|
||||
"source_url": "https://hieujan.openai.azure.com",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "azure_openai",
|
||||
"url": "https://hieujan.openai.azure.com"
|
||||
}
|
||||
],
|
||||
// highlight-next-line
|
||||
"id": "gpt-35-hieu-jan",
|
||||
"object": "model",
|
||||
@ -75,8 +80,7 @@ Navigate to the `~/jan/models` folder. Create a folder named `<your-deployment-n
|
||||
"tags": ["General", "Big Context Length"]
|
||||
},
|
||||
// highlight-start
|
||||
"engine": "openai",
|
||||
"state": "ready"
|
||||
"engine": "openai"
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
@ -17,4 +17,8 @@ keywords:
|
||||
]
|
||||
---
|
||||
|
||||
1. You may receive an error response `Error occurred: Unexpected token '<', "<!DOCTYPE"...is not valid JSON`, when you start a chat with OpenAI models. Using a VPN may help fix the issue.
|
||||
You may receive an error response `Error occurred: Unexpected token '<', "<!DOCTYPE"...is not valid JSON`, when you start a chat with OpenAI models.
|
||||
|
||||
1. Check that you added an OpenAI API key. You can get an API key from OpenAI's [developer platform](https://platform.openai.com/). Alternatively, we recommend you download a local model from Jan Hub, which remains free to use and runs on your own computer!
|
||||
|
||||
2. Using a VPN may help fix the issue.
|
||||
|
||||
@ -1 +1 @@
|
||||
0.2.11
|
||||
0.2.12
|
||||
|
||||
@ -119,11 +119,19 @@ async function runModel(
|
||||
wrapper.model.settings.ai_prompt = prompt.ai_prompt;
|
||||
}
|
||||
|
||||
const modelFolderPath = path.join(janRoot, "models", wrapper.model.id);
|
||||
const modelPath = wrapper.model.settings.llama_model_path
|
||||
? path.join(modelFolderPath, wrapper.model.settings.llama_model_path)
|
||||
: currentModelFile;
|
||||
|
||||
currentSettings = {
|
||||
llama_model_path: currentModelFile,
|
||||
...wrapper.model.settings,
|
||||
llama_model_path: modelPath,
|
||||
// This is critical and requires real CPU physical core count (or performance core)
|
||||
cpu_threads: Math.max(1, nitroResourceProbe.numCpuPhysicalCore),
|
||||
...(wrapper.model.settings.mmproj && {
|
||||
mmproj: path.join(modelFolderPath, wrapper.model.settings.mmproj),
|
||||
}),
|
||||
};
|
||||
console.log(currentSettings);
|
||||
return runNitroAndLoadModel();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@janhq/model-extension",
|
||||
"version": "1.0.22",
|
||||
"version": "1.0.23",
|
||||
"description": "Model Management Extension provides model exploration and seamless downloads",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/module.js",
|
||||
|
||||
@ -80,16 +80,34 @@ export default class JanModelExtension extends ModelExtension {
|
||||
const modelDirPath = await joinPath([JanModelExtension._homeDir, model.id])
|
||||
if (!(await fs.existsSync(modelDirPath))) await fs.mkdirSync(modelDirPath)
|
||||
|
||||
// try to retrieve the download file name from the source url
|
||||
// if it fails, use the model ID as the file name
|
||||
const extractedFileName = await model.source_url.split('/').pop()
|
||||
if (model.sources.length > 1) {
|
||||
// path to model binaries
|
||||
for (const source of model.sources) {
|
||||
let path = this.extractFileName(source.url)
|
||||
if (source.filename) {
|
||||
path = await joinPath([modelDirPath, source.filename])
|
||||
}
|
||||
|
||||
downloadFile(source.url, path, network)
|
||||
}
|
||||
} else {
|
||||
const fileName = this.extractFileName(model.sources[0]?.url)
|
||||
const path = await joinPath([modelDirPath, fileName])
|
||||
downloadFile(model.sources[0]?.url, path, network)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* try to retrieve the download file name from the source url
|
||||
*/
|
||||
private extractFileName(url: string): string {
|
||||
const extractedFileName = url.split('/').pop()
|
||||
const fileName = extractedFileName
|
||||
.toLowerCase()
|
||||
.endsWith(JanModelExtension._supportedModelFormat)
|
||||
? extractedFileName
|
||||
: model.id
|
||||
const path = await joinPath([modelDirPath, fileName])
|
||||
downloadFile(model.source_url, path, network)
|
||||
: extractedFileName + JanModelExtension._supportedModelFormat
|
||||
return fileName
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,6 +116,7 @@ export default class JanModelExtension extends ModelExtension {
|
||||
* @returns {Promise<void>} A promise that resolves when the download has been cancelled.
|
||||
*/
|
||||
async cancelModelDownload(modelId: string): Promise<void> {
|
||||
const model = await this.getConfiguredModels()
|
||||
return abortDownload(
|
||||
await joinPath([JanModelExtension._homeDir, modelId, modelId])
|
||||
).then(async () => {
|
||||
@ -163,15 +182,16 @@ export default class JanModelExtension extends ModelExtension {
|
||||
.then((files: string[]) => {
|
||||
// or model binary exists in the directory
|
||||
// model binary name can match model ID or be a .gguf file and not be an incompleted model file
|
||||
// TODO: Check diff between urls, filenames
|
||||
return (
|
||||
files.includes(modelDir) ||
|
||||
files.some(
|
||||
files.filter(
|
||||
(file) =>
|
||||
file
|
||||
.toLowerCase()
|
||||
.includes(JanModelExtension._supportedModelFormat) &&
|
||||
!file.endsWith(JanModelExtension._incompletedModelFileName)
|
||||
)
|
||||
)?.length >= model.sources.length
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -198,7 +218,6 @@ export default class JanModelExtension extends ModelExtension {
|
||||
|
||||
const readJsonPromises = allDirectories.map(async (dirName) => {
|
||||
// filter out directories that don't match the selector
|
||||
|
||||
// read model.json
|
||||
const jsonPath = await joinPath([
|
||||
JanModelExtension._homeDir,
|
||||
@ -226,7 +245,21 @@ export default class JanModelExtension extends ModelExtension {
|
||||
const modelData = results.map((result) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
try {
|
||||
return result.value as Model
|
||||
// This to ensure backward compatibility with `model.json` with `source_url`
|
||||
const tmpModel =
|
||||
typeof result.value === 'object'
|
||||
? result.value
|
||||
: JSON.parse(result.value)
|
||||
if (tmpModel['source_url'] != null) {
|
||||
tmpModel['source'] = [
|
||||
{
|
||||
filename: tmpModel.id,
|
||||
url: tmpModel['source_url'],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return tmpModel as Model
|
||||
} catch {
|
||||
console.debug(`Unable to parse model metadata: ${result.value}`)
|
||||
return undefined
|
||||
|
||||
33
models/bakllava-1/model.json
Normal file
33
models/bakllava-1/model.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"filename": "ggml-model-q5_k.gguf",
|
||||
"url": "https://huggingface.co/mys/ggml_bakllava-1/resolve/main/ggml-model-q5_k.gguf"
|
||||
},
|
||||
{
|
||||
"filename": "mmproj-model-f16.gguf",
|
||||
"url": "https://huggingface.co/mys/ggml_bakllava-1/resolve/main/mmproj-model-f16.gguf"
|
||||
}
|
||||
],
|
||||
"id": "bakllava-1",
|
||||
"object": "model",
|
||||
"name": "BakLlava 1",
|
||||
"version": "1.0",
|
||||
"description": "BakLlava 1 can bring vision understanding to Jan",
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "\n### Instruction:\n{prompt}\n### Response:\n",
|
||||
"llama_model_path": "ggml-model-q5_k.gguf",
|
||||
"mmproj": "mmproj-model-f16.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"max_tokens": 4096
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Mys",
|
||||
"tags": ["Vision"],
|
||||
"size": 5750000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Nous-Capybara-34B-GGUF/resolve/main/nous-capybara-34b.Q5_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "nous-capybara-34b.Q5_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Nous-Capybara-34B-GGUF/resolve/main/nous-capybara-34b.Q5_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "capybara-34b",
|
||||
"object": "model",
|
||||
"name": "Capybara 200k 34B Q5",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "USER:\n{prompt}\nASSISTANT:"
|
||||
"prompt_template": "USER:\n{prompt}\nASSISTANT:",
|
||||
"llama_model_path": "nous-capybara-34b.Q5_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 24320000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/beowolx/CodeNinja-1.0-OpenChat-7B-GGUF/resolve/main/codeninja-1.0-openchat-7b.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "codeninja-1.0-openchat-7b.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/beowolx/CodeNinja-1.0-OpenChat-7B-GGUF/resolve/main/codeninja-1.0-openchat-7b.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "codeninja-1.0-7b",
|
||||
"object": "model",
|
||||
"name": "CodeNinja 7B Q4",
|
||||
@ -8,14 +13,14 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "GPT4 Correct User: {prompt}<|end_of_turn|>GPT4 Correct Assistant:"
|
||||
"prompt_template": "GPT4 Correct User: {prompt}<|end_of_turn|>GPT4 Correct Assistant:",
|
||||
"llama_model_path": "codeninja-1.0-openchat-7b.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": ["<|end_of_turn|>"],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
@ -25,5 +30,4 @@
|
||||
"size": 4370000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,7 +2,12 @@
|
||||
"object": "model",
|
||||
"version": 1,
|
||||
"format": "gguf",
|
||||
"source_url": "N/A",
|
||||
"sources": [
|
||||
{
|
||||
"url": "N/A",
|
||||
"filename": "N/A"
|
||||
}
|
||||
],
|
||||
"id": "N/A",
|
||||
"name": "N/A",
|
||||
"created": 0,
|
||||
@ -10,7 +15,8 @@
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"embedding": false,
|
||||
"prompt_template": "{system_message}\n### Instruction: {prompt}\n### Response:"
|
||||
"prompt_template": "{system_message}\n### Instruction: {prompt}\n### Response:",
|
||||
"llama_model_path": "N/A"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/deepseek-coder-1.3b-instruct-GGUF/resolve/main/deepseek-coder-1.3b-instruct.Q8_0.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "deepseek-coder-1.3b-instruct.Q8_0.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/deepseek-coder-1.3b-instruct-GGUF/resolve/main/deepseek-coder-1.3b-instruct.Q8_0.gguf"
|
||||
}
|
||||
],
|
||||
"id": "deepseek-coder-1.3b",
|
||||
"object": "model",
|
||||
"name": "Deepseek Coder 1.3B Q8",
|
||||
@ -9,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "### Instruction:\n{prompt}\n### Response:"
|
||||
"prompt_template": "### Instruction:\n{prompt}\n### Response:",
|
||||
"llama_model_path": "deepseek-coder-1.3b-instruct.Q8_0.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -26,4 +31,4 @@
|
||||
"size": 1430000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/deepseek-coder-33B-instruct-GGUF/resolve/main/deepseek-coder-33b-instruct.Q5_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "deepseek-coder-33b-instruct.Q5_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/deepseek-coder-33B-instruct-GGUF/resolve/main/deepseek-coder-33b-instruct.Q5_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "deepseek-coder-34b",
|
||||
"object": "model",
|
||||
"name": "Deepseek Coder 33B Q5",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "### Instruction:\n{prompt}\n### Response:"
|
||||
"prompt_template": "### Instruction:\n{prompt}\n### Response:",
|
||||
"llama_model_path": "deepseek-coder-33b-instruct.Q5_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 19940000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/dolphin-2.7-mixtral-8x7b-GGUF/resolve/main/dolphin-2.7-mixtral-8x7b.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "dolphin-2.7-mixtral-8x7b.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/dolphin-2.7-mixtral-8x7b-GGUF/resolve/main/dolphin-2.7-mixtral-8x7b.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "dolphin-2.7-mixtral-8x7b",
|
||||
"object": "model",
|
||||
"name": "Dolphin 8x7B Q4",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant"
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant",
|
||||
"llama_model_path": "dolphin-2.7-mixtral-8x7b.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,4 +31,4 @@
|
||||
"size": 26440000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
{
|
||||
"source_url": "https://openai.com",
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://openai.com"
|
||||
}
|
||||
],
|
||||
"id": "gpt-3.5-turbo-16k-0613",
|
||||
"object": "model",
|
||||
"name": "OpenAI GPT 3.5 Turbo 16k 0613",
|
||||
@ -12,7 +16,5 @@
|
||||
"author": "OpenAI",
|
||||
"tags": ["General", "Big Context Length"]
|
||||
},
|
||||
"engine": "openai",
|
||||
"state": "ready"
|
||||
"engine": "openai"
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
{
|
||||
"source_url": "https://openai.com",
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://openai.com"
|
||||
}
|
||||
],
|
||||
"id": "gpt-3.5-turbo",
|
||||
"object": "model",
|
||||
"name": "OpenAI GPT 3.5 Turbo",
|
||||
@ -12,7 +16,5 @@
|
||||
"author": "OpenAI",
|
||||
"tags": ["General", "Big Context Length"]
|
||||
},
|
||||
"engine": "openai",
|
||||
"state": "ready"
|
||||
"engine": "openai"
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
{
|
||||
"source_url": "https://openai.com",
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://openai.com"
|
||||
}
|
||||
],
|
||||
"id": "gpt-4",
|
||||
"object": "model",
|
||||
"name": "OpenAI GPT 4",
|
||||
@ -12,7 +16,5 @@
|
||||
"author": "OpenAI",
|
||||
"tags": ["General", "Big Context Length"]
|
||||
},
|
||||
"engine": "openai",
|
||||
"state": "ready"
|
||||
"engine": "openai"
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Llama-2-70B-Chat-GGUF/resolve/main/llama-2-70b-chat.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "llama-2-70b-chat.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Llama-2-70B-Chat-GGUF/resolve/main/llama-2-70b-chat.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "llama2-chat-70b-q4",
|
||||
"object": "model",
|
||||
"name": "Llama 2 Chat 70B Q4",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "[INST] <<SYS>>\n{system_message}<</SYS>>\n{prompt}[/INST]"
|
||||
"prompt_template": "[INST] <<SYS>>\n{system_message}<</SYS>>\n{prompt}[/INST]",
|
||||
"llama_model_path": "llama-2-70b-chat.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 43920000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "llama-2-7b-chat.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "llama2-chat-7b-q4",
|
||||
"object": "model",
|
||||
"name": "Llama 2 Chat 7B Q4",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "[INST] <<SYS>>\n{system_message}<</SYS>>\n{prompt}[/INST]"
|
||||
"prompt_template": "[INST] <<SYS>>\n{system_message}<</SYS>>\n{prompt}[/INST]",
|
||||
"llama_model_path": "llama-2-7b-chat.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 4080000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
33
models/llava-1.5-13b-q5/model.json
Normal file
33
models/llava-1.5-13b-q5/model.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"filename": "ggml-model-q5_k.gguf",
|
||||
"url": "https://huggingface.co/mys/ggml_llava-v1.5-13b/resolve/main/ggml-model-q5_k.gguf"
|
||||
},
|
||||
{
|
||||
"filename": "mmproj-model-f16.gguf",
|
||||
"url": "https://huggingface.co/mys/ggml_llava-v1.5-13b/resolve/main/mmproj-model-f16.gguf"
|
||||
}
|
||||
],
|
||||
"id": "llava-1.5-13b-q5",
|
||||
"object": "model",
|
||||
"name": "LlaVa 1.5 13B Q5 K",
|
||||
"version": "1.0",
|
||||
"description": "LlaVa 1.5 can bring vision understanding to Jan",
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "\n### Instruction:\n{prompt}\n### Response:\n",
|
||||
"llama_model_path": "ggml-model-q5_k.gguf",
|
||||
"mmproj": "mmproj-model-f16.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"max_tokens": 4096
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Mys",
|
||||
"tags": ["Vision"],
|
||||
"size": 9850000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
33
models/llava-1.5-7b-q5/model.json
Normal file
33
models/llava-1.5-7b-q5/model.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"filename": "ggml-model-q5_k.gguf",
|
||||
"url": "https://huggingface.co/mys/ggml_llava-v1.5-7b/resolve/main/ggml-model-q5_k.gguf"
|
||||
},
|
||||
{
|
||||
"filename": "mmproj-model-f16.gguf",
|
||||
"url": "https://huggingface.co/mys/ggml_llava-v1.5-7b/resolve/main/mmproj-model-f16.gguf"
|
||||
}
|
||||
],
|
||||
"id": "llava-1.5-7b-q5",
|
||||
"object": "model",
|
||||
"name": "LlaVa 1.5 7B Q5 K",
|
||||
"version": "1.0",
|
||||
"description": "LlaVa 1.5 can bring vision understanding to Jan",
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "\n### Instruction:\n{prompt}\n### Response:\n",
|
||||
"llama_model_path": "ggml-model-q5_k.gguf",
|
||||
"mmproj": "mmproj-model-f16.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"max_tokens": 4096
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Mys",
|
||||
"tags": ["Vision"],
|
||||
"size": 5400000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF/resolve/main/mistral-7b-instruct-v0.2.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "mistral-7b-instruct-v0.2.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF/resolve/main/mistral-7b-instruct-v0.2.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "mistral-ins-7b-q4",
|
||||
"object": "model",
|
||||
"name": "Mistral Instruct 7B Q4",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "[INST] {prompt} [/INST]"
|
||||
"prompt_template": "[INST] {prompt} [/INST]",
|
||||
"llama_model_path": "mistral-7b-instruct-v0.2.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -26,5 +32,4 @@
|
||||
"cover": "https://raw.githubusercontent.com/janhq/jan/main/models/mistral-ins-7b-q4/cover.png"
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF/resolve/main/mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF/resolve/main/mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "mixtral-8x7b-instruct",
|
||||
"object": "model",
|
||||
"name": "Mixtral 8x7B Instruct Q4",
|
||||
@ -8,14 +13,14 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "[INST] {prompt} [/INST]"
|
||||
"prompt_template": "[INST] {prompt} [/INST]",
|
||||
"llama_model_path": "mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": [],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
@ -25,4 +30,4 @@
|
||||
"size": 26440000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/NeverSleep/Noromaid-7b-v0.1.1-GGUF/resolve/main/Noromaid-7b-v0.1.1.q5_k_m.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "Noromaid-7b-v0.1.1.q5_k_m.gguf",
|
||||
"url": "https://huggingface.co/NeverSleep/Noromaid-7b-v0.1.1-GGUF/resolve/main/Noromaid-7b-v0.1.1.q5_k_m.gguf"
|
||||
}
|
||||
],
|
||||
"id": "noromaid-7b",
|
||||
"object": "model",
|
||||
"name": "Noromaid 7B Q5",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "### Instruction:{prompt}\n### Response:"
|
||||
"prompt_template": "### Instruction:{prompt}\n### Response:",
|
||||
"llama_model_path": "Noromaid-7b-v0.1.1.q5_k_m.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 4370000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/openchat-3.5-1210-GGUF/resolve/main/openchat-3.5-1210.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "openchat-3.5-1210.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/openchat-3.5-1210-GGUF/resolve/main/openchat-3.5-1210.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "openchat-3.5-7b",
|
||||
"object": "model",
|
||||
"name": "Openchat-3.5 7B Q4",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "GPT4 Correct User: {prompt}<|end_of_turn|>GPT4 Correct Assistant:"
|
||||
"prompt_template": "GPT4 Correct User: {prompt}<|end_of_turn|>GPT4 Correct Assistant:",
|
||||
"llama_model_path": "openchat-3.5-1210.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,4 +31,4 @@
|
||||
"size": 4370000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/janhq/openhermes-2.5-neural-chat-v3-3-slerp-GGUF/resolve/main/openhermes-2.5-neural-chat-v3-3-slerp.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "openhermes-2.5-neural-chat-v3-3-slerp.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/janhq/openhermes-2.5-neural-chat-v3-3-slerp-GGUF/resolve/main/openhermes-2.5-neural-chat-v3-3-slerp.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "openhermes-neural-7b",
|
||||
"object": "model",
|
||||
"name": "OpenHermes Neural 7B Q4",
|
||||
@ -8,14 +13,14 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant"
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant",
|
||||
"llama_model_path": "openhermes-2.5-neural-chat-v3-3-slerp.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": [],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
@ -26,4 +31,4 @@
|
||||
"cover": "https://raw.githubusercontent.com/janhq/jan/main/models/openhermes-neural-7b/cover.png"
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/phi-2-GGUF/resolve/main/phi-2.Q8_0.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "phi-2.Q8_0.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/phi-2-GGUF/resolve/main/phi-2.Q8_0.gguf"
|
||||
}
|
||||
],
|
||||
"id": "phi-2-3b",
|
||||
"object": "model",
|
||||
"name": "Phi-2 3B Q8",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "Intruct:\n{prompt}\nOutput:"
|
||||
"prompt_template": "Intruct:\n{prompt}\nOutput:",
|
||||
"llama_model_path": "phi-2.Q8_0.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -21,9 +27,8 @@
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Microsoft",
|
||||
"tags": ["3B","Foundational Model"],
|
||||
"tags": ["3B", "Foundational Model"],
|
||||
"size": 2960000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Phind-CodeLlama-34B-v2-GGUF/resolve/main/phind-codellama-34b-v2.Q5_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "phind-codellama-34b-v2.Q5_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Phind-CodeLlama-34B-v2-GGUF/resolve/main/phind-codellama-34b-v2.Q5_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "phind-34b",
|
||||
"object": "model",
|
||||
"name": "Phind 34B Q5",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "### System Prompt\n{system_message}\n### User Message\n{prompt}\n### Assistant"
|
||||
"prompt_template": "### System Prompt\n{system_message}\n### User Message\n{prompt}\n### Assistant",
|
||||
"llama_model_path": "phind-codellama-34b-v2.Q5_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 20220000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/janhq/Solar-10.7B-SLERP-GGUF/resolve/main/solar-10.7b-slerp.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "solar-10.7b-slerp.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/janhq/Solar-10.7B-SLERP-GGUF/resolve/main/solar-10.7b-slerp.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "solar-10.7b-slerp",
|
||||
"object": "model",
|
||||
"name": "Solar Slerp 10.7B Q4",
|
||||
@ -8,22 +13,21 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "### User: {prompt}\n### Assistant:"
|
||||
"prompt_template": "### User: {prompt}\n### Assistant:",
|
||||
"llama_model_path": "solar-10.7b-slerp.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": [],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Jan",
|
||||
"tags": ["13B","Finetuned"],
|
||||
"tags": ["13B", "Finetuned"],
|
||||
"size": 6360000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Starling-LM-7B-alpha-GGUF/resolve/main/starling-lm-7b-alpha.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "starling-lm-7b-alpha.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Starling-LM-7B-alpha-GGUF/resolve/main/starling-lm-7b-alpha.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "starling-7b",
|
||||
"object": "model",
|
||||
"name": "Starling alpha 7B Q4",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "GPT4 User: {prompt}<|end_of_turn|>GPT4 Assistant:"
|
||||
"prompt_template": "GPT4 User: {prompt}<|end_of_turn|>GPT4 Assistant:",
|
||||
"llama_model_path": "starling-lm-7b-alpha.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -21,9 +27,8 @@
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Berkeley-nest, The Bloke",
|
||||
"tags": ["7B","Finetuned"],
|
||||
"tags": ["7B", "Finetuned"],
|
||||
"size": 4370000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/janhq/stealth-v1.3-GGUF/resolve/main/stealth-v1.3.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "stealth-v1.3.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/janhq/stealth-v1.3-GGUF/resolve/main/stealth-v1.3.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "stealth-v1.2-7b",
|
||||
"object": "model",
|
||||
"name": "Stealth 7B Q4",
|
||||
@ -8,25 +13,21 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant"
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant",
|
||||
"llama_model_path": "stealth-v1.3.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": [],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Jan",
|
||||
"tags": [
|
||||
"7B",
|
||||
"Finetuned",
|
||||
"Featured"
|
||||
],
|
||||
"tags": ["7B", "Finetuned", "Featured"],
|
||||
"size": 4370000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "tinyllama-1.1b",
|
||||
"object": "model",
|
||||
"name": "TinyLlama Chat 1.1B Q4",
|
||||
@ -7,8 +12,9 @@
|
||||
"description": "TinyLlama is a tiny model with only 1.1B. It's a good model for less powerful computers.",
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 2048,
|
||||
"prompt_template": "<|system|>\n{system_message}<|user|>\n{prompt}<|assistant|>"
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "<|system|>\n{system_message}<|user|>\n{prompt}<|assistant|>",
|
||||
"llama_model_path": "tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/janhq/trinity-v1.2-GGUF/resolve/main/trinity-v1.2.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "trinity-v1.2.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/janhq/trinity-v1.2-GGUF/resolve/main/trinity-v1.2.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "trinity-v1.2-7b",
|
||||
"object": "model",
|
||||
"name": "Trinity-v1.2 7B Q4",
|
||||
@ -8,14 +13,14 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant"
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant",
|
||||
"llama_model_path": "trinity-v1.2.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": [],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
@ -26,4 +31,4 @@
|
||||
"cover": "https://raw.githubusercontent.com/janhq/jan/main/models/trinity-v1.2-7b/cover.png"
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/tulu-2-dpo-70B-GGUF/resolve/main/tulu-2-dpo-70b.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "tulu-2-dpo-70b.Q4_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/tulu-2-dpo-70B-GGUF/resolve/main/tulu-2-dpo-70b.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "tulu-2-70b",
|
||||
"object": "model",
|
||||
"name": "Tulu 2 70B Q4",
|
||||
@ -8,14 +13,14 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "<|user|>\n{prompt}\n<|assistant|>"
|
||||
"prompt_template": "<|user|>\n{prompt}\n<|assistant|>",
|
||||
"llama_model_path": "tulu-2-dpo-70b.Q4_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": [],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
@ -25,4 +30,4 @@
|
||||
"size": 41400000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/WizardCoder-Python-13B-V1.0-GGUF/resolve/main/wizardcoder-python-13b-v1.0.Q5_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "wizardcoder-python-13b-v1.0.Q5_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/WizardCoder-Python-13B-V1.0-GGUF/resolve/main/wizardcoder-python-13b-v1.0.Q5_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "wizardcoder-13b",
|
||||
"object": "model",
|
||||
"name": "Wizard Coder Python 13B Q5",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "### Instruction:\n{prompt}\n### Response:"
|
||||
"prompt_template": "### Instruction:\n{prompt}\n### Response:",
|
||||
"llama_model_path": "wizardcoder-python-13b-v1.0.Q5_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 7870000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Yarn-Mistral-7B-128k-GGUF/resolve/main/yarn-mistral-7b-128k.Q4_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://huggingface.co/TheBloke/Yarn-Mistral-7B-128k-GGUF/resolve/main/yarn-mistral-7b-128k.Q4_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "yarn-mistral-7b",
|
||||
"object": "model",
|
||||
"name": "Yarn Mistral 7B Q4",
|
||||
@ -15,15 +19,13 @@
|
||||
"top_p": 0.95,
|
||||
"stream": true,
|
||||
"max_tokens": 4096,
|
||||
"stop": [],
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0
|
||||
},
|
||||
"metadata": {
|
||||
"author": "NousResearch, The Bloke",
|
||||
"tags": ["7B","Finetuned"],
|
||||
"tags": ["7B", "Finetuned"],
|
||||
"size": 4370000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
{
|
||||
"source_url": "https://huggingface.co/TheBloke/Yi-34B-Chat-GGUF/resolve/main/yi-34b-chat.Q5_K_M.gguf",
|
||||
"sources": [
|
||||
{
|
||||
"filename": "yi-34b-chat.Q5_K_M.gguf",
|
||||
"url": "https://huggingface.co/TheBloke/Yi-34B-Chat-GGUF/resolve/main/yi-34b-chat.Q5_K_M.gguf"
|
||||
}
|
||||
],
|
||||
"id": "yi-34b",
|
||||
"object": "model",
|
||||
"name": "Yi 34B Q5",
|
||||
@ -8,7 +13,8 @@
|
||||
"format": "gguf",
|
||||
"settings": {
|
||||
"ctx_len": 4096,
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant"
|
||||
"prompt_template": "<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant",
|
||||
"llama_model_path": "yi-34b-chat.Q5_K_M.gguf"
|
||||
},
|
||||
"parameters": {
|
||||
"temperature": 0.7,
|
||||
@ -25,5 +31,4 @@
|
||||
"size": 20660000000
|
||||
},
|
||||
"engine": "nitro"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ const buttonVariants = cva('btn', {
|
||||
outline: 'btn-outline',
|
||||
secondary: 'btn-secondary',
|
||||
secondaryBlue: 'btn-secondary-blue',
|
||||
secondaryDanger: 'btn-secondary-danger',
|
||||
ghost: 'btn-ghost',
|
||||
success: 'btn-success',
|
||||
},
|
||||
|
||||
@ -9,13 +9,17 @@
|
||||
}
|
||||
|
||||
&-secondary-blue {
|
||||
@apply bg-blue-200 text-blue-600 hover:bg-blue-500/80;
|
||||
@apply bg-blue-200 text-blue-600 hover:bg-blue-500/50;
|
||||
}
|
||||
|
||||
&-danger {
|
||||
@apply bg-danger text-danger-foreground hover:bg-danger/90;
|
||||
}
|
||||
|
||||
&-secondary-danger {
|
||||
@apply bg-red-200 text-red-600 hover:bg-red-500/50;
|
||||
}
|
||||
|
||||
&-outline {
|
||||
@apply border-input border bg-transparent;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
.input {
|
||||
@apply border-border placeholder:text-muted-foreground flex h-9 w-full rounded-lg border bg-transparent px-3 py-1 transition-colors;
|
||||
@apply disabled:cursor-not-allowed disabled:opacity-50;
|
||||
@apply disabled:cursor-not-allowed disabled:bg-zinc-100;
|
||||
@apply focus-within:outline-none focus-visible:outline-0 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1;
|
||||
@apply file:border-0 file:bg-transparent file:font-medium;
|
||||
}
|
||||
|
||||
@ -41,7 +41,10 @@ export default function RibbonNav() {
|
||||
icon: (
|
||||
<MessageCircleIcon
|
||||
size={20}
|
||||
className="flex-shrink-0 text-muted-foreground"
|
||||
className={twMerge(
|
||||
'flex-shrink-0 text-muted-foreground',
|
||||
serverEnabled && 'text-gray-300 dark:text-gray-700'
|
||||
)}
|
||||
/>
|
||||
),
|
||||
state: MainViewState.Thread,
|
||||
@ -60,7 +63,7 @@ export default function RibbonNav() {
|
||||
|
||||
const secondaryMenus = [
|
||||
{
|
||||
name: 'Local Server',
|
||||
name: 'Local API Server',
|
||||
icon: (
|
||||
<SquareCodeIcon
|
||||
size={20}
|
||||
|
||||
@ -9,11 +9,14 @@ import RibbonNav from '@/containers/Layout/Ribbon'
|
||||
|
||||
import TopBar from '@/containers/Layout/TopBar'
|
||||
|
||||
import { MainViewState } from '@/constants/screens'
|
||||
|
||||
import { useMainViewState } from '@/hooks/useMainViewState'
|
||||
import { SUCCESS_SET_NEW_DESTINATION } from '@/hooks/useVaultDirectory'
|
||||
|
||||
const BaseLayout = (props: PropsWithChildren) => {
|
||||
const { children } = props
|
||||
const { mainViewState } = useMainViewState()
|
||||
const { mainViewState, setMainViewState } = useMainViewState()
|
||||
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
@ -21,6 +24,12 @@ const BaseLayout = (props: PropsWithChildren) => {
|
||||
setTheme(theme as string)
|
||||
}, [setTheme, theme])
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem(SUCCESS_SET_NEW_DESTINATION) === 'true') {
|
||||
setMainViewState(MainViewState.Settings)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-screen flex-1 overflow-hidden">
|
||||
<RibbonNav />
|
||||
|
||||
@ -105,6 +105,7 @@ export default function EventListenerWrapper({ children }: PropsWithChildren) {
|
||||
})
|
||||
}
|
||||
return () => {}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
||||
@ -50,10 +50,12 @@ const availableShortcuts = [
|
||||
|
||||
const ShortcutModal: React.FC = () => (
|
||||
<Modal>
|
||||
<ModalTrigger asChild>
|
||||
<Button size="sm" themes="secondary">
|
||||
<ModalTrigger>
|
||||
<div>
|
||||
<Button size="sm" themes="secondaryBlue">
|
||||
Show
|
||||
</Button>
|
||||
</div>
|
||||
</ModalTrigger>
|
||||
<ModalContent className="max-w-2xl">
|
||||
<ModalHeader>
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
ModelExtension,
|
||||
abortDownload,
|
||||
joinPath,
|
||||
ModelArtifact,
|
||||
} from '@janhq/core'
|
||||
|
||||
import { useSetAtom } from 'jotai'
|
||||
@ -25,6 +26,23 @@ export default function useDownloadModel() {
|
||||
const addNewDownloadingModel = useSetAtom(addNewDownloadingModelAtom)
|
||||
|
||||
const downloadModel = async (model: Model) => {
|
||||
const childrenDownloadProgress: DownloadState[] = []
|
||||
model.sources.forEach((source: ModelArtifact) => {
|
||||
childrenDownloadProgress.push({
|
||||
modelId: source.filename,
|
||||
time: {
|
||||
elapsed: 0,
|
||||
remaining: 0,
|
||||
},
|
||||
speed: 0,
|
||||
percent: 0,
|
||||
size: {
|
||||
total: 0,
|
||||
transferred: 0,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
// set an initial download state
|
||||
setDownloadState({
|
||||
modelId: model.id,
|
||||
@ -38,6 +56,7 @@ export default function useDownloadModel() {
|
||||
total: 0,
|
||||
transferred: 0,
|
||||
},
|
||||
children: childrenDownloadProgress,
|
||||
})
|
||||
|
||||
addNewDownloadingModel(model)
|
||||
@ -46,6 +65,7 @@ export default function useDownloadModel() {
|
||||
.get<ModelExtension>(ExtensionTypeEnum.Model)
|
||||
?.downloadModel(model, { ignoreSSL, proxy })
|
||||
}
|
||||
|
||||
const abortModelDownload = async (model: Model) => {
|
||||
await abortDownload(
|
||||
await joinPath(['models', model.id, modelBinFileName(model)])
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { ExtensionTypeEnum, ModelExtension } from '@janhq/core'
|
||||
import { Model } from '@janhq/core'
|
||||
import { ExtensionTypeEnum, ModelExtension, Model } from '@janhq/core'
|
||||
|
||||
import { extensionManager } from '@/extension/ExtensionManager'
|
||||
|
||||
@ -25,6 +24,7 @@ export function useGetConfiguredModels() {
|
||||
|
||||
useEffect(() => {
|
||||
fetchModels()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return { loading, models }
|
||||
|
||||
@ -6,7 +6,7 @@ import { atom, useAtom } from 'jotai'
|
||||
|
||||
import { extensionManager } from '@/extension/ExtensionManager'
|
||||
|
||||
const downloadedModelsAtom = atom<Model[]>([])
|
||||
export const downloadedModelsAtom = atom<Model[]>([])
|
||||
|
||||
export function useGetDownloadedModels() {
|
||||
const [downloadedModels, setDownloadedModels] = useAtom(downloadedModelsAtom)
|
||||
@ -15,7 +15,8 @@ export function useGetDownloadedModels() {
|
||||
getDownloadedModels().then((downloadedModels) => {
|
||||
setDownloadedModels(downloadedModels)
|
||||
})
|
||||
}, [setDownloadedModels])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return { downloadedModels, setDownloadedModels }
|
||||
}
|
||||
|
||||
@ -110,6 +110,7 @@ export default function useRecommendedModel() {
|
||||
|
||||
console.debug(`Using last used model ${lastUsedModel.id}`)
|
||||
setRecommendedModel(lastUsedModel)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [getAndSortDownloadedModels, activeThread])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -13,6 +13,7 @@ export const useSettings = () => {
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => validateSettings, 3000)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const validateSettings = async () => {
|
||||
|
||||
105
web/hooks/useVaultDirectory.ts
Normal file
105
web/hooks/useVaultDirectory.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { fs, AppConfiguration } from '@janhq/core'
|
||||
|
||||
import { atom, useAtom } from 'jotai'
|
||||
|
||||
import { useMainViewState } from './useMainViewState'
|
||||
|
||||
const isSameDirectoryAtom = atom(false)
|
||||
const isDirectoryConfirmAtom = atom(false)
|
||||
const isErrorSetNewDestAtom = atom(false)
|
||||
const currentPathAtom = atom('')
|
||||
const newDestinationPathAtom = atom('')
|
||||
|
||||
export const SUCCESS_SET_NEW_DESTINATION = 'successSetNewDestination'
|
||||
|
||||
export function useVaultDirectory() {
|
||||
const [isSameDirectory, setIsSameDirectory] = useAtom(isSameDirectoryAtom)
|
||||
const { setMainViewState } = useMainViewState()
|
||||
const [isDirectoryConfirm, setIsDirectoryConfirm] = useAtom(
|
||||
isDirectoryConfirmAtom
|
||||
)
|
||||
const [isErrorSetNewDest, setIsErrorSetNewDest] = useAtom(
|
||||
isErrorSetNewDestAtom
|
||||
)
|
||||
const [currentPath, setCurrentPath] = useAtom(currentPathAtom)
|
||||
const [newDestinationPath, setNewDestinationPath] = useAtom(
|
||||
newDestinationPathAtom
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
window.core?.api
|
||||
?.getAppConfigurations()
|
||||
?.then((appConfig: AppConfiguration) => {
|
||||
setCurrentPath(appConfig.data_folder)
|
||||
})
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const setNewDestination = async () => {
|
||||
const destFolder = await window.core?.api?.selectDirectory()
|
||||
setNewDestinationPath(destFolder)
|
||||
|
||||
if (destFolder) {
|
||||
console.debug(`Destination folder selected: ${destFolder}`)
|
||||
try {
|
||||
const appConfiguration: AppConfiguration =
|
||||
await window.core?.api?.getAppConfigurations()
|
||||
const currentJanDataFolder = appConfiguration.data_folder
|
||||
|
||||
if (currentJanDataFolder === destFolder) {
|
||||
console.debug(
|
||||
`Destination folder is the same as current folder. Ignore..`
|
||||
)
|
||||
setIsSameDirectory(true)
|
||||
setIsDirectoryConfirm(false)
|
||||
return
|
||||
} else {
|
||||
setIsSameDirectory(false)
|
||||
setIsDirectoryConfirm(true)
|
||||
}
|
||||
setIsErrorSetNewDest(false)
|
||||
} catch (e) {
|
||||
console.error(`Error: ${e}`)
|
||||
setIsErrorSetNewDest(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const applyNewDestination = async () => {
|
||||
try {
|
||||
const appConfiguration: AppConfiguration =
|
||||
await window.core?.api?.getAppConfigurations()
|
||||
const currentJanDataFolder = appConfiguration.data_folder
|
||||
|
||||
appConfiguration.data_folder = newDestinationPath
|
||||
|
||||
await fs.syncFile(currentJanDataFolder, newDestinationPath)
|
||||
await window.core?.api?.updateAppConfiguration(appConfiguration)
|
||||
console.debug(
|
||||
`File sync finished from ${currentPath} to ${newDestinationPath}`
|
||||
)
|
||||
|
||||
setIsErrorSetNewDest(false)
|
||||
localStorage.setItem(SUCCESS_SET_NEW_DESTINATION, 'true')
|
||||
await window.core?.api?.relaunch()
|
||||
} catch (e) {
|
||||
console.error(`Error: ${e}`)
|
||||
setIsErrorSetNewDest(true)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
setNewDestination,
|
||||
newDestinationPath,
|
||||
applyNewDestination,
|
||||
isSameDirectory,
|
||||
setIsDirectoryConfirm,
|
||||
isDirectoryConfirm,
|
||||
setIsSameDirectory,
|
||||
currentPath,
|
||||
isErrorSetNewDest,
|
||||
setIsErrorSetNewDest,
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,7 @@
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"framer-motion": "^10.16.4",
|
||||
"highlight.js": "^11.9.0",
|
||||
"jotai": "^2.4.0",
|
||||
"jotai": "^2.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.291.0",
|
||||
"marked": "^9.1.2",
|
||||
|
||||
@ -26,7 +26,7 @@ import { useCreateNewThread } from '@/hooks/useCreateNewThread'
|
||||
import useDownloadModel from '@/hooks/useDownloadModel'
|
||||
import { useDownloadState } from '@/hooks/useDownloadState'
|
||||
import { getAssistants } from '@/hooks/useGetAssistants'
|
||||
import { useGetDownloadedModels } from '@/hooks/useGetDownloadedModels'
|
||||
import { downloadedModelsAtom } from '@/hooks/useGetDownloadedModels'
|
||||
import { useMainViewState } from '@/hooks/useMainViewState'
|
||||
|
||||
import { toGibibytes } from '@/utils/converter'
|
||||
@ -43,8 +43,8 @@ type Props = {
|
||||
|
||||
const ExploreModelItemHeader: React.FC<Props> = ({ model, onClick, open }) => {
|
||||
const { downloadModel } = useDownloadModel()
|
||||
const { downloadedModels } = useGetDownloadedModels()
|
||||
const { modelDownloadStateAtom, downloadStates } = useDownloadState()
|
||||
const downloadedModels = useAtomValue(downloadedModelsAtom)
|
||||
const { modelDownloadStateAtom } = useDownloadState()
|
||||
const { requestCreateNewThread } = useCreateNewThread()
|
||||
const totalRam = useAtomValue(totalRamAtom)
|
||||
const serverEnabled = useAtomValue(serverEnabledAtom)
|
||||
@ -100,9 +100,7 @@ const ExploreModelItemHeader: React.FC<Props> = ({ model, onClick, open }) => {
|
||||
)}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
if (downloadState != null && downloadStates.length > 0) {
|
||||
} else if (downloadState != null) {
|
||||
downloadButton = <ModalCancelDownload model={model} />
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
|
||||
import React, { useEffect, useState } from 'react'
|
||||
@ -55,16 +56,16 @@ const hostAtom = atom('127.0.0.1')
|
||||
const portAtom = atom('1337')
|
||||
|
||||
const LocalServerScreen = () => {
|
||||
const [errorRangePort, setErrorRangePort] = useState(false)
|
||||
const [serverEnabled, setServerEnabled] = useAtom(serverEnabledAtom)
|
||||
const showing = useAtomValue(showRightSideBarAtom)
|
||||
const activeModelParams = useAtomValue(getActiveThreadModelParamsAtom)
|
||||
|
||||
const modelEngineParams = toSettingParams(activeModelParams)
|
||||
|
||||
const componentDataEngineSetting = getConfigurationsData(modelEngineParams)
|
||||
|
||||
const { openServerLog, clearServerLog } = useServerLog()
|
||||
const { activeModel, startModel, stateModel } = useActiveModel()
|
||||
const { startModel, stateModel } = useActiveModel()
|
||||
const [selectedModel] = useAtom(selectedModelAtom)
|
||||
|
||||
const [isCorsEnabled, setIsCorsEnabled] = useAtom(corsEnabledAtom)
|
||||
@ -77,6 +78,15 @@ const LocalServerScreen = () => {
|
||||
const [firstTimeVisitAPIServer, setFirstTimeVisitAPIServer] =
|
||||
useState<boolean>(false)
|
||||
|
||||
const handleChangePort = (value: any) => {
|
||||
if (Number(value) <= 0 || Number(value) >= 65536) {
|
||||
setErrorRangePort(true)
|
||||
} else {
|
||||
setErrorRangePort(false)
|
||||
}
|
||||
setPort(value)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
localStorage.getItem(FIRST_TIME_VISIT_API_SERVER) === null ||
|
||||
@ -87,6 +97,10 @@ const LocalServerScreen = () => {
|
||||
}
|
||||
}, [firstTimeVisitAPIServer])
|
||||
|
||||
useEffect(() => {
|
||||
handleChangePort(port)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full">
|
||||
{/* Left SideBar */}
|
||||
@ -102,7 +116,7 @@ const LocalServerScreen = () => {
|
||||
<Button
|
||||
block
|
||||
themes={serverEnabled ? 'danger' : 'primary'}
|
||||
disabled={stateModel.loading}
|
||||
disabled={stateModel.loading || errorRangePort}
|
||||
onClick={() => {
|
||||
if (serverEnabled) {
|
||||
window.core?.api?.stopServer()
|
||||
@ -158,13 +172,21 @@ const LocalServerScreen = () => {
|
||||
</Select>
|
||||
|
||||
<Input
|
||||
className="w-[60px] flex-shrink-0"
|
||||
className={twMerge(
|
||||
'w-[70px] flex-shrink-0',
|
||||
errorRangePort && 'border-danger'
|
||||
)}
|
||||
value={port}
|
||||
onChange={(e) => setPort(e.target.value)}
|
||||
maxLength={4}
|
||||
onChange={(e) => {
|
||||
handleChangePort(e.target.value)
|
||||
}}
|
||||
maxLength={5}
|
||||
disabled={serverEnabled}
|
||||
/>
|
||||
</div>
|
||||
{errorRangePort && (
|
||||
<p className="mt-2 text-xs text-danger">{`The port range should be from 0 to 65536`}</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
import React from 'react'
|
||||
|
||||
import {
|
||||
Modal,
|
||||
ModalPortal,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalTitle,
|
||||
ModalFooter,
|
||||
ModalClose,
|
||||
Button,
|
||||
} from '@janhq/uikit'
|
||||
|
||||
import { useVaultDirectory } from '@/hooks/useVaultDirectory'
|
||||
|
||||
const ModalChangeDirectory = () => {
|
||||
const {
|
||||
isDirectoryConfirm,
|
||||
setIsDirectoryConfirm,
|
||||
applyNewDestination,
|
||||
newDestinationPath,
|
||||
} = useVaultDirectory()
|
||||
return (
|
||||
<Modal
|
||||
open={isDirectoryConfirm}
|
||||
onOpenChange={() => setIsDirectoryConfirm(false)}
|
||||
>
|
||||
<ModalPortal />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
<ModalTitle>Relocate Jan Data Folder</ModalTitle>
|
||||
</ModalHeader>
|
||||
<p className="text-muted-foreground">
|
||||
Are you sure you want to relocate Jan data folder to{' '}
|
||||
<span className="font-medium text-foreground">
|
||||
{newDestinationPath}
|
||||
</span>
|
||||
? A restart will be required afterward.
|
||||
</p>
|
||||
<ModalFooter>
|
||||
<div className="flex gap-x-2">
|
||||
<ModalClose asChild onClick={() => setIsDirectoryConfirm(false)}>
|
||||
<Button themes="ghost">Cancel</Button>
|
||||
</ModalClose>
|
||||
<ModalClose asChild>
|
||||
<Button onClick={applyNewDestination} autoFocus>
|
||||
Yes, Proceed
|
||||
</Button>
|
||||
</ModalClose>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModalChangeDirectory
|
||||
@ -0,0 +1,44 @@
|
||||
import React from 'react'
|
||||
|
||||
import {
|
||||
Modal,
|
||||
ModalPortal,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalTitle,
|
||||
ModalFooter,
|
||||
ModalClose,
|
||||
Button,
|
||||
} from '@janhq/uikit'
|
||||
|
||||
import { useVaultDirectory } from '@/hooks/useVaultDirectory'
|
||||
|
||||
const ModalErrorSetDestGlobal = () => {
|
||||
const { isErrorSetNewDest, setIsErrorSetNewDest } = useVaultDirectory()
|
||||
return (
|
||||
<Modal
|
||||
open={isErrorSetNewDest}
|
||||
onOpenChange={() => setIsErrorSetNewDest(false)}
|
||||
>
|
||||
<ModalPortal />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
<ModalTitle>Error Occurred</ModalTitle>
|
||||
</ModalHeader>
|
||||
<p className="text-muted-foreground">
|
||||
Oops! Something went wrong. Jan data folder remains the same. Please
|
||||
try again.
|
||||
</p>
|
||||
<ModalFooter>
|
||||
<div className="flex gap-x-2">
|
||||
<ModalClose asChild onClick={() => setIsErrorSetNewDest(false)}>
|
||||
<Button themes="danger">Got it</Button>
|
||||
</ModalClose>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModalErrorSetDestGlobal
|
||||
@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
|
||||
import {
|
||||
Modal,
|
||||
ModalPortal,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalTitle,
|
||||
ModalFooter,
|
||||
ModalClose,
|
||||
Button,
|
||||
} from '@janhq/uikit'
|
||||
|
||||
import { useVaultDirectory } from '@/hooks/useVaultDirectory'
|
||||
|
||||
const ModalSameDirectory = () => {
|
||||
const { isSameDirectory, setIsSameDirectory, setNewDestination } =
|
||||
useVaultDirectory()
|
||||
return (
|
||||
<Modal
|
||||
open={isSameDirectory}
|
||||
onOpenChange={() => setIsSameDirectory(false)}
|
||||
>
|
||||
<ModalPortal />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
<ModalTitle>Unable to move files</ModalTitle>
|
||||
</ModalHeader>
|
||||
<p className="text-muted-foreground">
|
||||
{`It seems like the folder you've chosen same with current directory`}
|
||||
</p>
|
||||
<ModalFooter>
|
||||
<div className="flex gap-x-2">
|
||||
<ModalClose asChild onClick={() => setIsSameDirectory(false)}>
|
||||
<Button themes="ghost">Cancel</Button>
|
||||
</ModalClose>
|
||||
<ModalClose asChild>
|
||||
<Button themes="danger" onClick={setNewDestination} autoFocus>
|
||||
Choose a different folder
|
||||
</Button>
|
||||
</ModalClose>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModalSameDirectory
|
||||
52
web/screens/Settings/Advanced/DataFolder/index.tsx
Normal file
52
web/screens/Settings/Advanced/DataFolder/index.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { Button, Input } from '@janhq/uikit'
|
||||
import { PencilIcon, FolderOpenIcon } from 'lucide-react'
|
||||
|
||||
import { useVaultDirectory } from '@/hooks/useVaultDirectory'
|
||||
|
||||
import ModalChangeDirectory from './ModalChangeDirectory'
|
||||
import ModalErrorSetDestGlobal from './ModalErrorSetDestGlobal'
|
||||
import ModalSameDirectory from './ModalSameDirectory'
|
||||
|
||||
const DataFolder = () => {
|
||||
const { currentPath, setNewDestination } = useVaultDirectory()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Jan Data Folder
|
||||
</h6>
|
||||
</div>
|
||||
<p className="leading-relaxed">
|
||||
Where messages, model configurations, and other user data are
|
||||
placed.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-3">
|
||||
<div className="relative">
|
||||
<Input value={currentPath} className="w-[240px] pr-8" disabled />
|
||||
<FolderOpenIcon
|
||||
size={16}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
themes="outline"
|
||||
className="h-9 w-9 p-0"
|
||||
onClick={setNewDestination}
|
||||
>
|
||||
<PencilIcon size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<ModalSameDirectory />
|
||||
<ModalChangeDirectory />
|
||||
<ModalErrorSetDestGlobal />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DataFolder
|
||||
@ -9,7 +9,7 @@ import {
|
||||
ChangeEvent,
|
||||
} from 'react'
|
||||
|
||||
import { fs, AppConfiguration } from '@janhq/core'
|
||||
import { fs } from '@janhq/core'
|
||||
import { Switch, Button, Input } from '@janhq/uikit'
|
||||
|
||||
import ShortcutModal from '@/containers/ShortcutModal'
|
||||
@ -20,6 +20,8 @@ import { FeatureToggleContext } from '@/context/FeatureToggle'
|
||||
|
||||
import { useSettings } from '@/hooks/useSettings'
|
||||
|
||||
import DataFolder from './DataFolder'
|
||||
|
||||
const Advanced = () => {
|
||||
const {
|
||||
experimentalFeature,
|
||||
@ -31,6 +33,7 @@ const Advanced = () => {
|
||||
} = useContext(FeatureToggleContext)
|
||||
const [partialProxy, setPartialProxy] = useState<string>(proxy)
|
||||
const [gpuEnabled, setGpuEnabled] = useState<boolean>(false)
|
||||
|
||||
const { readSettings, saveSettings, validateSettings, setShowNotification } =
|
||||
useSettings()
|
||||
const onProxyChange = useCallback(
|
||||
@ -46,17 +49,6 @@ const Advanced = () => {
|
||||
[setPartialProxy, setProxy]
|
||||
)
|
||||
|
||||
// TODO: remove me later.
|
||||
const [currentPath, setCurrentPath] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
window.core?.api
|
||||
?.getAppConfigurations()
|
||||
?.then((appConfig: AppConfiguration) => {
|
||||
setCurrentPath(appConfig.data_folder)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
readSettings().then((settings) => {
|
||||
setGpuEnabled(settings.run_mode === 'gpu')
|
||||
@ -73,45 +65,55 @@ const Advanced = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const onJanVaultDirectoryClick = async () => {
|
||||
const destFolder = await window.core?.api?.selectDirectory()
|
||||
if (destFolder) {
|
||||
console.debug(`Destination folder selected: ${destFolder}`)
|
||||
|
||||
try {
|
||||
const appConfiguration: AppConfiguration =
|
||||
await window.core?.api?.getAppConfigurations()
|
||||
const currentJanDataFolder = appConfiguration.data_folder
|
||||
if (currentJanDataFolder === destFolder) {
|
||||
console.debug(
|
||||
`Destination folder is the same as current folder. Ignore..`
|
||||
)
|
||||
return
|
||||
}
|
||||
appConfiguration.data_folder = destFolder
|
||||
|
||||
await fs.syncFile(currentJanDataFolder, destFolder)
|
||||
await window.core?.api?.updateAppConfiguration(appConfiguration)
|
||||
console.debug(
|
||||
`File sync finished from ${currentJanDataFolder} to ${destFolder}`
|
||||
)
|
||||
await window.core?.api?.relaunch()
|
||||
} catch (e) {
|
||||
console.error(`Error: ${e}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="block w-full">
|
||||
{/* Keyboard shortcut */}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Keyboard Shortcuts
|
||||
</h6>
|
||||
</div>
|
||||
<p className="leading-relaxed">
|
||||
Shortcuts that you might find useful in Jan app.
|
||||
</p>
|
||||
</div>
|
||||
<ShortcutModal />
|
||||
</div>
|
||||
|
||||
{/* Experimental */}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Experimental Mode
|
||||
</h6>
|
||||
</div>
|
||||
<p className="leading-relaxed">
|
||||
Enable experimental features that may be unstable tested.
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={experimentalFeature}
|
||||
onCheckedChange={(e) => {
|
||||
if (e === true) {
|
||||
setExperimentalFeature(true)
|
||||
} else {
|
||||
setExperimentalFeature(false)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* CPU / GPU switching */}
|
||||
{!isMac && (
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">NVidia GPU</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
<p className="leading-relaxed">
|
||||
Enable GPU acceleration for NVidia GPUs.
|
||||
</p>
|
||||
</div>
|
||||
@ -133,36 +135,17 @@ const Advanced = () => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Experimental */}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Experimental Mode
|
||||
</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
Enable experimental features that may be unstable tested.
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={experimentalFeature}
|
||||
onCheckedChange={(e) => {
|
||||
if (e === true) {
|
||||
setExperimentalFeature(true)
|
||||
} else {
|
||||
setExperimentalFeature(false)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Directory */}
|
||||
{experimentalFeature && <DataFolder />}
|
||||
|
||||
{/* Proxy */}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">HTTPS Proxy</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
<p className="leading-relaxed">
|
||||
Specify the HTTPS proxy or leave blank (proxy auto-configuration and
|
||||
SOCKS not supported).
|
||||
</p>
|
||||
@ -173,15 +156,16 @@ const Advanced = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Ignore SSL certificates */}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Ignore SSL certificates
|
||||
</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
<p className="leading-relaxed">
|
||||
Allow self-signed or unverified certificates - may be required for
|
||||
certain proxies.
|
||||
</p>
|
||||
@ -197,79 +181,19 @@ const Advanced = () => {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{window.electronAPI && (
|
||||
|
||||
{/* Claer log */}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Open App Directory
|
||||
</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
Open the directory where your app data, like conversation history
|
||||
and model configurations, is located.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
themes="secondary"
|
||||
onClick={() => window.electronAPI.openAppDirectory()}
|
||||
>
|
||||
Open
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">Clear logs</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
Clear all logs from Jan app.
|
||||
</p>
|
||||
<p className="leading-relaxed">Clear all logs from Jan app.</p>
|
||||
</div>
|
||||
<Button size="sm" themes="secondary" onClick={clearLogs}>
|
||||
<Button size="sm" themes="secondaryDanger" onClick={clearLogs}>
|
||||
Clear
|
||||
</Button>
|
||||
</div>
|
||||
{experimentalFeature && (
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Jan Data Folder
|
||||
</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
Where messages, model configurations, and other user data is
|
||||
placed.
|
||||
</p>
|
||||
<p className="whitespace-pre-wrap leading-relaxed text-gray-500">
|
||||
{`${currentPath}`}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
themes="secondary"
|
||||
onClick={onJanVaultDirectoryClick}
|
||||
>
|
||||
Select
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
|
||||
<div className="w-4/5 flex-shrink-0 space-y-1.5">
|
||||
<div className="flex gap-x-2">
|
||||
<h6 className="text-sm font-semibold capitalize">
|
||||
Keyboard Shortcuts
|
||||
</h6>
|
||||
</div>
|
||||
<p className="whitespace-pre-wrap leading-relaxed">
|
||||
Shortcuts that you might find useful in Jan app.
|
||||
</p>
|
||||
</div>
|
||||
<ShortcutModal />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ const ExtensionCatalog = () => {
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
<Button
|
||||
themes="secondary"
|
||||
themes="secondaryBlue"
|
||||
size="sm"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
|
||||
@ -7,14 +7,14 @@ import { motion as m } from 'framer-motion'
|
||||
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
import { SUCCESS_SET_NEW_DESTINATION } from '@/hooks/useVaultDirectory'
|
||||
|
||||
import Advanced from '@/screens/Settings/Advanced'
|
||||
import AppearanceOptions from '@/screens/Settings/Appearance'
|
||||
import ExtensionCatalog from '@/screens/Settings/CoreExtensions'
|
||||
|
||||
import Models from '@/screens/Settings/Models'
|
||||
|
||||
import { formatExtensionsName } from '@/utils/converter'
|
||||
|
||||
const SettingsScreen = () => {
|
||||
const [activeStaticMenu, setActiveStaticMenu] = useState('My Models')
|
||||
const [menus, setMenus] = useState<any[]>([])
|
||||
@ -46,6 +46,12 @@ const SettingsScreen = () => {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem(SUCCESS_SET_NEW_DESTINATION) === 'true') {
|
||||
setActiveStaticMenu('Advanced Settings')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex h-full bg-background">
|
||||
<div className="flex h-full w-64 flex-shrink-0 flex-col overflow-y-auto border-r border-border">
|
||||
|
||||
2
web/types/downloadState.d.ts
vendored
2
web/types/downloadState.d.ts
vendored
@ -4,6 +4,8 @@ type DownloadState = {
|
||||
speed: number
|
||||
percent: number
|
||||
size: DownloadSize
|
||||
isFinished?: boolean
|
||||
children?: DownloadState[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import { Model } from '@janhq/core'
|
||||
|
||||
export const modelBinFileName = (model: Model) => {
|
||||
const modelFormatExt = '.gguf'
|
||||
const extractedFileName = model.source_url?.split('/').pop() ?? model.id
|
||||
const extractedFileName = model.sources[0]?.url.split('/').pop() ?? model.id
|
||||
const fileName = extractedFileName.toLowerCase().endsWith(modelFormatExt)
|
||||
? extractedFileName
|
||||
: model.id
|
||||
|
||||
@ -40,6 +40,8 @@ export const toSettingParams = (
|
||||
n_parallel: undefined,
|
||||
cpu_threads: undefined,
|
||||
prompt_template: undefined,
|
||||
llama_model_path: undefined,
|
||||
mmproj: undefined,
|
||||
}
|
||||
const settingParams: ModelSettingParams = {}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user