Merge branch 'dev' into feat/old-mac-support

This commit is contained in:
Sherzod Mutalov 2025-08-05 08:17:55 +05:00 committed by GitHub
commit 0a79cf79a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
240 changed files with 21458 additions and 133 deletions

98
.github/workflows/jan-astro-docs.yml vendored Normal file
View File

@ -0,0 +1,98 @@
name: Jan Astro Docs
on:
push:
branches:
- dev
paths:
- 'website/**'
- '.github/workflows/jan-astro-docs.yml'
pull_request:
paths:
- 'website/**'
- '.github/workflows/jan-astro-docs.yml'
# Review gh actions docs if you want to further define triggers, paths, etc
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
workflow_dispatch:
jobs:
deploy:
name: Deploy to CloudFlare Pages
env:
CLOUDFLARE_PROJECT_NAME: astro-docs
runs-on: ubuntu-latest
permissions:
contents: write
deployments: write
pull-requests: write
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- uses: oven-sh/setup-bun@v2
- name: Install jq
uses: dcarbone/install-jq-action@v2.0.1
- name: Fill env vars
continue-on-error: true
working-directory: website
run: |
env_example_file=".env.example"
touch .env
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" == *"="* ]]; then
var_name=$(echo $line | cut -d '=' -f 1)
echo $var_name
var_value="$(jq -r --arg key "$var_name" '.[$key]' <<< "$SECRETS")"
echo "$var_name=$var_value" >> .env
fi
done < "$env_example_file"
env:
SECRETS: '${{ toJson(secrets) }}'
- name: Install dependencies
working-directory: website
run: bun install
- name: Build website
working-directory: website
run: bun run build
- name: copy redirects and headers
continue-on-error: true
working-directory: website
run: |
cp _redirects dist/_redirects
cp _headers dist/_headers
- name: Publish to Cloudflare Pages PR Preview and Staging
if: github.event_name == 'pull_request'
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ${{ env.CLOUDFLARE_PROJECT_NAME }}
directory: ./website/dist
# Optional: Enable this if you want to have GitHub Deployments triggered
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
id: deployCloudflarePages
- uses: mshick/add-pr-comment@v2
if: github.event_name == 'pull_request'
with:
message: |
Preview URL Astro Docs: ${{ steps.deployCloudflarePages.outputs.url }}
- name: Publish to Cloudflare Pages Production
if: (github.event_name == 'push' && github.ref == 'refs/heads/dev') || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/dev')
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ${{ env.CLOUDFLARE_PROJECT_NAME }}
directory: ./website/dist
branch: main
# Optional: Enable this if you want to have GitHub Deployments triggered
gitHubToken: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,5 +0,0 @@
{
"recommendations": [
"esbenp.prettier-vscode"
]
}

View File

@ -1,7 +0,0 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}

View File

@ -1,9 +0,0 @@
{
"-- Switcher": {
"type": "separator",
"title": "Switcher"
},
"index": {
"display": "hidden"
}
}

View File

