diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..45fd5d159 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ +## Describe Your Changes + +- + +## Fixes Issues + +- + +## Self Checklist + +- [ ] Added relevant comments, esp in complex areas +- [ ] Updated docs (for bug fixes / features) +- [ ] Created issues for follow-up changes or refactoring needed diff --git a/README.md b/README.md index 7d8cd7802..31e2c4714 100644 --- a/README.md +++ b/README.md @@ -70,25 +70,25 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Experimental (Nightly Build) - + jan.exe - + Intel - + M1/M2 - + jan.deb diff --git a/core/src/node/index.ts b/core/src/node/index.ts index 49c2c3c26..50651d1fd 100644 --- a/core/src/node/index.ts +++ b/core/src/node/index.ts @@ -5,3 +5,4 @@ export * from './extension/store' export * from './download' export * from './module' export * from './api' +export * from './log' diff --git a/core/src/node/log.ts b/core/src/node/log.ts new file mode 100644 index 000000000..7291516cd --- /dev/null +++ b/core/src/node/log.ts @@ -0,0 +1,18 @@ +import fs from 'fs' +import util from 'util' +import path from 'path' +import os from 'os' + +const appDir = path.join(os.homedir(), 'jan') + +export const logPath = path.join(appDir, 'app.log') + +export const log = function (d: any) { + if (fs.existsSync(appDir)) { + var log_file = fs.createWriteStream(logPath, { + flags: 'a', + }) + log_file.write(util.format(d) + '\n') + log_file.close() + } +} diff --git a/docs/docs/docs/README.md b/docs/docs/docs/README.md index d6ff08d55..a82a8a801 100644 --- a/docs/docs/docs/README.md +++ b/docs/docs/docs/README.md @@ -3,4 +3,69 @@ title: Overview slug: /docs --- -Hello world +The following low-level docs are aimed at core contributors and cover how to contribute to the Core SDK. + +:::tip +If you are interested to **build on top of the SDK**, like creating assistants or adding app level extensions, please refer to [developer docs](/developer) instead. +::: + +## Core SDK + +At its Core, Jan is a cross-platform, local-first and AI native framework that can be used to build anything. In fact, current features are all implemented as 3rd party extensions on top of this Core SDK. + +Ultimately, we aim for a VSCode or Obsidian like framework that allows devs to build and customize complex AI applications for their specific needs, in less than 15 minutes. + +### Cross Platform + +Jan follows [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) to the best of our ability. Though leaky abstractions remain (we're a fast moving, open source codebase), we do our best to build an SDK that allows devs to **build once, deploy everywhere.** + +Currently, Jan supports: + +- `Node Native Runtime`, good for server side apps +- `Electron Chromium`, good for Desktop Native apps +- `Capacitor`, good for Mobile apps (planned, not built yet) +- `Python Runtime`, good for MLOps workflows (planned, not built yet) + +Currently, Jan works across: + +- Mac Intel & Silicon +- Windows +- Ubuntu +- Nvidia GPUs + +Read more: + +- [Code Entrypoint](https://github.com/janhq/jan/tree/main/core) +- [Dependency Inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle) + +### Local First + +Jan's data persistence happens on the user's local filesystem. + +We implemented abstractions on top of `fs` and other core modules in an opinionated way, s.t. user data is saved in a folder-based framework that lets users easily package, export, and manage their data. + +Read more: + +- [Folder-based fs wrapper](https://github.com/janhq/jan/blob/main/core/src/fs.ts) +- [Piping Node modules across infrastructures](https://github.com/janhq/jan/tree/main/core/src/node) + +### AI Native + +All software applications can be natively supercharged with an embedded AI server and AI abstractions. + +Including: + +- OpenAI Compatible AI [types](https://github.com/janhq/jan/tree/main/core/src/types) and [core extensions](https://github.com/janhq/jan/tree/main/core/src/extensions) to support common functionality like making an inference call. +- A lightweight, embedded C++ [inference engine](https://github.com/janhq/jan/tree/main/extensions/inference-nitro-extension) that's immediately callable from code. + +- [Code Entrypoint](https://github.com/janhq/jan/tree/main/core/src/api) + +## Fun Project Ideas + +Beyond the current Jan client and UX, the Core SDK can be used to build many other AI-powered and privacy preserving applications. + +- `Game engine`: For AI enabled character games, procedural generation games +- `Health app`: For a personal healthcare app that improves habits +- Got ideas? Make a PR into this docs page! + +If you are interested to tackle these issues, or have suggestions for integrations and other OSS tools we can use, please hit us up in [Discord](https://discord.gg/5rQ2zTv3be). diff --git a/docs/docs/handbook/onboarding.md b/docs/docs/handbook/onboarding.md index e9124bdad..3aec99258 100644 --- a/docs/docs/handbook/onboarding.md +++ b/docs/docs/handbook/onboarding.md @@ -32,7 +32,7 @@ Welcome to Jan! We’re really excited to bring you onboard. - We operate on the basis of trust. - We expect you to be available and communicative during scheduled meetings or work hours. - Turning on video during meetings is encouraged. -- Casual dress during meetings is acceptable; however, use discretion (No naked top, pajamas, etc.) +- Casual dress during meetings is acceptable; however, use discretion (No nudity, pajamas, etc.) - While it’s natural for people to disagree at times, disagreement is no excuse for poor behavior and poor manners. We cannot allow that frustration to turn into a personal attack. - Respect other people's cultures. Especially since we are working in a diverse working culture. - Sexual harassment is a specific type of prohibited conduct. Sexual harassment is any unwelcome conduct of a sexual nature that might reasonably be expected or be perceived to cause offense or humiliation. Sexual harassment may involve any conduct of a verbal, nonverbal, or physical nature, including written and electronic communications, and may occur between persons of the same or different genders. diff --git a/electron/main.ts b/electron/main.ts index 4ddf4df56..257842cf5 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -68,6 +68,12 @@ function createMainWindow() { if (process.platform !== 'darwin') app.quit() }) + /* Open external links in the default browser */ + mainWindow.webContents.setWindowOpenHandler(({ url }) => { + require('electron').shell.openExternal(url) + return { action: 'deny' } + }) + /* Enable dev tools for development */ if (!app.isPackaged) mainWindow.webContents.openDevTools() } diff --git a/extensions/monitoring-extension/package.json b/extensions/monitoring-extension/package.json index 4fc51d578..9935e536e 100644 --- a/extensions/monitoring-extension/package.json +++ b/extensions/monitoring-extension/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@janhq/core": "file:../../core", - "os-utils": "^0.0.14", + "node-os-utils": "^1.3.7", "ts-loader": "^9.5.0" }, "files": [ @@ -26,6 +26,6 @@ "README.md" ], "bundleDependencies": [ - "os-utils" + "node-os-utils" ] } diff --git a/extensions/monitoring-extension/src/module.ts b/extensions/monitoring-extension/src/module.ts index 18b3b6c49..310e7359c 100644 --- a/extensions/monitoring-extension/src/module.ts +++ b/extensions/monitoring-extension/src/module.ts @@ -1,25 +1,25 @@ const os = require("os"); -const osUtils = require("os-utils"); +const nodeOsUtils = require("node-os-utils"); const getResourcesInfo = () => new Promise((resolve) => { - const totalMemory = os.totalmem(); - const freeMemory = os.freemem(); - const usedMemory = totalMemory - freeMemory; - - const response = { - mem: { - totalMemory, - usedMemory, - }, - }; - resolve(response); + nodeOsUtils.mem.used() + .then(ramUsedInfo => { + const totalMemory = ramUsedInfo.totalMemMb * 1024 * 1024; + const usedMemory = ramUsedInfo.usedMemMb * 1024 * 1024; + const response = { + mem: { + totalMemory, + usedMemory, + }, + }; + resolve(response); + }) }); const getCurrentLoad = () => new Promise((resolve) => { - osUtils.cpuUsage(function(v){ - const cpuPercentage = v * 100; + nodeOsUtils.cpu.usage().then(cpuPercentage =>{ const response = { cpu: { usage: cpuPercentage, diff --git a/server/index.ts b/server/index.ts index 6a03c06fd..55b4a8d3c 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1,9 +1,8 @@ import fastify from "fastify"; import dotenv from "dotenv"; -import { v1Router } from "@janhq/core/node"; +import { log, v1Router } from "@janhq/core/node"; import path from "path"; -import fs from "fs"; -import util from "util"; + import os from "os"; dotenv.config(); @@ -14,18 +13,6 @@ const serverLogPath = path.join(os.homedir(), "jan", "server.log"); let server: any | undefined = undefined; -var log_file = fs.createWriteStream(serverLogPath, { - flags: "a", -}); -var log_stdout = process.stdout; -var log_stderr = process.stderr; - -const logServer = function (d: any) { - log_file.write(util.format(d) + "\n"); - log_stdout.write(util.format(d) + "\n"); - log_stderr.write(util.format(d) + "\n"); -}; - export const startServer = async (schemaPath?: string, baseDir?: string) => { try { server = fastify({ @@ -75,12 +62,10 @@ export const startServer = async (schemaPath?: string, baseDir?: string) => { host: JAN_API_HOST, }) .then(() => { - logServer( - `JAN API listening at: http://${JAN_API_HOST}:${JAN_API_PORT}` - ); + log(`JAN API listening at: http://${JAN_API_HOST}:${JAN_API_PORT}`); }); } catch (e) { - logServer(e); + log(e); } }; @@ -88,6 +73,6 @@ export const stopServer = async () => { try { await server.close(); } catch (e) { - logServer(e); + log(e); } }; diff --git a/web/containers/Layout/Ribbon/index.tsx b/web/containers/Layout/Ribbon/index.tsx index fa6d53193..6a0146e64 100644 --- a/web/containers/Layout/Ribbon/index.tsx +++ b/web/containers/Layout/Ribbon/index.tsx @@ -11,6 +11,8 @@ import { SettingsIcon, MonitorIcon, LayoutGridIcon, + Twitter, + Github, } from 'lucide-react' import { twMerge } from 'tailwind-merge' @@ -52,6 +54,23 @@ export default function RibbonNav() { }, ] + const linksMenu = [ + { + name: 'Twitter', + icon: ( + + ), + link: 'https://twitter.com/janhq_', + }, + { + name: 'Github', + icon: ( + + ), + link: 'https://github.com/janhq/jan', + }, + ] + const secondaryMenus = [ { name: 'System Monitor', @@ -118,6 +137,32 @@ export default function RibbonNav() {
+ <> + {linksMenu + .filter((link) => !!link) + .map((link, i) => { + return ( +
+ + + + {link.icon} + + + + {link.name} + + + +
+ ) + })} + {secondaryMenus .filter((secondary) => !!secondary) .map((secondary, i) => { diff --git a/web/hooks/useGetSystemResources.ts b/web/hooks/useGetSystemResources.ts index 74f8e6c40..9d6716480 100644 --- a/web/hooks/useGetSystemResources.ts +++ b/web/hooks/useGetSystemResources.ts @@ -46,12 +46,12 @@ export default function useGetSystemResources() { useEffect(() => { getSystemResources() - // Fetch interval - every 2s + // Fetch interval - every 0.5s // TODO: Will we really need this? // There is a possibility that this will be removed and replaced by the process event hook? const intervalId = setInterval(() => { getSystemResources() - }, 2000) + }, 500) // clean up interval return () => clearInterval(intervalId)