@ -1,87 +0,0 @@
---
title: Coming Soon
description: Exciting new features and platforms are on the way. Stay tuned for Jan Web, Jan Mobile, and our API Platform.
keywords:
[
Jan,
Customizable Intelligence, LLM,
local AI,
privacy focus,
free and open source,
private and offline,
conversational AI,
no-subscription fee,
large language models,
coming soon,
Jan Web,
Jan Mobile,
API Platform,
]
---
import { Callout } from 'nextra/components'
<div className="text-center py-12">
<div className="mb-8">
<h1 className="text-4xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent mb-4 py-2">
🚀 Coming Soon
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
We're working on the next stage of Jan - making our local assistant more powerful and available in more platforms.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-4xl mx-auto mb-12">
<div className="p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20">
<div className="text-3xl mb-3">🌐</div>
<h3 className="text-lg font-semibold mb-2">Jan Web</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
Access Jan directly from your browser with our powerful web interface
</p>
</div>
<div className="p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-gradient-to-br from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20">
<div className="text-3xl mb-3">📱</div>
<h3 className="text-lg font-semibold mb-2">Jan Mobile</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
Take Jan on the go with our native mobile applications
</p>
</div>
<div className="p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-gradient-to-br from-purple-50 to-pink-50 dark:from-purple-900/20 dark:to-pink-900/20">
<div className="text-3xl mb-3">⚡</div>
<h3 className="text-lg font-semibold mb-2">Jan Server</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
Integrate Jan's capabilities into your applications with our API
</p>
</div>
</div>
<Callout type="info">
**Stay Updated**: Follow our [GitHub repository](https://github.com/menloresearch/jan) and join our [Discord community](https://discord.com/invite/FTk2MvZwJH) for the latest updates on these exciting releases!
</Callout>
<div className="mt-12">
<h2 className="text-2xl font-semibold mb-6">What to Expect</h2>
<div className="text-left max-w-2xl mx-auto space-y-4">
<div className="flex items-start gap-3">
<span className="text-green-500 text-xl">✓</span>
<div>
<strong>Seamless Experience:</strong> Unified interface across all platforms
</div>
</div>
<div className="flex items-start gap-3">
<span className="text-green-500 text-xl">✓</span>
<div>
<strong>Privacy First:</strong> Same privacy-focused approach you trust
</div>
</div>
<div className="flex items-start gap-3">
<span className="text-green-500 text-xl">✓</span>
<div>
<strong>Developer Friendly:</strong> Robust APIs and comprehensive documentation
</div>
</div>
</div>
</div>
</div>

View File

@ -1247,11 +1247,6 @@ export default class llamacpp_extension extends AIEngine {
]) ])
args.push('--mmproj', mmprojPath) args.push('--mmproj', mmprojPath)
} }
if (cfg.ctx_size !== undefined) {
args.push('-c', String(cfg.ctx_size))
}
// Add remaining options from the interface // Add remaining options from the interface
if (cfg.chat_template) args.push('--chat-template', cfg.chat_template) if (cfg.chat_template) args.push('--chat-template', cfg.chat_template)
const gpu_layers = const gpu_layers =
@ -1263,8 +1258,9 @@ export default class llamacpp_extension extends AIEngine {
if (cfg.batch_size > 0) args.push('--batch-size', String(cfg.batch_size)) if (cfg.batch_size > 0) args.push('--batch-size', String(cfg.batch_size))
if (cfg.ubatch_size > 0) args.push('--ubatch-size', String(cfg.ubatch_size)) if (cfg.ubatch_size > 0) args.push('--ubatch-size', String(cfg.ubatch_size))
if (cfg.device.length > 0) args.push('--device', cfg.device) if (cfg.device.length > 0) args.push('--device', cfg.device)
if (cfg.split_mode.length > 0) args.push('--split-mode', cfg.split_mode) if (cfg.split_mode.length > 0 && cfg.split_mode != 'layer')
if (cfg.main_gpu !== undefined) args.push('--split-mode', cfg.split_mode)
if (cfg.main_gpu !== undefined && cfg.main_gpu != 0)
args.push('--main-gpu', String(cfg.main_gpu)) args.push('--main-gpu', String(cfg.main_gpu))
// Boolean flags // Boolean flags
@ -1280,18 +1276,24 @@ export default class llamacpp_extension extends AIEngine {
} else { } else {
if (cfg.ctx_size > 0) args.push('--ctx-size', String(cfg.ctx_size)) if (cfg.ctx_size > 0) args.push('--ctx-size', String(cfg.ctx_size))
if (cfg.n_predict > 0) args.push('--n-predict', String(cfg.n_predict)) if (cfg.n_predict > 0) args.push('--n-predict', String(cfg.n_predict))
if (cfg.cache_type_k && cfg.cache_type_k != 'f16')
args.push('--cache-type-k', cfg.cache_type_k) args.push('--cache-type-k', cfg.cache_type_k)
if ( if (
(cfg.flash_attn && cfg.cache_type_v != 'f16') || cfg.flash_attn &&
cfg.cache_type_v != 'f32' (cfg.cache_type_v != 'f16' && cfg.cache_type_v != 'f32')
) { ) {
args.push('--cache-type-v', cfg.cache_type_v) args.push('--cache-type-v', cfg.cache_type_v)
} }
if (cfg.defrag_thold && cfg.defrag_thold != 0.1)
args.push('--defrag-thold', String(cfg.defrag_thold)) args.push('--defrag-thold', String(cfg.defrag_thold))
if (cfg.rope_scaling && cfg.rope_scaling != 'none')
args.push('--rope-scaling', cfg.rope_scaling) args.push('--rope-scaling', cfg.rope_scaling)
if (cfg.rope_scale && cfg.rope_scale != 1)
args.push('--rope-scale', String(cfg.rope_scale)) args.push('--rope-scale', String(cfg.rope_scale))
if (cfg.rope_freq_base && cfg.rope_freq_base != 0)
args.push('--rope-freq-base', String(cfg.rope_freq_base)) args.push('--rope-freq-base', String(cfg.rope_freq_base))
if (cfg.rope_freq_scale && cfg.rope_freq_scale != 1)
args.push('--rope-freq-scale', String(cfg.rope_freq_scale)) args.push('--rope-freq-scale', String(cfg.rope_freq_scale))
} }

View File

@ -708,3 +708,195 @@ pub async fn is_process_running(pid: i32, state: State<'_, AppState>) -> Result<
pub fn is_port_available(port: u16) -> bool { pub fn is_port_available(port: u16) -> bool {
std::net::TcpListener::bind(("127.0.0.1", port)).is_ok() std::net::TcpListener::bind(("127.0.0.1", port)).is_ok()
} }
// tests
//
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_multiple_devices() {
let output = r#"ggml_vulkan: Found 2 Vulkan devices:
ggml_vulkan: 0 = NVIDIA GeForce RTX 3090 (NVIDIA) | uma: 0 | fp16: 1 | bf16: 0 | warp size: 32 | shared memory: 49152 | int dot: 0 | matrix cores: KHR_coopmat
ggml_vulkan: 1 = AMD Radeon Graphics (RADV GFX1151) (radv) | uma: 1 | fp16: 1 | bf16: 0 | warp size: 64 | shared memory: 65536 | int dot: 0 | matrix cores: KHR_coopmat
Available devices:
Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 24576 MiB free)
Vulkan1: AMD Radeon Graphics (RADV GFX1151) (87722 MiB, 87722 MiB free)
"#;
let devices = parse_device_output(output).unwrap();
assert_eq!(devices.len(), 2);
// Check first device
assert_eq!(devices[0].id, "Vulkan0");
assert_eq!(devices[0].name, "NVIDIA GeForce RTX 3090");
assert_eq!(devices[0].mem, 24576);
assert_eq!(devices[0].free, 24576);
// Check second device
assert_eq!(devices[1].id, "Vulkan1");
assert_eq!(devices[1].name, "AMD Radeon Graphics (RADV GFX1151)");
assert_eq!(devices[1].mem, 87722);
assert_eq!(devices[1].free, 87722);
}
#[test]
fn test_parse_single_device() {
let output = r#"Available devices:
CUDA0: NVIDIA GeForce RTX 4090 (24576 MiB, 24000 MiB free)"#;
let devices = parse_device_output(output).unwrap();
assert_eq!(devices.len(), 1);
assert_eq!(devices[0].id, "CUDA0");
assert_eq!(devices[0].name, "NVIDIA GeForce RTX 4090");
assert_eq!(devices[0].mem, 24576);
assert_eq!(devices[0].free, 24000);
}
#[test]
fn test_parse_with_extra_whitespace_and_empty_lines() {
let output = r#"
Available devices:
Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 24576 MiB free)
Vulkan1: AMD Radeon Graphics (RADV GFX1151) (87722 MiB, 87722 MiB free)
"#;
let devices = parse_device_output(output).unwrap();
assert_eq!(devices.len(), 2);
assert_eq!(devices[0].id, "Vulkan0");
assert_eq!(devices[1].id, "Vulkan1");
}
#[test]
fn test_parse_different_backends() {
let output = r#"Available devices:
CUDA0: NVIDIA GeForce RTX 4090 (24576 MiB, 24000 MiB free)
Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 24576 MiB free)
SYCL0: Intel(R) Arc(TM) A750 Graphics (8000 MiB, 7721 MiB free)"#;
let devices = parse_device_output(output).unwrap();
assert_eq!(devices.len(), 3);
assert_eq!(devices[0].id, "CUDA0");
assert_eq!(devices[0].name, "NVIDIA GeForce RTX 4090");
assert_eq!(devices[1].id, "Vulkan0");
assert_eq!(devices[1].name, "NVIDIA GeForce RTX 3090");
assert_eq!(devices[2].id, "SYCL0");
assert_eq!(devices[2].name, "Intel(R) Arc(TM) A750 Graphics");
assert_eq!(devices[2].mem, 8000);
assert_eq!(devices[2].free, 7721);
}
#[test]
fn test_parse_complex_gpu_names() {
let output = r#"Available devices:
Vulkan0: Intel(R) Arc(tm) A750 Graphics (DG2) (8128 MiB, 8128 MiB free)
Vulkan1: AMD Radeon RX 7900 XTX (Navi 31) [RDNA 3] (24576 MiB, 24000 MiB free)"#;
let devices = parse_device_output(output).unwrap();
assert_eq!(devices.len(), 2);
assert_eq!(devices[0].id, "Vulkan0");
assert_eq!(devices[0].name, "Intel(R) Arc(tm) A750 Graphics (DG2)");
assert_eq!(devices[0].mem, 8128);
assert_eq!(devices[0].free, 8128);
assert_eq!(devices[1].id, "Vulkan1");
assert_eq!(devices[1].name, "AMD Radeon RX 7900 XTX (Navi 31) [RDNA 3]");
assert_eq!(devices[1].mem, 24576);
assert_eq!(devices[1].free, 24000);
}
#[test]
fn test_parse_no_devices() {
let output = r#"Available devices:"#;
let devices = parse_device_output(output).unwrap();
assert_eq!(devices.len(), 0);
}
#[test]
fn test_parse_missing_header() {
let output = r#"Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 24576 MiB free)"#;
let result = parse_device_output(output);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Could not find 'Available devices:' section"));
}
#[test]
fn test_parse_malformed_device_line() {
let output = r#"Available devices:
Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 24576 MiB free)
Invalid line without colon
Vulkan1: AMD Radeon Graphics (RADV GFX1151) (87722 MiB, 87722 MiB free)"#;
let devices = parse_device_output(output).unwrap();
// Should skip the malformed line and parse the valid ones
assert_eq!(devices.len(), 2);
assert_eq!(devices[0].id, "Vulkan0");
assert_eq!(devices[1].id, "Vulkan1");
}
#[test]
fn test_parse_device_line_individual() {
// Test the individual line parser
let line = "Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 24576 MiB free)";
let device = parse_device_line(line).unwrap().unwrap();
assert_eq!(device.id, "Vulkan0");
assert_eq!(device.name, "NVIDIA GeForce RTX 3090");
assert_eq!(device.mem, 24576);
assert_eq!(device.free, 24576);
}
#[test]
fn test_memory_pattern_detection() {
assert!(is_memory_pattern("24576 MiB, 24576 MiB free"));
assert!(is_memory_pattern("8000 MiB, 7721 MiB free"));
assert!(!is_memory_pattern("just some text"));
assert!(!is_memory_pattern("24576 MiB"));
assert!(!is_memory_pattern("24576, 24576"));
}
#[test]
fn test_parse_memory_value() {
assert_eq!(parse_memory_value("24576 MiB").unwrap(), 24576);
assert_eq!(parse_memory_value("7721 MiB free").unwrap(), 7721);
assert_eq!(parse_memory_value("8000").unwrap(), 8000);
assert!(parse_memory_value("").is_err());
assert!(parse_memory_value("not_a_number MiB").is_err());
}
#[test]
fn test_find_memory_pattern() {
let text = "NVIDIA GeForce RTX 3090 (24576 MiB, 24576 MiB free)";
let result = find_memory_pattern(text);
assert!(result.is_some());
let (_start, content) = result.unwrap();
assert_eq!(content, "24576 MiB, 24576 MiB free");
// Test with multiple parentheses
let text = "Intel(R) Arc(tm) A750 Graphics (DG2) (8128 MiB, 8128 MiB free)";
let result = find_memory_pattern(text);
assert!(result.is_some());
let (_start, content) = result.unwrap();
assert_eq!(content, "8128 MiB, 8128 MiB free");
}
}

View File

@ -161,8 +161,14 @@ export function DownloadManagement() {
console.debug('onFileDownloadError', state) console.debug('onFileDownloadError', state)
removeDownload(state.modelId) removeDownload(state.modelId)
removeLocalDownloadingModel(state.modelId) removeLocalDownloadingModel(state.modelId)
toast.error(t('common:toast.downloadFailed.title'), {
id: 'download-failed',
description: t('common:toast.downloadFailed.description', {
item: state.modelId,
}),
})
}, },
[removeDownload, removeLocalDownloadingModel] [removeDownload, removeLocalDownloadingModel, t]
) )
const onFileDownloadStopped = useCallback( const onFileDownloadStopped = useCallback(

View File

@ -36,7 +36,10 @@ export default function OutOfContextPromiseModal() {
return ( return (
<Dialog open={isModalOpen} onOpenChange={handleDialogOpen}> <Dialog open={isModalOpen} onOpenChange={handleDialogOpen}>
<DialogContent> <DialogContent
showCloseButton={false}
onInteractOutside={(e) => e.preventDefault()}
>
<DialogHeader> <DialogHeader>
<DialogTitle>{t('model-errors:title')}</DialogTitle> <DialogTitle>{t('model-errors:title')}</DialogTitle>
</DialogHeader> </DialogHeader>
@ -57,7 +60,7 @@ export default function OutOfContextPromiseModal() {
{t('model-errors:truncateInput')} {t('model-errors:truncateInput')}
</Button> </Button>
<Button <Button
asChild autoFocus
onClick={() => { onClick={() => {
handleContextLength() handleContextLength()
}} }}

View File

@ -365,8 +365,7 @@ export const useChat = () => {
if ( if (
typeof errorMessage === 'string' && typeof errorMessage === 'string' &&
errorMessage.includes(OUT_OF_CONTEXT_SIZE) && errorMessage.includes(OUT_OF_CONTEXT_SIZE) &&
selectedModel && selectedModel
troubleshooting
) { ) {
const method = await showIncreaseContextSizeModal() const method = await showIncreaseContextSizeModal()
if (method === 'ctx_len') { if (method === 'ctx_len') {

View File

@ -257,6 +257,10 @@
"downloadCancelled": { "downloadCancelled": {
"title": "Download Cancelled", "title": "Download Cancelled",
"description": "The download process was cancelled" "description": "The download process was cancelled"
},
"downloadFailed": {
"title": "Download Failed",
"description": "{{item}} download failed"
} }
} }
} }

View File

@ -4,8 +4,7 @@ import { UIEventHandler } from 'react'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import cloneDeep from 'lodash.clonedeep' import cloneDeep from 'lodash.clonedeep'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ArrowDown } from 'lucide-react' import { ArrowDown, Play } from 'lucide-react'
import { Play } from 'lucide-react'
import HeaderPage from '@/containers/HeaderPage' import HeaderPage from '@/containers/HeaderPage'
import { useThreads } from '@/hooks/useThreads' import { useThreads } from '@/hooks/useThreads'
@ -328,7 +327,7 @@ function ThreadDetail() {
> >
{showScrollToBottomBtn && ( {showScrollToBottomBtn && (
<div <div
className="bg-main-view-fg/10 px-4 border border-main-view-fg/5 flex items-center justify-center rounded-xl gap-x-2 cursor-pointer pointer-events-auto" className="bg-main-view-fg/10 px-2 border border-main-view-fg/5 flex items-center justify-center rounded-xl gap-x-2 cursor-pointer pointer-events-auto"
onClick={() => { onClick={() => {
scrollToBottom(true) scrollToBottom(true)
setIsUserScrolling(false) setIsUserScrolling(false)
@ -340,7 +339,7 @@ function ThreadDetail() {
)} )}
{showGenerateAIResponseBtn && ( {showGenerateAIResponseBtn && (
<div <div
className="bg-main-view-fg/10 px-4 border border-main-view-fg/5 flex items-center justify-center rounded-xl gap-x-2 cursor-pointer pointer-events-auto" className="mx-2 bg-main-view-fg/10 px-2 border border-main-view-fg/5 flex items-center justify-center rounded-xl gap-x-2 cursor-pointer pointer-events-auto"
onClick={generateAIResponse} onClick={generateAIResponse}
> >
<p className="text-xs">{t('common:generateAiResponse')}</p> <p className="text-xs">{t('common:generateAiResponse')}</p>

21
website/.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

28
website/README.md Normal file
View File

@ -0,0 +1,28 @@
# Jan's Website
This website is [built with Starlight](https://starlight.astro.build)
Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed
as a route based on its file name.
Images can be added to `src/assets/` and embedded in Markdown with a relative link.
Static assets, like favicons, can be placed in the `public/` directory.
If you want to add new pages, these can go in the `src/pages/` directory. Because of the topics plugin
we are using ([starlight sidebar topics](https://starlight-sidebar-topics.netlify.app/docs/guides/excluded-pages/))
you will need to exclude them from the sidebar by adding them to the exclude list in `astro.config.mjs`, e.g., `exclude: ['/example'],`.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `bun install` | Installs dependencies |
| `bun dev` | Starts local dev server at `localhost:4321` |
| `bun build` | Build your production site to `./dist/` |
| `bun preview` | Preview your build locally, before deploying |
| `bun astro ...` | Run CLI commands like `astro add`, `astro check` |
| `bun astro -- --help` | Get help using the Astro CLI |

175
website/astro.config.mjs Normal file
View File

@ -0,0 +1,175 @@
// @ts-check
import { defineConfig } from 'astro/config'
import starlight from '@astrojs/starlight'
import starlightThemeRapide from 'starlight-theme-rapide'
import starlightSidebarTopics from 'starlight-sidebar-topics'
import mermaid from 'astro-mermaid'
// https://astro.build/config
export default defineConfig({
// Deploy to the new v2 subdomain
site: 'https://v2.jan.ai',
// No 'base' property is needed, as this will be deployed to the root of the subdomain.
integrations: [
mermaid({
theme: 'default',
autoTheme: true,
}),
starlight({
title: '👋 Jan',
favicon: 'jan2.png',
plugins: [
starlightThemeRapide(),
starlightSidebarTopics(
[
{
label: 'Jan Desktop',
link: '/',
icon: 'rocket',
items: [
{
label: 'HOW TO',
items: [
{
label: 'Install 👋 Jan',
collapsed: false,
autogenerate: { directory: 'jan/installation' },
},
{ label: 'Start Chatting', slug: 'jan/threads' },
{
label: 'Use Jan Models',
collapsed: true,
autogenerate: { directory: 'jan/jan-models' },
},
{ label: 'Assistants', slug: 'jan/assistants' },
],
},
{
label: 'Cloud Providers',
items: [
{ label: 'Anthropic', slug: 'jan/remote-models/anthropic' },
{ label: 'OpenAI', slug: 'jan/remote-models/openai' },
{ label: 'Gemini', slug: 'jan/remote-models/google' },
{
label: 'OpenRouter',
slug: 'jan/remote-models/openrouter',
},
{ label: 'Cohere', slug: 'jan/remote-models/cohere' },
{ label: 'Mistral', slug: 'jan/remote-models/mistralai' },
{ label: 'Groq', slug: 'jan/remote-models/groq' },
],
},
{
label: 'EXPLANATION',
items: [
{
label: 'Local AI Engine',
slug: 'jan/explanation/llama-cpp',
},
{
label: 'Model Parameters',
slug: 'jan/explanation/model-parameters',
},
],
},
{
label: 'ADVANCED',
items: [
{ label: 'Manage Models', slug: 'jan/manage-models' },
{ label: 'Model Context Protocol', slug: 'jan/mcp' },
{
label: 'MCP Examples',
collapsed: true,
items: [
{
label: 'Code Sandbox (E2B)',
slug: 'jan/mcp-examples/data-analysis/e2b',
},
{
label: 'Web Search with Exa',
slug: 'jan/mcp-examples/search/exa',
},
],
},
],
},
{
label: 'Local Server',
items: [
{ label: 'Introduction', link: '/local-server/' },
{ label: 'Server Setup', slug: 'local-server/api-server' },
{
label: 'Jan Data Folder',
slug: 'local-server/data-folder',
},
{ label: 'Server Settings', slug: 'local-server/settings' },
{
label: 'Llama.cpp Server',
slug: 'local-server/llama-cpp',
},
{
label: 'Integrations',
collapsed: true,
autogenerate: { directory: 'local-server/integrations' },
},
],
},
{
label: 'REFERENCE',
items: [
{ label: 'Settings', slug: 'jan/settings' },
{ label: 'Jan Data Folder', slug: 'jan/data-folder' },
{ label: 'Troubleshooting', slug: 'jan/troubleshooting' },
{ label: 'Privacy Policy', slug: 'jan/privacy' },
],
},
],
},
{
label: 'Jan Mobile',
link: '/mobile/',
badge: { text: 'Coming Soon', variant: 'caution' },
icon: 'phone',
items: [{ label: 'Overview', slug: 'mobile' }],
},
{
label: 'Jan Server',
link: '/server/',
badge: { text: 'Coming Soon', variant: 'caution' },
icon: 'forward-slash',
items: [{ label: 'Overview', slug: 'server' }],
},
],
{
exclude: [
'/prods',
'/api-reference',
'/products',
'/products/**/*',
],
}
),
],
social: [
{
icon: 'github',
label: 'GitHub',
href: 'https://github.com/menloresearch/jan',
},
{
icon: 'x.com',
label: 'X',
href: 'https://twitter.com/jandotai',
},
{
icon: 'discord',
label: 'Discord',
href: 'https://discord.com/invite/FTk2MvZwJH',
},
],
components: {
Header: './src/components/CustomNav.astro',
},
}),
],
})

1299
website/bun.lock Normal file

File diff suppressed because it is too large Load Diff

27
website/package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "website",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/starlight": "^0.35.1",
"@lorenzo_lewis/starlight-utils": "^0.3.2",
"astro": "^5.6.1",
"astro-mermaid": "^1.0.4",
"gsap": "^3.13.0",
"mermaid": "^11.9.0",
"phosphor-astro": "^2.1.0",
"sharp": "^0.34.3",
"starlight-openapi": "^0.19.1",
"starlight-sidebar-topics": "^0.6.0",
"starlight-theme-rapide": "^0.5.1",
"starlight-videos": "^0.3.0"
},
"packageManager": "yarn@1.22.22"
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill-rule="evenodd" d="M81 36 64 0 47 36l-1 2-9-10a6 6 0 0 0-9 9l10 10h-2L0 64l36 17h2L28 91a6 6 0 1 0 9 9l9-10 1 2 17 36 17-36v-2l9 10a6 6 0 1 0 9-9l-9-9 2-1 36-17-36-17-2-1 9-9a6 6 0 1 0-9-9l-9 10v-2Zm-17 2-2 5c-4 8-11 15-19 19l-5 2 5 2c8 4 15 11 19 19l2 5 2-5c4-8 11-15 19-19l5-2-5-2c-8-4-15-11-19-19l-2-5Z" clip-rule="evenodd"/><path d="M118 19a6 6 0 0 0-9-9l-3 3a6 6 0 1 0 9 9l3-3Zm-96 4c-2 2-6 2-9 0l-3-3a6 6 0 1 1 9-9l3 3c3 2 3 6 0 9Zm0 82c-2-2-6-2-9 0l-3 3a6 6 0 1 0 9 9l3-3c3-2 3-6 0-9Zm96 4a6 6 0 0 1-9 9l-3-3a6 6 0 1 1 9-9l3 3Z"/><style>path{fill:#000}@media (prefers-color-scheme:dark){path{fill:#fff}}</style></svg>

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 MiB

BIN
website/public/jan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
website/public/jan2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 KiB

BIN
website/src/assets/exa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
website/src/assets/exa1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

BIN
website/src/assets/exa2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 KiB

BIN
website/src/assets/exa3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

BIN
website/src/assets/exa4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

BIN
website/src/assets/groq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

BIN
website/src/assets/ls.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 KiB

Some files were not shown because too many files have changed in this diff Show More