├── rustfmt.toml ├── openapi-docs └── .keep ├── edgen ├── src │ ├── assets │ │ └── KEEP │ ├── vite-env.d.ts │ ├── App.css │ ├── main.tsx │ ├── App.tsx │ └── styles.css ├── src-tauri │ ├── icons │ │ ├── 32x32.png │ │ ├── icon.icns │ │ ├── icon.ico │ │ ├── icon.png │ │ ├── 128x128.png │ │ ├── 128x128@2x.png │ │ ├── StoreLogo.png │ │ ├── Square30x30Logo.png │ │ ├── Square44x44Logo.png │ │ ├── Square71x71Logo.png │ │ ├── Square89x89Logo.png │ │ ├── Square107x107Logo.png │ │ ├── Square142x142Logo.png │ │ ├── Square150x150Logo.png │ │ ├── Square284x284Logo.png │ │ ├── Square310x310Logo.png │ │ └── ios │ │ │ ├── AppIcon-512@2x.png │ │ │ ├── AppIcon-20x20@1x.png │ │ │ ├── AppIcon-20x20@2x.png │ │ │ ├── AppIcon-20x20@3x.png │ │ │ ├── AppIcon-29x29@1x.png │ │ │ ├── AppIcon-29x29@2x.png │ │ │ ├── AppIcon-29x29@3x.png │ │ │ ├── AppIcon-40x40@1x.png │ │ │ ├── AppIcon-40x40@2x.png │ │ │ ├── AppIcon-40x40@3x.png │ │ │ ├── AppIcon-60x60@2x.png │ │ │ ├── AppIcon-60x60@3x.png │ │ │ ├── AppIcon-76x76@1x.png │ │ │ ├── AppIcon-76x76@2x.png │ │ │ ├── AppIcon-20x20@2x-1.png │ │ │ ├── AppIcon-29x29@2x-1.png │ │ │ ├── AppIcon-40x40@2x-1.png │ │ │ └── AppIcon-83.5x83.5@2x.png │ ├── .gitignore │ ├── build.rs │ ├── Cargo.toml │ ├── tauri.conf.json │ └── src │ │ ├── main.rs │ │ └── gui.rs ├── tsconfig.node.json ├── .gitignore ├── index.html ├── package.json ├── vite.config.ts ├── tsconfig.json ├── README.md └── public │ └── EdgenAI_dark_colored.svg ├── docs ├── src │ ├── app │ │ ├── guides │ │ │ ├── migrate │ │ │ │ └── page.mdx │ │ │ ├── page.tsx │ │ │ ├── examples │ │ │ │ └── page.mdx │ │ │ └── quickstart │ │ │ │ └── page.mdx │ │ ├── favicon.ico │ │ ├── api-reference │ │ │ ├── page.tsx │ │ │ ├── embeddings │ │ │ │ └── page.mdx │ │ │ └── image │ │ │ │ └── page.mdx │ │ ├── documentation │ │ │ ├── page.tsx │ │ │ ├── api-clients │ │ │ │ └── page.mdx │ │ │ ├── models │ │ │ │ └── page.mdx │ │ │ ├── getting-started │ │ │ │ └── page.mdx │ │ │ ├── errors │ │ │ │ └── page.mdx │ │ │ └── configuration │ │ │ │ └── page.mdx │ │ ├── not-found.tsx │ │ ├── providers.tsx │ │ ├── page.mdx │ │ └── layout.tsx │ ├── image.d.ts │ ├── mdx │ │ ├── recma.mjs │ │ ├── remark.mjs │ │ ├── rehype.mjs │ │ └── search.mjs │ ├── lib │ │ └── remToPx.ts │ ├── components │ │ ├── icons │ │ │ ├── BoltIcon.tsx │ │ │ ├── CubeIcon.tsx │ │ │ ├── ShirtIcon.tsx │ │ │ ├── LinkIcon.tsx │ │ │ ├── MicrophoneIcon.tsx │ │ │ ├── MagnifyingGlassIcon.tsx │ │ │ ├── CheckIcon.tsx │ │ │ ├── BookIcon.tsx │ │ │ ├── DocumentIcon.tsx │ │ │ ├── PaperAirplaneIcon.tsx │ │ │ ├── FaceSmileIcon.tsx │ │ │ ├── ListIcon.tsx │ │ │ ├── PaperClipIcon.tsx │ │ │ ├── PackageIcon.tsx │ │ │ ├── CopyIcon.tsx │ │ │ ├── ChevronRightLeftIcon.tsx │ │ │ ├── EnvelopeIcon.tsx │ │ │ ├── BellIcon.tsx │ │ │ ├── CartIcon.tsx │ │ │ ├── ChatBubbleIcon.tsx │ │ │ ├── ShapesIcon.tsx │ │ │ ├── SquaresPlusIcon.tsx │ │ │ ├── ClipboardIcon.tsx │ │ │ ├── MapPinIcon.tsx │ │ │ ├── CalendarIcon.tsx │ │ │ ├── FolderIcon.tsx │ │ │ ├── UsersIcon.tsx │ │ │ ├── UserIcon.tsx │ │ │ ├── TagIcon.tsx │ │ │ └── CogIcon.tsx │ │ ├── Prose.tsx │ │ ├── GridPattern.tsx │ │ ├── HeroPattern.tsx │ │ ├── Highlights.tsx │ │ ├── ThemeToggle.tsx │ │ ├── Layout.tsx │ │ ├── ButtonRow.tsx │ │ ├── Tag.tsx │ │ ├── APIClients.tsx │ │ ├── Button.tsx │ │ ├── Feedback.tsx │ │ ├── Header.tsx │ │ ├── Logo.tsx │ │ ├── mdx.tsx │ │ ├── SectionProvider.tsx │ │ ├── Heading.tsx │ │ └── EdgenAI_dark_colored.svg │ ├── images │ │ └── logos │ │ │ ├── ruby.svg │ │ │ ├── python.svg │ │ │ ├── node.svg │ │ │ ├── php.svg │ │ │ └── go.svg │ └── styles │ │ └── tailwind.css ├── .eslintrc.json ├── postcss.config.js ├── prettier.config.js ├── mdx-components.tsx ├── types.d.ts ├── assets │ └── stylesheets │ │ └── extra.css ├── .gitignore ├── next.config.mjs ├── tsconfig.json ├── README.md ├── tailwind.config.ts └── package.json ├── crates ├── edgen_server │ ├── resources │ │ ├── dummy.gguf │ │ └── frost.wav │ ├── src │ │ ├── util.rs │ │ ├── graceful_shutdown.rs │ │ ├── llm.rs │ │ ├── chat_faker.rs │ │ └── whisper.rs │ └── Cargo.toml ├── edgen_rt_chat_faker │ └── Cargo.toml ├── edgen_async_compat │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── edgen_rt_llama_cpp │ └── Cargo.toml ├── edgen_rt_image_generation_candle │ └── Cargo.toml ├── edgen_rt_whisper_cpp │ └── Cargo.toml └── edgen_core │ ├── Cargo.toml │ └── src │ ├── image_generation.rs │ └── lib.rs ├── tests ├── requirements.txt ├── runtests.sh ├── test_models.py ├── test_misc.py ├── test_audio.py └── test_chat.py ├── .cargo └── config.toml ├── rust-toolchain.toml ├── .editorconfig ├── scripts ├── gen-openapi-spec.sh └── add_copyright.sh ├── .vscode └── settings.json ├── .github └── workflows │ ├── ci.yml │ ├── docs.yml │ └── build.yml ├── Cargo.toml ├── .gitignore ├── flake.nix └── flake.lock /rustfmt.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openapi-docs/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /edgen/src/assets/KEEP: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/app/guides/migrate/page.mdx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /crates/edgen_server/resources/dummy.gguf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | edgen==0.1.2 2 | Levenshtein==0.24.0 3 | -------------------------------------------------------------------------------- /edgen/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /docs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = [ 3 | "--cfg", "tokio_unstable", 4 | ] 5 | -------------------------------------------------------------------------------- /docs/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/docs/src/app/favicon.ico -------------------------------------------------------------------------------- /edgen/src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /edgen/src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /edgen/src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /edgen/src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | -------------------------------------------------------------------------------- /edgen/src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /crates/edgen_server/resources/frost.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/crates/edgen_server/resources/frost.wav -------------------------------------------------------------------------------- /docs/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /docs/src/image.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: Element; 3 | export default content; 4 | } -------------------------------------------------------------------------------- /docs/src/mdx/recma.mjs: -------------------------------------------------------------------------------- 1 | import { mdxAnnotations } from 'mdx-annotations' 2 | 3 | export const recmaPlugins = [mdxAnnotations.recma] 4 | -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-512@2x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /docs/src/app/guides/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | export default async function Home({}) { 3 | redirect('/') 4 | } 5 | -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /edgen/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgenai/edgen/HEAD/edgen/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /docs/src/app/api-reference/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | export default async function Home({}) { 3 | redirect('/api-reference/audio') 4 | } 5 | -------------------------------------------------------------------------------- /edgen/src/App.css: -------------------------------------------------------------------------------- 1 | .logo.vite:hover { 2 | filter: drop-shadow(0 0 2em #747bff); 3 | } 4 | 5 | .logo.react:hover { 6 | filter: drop-shadow(0 0 2em #61dafb); 7 | } 8 | -------------------------------------------------------------------------------- /docs/src/app/documentation/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | export default async function Home({}) { 3 | redirect('/documentation/getting-started') 4 | } 5 | -------------------------------------------------------------------------------- /docs/src/app/guides/examples/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Examples', 3 | description: 'TODO', 4 | } 5 | 6 | # Examples 7 | 8 | TODO {{ className: 'lead' }} 9 | -------------------------------------------------------------------------------- /docs/src/mdx/remark.mjs: -------------------------------------------------------------------------------- 1 | import { mdxAnnotations } from 'mdx-annotations' 2 | import remarkGfm from 'remark-gfm' 3 | 4 | export const remarkPlugins = [mdxAnnotations.remark, remarkGfm] 5 | -------------------------------------------------------------------------------- /docs/prettier.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Options} */ 2 | module.exports = { 3 | singleQuote: true, 4 | semi: false, 5 | plugins: ['prettier-plugin-tailwindcss'], 6 | } 7 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "beta-2023-11-21" 3 | profile = "minimal" 4 | targets = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-pc-windows-gnu", "wasm32-unknown-unknown"] 5 | -------------------------------------------------------------------------------- /docs/src/lib/remToPx.ts: -------------------------------------------------------------------------------- 1 | export function remToPx(remValue: number) { 2 | let rootFontSize = 3 | typeof window === 'undefined' 4 | ? 16 5 | : parseFloat(window.getComputedStyle(document.documentElement).fontSize) 6 | 7 | return remValue * rootFontSize 8 | } 9 | -------------------------------------------------------------------------------- /docs/mdx-components.tsx: -------------------------------------------------------------------------------- 1 | import * as mdxComponents from '@/components/mdx' 2 | import { type MDXComponents } from 'mdx/types' 3 | 4 | export function useMDXComponents(components: MDXComponents) { 5 | return { 6 | ...components, 7 | ...mdxComponents, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /edgen/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /edgen/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App"; 4 | import "./styles.css"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( 7 | 8 | 9 | , 10 | ); 11 | -------------------------------------------------------------------------------- /docs/types.d.ts: -------------------------------------------------------------------------------- 1 | import { type SearchOptions } from 'flexsearch' 2 | 3 | declare module '@/mdx/search.mjs' { 4 | export type Result = { 5 | url: string 6 | title: string 7 | pageTitle?: string 8 | } 9 | 10 | export function search(query: string, options?: SearchOptions): Array 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | root = true 3 | max_line_length = 80 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | end_of_line = lf 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [*.rs] 12 | indent_size = 4 13 | max_line_length = 120 14 | 15 | [*.py] 16 | indent_size = 4 17 | -------------------------------------------------------------------------------- /edgen/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /docs/src/components/icons/BoltIcon.tsx: -------------------------------------------------------------------------------- 1 | export function BoltIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /docs/src/components/icons/CubeIcon.tsx: -------------------------------------------------------------------------------- 1 | export function CubeIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 10 | ) 11 | } 12 | 13 | -------------------------------------------------------------------------------- /edgen/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tauri + React + TS 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/src/components/icons/ShirtIcon.tsx: -------------------------------------------------------------------------------- 1 | export function ShirtIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /docs/assets/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | .md-header { 2 | display: flex !important; 3 | flex-direction: row-reverse !important; 4 | } 5 | .md-tabs { 6 | order: 2; 7 | margin-left: 120px !important; 8 | } 9 | .md-logo { 10 | order: 1; 11 | } 12 | .md-header__inner { 13 | flex-direction: row-reverse !important; 14 | } 15 | .md-logo { 16 | position: absolute !important; 17 | left: 15px !important; 18 | } 19 | 20 | .img_container{ 21 | align: "center"; 22 | } 23 | -------------------------------------------------------------------------------- /docs/src/components/icons/LinkIcon.tsx: -------------------------------------------------------------------------------- 1 | export function LinkIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /docs/src/components/icons/MicrophoneIcon.tsx: -------------------------------------------------------------------------------- 1 | export function MicrophoneIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /docs/src/components/icons/MagnifyingGlassIcon.tsx: -------------------------------------------------------------------------------- 1 | export function MagnifyingGlassIcon( 2 | props: React.ComponentPropsWithoutRef<'svg'>, 3 | ) { 4 | return ( 5 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /docs/src/components/icons/CheckIcon.tsx: -------------------------------------------------------------------------------- 1 | export function CheckIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/BookIcon.tsx: -------------------------------------------------------------------------------- 1 | export function BookIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /tests/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -i 2 | # ubuntu does not source .bashrc in (non-interactive) scripts 3 | 4 | # run all tests: 5 | # starts the edgen server 6 | # runs tests with pytest 7 | # stops the server 8 | 9 | cargo build --release 10 | 11 | echo "================================================" 12 | date 13 | target/release/edgen version 14 | echo "================================================" 15 | 16 | target/release/edgen serve --nogui & > tests/tests.log 2>&1 17 | PID=$! 18 | 19 | sleep 1 20 | 21 | python -m pytest tests 22 | 23 | kill -2 $PID 24 | -------------------------------------------------------------------------------- /docs/src/components/icons/DocumentIcon.tsx: -------------------------------------------------------------------------------- 1 | export function DocumentIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/PaperAirplaneIcon.tsx: -------------------------------------------------------------------------------- 1 | export function PaperAirplaneIcon( 2 | props: React.ComponentPropsWithoutRef<'svg'>, 3 | ) { 4 | return ( 5 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /tests/test_models.py: -------------------------------------------------------------------------------- 1 | 2 | from edgen import Edgen, APIConnectionError 3 | from edgen.pagination import SyncPage 4 | from edgen.resources.models import Model 5 | import pytest 6 | import subprocess 7 | 8 | client = Edgen() 9 | 10 | def test_models(): 11 | try: 12 | models = client.models.list() 13 | except APIConnectionError: 14 | pytest.fail("No connection. Is edgen running?") 15 | 16 | assert(type(models) is SyncPage[Model]) 17 | 18 | for model in models: 19 | print(model) 20 | 21 | if __name__ == "__main__": 22 | test_models() 23 | -------------------------------------------------------------------------------- /docs/src/components/icons/FaceSmileIcon.tsx: -------------------------------------------------------------------------------- 1 | export function FaceSmileIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/ListIcon.tsx: -------------------------------------------------------------------------------- 1 | export function ListIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/images/logos/ruby.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /docs/src/components/icons/PaperClipIcon.tsx: -------------------------------------------------------------------------------- 1 | export function PaperClipIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /docs/src/components/icons/PackageIcon.tsx: -------------------------------------------------------------------------------- 1 | export function PackageIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /docs/src/components/icons/CopyIcon.tsx: -------------------------------------------------------------------------------- 1 | export function CopyIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /crates/edgen_rt_chat_faker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen_rt_chat_faker" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | async-trait = { workspace = true } 10 | blake3 = { workspace = true } 11 | dashmap = { workspace = true } 12 | derive_more = { workspace = true } 13 | edgen_core = { path = "../edgen_core" } 14 | futures = { workspace = true } 15 | thiserror = { workspace = true } 16 | tokio = { workspace = true, features = ["sync", "rt", "fs"] } 17 | tracing = { workspace = true } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/ChevronRightLeftIcon.tsx: -------------------------------------------------------------------------------- 1 | export function ChevronRightLeftIcon( 2 | props: React.ComponentPropsWithoutRef<'svg'>, 3 | ) { 4 | return ( 5 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /edgen/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "edgen", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "tsc && vite build", 8 | "preview": "vite preview", 9 | "tauri": "tauri" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "@tauri-apps/api": "^1.5.2" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "^18.2.15", 18 | "@types/react-dom": "^18.2.7", 19 | "@vitejs/plugin-react": "^4.2.1", 20 | "typescript": "^5.0.2", 21 | "vite": "^5.0.13", 22 | "@tauri-apps/cli": "^1.5.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/src/components/icons/EnvelopeIcon.tsx: -------------------------------------------------------------------------------- 1 | export function EnvelopeIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/BellIcon.tsx: -------------------------------------------------------------------------------- 1 | export function BellIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/CartIcon.tsx: -------------------------------------------------------------------------------- 1 | export function CartIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /docs/next.config.mjs: -------------------------------------------------------------------------------- 1 | import nextMDX from '@next/mdx' 2 | 3 | import { recmaPlugins } from './src/mdx/recma.mjs' 4 | import { rehypePlugins } from './src/mdx/rehype.mjs' 5 | import { remarkPlugins } from './src/mdx/remark.mjs' 6 | import withSearch from './src/mdx/search.mjs' 7 | 8 | const withMDX = nextMDX({ 9 | options: { 10 | remarkPlugins, 11 | rehypePlugins, 12 | recmaPlugins, 13 | }, 14 | }) 15 | 16 | /** @type {import('next').NextConfig} */ 17 | const nextConfig = { 18 | output: 'export', 19 | // basePath: 'edgen/', 20 | pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'mdx'], 21 | } 22 | 23 | export default withSearch(withMDX(nextConfig)) 24 | -------------------------------------------------------------------------------- /docs/src/components/icons/ChatBubbleIcon.tsx: -------------------------------------------------------------------------------- 1 | export function ChatBubbleIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/ShapesIcon.tsx: -------------------------------------------------------------------------------- 1 | export function ShapesIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /edgen/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig(async () => ({ 6 | plugins: [react()], 7 | 8 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 9 | // 10 | // 1. prevent vite from obscuring rust errors 11 | clearScreen: false, 12 | // 2. tauri expects a fixed port, fail if that port is not available 13 | server: { 14 | port: 1420, 15 | strictPort: true, 16 | watch: { 17 | // 3. tell vite to ignore watching `src-tauri` 18 | ignored: ["**/src-tauri/**"], 19 | }, 20 | }, 21 | })); 22 | -------------------------------------------------------------------------------- /edgen/src/App.tsx: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | 3 | function App() { 4 | return ( 5 |
6 |
7 | 8 | EdgenChat 13 | 14 |
15 |

16 | Edgen is now running! Start chatting now with 17 | EdgenChat. 18 |

19 | 20 | 21 | 22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /crates/edgen_async_compat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen_async_compat" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | runtime-smol = ["smol", "async-task", "futures-lite"] 8 | runtime-tokio = ["tokio", "futures"] 9 | runtime-glommio = ["glommio"] 10 | 11 | [dependencies] 12 | async-task = { workspace = true, optional = true } 13 | cfg-if = { workspace = true } 14 | futures = { workspace = true, optional = true } 15 | futures-lite = { workspace = true, optional = true } 16 | glommio = { workspace = true, optional = true } 17 | smol = { workspace = true, optional = true } 18 | static_assertions = { workspace = true } 19 | tokio = { workspace = true, optional = true, features = ["rt"] } 20 | -------------------------------------------------------------------------------- /edgen/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /edgen/src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | fn main() { 14 | tauri_build::build() 15 | } 16 | -------------------------------------------------------------------------------- /crates/edgen_rt_llama_cpp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen_rt_llama_cpp" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | async-trait = { workspace = true } 8 | blake3 = { workspace = true } 9 | dashmap = { workspace = true } 10 | derive_more = { workspace = true } 11 | edgen_core = { path = "../edgen_core" } 12 | futures = { workspace = true } 13 | llama_cpp = { git = "https://github.com/edgenai/llama_cpp-rs", branch = "main", features = ["native"] } 14 | thiserror = { workspace = true } 15 | tokio = { workspace = true, features = ["sync", "rt", "fs"] } 16 | tracing = { workspace = true } 17 | 18 | [features] 19 | vulkan = ["llama_cpp/vulkan"] 20 | cuda = ["llama_cpp/cuda"] 21 | metal = ["llama_cpp/metal"] 22 | -------------------------------------------------------------------------------- /docs/src/components/icons/SquaresPlusIcon.tsx: -------------------------------------------------------------------------------- 1 | export function SquaresPlusIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/ClipboardIcon.tsx: -------------------------------------------------------------------------------- 1 | export function ClipboardIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/components/icons/MapPinIcon.tsx: -------------------------------------------------------------------------------- 1 | export function MapPinIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /docs/src/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @layer base { 2 | :root { 3 | --shiki-color-text: theme('colors.white'); 4 | --shiki-token-constant: theme('colors.yellow.300'); 5 | --shiki-token-string: theme('colors.yellow.300'); 6 | --shiki-token-comment: theme('colors.zinc.500'); 7 | --shiki-token-keyword: theme('colors.sky.300'); 8 | --shiki-token-parameter: theme('colors.pink.300'); 9 | --shiki-token-function: theme('colors.violet.300'); 10 | --shiki-token-string-expression: theme('colors.yellow.300'); 11 | --shiki-token-punctuation: theme('colors.zinc.200'); 12 | } 13 | 14 | [inert] ::-webkit-scrollbar { 15 | display: none; 16 | } 17 | } 18 | 19 | @tailwind base; 20 | @tailwind components; 21 | @tailwind utilities; 22 | -------------------------------------------------------------------------------- /crates/edgen_rt_image_generation_candle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen_rt_image_generation_candle" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | async-trait = { workspace = true } 8 | candle-core = "0.4.1" 9 | candle-nn = "0.4.1" 10 | candle-transformers = "0.4.1" 11 | edgen_core = { path = "../edgen_core" } 12 | image = "0.25.1" 13 | rand = "0.8.5" 14 | thiserror = { workspace = true } 15 | # https://github.com/huggingface/tokenizers/issues/1454 16 | tokenizers = { version = "0.19.1", default-features = false, features = ["progressbar", "onig"] } 17 | tokio = { workspace = true, features = ["sync", "rt", "fs"] } 18 | tracing = { workspace = true } 19 | 20 | [features] 21 | cuda = ["candle-core/cuda", "candle-transformers/cuda"] 22 | -------------------------------------------------------------------------------- /docs/src/components/icons/CalendarIcon.tsx: -------------------------------------------------------------------------------- 1 | export function CalendarIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "bundler", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /docs/src/app/documentation/api-clients/page.mdx: -------------------------------------------------------------------------------- 1 | import { APIClients } from '@/components/APIClients' 2 | 3 | export const metadata = { 4 | title: 'Edgen API Clients', 5 | description: 6 | 'Edgen offers several ready-to-use API Clients: Python and Node.js SDKs.', 7 | } 8 | 9 | export const sections = [ 10 | { title: 'Official API Clients', id: 'official-apiclients' }, 11 | ] 12 | 13 | # Edgen API Clients 14 | 15 | The recommended way to interact with the Edgen API is by using one of our official API clients. {{ className: 'lead' }} 16 | 17 |
18 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /scripts/gen-openapi-spec.sh: -------------------------------------------------------------------------------- 1 | # ===================================================================================================================== 2 | # Generates the Edgen OpenAPI Spec for edgend 3 | # ------------------------------------------- 4 | # Input: 5 | # - edgend source code 6 | # 7 | # Output: 8 | # - OpenAPI Spec as yaml 9 | # - OpenAPI Spec as json 10 | # -------------------------------------------------------------------------------------------------------------------- 11 | # (c) Binedge 2023 12 | # ===================================================================================================================== 13 | cargo run --bin edgend -- -o > openapi-docs/edgen-api-spec.yaml 14 | swagger-cli bundle -o openapi-docs/edgen-api-spec.json openapi-docs/edgen-api-spec.yaml 15 | 16 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Edgen Docs 2 | 3 | ## Getting started 4 | 5 | To get started developing, first install the npm dependencies: 6 | 7 | ```bash 8 | npm install 9 | ``` 10 | 11 | Next, run the development server: 12 | 13 | ```bash 14 | npm run dev 15 | ``` 16 | 17 | Finally, open [http://localhost:3000](http://localhost:3000) in your browser. 18 | 19 | ## Global search 20 | 21 | The docs includes a global search that's powered by the [FlexSearch](https://github.com/nextapps-de/flexsearch) library. It's available by clicking the search input or by using the `CTRL+K` shortcut. 22 | 23 | This feature requires no configuration, and works out of the box by automatically scanning your documentation pages to build its index. The search parameters can be adjusted by editing the `src/mdx/search.mjs` file. 24 | -------------------------------------------------------------------------------- /docs/src/components/Prose.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx' 2 | 3 | export function Prose({ 4 | as, 5 | className, 6 | ...props 7 | }: Omit, 'as' | 'className'> & { 8 | as?: T 9 | className?: string 10 | }) { 11 | let Component = as ?? 'div' 12 | 13 | return ( 14 | *)` is used to select all direct children without an increase in specificity like you'd get from just `& > *` 19 | '[html_:where(&>*)]:mx-auto [html_:where(&>*)]:max-w-2xl [html_:where(&>*)]:lg:mx-[calc(50%-min(50%,theme(maxWidth.lg)))] [html_:where(&>*)]:lg:max-w-3xl', 20 | )} 21 | {...props} 22 | /> 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /crates/edgen_rt_whisper_cpp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen_rt_whisper_cpp" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | async-trait = { workspace = true } 10 | dashmap = { workspace = true } 11 | edgen_core = { path = "../edgen_core" } 12 | futures = { workspace = true } 13 | derive_more = { workspace = true } 14 | thiserror = { workspace = true } 15 | tokio = { workspace = true, features = ["sync"] } 16 | once_cell = { workspace = true } 17 | tracing = { workspace = true } 18 | uuid = { workspace = true, features = ["v4"] } 19 | whisper_cpp = { git = "https://github.com/edgenai/whisper_cpp-rs", branch = "main", features = ["native"] } 20 | 21 | [features] 22 | cuda = ["whisper_cpp/cuda"] 23 | -------------------------------------------------------------------------------- /crates/edgen_server/src/util.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | //! Utility types. 14 | 15 | pub use perishable::*; 16 | pub use stopping_stream::*; 17 | 18 | mod perishable; 19 | mod stopping_stream; 20 | -------------------------------------------------------------------------------- /docs/src/components/icons/FolderIcon.tsx: -------------------------------------------------------------------------------- 1 | export function FolderIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /docs/src/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@/components/Button' 2 | import { HeroPattern } from '@/components/HeroPattern' 3 | 4 | export default function NotFound() { 5 | return ( 6 | <> 7 | 8 |
9 |

10 | 404 11 |

12 |

13 | Page not found 14 |

15 |

16 | Sorry, we couldn’t find the page you’re looking for. 17 |

18 | 21 |
22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.files": [ 3 | "docs/**", 4 | "**/*.md" 5 | ], 6 | "cSpell.caseSensitive": true, 7 | "cSpell.enabledLanguageIds": [ 8 | "asciidoc", 9 | "c", 10 | "cpp", 11 | "csharp", 12 | "css", 13 | "elixir", 14 | "erlang", 15 | "git-commit", 16 | "go", 17 | "graphql", 18 | "handlebars", 19 | "haskell", 20 | "html", 21 | "jade", 22 | "java", 23 | "javascript", 24 | "javascriptreact", 25 | "json", 26 | "jsonc", 27 | "jupyter", 28 | "latex", 29 | "less", 30 | "markdown", 31 | "php", 32 | "plaintext", 33 | "python", 34 | "pug", 35 | "restructuredtext", 36 | "rust", 37 | "scala", 38 | "scss", 39 | "scminput", 40 | "swift", 41 | "text", 42 | "typescript", 43 | "typescriptreact", 44 | "vue", 45 | "yaml", 46 | "yml", 47 | "mdx" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /docs/src/images/logos/python.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/src/components/icons/UsersIcon.tsx: -------------------------------------------------------------------------------- 1 | export function UsersIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /docs/src/components/icons/UserIcon.tsx: -------------------------------------------------------------------------------- 1 | export function UserIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /docs/src/app/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect } from 'react' 4 | import { ThemeProvider, useTheme } from 'next-themes' 5 | 6 | function ThemeWatcher() { 7 | let { resolvedTheme, setTheme } = useTheme() 8 | 9 | useEffect(() => { 10 | let media = window.matchMedia('(prefers-color-scheme: dark)') 11 | 12 | function onMediaChange() { 13 | let systemTheme = media.matches ? 'dark' : 'light' 14 | if (resolvedTheme === systemTheme) { 15 | setTheme('system') 16 | } 17 | } 18 | 19 | onMediaChange() 20 | media.addEventListener('change', onMediaChange) 21 | 22 | return () => { 23 | media.removeEventListener('change', onMediaChange) 24 | } 25 | }, [resolvedTheme, setTheme]) 26 | 27 | return null 28 | } 29 | 30 | export function Providers({ children }: { children: React.ReactNode }) { 31 | return ( 32 | 33 | 34 | {children} 35 | 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /tests/test_misc.py: -------------------------------------------------------------------------------- 1 | 2 | from edgen import Edgen, APIConnectionError 3 | from edgen.resources.misc import Version 4 | import pytest 5 | import subprocess 6 | 7 | client = Edgen() 8 | 9 | def test_version(): 10 | expected = edgen_version() 11 | 12 | try: 13 | version = client.misc.version.create() 14 | except APIConnectionError: 15 | pytest.fail("No connection. Is edgen running?") 16 | 17 | print(f"{expected} == {format_version(version)}") 18 | 19 | assert(type(version) is Version) 20 | assert(format_version(version) == expected) 21 | 22 | def edgen_version(): 23 | finished = subprocess.run(["target/release/edgen", "version"], capture_output=True, text=True) 24 | version = ''.join(f"{finished.stdout}".splitlines()) 25 | return version 26 | 27 | def format_version(version): 28 | build = '' 29 | if version.build: 30 | build = '-'.join(version.build) 31 | return f"{version.major}.{version.minor}.{version.patch}{build}" 32 | 33 | if __name__ == "__main__": 34 | test_version() 35 | -------------------------------------------------------------------------------- /docs/src/app/page.mdx: -------------------------------------------------------------------------------- 1 | import { Highlights } from '@/components/Highlights' 2 | import { Endpoints } from '@/components/Endpoints' 3 | import { HeroPattern } from '@/components/HeroPattern' 4 | 5 | export const metadata = { 6 | title: 'Documentation Edgen', 7 | description: 8 | 'Discover valuable resources, tutorials, API docs, and out-of-the-box examples to maximize your development with Edgen.', 9 | } 10 | 11 | export const sections = [ 12 | { title: 'Highlights', id: 'highlights' }, 13 | { title: 'Endpoints', id: 'endpoints' }, 14 | ] 15 | 16 | 17 | 18 | # ⚡Edgen Documentation 19 | 20 | You can connect to the API using HTTP requests from any programming language through our provided API clients. {{ className: 'lead' }} 21 | 22 |
23 | 26 | 29 |
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/src/components/icons/TagIcon.tsx: -------------------------------------------------------------------------------- 1 | export function TagIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /crates/edgen_core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen_core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ahash = { workspace = true } 8 | async-trait = { workspace = true } 9 | dashmap = { workspace = true } 10 | directories = { workspace = true } 11 | derive_more = { workspace = true } 12 | either = { workspace = true } 13 | edgen_async_compat = { path = "../edgen_async_compat", features = ["runtime-tokio"] } 14 | notify = { workspace = true } 15 | num_cpus = { workspace = true } 16 | once_cell = { workspace = true } 17 | rubato = "0.15.0" 18 | serde = { workspace = true, features = ["derive"] } 19 | serde_yaml = { workspace = true } 20 | smol = { workspace = true } 21 | symphonia = { version = "0.5.4", features = ["all-codecs", "all-formats"] } 22 | time = { workspace = true } 23 | tracing = { workspace = true } 24 | futures = { workspace = true } 25 | thiserror = { workspace = true } 26 | tokio = { workspace = true, features = ["sync"] } 27 | utoipa = { workspace = true } 28 | uuid = { workspace = true, features = ["v4"] } 29 | 30 | [dev-dependencies] 31 | tempfile = { workspace = true } 32 | tokio = { workspace = true, features = ["full"] } 33 | -------------------------------------------------------------------------------- /scripts/add_copyright.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | header='/* Copyright 2023- The Binedge, Lda team. All rights reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | ' 15 | 16 | # Use find with -type f to find only files 17 | find ../ \( -path '../target' -o -path '../edgen/node_modules' \) -prune -o -type f -name '*.rs' | while read -r file; do 18 | if [ -f "$file" ]; then 19 | if ! grep -q 'The Binedge, Lda team. All rights reserved' "$file"; then 20 | echo -e "$header\n$(cat "$file")" > "$file" 21 | echo "Added header to $file" 22 | else 23 | echo "Header already exists in $file" 24 | fi 25 | fi 26 | done 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI" 2 | on: 3 | push: 4 | branches: ["main"] 5 | pull_request: 6 | branches: ["main"] 7 | 8 | jobs: 9 | ci: 10 | name: CI 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - name: "Setup actions/checkout" 14 | uses: actions/checkout@v4 15 | 16 | # setup ubuntu dependencies 17 | - name: "Setup Ubuntu dependencies" 18 | run: | 19 | sudo apt-get update 20 | sudo apt-get install -y build-essential curl wget file libssl-dev libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev patchelf 21 | 22 | - name: "Install Node.js" 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: 18 26 | 27 | - name: "Install pnpm" 28 | uses: pnpm/action-setup@v2 29 | with: 30 | version: 8 31 | run_install: false 32 | 33 | - name: "Setup rust" 34 | uses: actions-rust-lang/setup-rust-toolchain@v1 35 | with: 36 | components: rustfmt 37 | 38 | - name: "Add rust target" 39 | run: rustup target add x86_64-unknown-linux-gnu 40 | 41 | - name: Rustfmt Check 42 | uses: actions-rust-lang/rustfmt@v1 43 | -------------------------------------------------------------------------------- /crates/edgen_core/src/image_generation.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | use std::path::PathBuf; 3 | use thiserror::Error; 4 | 5 | pub struct ImageGenerationArgs { 6 | pub prompt: String, 7 | pub uncond_prompt: String, 8 | pub width: Option, 9 | pub height: Option, 10 | pub steps: usize, 11 | pub images: u32, 12 | pub seed: Option, 13 | pub guidance_scale: f64, 14 | pub vae_scale: f64, 15 | } 16 | 17 | pub struct ModelFiles { 18 | pub tokenizer: PathBuf, 19 | pub clip_weights: PathBuf, 20 | pub clip2_weights: Option, 21 | pub vae_weights: PathBuf, 22 | pub unet_weights: PathBuf, 23 | } 24 | 25 | #[derive(Serialize, Error, Debug)] 26 | pub enum ImageGenerationEndpointError { 27 | #[error("Could not load model: {0}")] 28 | Load(String), 29 | #[error("Failed to tokenize prompts: {0}")] 30 | Decoding(String), 31 | #[error("Failed to generate image: {0}")] 32 | Generation(String), 33 | #[error("Could not convert the output tensor into an encoded image")] 34 | Encoding(String), 35 | } 36 | 37 | #[async_trait::async_trait] 38 | pub trait ImageGenerationEndpoint { 39 | async fn generate_image( 40 | &self, 41 | model: ModelFiles, 42 | args: ImageGenerationArgs, 43 | ) -> Result>, ImageGenerationEndpointError>; 44 | } 45 | -------------------------------------------------------------------------------- /docs/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import glob from 'fast-glob' 2 | 3 | import { Providers } from '@/app/providers' 4 | import { Layout } from '@/components/Layout' 5 | 6 | import '@/styles/tailwind.css' 7 | import { type Metadata } from 'next' 8 | import { type Section } from '@/components/SectionProvider' 9 | 10 | export const metadata: Metadata = { 11 | title: { 12 | template: '%s - Edgen Documentation', 13 | default: 'Edgen Documentation', 14 | }, 15 | } 16 | 17 | export default async function RootLayout({ 18 | children, 19 | }: { 20 | children: React.ReactNode 21 | }) { 22 | let pages = await glob('**/*.mdx', { cwd: 'src/app' }) 23 | let allSectionsEntries = (await Promise.all( 24 | pages.map(async (filename) => [ 25 | '/' + filename.replace(/(^|\/)page\.mdx$/, ''), 26 | (await import(`./${filename}`)).sections, 27 | ]), 28 | )) as Array<[string, Array
]> 29 | let allSections = Object.fromEntries(allSectionsEntries) 30 | 31 | return ( 32 | 33 | 34 | 35 |
36 | {children} 37 |
38 |
39 | 40 | 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /docs/src/images/logos/node.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /docs/src/components/GridPattern.tsx: -------------------------------------------------------------------------------- 1 | import { useId } from 'react' 2 | 3 | export function GridPattern({ 4 | width, 5 | height, 6 | x, 7 | y, 8 | squares, 9 | ...props 10 | }: React.ComponentPropsWithoutRef<'svg'> & { 11 | width: number 12 | height: number 13 | x: string | number 14 | y: string | number 15 | squares: Array<[x: number, y: number]> 16 | }) { 17 | let patternId = useId() 18 | 19 | return ( 20 | 54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /crates/edgen_core/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | //! A brutally simple session management framework for Edgen's transport-agnostic, Protobuf-based 14 | //! message-passing protocol. 15 | //! 16 | //! The heart of this crate is the [`Server`], which can open many [`Session`]s backed by an 17 | //! arbitrary [`EnvelopeHandler`]. 18 | 19 | extern crate alloc; 20 | 21 | use std::time::Duration; 22 | 23 | pub mod llm; 24 | pub mod whisper; 25 | 26 | pub mod settings; 27 | 28 | pub mod image_generation; 29 | pub mod perishable; 30 | 31 | /// Return the [`Duration`] that cleanup threads should wait before looking for and freeing unused 32 | /// resources, after last doing so. 33 | pub fn cleanup_interval() -> Duration { 34 | // TODO this should come from the settings 35 | Duration::from_secs(20) 36 | } 37 | -------------------------------------------------------------------------------- /docs/src/images/logos/php.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /edgen/src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen" 3 | version = "0.1.5" 4 | description = "Edgen: Local, private GenAI server alternative to OpenAI" 5 | authors = ["EdgenAI"] 6 | license = "" 7 | repository = "" 8 | edition = "2021" 9 | default-run = "edgen" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [build-dependencies] 14 | tauri-build = { version = "1.5.1", features = [] } 15 | 16 | [dependencies] 17 | once_cell = { workspace = true } 18 | tauri = { workspace = true, features = ["shell-open", "system-tray", "updater"] } 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = "1.0" 21 | tokio = { workspace = true, features = ["full", "tracing"] } 22 | tracing = { workspace = true } 23 | opener = "0.7.0" 24 | edgen_server = { path = "../../crates/edgen_server" } 25 | edgen_core = { path = "../../crates/edgen_core" } 26 | 27 | [target.'cfg(windows)'.dependencies] 28 | winapi = { version = "0.3", features = ["wincon"] } 29 | 30 | [features] 31 | no_gui = [] 32 | # this feature is used for production builds or when `devPath` points to the filesystem 33 | # DO NOT REMOVE!! 34 | custom-protocol = ["tauri/custom-protocol"] 35 | llama_vulkan = ["edgen_server/llama_vulkan"] 36 | llama_cuda = ["edgen_server/llama_cuda"] 37 | llama_metal = ["edgen_server/llama_metal"] 38 | whisper_cuda = ["edgen_server/whisper_cuda"] 39 | candle_cuda = ["edgen_server/candle_cuda"] 40 | -------------------------------------------------------------------------------- /docs/src/components/HeroPattern.tsx: -------------------------------------------------------------------------------- 1 | import { GridPattern } from '@/components/GridPattern' 2 | 3 | export function HeroPattern() { 4 | return ( 5 |
6 |
7 |
8 | 21 |
22 | 29 |
30 |
31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /edgen/src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "beforeDevCommand": "pnpm install && pnpm dev", 4 | "beforeBuildCommand": "pnpm install && pnpm build", 5 | "devPath": "http://localhost:1420", 6 | "distDir": "../dist" 7 | }, 8 | "package": { 9 | "productName": "Edgen", 10 | "version": "0.1.5" 11 | }, 12 | "tauri": { 13 | "allowlist": { 14 | "all": false, 15 | "shell": { 16 | "all": false, 17 | "open": true 18 | } 19 | }, 20 | "bundle": { 21 | "active": true, 22 | "targets": "all", 23 | "identifier": "edgen.edgen.co", 24 | "icon": [ 25 | "icons/32x32.png", 26 | "icons/128x128.png", 27 | "icons/128x128@2x.png", 28 | "icons/icon.icns", 29 | "icons/icon.ico" 30 | ] 31 | }, 32 | "security": { 33 | "csp": null 34 | }, 35 | "windows": [ 36 | { 37 | "fullscreen": false, 38 | "resizable": true, 39 | "title": "Edgen", 40 | "width": 800, 41 | "height": 600 42 | } 43 | ], 44 | "systemTray": { 45 | "iconPath": "icons/icon.png", 46 | "iconAsTemplate": true 47 | }, 48 | "updater": { 49 | "active": true, 50 | "endpoints": [ 51 | "https://github.com/edgenai/edgen/releases/latest/download/latest.json" 52 | ], 53 | "dialog": true, 54 | "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUzMjgzN0I5N0ZFQUM2QzEKUldUQnh1cC91VGNvNDlGYU44a3VqUk1KRHhOdzJUbjNjUzBIZTNIQU9HYWJ4Q3BTdTV2Q2U1TEIK" 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/test_audio.py: -------------------------------------------------------------------------------- 1 | 2 | from pathlib import Path 3 | import Levenshtein 4 | 5 | from edgen import Edgen, APIConnectionError 6 | import pytest 7 | 8 | expected = ' The woods are lovely, dark and deep, ' \ 9 | 'but I have promises to keep ' \ 10 | 'and miles to go before I sleep, ' \ 11 | 'and miles to go before I sleep.' 12 | 13 | client = Edgen() 14 | 15 | def test_transcriptions(): 16 | 17 | speech_file_path = Path(__file__).parent.parent / "crates" / "edgen_server" / "resources" / "frost.wav" 18 | 19 | try: 20 | transcription = client.audio.transcriptions.create( 21 | model = "default", 22 | file = speech_file_path, 23 | ) 24 | except APIConnectionError: 25 | pytest.fail("No connection. Is edgen running?") 26 | 27 | print(transcription) 28 | print(expected) 29 | 30 | have = transcription.text 31 | 32 | assert(type(have) is str) 33 | 34 | d = Levenshtein.distance(have, expected) 35 | similarity = 100 - ((d / len(expected)) * 100) 36 | print(f"distance: {d} of '{have}', similarity: {similarity}") 37 | 38 | assert(similarity > 90.0) 39 | 40 | def test_transcriptions_status(): 41 | try: 42 | status = client.audio.transcriptions.status.create() 43 | except APIConnectionError: 44 | pytest.fail("No connection. Is edgen running?") 45 | 46 | model = status.active_model 47 | assert(type(model) is str) 48 | print(model) 49 | 50 | if __name__ == "__main__": 51 | test_transcriptions() 52 | test_transcriptions_status() 53 | -------------------------------------------------------------------------------- /docs/src/components/Highlights.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@/components/Button' 2 | import { Heading } from '@/components/Heading' 3 | 4 | const highlights = [ 5 | { 6 | href: '/guides/quickstart', 7 | name: 'Quickstart', 8 | description: 'Start developing your next GenAI app powered by Edgen.', 9 | }, 10 | { 11 | href: '/documentation/configuration', 12 | name: 'Configuration', 13 | description: 'How to configure Edgen. How to switch between models.', 14 | }, 15 | { 16 | href: '/documentation/models', 17 | name: 'Models', 18 | description: 'Learn which models Edgen support, for each endpoint.', 19 | }, 20 | ] 21 | 22 | export function Highlights() { 23 | return ( 24 |
25 | 26 | Highlights 27 | 28 |
29 | {highlights.map((guide) => ( 30 |
31 |

32 | {guide.name} 33 |

34 |

35 | {guide.description} 36 |

37 |

38 | 41 |

42 |
43 | ))} 44 |
45 |
46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "crates/edgen_core", 5 | "crates/edgen_server", 6 | "crates/edgen_async_compat", 7 | "crates/edgen_rt_image_generation_candle", 8 | "crates/edgen_rt_llama_cpp", 9 | "crates/edgen_rt_whisper_cpp", 10 | "crates/edgen_rt_chat_faker", 11 | "edgen/src-tauri", 12 | ] 13 | 14 | [workspace.dependencies] 15 | ahash = "0.8.6" 16 | argh = "0.1.12" 17 | async-executor = "1.6.0" 18 | async-task = "4.5.0" 19 | async-trait = "0.1.80" 20 | axum = "0.7.1" 21 | blake3 = "1.5.0" 22 | cfg-if = "1.0.0" 23 | clap = "4.4.8" 24 | console-subscriber = "0.2.0" 25 | dashmap = "5.5.3" 26 | data-encoding = "2.4.0" 27 | derive_more = "0.99.17" 28 | directories = "5.0.1" 29 | either = "1.9.0" 30 | flume = "0.11.0" 31 | futures = "0.3.29" 32 | futures-lite = "2.0.1" 33 | glommio = "0.9.0" 34 | hyper = "1.0.1" 35 | hyper-util = "0.1.1" 36 | link-cplusplus = "1.0.9" 37 | notify = "6.1.1" 38 | num_cpus = "1.16.0" 39 | once_cell = "1.18.0" 40 | pin-project = "1.1.3" 41 | prost = "0.12.2" 42 | prost-build = "0.12.2" 43 | reqwest = { version = "0.12.3", default-features = false } 44 | serde = "1.0.193" 45 | serde_derive = "1.0.193" 46 | serde_json = "1.0.108" 47 | serde_yaml = "0.9.30" 48 | sled = "0.34.7" 49 | smol = "2.0.0" 50 | static_assertions = "1.1.0" 51 | tempfile = "3.9.0" 52 | thiserror = "1.0.50" 53 | time = "0.3.30" 54 | tinyvec = "1.6.0" 55 | tauri = { version = "1.5.4", features = [] } 56 | tokio = "1.34.0" 57 | tokio-stream = "0.1.14" 58 | tokio-util = "0.7.10" 59 | toml_edit = "0.22.5" 60 | tracing = "0.1.40" 61 | uuid = "1.6.1" 62 | utoipa = { version = "4", features = ["yaml"] } 63 | -------------------------------------------------------------------------------- /docs/src/components/ThemeToggle.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import { useTheme } from 'next-themes' 3 | 4 | function SunIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 5 | return ( 6 | 13 | ) 14 | } 15 | 16 | function MoonIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 17 | return ( 18 | 21 | ) 22 | } 23 | 24 | export function ThemeToggle() { 25 | let { resolvedTheme, setTheme } = useTheme() 26 | let otherTheme = resolvedTheme === 'dark' ? 'light' : 'dark' 27 | let [mounted, setMounted] = useState(false) 28 | 29 | useEffect(() => { 30 | setMounted(true) 31 | }, []) 32 | 33 | return ( 34 | 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /docs/src/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import Link from 'next/link' 4 | import { usePathname } from 'next/navigation' 5 | import { motion } from 'framer-motion' 6 | 7 | import { Footer } from '@/components/Footer' 8 | import { Header } from '@/components/Header' 9 | import { Logo } from '@/components/Logo' 10 | import { Navigation } from '@/components/Navigation' 11 | import { type Section, SectionProvider } from '@/components/SectionProvider' 12 | 13 | export function Layout({ 14 | children, 15 | allSections, 16 | }: { 17 | children: React.ReactNode 18 | allSections: Record> 19 | }) { 20 | let pathname = usePathname() 21 | 22 | return ( 23 | 24 |
25 | 29 |
30 |
31 | 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |
40 |
{children}
41 |
42 |
43 |
44 |
45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /docs/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import { type Config } from 'tailwindcss' 2 | import typographyStyles from './typography' 3 | import typographyPlugin from '@tailwindcss/typography' 4 | import headlessuiPlugin from '@headlessui/tailwindcss' 5 | 6 | export default { 7 | content: ['./src/**/*.{js,mjs,jsx,ts,tsx,mdx}'], 8 | darkMode: 'class', 9 | theme: { 10 | fontSize: { 11 | '2xs': ['0.75rem', { lineHeight: '1.25rem' }], 12 | xs: ['0.8125rem', { lineHeight: '1.5rem' }], 13 | sm: ['0.875rem', { lineHeight: '1.5rem' }], 14 | base: ['1rem', { lineHeight: '1.75rem' }], 15 | lg: ['1.125rem', { lineHeight: '1.75rem' }], 16 | xl: ['1.25rem', { lineHeight: '1.75rem' }], 17 | '2xl': ['1.5rem', { lineHeight: '2rem' }], 18 | '3xl': ['1.875rem', { lineHeight: '2.25rem' }], 19 | '4xl': ['2.25rem', { lineHeight: '2.5rem' }], 20 | '5xl': ['3rem', { lineHeight: '1' }], 21 | '6xl': ['3.75rem', { lineHeight: '1' }], 22 | '7xl': ['4.5rem', { lineHeight: '1' }], 23 | '8xl': ['6rem', { lineHeight: '1' }], 24 | '9xl': ['8rem', { lineHeight: '1' }], 25 | }, 26 | typography: typographyStyles, 27 | extend: { 28 | boxShadow: { 29 | glow: '0 0 4px rgb(0 0 0 / 0.1)', 30 | }, 31 | maxWidth: { 32 | lg: '33rem', 33 | '2xl': '40rem', 34 | '3xl': '50rem', 35 | '5xl': '66rem', 36 | }, 37 | opacity: { 38 | 1: '0.01', 39 | 2.5: '0.025', 40 | 7.5: '0.075', 41 | 15: '0.15', 42 | }, 43 | fill:{ 44 | cl1:'#333333', 45 | cl2:'#ffd000' 46 | }, 47 | screens: { 48 | 'clg': '1120px', 49 | }, 50 | }, 51 | }, 52 | plugins: [typographyPlugin, headlessuiPlugin], 53 | } satisfies Config 54 | -------------------------------------------------------------------------------- /docs/src/app/documentation/models/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Models', 3 | description: 'Models supported by Edgen.', 4 | } 5 | 6 | # Models 7 | 8 | ## Chat Completions Endpoint 9 | For the chat completions endpoint, Edgen supports any model on Hugging Face that is tagged with the library GGUF. You can explore the available models in the [HuggingFace repository](https://huggingface.co/models?library=gguf). 10 | 11 | ## Audio Transcriptions Endpoint 12 | For the audio transcriptions endpoint, Edgen supports all whisper.cpp models: 13 | 14 | | Models | Model URL | 15 | |------------|-----------| 16 | | Whisper (all variants) | [ggerganov/whisper.cpp](https://huggingface.co/ggerganov/whisper.cpp) | 17 | | distil-whisper-small.en | [distil-whisper/distil-small.en](https://huggingface.co/distil-whisper/distil-small.en/resolve/main/ggml-distil-small.en.bin) | 18 | | distil-whisper-medium.en | [distil-whisper/distil-medium.en](https://huggingface.co/distil-whisper/distil-medium.en/resolve/main/ggml-medium-32-2.en.bin) | 19 | | distil-whisper-large-v2 | [distil-whisper/distil-large-v2](https://huggingface.co/distil-whisper/distil-large-v2/resolve/main/ggml-large-32-2.en.bin) | 20 | 21 | ## How to switch an active model? 22 | Just change the configuration file! Check [Documentation » Configuration](/documentation/configuration) and if Edgen cannot find the model you specified locally, it'll download it automatically from HuggingFace. See also [API Reference » Models](/api-reference/models). 23 | 24 | You can also download your model manually and copy it to the model directory. In this case, Edgen will not manage this model. 25 | 26 | The configured model can be overridden by the "model" parameter of endpoint requests. See the [API Reference](/api-reference) for details. 27 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "edgen-docs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "browserslist": "defaults, not ie <= 11", 12 | "dependencies": { 13 | "@algolia/autocomplete-core": "^1.7.3", 14 | "@headlessui/react": "^1.7.15", 15 | "@headlessui/tailwindcss": "^0.2.0", 16 | "@mdx-js/loader": "^2.3.0", 17 | "@mdx-js/react": "^2.3.0", 18 | "@next/mdx": "13.4.16", 19 | "@sindresorhus/slugify": "^2.1.1", 20 | "@tailwindcss/typography": "^0.5.10", 21 | "@types/mdx": "^2.0.8", 22 | "@types/node": "20.4.7", 23 | "@types/react": "18.2.18", 24 | "@types/react-dom": "18.2.7", 25 | "@types/react-highlight-words": "^0.16.4", 26 | "acorn": "^8.8.1", 27 | "autoprefixer": "^10.4.7", 28 | "clsx": "^1.2.0", 29 | "fast-glob": "^3.3.0", 30 | "flexsearch": "^0.7.31", 31 | "framer-motion": "7.8.1", 32 | "mdast-util-to-string": "^3.2.0", 33 | "mdx-annotations": "^0.1.1", 34 | "next": "^14.0.5", 35 | "next-themes": "^0.2.1", 36 | "react": "18.2.0", 37 | "react-dom": "18.2.0", 38 | "react-highlight-words": "^0.20.0", 39 | "remark": "^14.0.2", 40 | "remark-gfm": "^3.0.1", 41 | "remark-mdx": "^2.3.0", 42 | "shiki": "^0.11.1", 43 | "simple-functional-loader": "^1.2.1", 44 | "tailwindcss": "^3.3.3", 45 | "typescript": "5.1.6", 46 | "unist-util-filter": "^4.0.1", 47 | "unist-util-visit": "^4.1.1", 48 | "zustand": "^4.3.2" 49 | }, 50 | "devDependencies": { 51 | "eslint": "8.45.0", 52 | "eslint-config-next": "13.4.16", 53 | "prettier": "^3.0.1", 54 | "prettier-plugin-tailwindcss": "^0.5.2", 55 | "sharp": "^0.32.6" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /docs/src/app/documentation/getting-started/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Getting Started', 3 | description: 'Get started in Edgen development', 4 | } 5 | 6 | # Getting Started 7 | 8 | This section is dedicated for developers looking to contribute to Edgen or build it from source. {{ className: 'lead' }} 9 | 10 | 11 | If you just want to quickly use Edgen by using pre-built binaries, please check [Guides » Quickstart](/guides/quickstart). 12 | 13 | 14 | ## Prerequisites 15 | 16 | ### Windows 17 | 18 | {/* #### 1. Microsoft Visual Studio C++ Build Tools */} 19 | TODO 20 | 21 | 22 | ### MacOS 23 | 24 | #### 1. CLang and macOS development dependencies 25 | ```bash 26 | xcode-select --install 27 | ``` 28 | #### 2. Install rust 29 | ```bash 30 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 31 | ``` 32 | 33 | ### Linux 34 | 35 | #### 1. Install system dependencies 36 | 37 | 38 | ```bash {{ title: 'Ubuntu' }} 39 | sudo apt update 40 | sudo apt install libwebkit2gtk-4.0-dev \ 41 | build-essential \ 42 | curl \ 43 | wget \ 44 | file \ 45 | libssl-dev \ 46 | libgtk-3-dev \ 47 | libayatana-appindicator3-dev \ 48 | librsvg2-dev \ 49 | cmake \ 50 | llvm \ 51 | clang 52 | ``` 53 | 54 | ```bash {{ title: 'NixOS' }} 55 | # with flake.nix 56 | nix develop 57 | ``` 58 | 59 | 60 | 61 | #### 2. Install rust 62 | ```bash 63 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 64 | ``` 65 | 66 | ## Build 67 | 68 | ### 1. Clone the repository 69 | ```bash 70 | git clone https://github.com/edgenai/edgen.git 71 | ``` 72 | 73 | ### 2. Build and run 74 | ```bash 75 | # or without --release for debug build 76 | cargo run --release 77 | ``` 78 | ### 2.1 Run without GUI 79 | ```bash 80 | cargo run --release -- --nogui 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/src/images/logos/go.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/test_chat.py: -------------------------------------------------------------------------------- 1 | 2 | from edgen import Edgen, APIConnectionError 3 | import pytest 4 | 5 | client = Edgen() 6 | 7 | def test_completions_streaming(): 8 | try: 9 | stream = client.chat.completions.create( 10 | model="default", 11 | messages=[ 12 | { 13 | "role": "user", 14 | "content": "What is the result of 1+2?", 15 | }, 16 | ], 17 | stream=True, 18 | ) 19 | except APIConnectionError: 20 | pytest.fail("No connection. Is edgen running?") 21 | 22 | assert(stream.response.status_code == 200) 23 | 24 | answer = "" 25 | for chunk in stream: 26 | if not chunk.choices: 27 | continue 28 | 29 | answer += chunk.choices[0].delta.content 30 | 31 | # print(answer) 32 | assert(type(answer) is str) 33 | 34 | def test_completions(): 35 | try: 36 | answer = client.chat.completions.create( 37 | model="default", 38 | messages=[ 39 | { 40 | "role": "user", 41 | "content": "What is the result of 1+2?", 42 | }, 43 | ] 44 | ) 45 | except APIConnectionError: 46 | pytest.fail("No connection. Is edgen running?") 47 | 48 | content = answer.choices[0].message.content 49 | print(content) 50 | assert(type(content) is str) 51 | assert("3" in content) 52 | 53 | def test_completions_status(): 54 | try: 55 | status = client.chat.completions.status.create() 56 | except APIConnectionError: 57 | pytest.fail("No connection. Is edgen running?") 58 | 59 | model = status.active_model 60 | assert(type(model) is str) 61 | print(model) 62 | 63 | if __name__ == "__main__": 64 | test_completions_streaming() 65 | test_completions() 66 | -------------------------------------------------------------------------------- /edgen/README.md: -------------------------------------------------------------------------------- 1 | # Edgen 2 | A Local GenAI API Server: A drop-in replacement for OpenAI's API for Local GenAI 3 | - [Description](#description) 4 | - [Getting Started](#getting-started) 5 | - [Dependencies](#dependencies) 6 | - [Installing](#installing) 7 | - [Executing program](#executing-program) 8 | - [Documentation](#documentation) 9 | - [Help](#help) 10 | - [Running the Application Locally](#running-the-application-locally) 11 | - [License](#license) 12 | 13 | ## Description 14 | 15 | Edgen is a Local, private GenAI server alternative to OpenAI. No GPU is required. Run AI models locally: LLMs (Llama2, Mistral, Mixtral...), Speech-to-text (whisper) and many others. 16 | 17 | ## Getting Started 18 | 19 | ### Dependencies 20 | 21 | - [Rust](https://www.rust-lang.org/tools/install) 22 | - [NodeJs](https://nodejs.org/en/download/) 23 | - [pnpm](https://pnpm.io/installation) 24 | 25 | ### Installing 26 | 27 | See the [releases](https://github.com/edgenai/edgen/releases) page for the latest binary. All major platforms are supported. 28 | 29 | 30 | ## Documentation 31 | See the [documentation page](https://docs.edgen.co) for help and support 32 | 33 | ## Help 34 | Should any error be encountered when building the application locally, ensure the following system dependencies are met 35 | 36 | 1. Minimum Required Rust Toolchain 37 | ```shell 38 | # use the rustup toolchain command to install the required toolchain 39 | rustup toolchain add beta-2023-11-21 40 | ``` 41 | 42 | 2. Install cmake from [https://cmake.org/download/](https://cmake.org/download/) 43 | 44 | ## Running the Application Locally 45 | To run the application locally, ensure the dependencies are met 46 | ```shell 47 | pnpm install 48 | pnpm tauri dev 49 | ``` 50 | 51 | 52 | 53 | ## License 54 | 55 | This project is licensed under the Apache 2.0 License - see the [LICENSE](../LICENSE) file for details 56 | -------------------------------------------------------------------------------- /edgen/public/EdgenAI_dark_colored.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/components/ButtonRow.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import clsx from 'clsx' 4 | import React, { useState } from 'react' 5 | import { Col } from './mdx' 6 | 7 | export function ButtonRow({ 8 | types, 9 | children 10 | }: { 11 | types: string[] 12 | children: React.ReactNode 13 | }) { 14 | const [currentType, setCurrentType] = useState(0) 15 | 16 | const onlyCurrent = (children: React.ReactNode ) => ( 17 |
18 | {React.Children.toArray(children).map((child, i) => i == currentType ?
{child}
:
)} 19 |
20 | ); 21 | 22 | return ( 23 | <> 24 |
25 |
    26 | {types.map((t, i) => { 27 | return ( 28 |
  • setCurrentType(i)} 38 | > 39 |
    40 | {t} 41 |
    42 |
  • 43 | ) 44 | })} 45 |
46 |
47 | 48 | {onlyCurrent(children)} 49 | 50 | 51 | ) 52 | } 53 | -------------------------------------------------------------------------------- /docs/src/components/icons/CogIcon.tsx: -------------------------------------------------------------------------------- 1 | export function CogIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /edgen/src/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color: #0f0f0f; 8 | background-color: #f6f6f6; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | .container { 18 | margin: 0; 19 | padding-top: 10vh; 20 | display: flex; 21 | flex-direction: column; 22 | justify-content: center; 23 | text-align: center; 24 | } 25 | 26 | .logo { 27 | height: 6em; 28 | padding: 1.5em; 29 | will-change: filter; 30 | transition: 0.75s; 31 | } 32 | 33 | .logo:hover { 34 | filter: drop-shadow(0 0 2em #FFD000); 35 | } 36 | 37 | .row { 38 | display: flex; 39 | justify-content: center; 40 | } 41 | 42 | a { 43 | font-weight: 500; 44 | text-decoration: inherit; 45 | } 46 | 47 | /* a:hover { 48 | color: #535bf2; 49 | } */ 50 | 51 | h1 { 52 | text-align: center; 53 | } 54 | 55 | input, 56 | button { 57 | border-radius: 8px; 58 | border: 1px solid transparent; 59 | padding: 0.6em 1.2em; 60 | font-size: 1em; 61 | font-weight: 500; 62 | font-family: inherit; 63 | color: #0f0f0f; 64 | background-color: #ffffff; 65 | transition: border-color 0.25s; 66 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); 67 | } 68 | 69 | button { 70 | cursor: pointer; 71 | } 72 | 73 | button:active { 74 | background-color: #e8e8e8; 75 | } 76 | 77 | input, 78 | button { 79 | outline: none; 80 | } 81 | 82 | #greet-input { 83 | margin-right: 5px; 84 | } 85 | 86 | @media (prefers-color-scheme: dark) { 87 | :root { 88 | color: #f6f6f6; 89 | background-color: #2f2f2f; 90 | } 91 | 92 | a:hover { 93 | color: #24c8db; 94 | } 95 | 96 | input, 97 | button { 98 | color: #ffffff; 99 | background-color: #0f0f0f98; 100 | } 101 | button:active { 102 | background-color: #0f0f0f69; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /docs/src/components/Tag.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx' 2 | 3 | const variantStyles = { 4 | small: '', 5 | medium: 'rounded-lg px-1.5 ring-1 ring-inset', 6 | } 7 | 8 | const colorStyles = { 9 | yellow: { 10 | small: 'text-yellow-500 dark:text-yellow-400', 11 | medium: 12 | 'ring-yellow-300 dark:ring-yellow-400/30 bg-yellow-400/10 text-yellow-500 dark:text-yellow-400', 13 | large: 14 | 'ring-yellow-300 dark:ring-yellow-400/30 bg-yellow-400/10 text-yellow-500 dark:text-yellow-400', 15 | }, 16 | sky: { 17 | small: 'text-sky-500', 18 | medium: 19 | 'ring-sky-300 bg-sky-400/10 text-sky-500 dark:ring-sky-400/30 dark:bg-sky-400/10 dark:text-sky-400', 20 | large: 21 | 'ring-sky-300 bg-sky-400/10 text-sky-500 dark:ring-sky-400/30 dark:bg-sky-400/10 dark:text-sky-400', 22 | }, 23 | amber: { 24 | small: 'text-amber-500', 25 | medium: 26 | 'ring-amber-300 bg-amber-400/10 text-amber-500 dark:ring-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400', 27 | }, 28 | rose: { 29 | small: 'text-red-500 dark:text-rose-500', 30 | medium: 31 | 'ring-rose-200 bg-rose-50 text-red-500 dark:ring-rose-500/20 dark:bg-rose-400/10 dark:text-rose-400', 32 | }, 33 | zinc: { 34 | small: 'text-zinc-400 dark:text-zinc-500', 35 | medium: 36 | 'ring-zinc-200 bg-zinc-50 text-zinc-500 dark:ring-zinc-500/20 dark:bg-zinc-400/10 dark:text-zinc-400', 37 | }, 38 | } 39 | 40 | const valueColorMap = { 41 | GET: 'yellow', 42 | POST: 'sky', 43 | PUT: 'amber', 44 | DELETE: 'rose', 45 | } as Record 46 | 47 | export function Tag({ 48 | children, 49 | variant = 'medium', 50 | color = valueColorMap[children] ?? 'yellow', 51 | }: { 52 | children: keyof typeof valueColorMap & (string | {}) 53 | variant?: keyof typeof variantStyles 54 | color?: keyof typeof colorStyles 55 | }) { 56 | return ( 57 | 64 | {children} 65 | 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /crates/edgen_server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "edgen_server" 3 | version = "0.1.5" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | argh = { workspace = true } 8 | axum = { workspace = true, features = ["tokio", "multipart"] } 9 | axum_typed_multipart = "0.11.0" 10 | axum-test = "14.4.0" 11 | console-subscriber = { workspace = true } 12 | dashmap = { workspace = true } 13 | derive_more = { workspace = true } 14 | edgen_core = { path = "../edgen_core" } 15 | edgen_rt_chat_faker = { path = "../edgen_rt_chat_faker" } 16 | edgen_rt_llama_cpp = { path = "../edgen_rt_llama_cpp" } 17 | edgen_rt_image_generation_candle = { path = "../edgen_rt_image_generation_candle" } 18 | edgen_rt_whisper_cpp = { path = "../edgen_rt_whisper_cpp" } 19 | either = { workspace = true, features = ["serde"] } 20 | futures = { workspace = true } 21 | hf-hub = "0.3.2" 22 | hyper = { workspace = true } 23 | hyper-util = { workspace = true } 24 | once_cell = { workspace = true } 25 | pin-project = { workspace = true } 26 | rand = "0.8.5" 27 | reqwest = { workspace = true, features = ["blocking", "multipart", "json"] } 28 | reqwest-eventsource = "0.6.0" 29 | rubato = "0.15.0" 30 | serde = { workspace = true } 31 | serde_derive = { workspace = true } 32 | serde_json = { workspace = true } 33 | serde_yaml = { workspace = true } 34 | testcontainers = "0.15.0" 35 | time = { workspace = true } 36 | tinyvec = { workspace = true, features = ["serde"] } 37 | thiserror = { workspace = true } 38 | tokio = { workspace = true, features = ["full", "tracing"] } 39 | tokio-stream = { workspace = true } 40 | tokio-util = { workspace = true } 41 | toml_edit = { workspace = true } 42 | tower-http = { version = "0.5.1", features = ["cors"] } 43 | tracing = { workspace = true } 44 | tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } 45 | utoipa = { workspace = true } 46 | uuid = { workspace = true, features = ["v4", "serde"] } 47 | 48 | [dev-dependencies] 49 | levenshtein = "1.0.5" 50 | tempfile = { workspace = true } 51 | copy_dir = "0.1.3" 52 | 53 | [features] 54 | llama_vulkan = ["edgen_rt_llama_cpp/vulkan"] 55 | llama_cuda = ["edgen_rt_llama_cpp/cuda"] 56 | llama_metal = ["edgen_rt_llama_cpp/metal"] 57 | whisper_cuda = ["edgen_rt_whisper_cpp/cuda"] 58 | candle_cuda = ["edgen_rt_image_generation_candle/cuda"] 59 | 60 | [[bin]] 61 | name = "chatter" 62 | test = false 63 | bench = false 64 | -------------------------------------------------------------------------------- /edgen/src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | #![cfg_attr(windows, windows_subsystem = "windows")] 14 | 15 | #[cfg(not(feature = "no_gui"))] 16 | mod gui; 17 | 18 | use edgen_server; 19 | use edgen_server::{cli, start, EdgenResult}; 20 | 21 | use once_cell::sync::Lazy; 22 | 23 | #[cfg(not(feature = "no_gui"))] 24 | fn main() -> EdgenResult { 25 | try_attach_terminal(); 26 | 27 | Lazy::force(&cli::PARSED_COMMANDS); 28 | 29 | match &cli::PARSED_COMMANDS.subcommand { 30 | None => serve(&cli::PARSED_COMMANDS, true)?, 31 | Some(cli::Command::Serve(args)) => serve(&cli::PARSED_COMMANDS, !args.nogui)?, 32 | Some(_) => start(&cli::PARSED_COMMANDS)?, 33 | } 34 | 35 | Ok(()) 36 | } 37 | 38 | #[cfg(feature = "no_gui")] 39 | fn main() -> EdgenResult { 40 | try_attach_terminal(); 41 | 42 | Lazy::force(&cli::PARSED_COMMANDS); 43 | start(&cli::PARSED_COMMANDS) 44 | } 45 | 46 | #[cfg(not(feature = "no_gui"))] 47 | fn serve(command: &'static cli::TopLevel, start_gui: bool) -> EdgenResult { 48 | let handle = std::thread::spawn(|| match start(command) { 49 | Ok(()) => std::process::exit(0), 50 | Err(e) => { 51 | eprintln!("{:?}", e); 52 | std::process::exit(1); 53 | } 54 | }); 55 | 56 | if start_gui { 57 | gui::run(); 58 | } 59 | 60 | handle.join()? 61 | } 62 | 63 | /// On Windows, attempt to attach to a parent process terminal if not already attached. 64 | /// 65 | /// This needed due to this being a Windows Subsystem binary. 66 | fn try_attach_terminal() { 67 | #[cfg(windows)] 68 | { 69 | use winapi::um::wincon; 70 | unsafe { 71 | if wincon::GetConsoleWindow().is_null() { 72 | wincon::AttachConsole(wincon::ATTACH_PARENT_PROCESS); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /crates/edgen_server/src/graceful_shutdown.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | //! Mechanisms for shutting down application without destroying anything important. 14 | 15 | use time::{Duration, OffsetDateTime}; 16 | use tokio::signal; 17 | use tokio::sync::OnceCell; 18 | use tracing::warn; 19 | 20 | /// The duration between [`global_shutdown_starts`] and [`global_shutdown_ends`]. 21 | pub const SHUTDOWN_GRACE_PERIOD: Duration = Duration::seconds(30); 22 | 23 | static SHUTDOWN_INVOKED_AT: OnceCell = OnceCell::const_new(); 24 | 25 | /// Listens for signals that cause the application to shut down; namely, `CTRL+C`. 26 | async fn signal_listener() -> OffsetDateTime { 27 | while signal::ctrl_c().await.is_err() { /* spin */ } 28 | 29 | warn!( 30 | "Global shutdown has been invoked at {}, and will result in a hard termination at {}", 31 | OffsetDateTime::now_utc(), 32 | OffsetDateTime::now_utc() + SHUTDOWN_GRACE_PERIOD 33 | ); 34 | 35 | OffsetDateTime::now_utc() 36 | } 37 | 38 | /// Resolves when a global shutdown has started. 39 | /// 40 | /// All threads **should** start gracefully exiting by this time. 41 | pub async fn global_shutdown_starts() { 42 | yield_until(*SHUTDOWN_INVOKED_AT.get_or_init(signal_listener).await).await; 43 | } 44 | 45 | /// Resolves when the application is about to unconditionally shut down, following 46 | /// [`global_shutdown_starts`]. 47 | /// 48 | /// This fires after a grace period of [`SHUTDOWN_GRACE_PERIOD`]. 49 | pub async fn global_shutdown_ends() { 50 | yield_until(*SHUTDOWN_INVOKED_AT.get_or_init(signal_listener).await + SHUTDOWN_GRACE_PERIOD) 51 | .await; 52 | } 53 | 54 | /// Yields until a [`time`]-based [`OffsetDateTime`] has elapsed. 55 | pub async fn yield_until(t: OffsetDateTime) { 56 | let now = OffsetDateTime::now_utc(); 57 | 58 | if t > now { 59 | tokio::time::sleep((t - OffsetDateTime::now_utc()).unsigned_abs()).await; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /crates/edgen_server/src/llm.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | use futures::Stream; 14 | use once_cell::sync::Lazy; 15 | 16 | use edgen_core::llm::{CompletionArgs, LLMEndpoint, LLMEndpointError}; 17 | use edgen_rt_llama_cpp::LlamaCppEndpoint; 18 | 19 | use crate::model::Model; 20 | use crate::util::StoppingStream; 21 | 22 | static ENDPOINT: Lazy = Lazy::new(Default::default); 23 | 24 | pub async fn chat_completion( 25 | model: Model, 26 | args: CompletionArgs, 27 | ) -> Result { 28 | ENDPOINT 29 | .chat_completions( 30 | model 31 | .file_path() 32 | .map_err(move |e| LLMEndpointError::Load(e.to_string()))?, 33 | args, 34 | ) 35 | .await 36 | } 37 | 38 | pub async fn chat_completion_stream( 39 | model: Model, 40 | args: CompletionArgs, 41 | ) -> Result + Unpin + Send>>, LLMEndpointError> { 42 | let stream = ENDPOINT 43 | .stream_chat_completions( 44 | model 45 | .file_path() 46 | .map_err(move |e| LLMEndpointError::Load(e.to_string()))?, 47 | args, 48 | ) 49 | .await?; 50 | 51 | Ok(StoppingStream::wrap_with_stop_words( 52 | stream, 53 | vec![ 54 | "<|ASSISTANT|>".to_string(), 55 | "<|USER|>".to_string(), 56 | "<|TOOL|>".to_string(), 57 | "<|SYSTEM|>".to_string(), 58 | ], 59 | )) 60 | } 61 | 62 | pub async fn embeddings( 63 | model: Model, 64 | input: Vec, 65 | ) -> Result>, LLMEndpointError> { 66 | ENDPOINT 67 | .embeddings( 68 | model 69 | .file_path() 70 | .map_err(move |e| LLMEndpointError::Load(e.to_string()))?, 71 | input, 72 | ) 73 | .await 74 | } 75 | 76 | pub async fn reset_environment() { 77 | ENDPOINT.reset() 78 | } 79 | -------------------------------------------------------------------------------- /docs/src/components/APIClients.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | import { Button } from '@/components/Button' 4 | import { Heading } from '@/components/Heading' 5 | import logoGo from '@/images/logos/go.svg' 6 | import logoNode from '@/images/logos/node.svg' 7 | import logoPython from '@/images/logos/python.svg' 8 | import logoRust from '@/images/logos/rust.svg' 9 | 10 | const apiclients = [ 11 | { 12 | href: 'https://github.com/edgenai/edgen-client-python', 13 | name: 'Python', 14 | description: 15 | 'Python is a programming language that lets you work quickly and integrate systems more effectively.', 16 | logo: logoPython, 17 | }, 18 | { 19 | href: 'https://github.com/edgenai/edgen-client-node', 20 | name: 'Node.js', 21 | description: 22 | 'Node.js® is an open-source, cross-platform JavaScript runtime environment.', 23 | logo: logoNode, 24 | }, 25 | // { 26 | // href: '#', 27 | // name: 'Rust', 28 | // description: 29 | // 'An open-source programming language that prioritizes memory safety and high performance.', 30 | // logo: logoRust, 31 | // }, 32 | // { 33 | // href: '#', 34 | // name: 'Go', 35 | // description: 36 | // 'An open-source programming language supported by Google with built-in concurrency.', 37 | // logo: logoGo, 38 | // }, 39 | ] 40 | 41 | export function APIClients() { 42 | return ( 43 |
44 | 45 | Official API Clients 46 | 47 |
48 | {apiclients.map((library) => ( 49 |
50 |
51 |

52 | {library.name} 53 |

54 |

55 | {library.description} 56 |

57 |

58 | 61 |

62 |
63 | 69 |
70 | ))} 71 |
72 |
73 | ) 74 | } 75 | -------------------------------------------------------------------------------- /crates/edgen_server/src/chat_faker.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | //! Endpoint for the chat faker model RT 14 | 15 | use futures::Stream; 16 | use once_cell::sync::Lazy; 17 | 18 | use edgen_core::llm::{CompletionArgs, LLMEndpoint, LLMEndpointError}; 19 | use edgen_rt_chat_faker::ChatFakerEndpoint; 20 | 21 | use crate::model::Model; 22 | use crate::util::StoppingStream; 23 | 24 | static ENDPOINT: Lazy = Lazy::new(Default::default); 25 | 26 | pub async fn chat_completion( 27 | model: Model, 28 | args: CompletionArgs, 29 | ) -> Result { 30 | ENDPOINT 31 | .chat_completions( 32 | model 33 | .file_path() 34 | .map_err(move |e| LLMEndpointError::Load(e.to_string()))?, 35 | args, 36 | ) 37 | .await 38 | } 39 | 40 | pub async fn chat_completion_stream( 41 | model: Model, 42 | args: CompletionArgs, 43 | ) -> Result + Unpin + Send>>, LLMEndpointError> { 44 | let stream = ENDPOINT 45 | .stream_chat_completions( 46 | model 47 | .file_path() 48 | .map_err(move |e| LLMEndpointError::Load(e.to_string()))?, 49 | args, 50 | ) 51 | .await?; 52 | 53 | Ok(StoppingStream::wrap_with_stop_words( 54 | stream, 55 | vec![ 56 | "<|ASSISTANT|>".to_string(), 57 | "<|USER|>".to_string(), 58 | "<|TOOL|>".to_string(), 59 | "<|SYSTEM|>".to_string(), 60 | ], 61 | )) 62 | } 63 | 64 | pub async fn embeddings( 65 | model: Model, 66 | input: Vec, 67 | ) -> Result>, LLMEndpointError> { 68 | ENDPOINT 69 | .embeddings( 70 | model 71 | .file_path() 72 | .map_err(move |e| LLMEndpointError::Load(e.to_string()))?, 73 | input, 74 | ) 75 | .await 76 | } 77 | 78 | // Not needed. Just for completeness. 79 | #[allow(dead_code)] 80 | pub async fn reset_environment() { 81 | ENDPOINT.reset() 82 | } 83 | -------------------------------------------------------------------------------- /docs/src/app/documentation/errors/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Errors', 3 | description: 4 | 'In this guide, we will talk about what happens when something goes wrong while you work with the API.', 5 | } 6 | 7 | # Errors 8 | 9 | In this guide, we will talk about what happens when something goes wrong while you work with the API. Mistakes happen, and mostly they will be yours, not ours. Let's look at some status codes and error types you might encounter. {{ className: 'lead' }} 10 | 11 | You can tell if your request was successful by checking the status code when receiving an API response. If a response comes back unsuccessful, you can use the error type and error message to figure out what has gone wrong and do some rudimentary debugging (before contacting support). 12 | 13 | 14 | Before reaching out to support with an error, please be aware that 99% of all 15 | reported errors are, in fact, user errors. Therefore, please carefully check 16 | your code before contacting Protocol support. 17 | 18 | 19 | --- 20 | 21 | ## Status codes 22 | 23 | Here is a list of the different categories of status codes returned by the Protocol API. Use these to understand if a request was successful. 24 | 25 | 26 | 27 | A 2xx status code indicates a successful response. 28 | 29 | 30 | A 4xx status code indicates a client error — this means it's a _you_ 31 | problem. 32 | 33 | 34 | A 5xx status code indicates a server error — you won't be seeing these. 35 | 36 | 37 | 38 | --- 39 | 40 | ## Error types 41 | 42 | 43 | 44 | 45 | Whenever a request is unsuccessful, the Protocol API will return an error response with an error type and message. You can use this information to understand better what has gone wrong and how to fix it. Most of the error messages are pretty helpful and actionable. 46 | 47 | Here is a list of the two error types supported by the Protocol API — use these to understand what you have done wrong. 48 | 49 | 50 | 51 | This means that we made an error, which is highly speculative and unlikely. 52 | 53 | 54 | This means that you made an error, which is much more likely. 55 | 56 | 57 | 58 | 59 | 60 | 61 | ```bash {{ title: "Error response" }} 62 | { 63 | "type": "api_error", 64 | "message": "No way this is happening!?", 65 | "documentation_url": "https://protocol.chat/docs/errors/api_error" 66 | } 67 | ``` 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import clsx from 'clsx' 3 | 4 | function ArrowIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 5 | return ( 6 | 14 | ) 15 | } 16 | 17 | const variantStyles = { 18 | primary: 19 | 'rounded-full bg-zinc-900 py-1 px-3 text-white hover:bg-zinc-700 dark:bg-yellow-400/10 dark:text-yellow-400 dark:ring-1 dark:ring-inset dark:ring-yellow-400/20 dark:hover:bg-yellow-400/10 dark:hover:text-yellow-300 dark:hover:ring-yellow-300', 20 | secondary: 21 | 'rounded-full bg-zinc-100 py-1 px-3 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800/40 dark:text-zinc-400 dark:ring-1 dark:ring-inset dark:ring-zinc-800 dark:hover:bg-zinc-800 dark:hover:text-zinc-300', 22 | filled: 23 | 'rounded-full bg-zinc-900 py-1 px-3 text-white hover:bg-zinc-700 dark:bg-yellow-500 dark:text-white dark:hover:bg-yellow-400', 24 | outline: 25 | 'rounded-full py-1 px-3 text-zinc-700 ring-1 ring-inset ring-zinc-900/10 hover:bg-zinc-900/2.5 hover:text-zinc-900 dark:text-zinc-400 dark:ring-white/10 dark:hover:bg-white/5 dark:hover:text-white', 26 | text: 'text-yellow-500 hover:text-yellow-600 dark:text-yellow-400 dark:hover:text-yellow-500', 27 | } 28 | 29 | type ButtonProps = { 30 | variant?: keyof typeof variantStyles 31 | arrow?: 'left' | 'right' 32 | } & ( 33 | | React.ComponentPropsWithoutRef 34 | | (React.ComponentPropsWithoutRef<'button'> & { href?: undefined }) 35 | ) 36 | 37 | export function Button({ 38 | variant = 'primary', 39 | className, 40 | children, 41 | arrow, 42 | ...props 43 | }: ButtonProps) { 44 | className = clsx( 45 | 'inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium transition', 46 | variantStyles[variant], 47 | className, 48 | ) 49 | 50 | let arrowIcon = ( 51 | 59 | ) 60 | 61 | let inner = ( 62 | <> 63 | {arrow === 'left' && arrowIcon} 64 | {children} 65 | {arrow === 'right' && arrowIcon} 66 | 67 | ) 68 | 69 | if (typeof props.href === 'undefined') { 70 | return ( 71 | 74 | ) 75 | } 76 | 77 | return ( 78 | 79 | {inner} 80 | 81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Next.js site to GitHub Pages 2 | # 3 | # To get started with Next.js see: https://nextjs.org/docs/getting-started 4 | # 5 | name: "docs" 6 | 7 | on: 8 | # Runs on pushes targeting the path 9 | push: 10 | branches: ["main"] 11 | paths: ["docs/**"] 12 | pull_request: 13 | branches: ["main"] 14 | paths: ["docs/**"] 15 | 16 | # Allows you to run this workflow manually from the Actions tab 17 | workflow_dispatch: 18 | 19 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 20 | permissions: 21 | contents: read 22 | pages: write 23 | id-token: write 24 | 25 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 26 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 27 | concurrency: 28 | group: "pages" 29 | cancel-in-progress: false 30 | 31 | jobs: 32 | # Build job 33 | build: 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Checkout 37 | uses: actions/checkout@v4 38 | 39 | - name: Install Node.js 40 | uses: actions/setup-node@v3 41 | with: 42 | node-version: 18 43 | 44 | - name: Detect package manager 45 | id: detect-package-manager 46 | run: | 47 | if [ -f "${{ github.workspace }}/docs/yarn.lock" ]; then 48 | echo "manager=yarn" >> $GITHUB_OUTPUT 49 | echo "command=install" >> $GITHUB_OUTPUT 50 | echo "runner=yarn" >> $GITHUB_OUTPUT 51 | exit 0 52 | elif [ -f "${{ github.workspace }}/docs/package.json" ]; then 53 | echo "manager=npm" >> $GITHUB_OUTPUT 54 | echo "command=ci" >> $GITHUB_OUTPUT 55 | echo "runner=npx --no-install" >> $GITHUB_OUTPUT 56 | exit 0 57 | else 58 | echo "Unable to determine package manager" 59 | exit 1 60 | fi 61 | 62 | - name: Build and Export 63 | run: cd docs && ${{ steps.detect-package-manager.outputs.manager }} install && ${{ steps.detect-package-manager.outputs.manager }} run build 64 | 65 | - name: Setup Pages 66 | uses: actions/configure-pages@v4 67 | with: 68 | # Automatically inject basePath in your Next.js configuration file and disable 69 | # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized). 70 | # 71 | # You may remove this line if you want to manage the configuration yourself. 72 | static_site_generator: next 73 | 74 | - name: Upload artifact 75 | uses: actions/upload-pages-artifact@v2 76 | with: 77 | path: ./docs/out 78 | 79 | # Deployment job 80 | deploy: 81 | environment: 82 | name: github-pages 83 | url: ${{ steps.deployment.outputs.page_url }} 84 | runs-on: ubuntu-latest 85 | needs: build 86 | steps: 87 | - name: Deploy to GitHub Pages 88 | id: deployment 89 | uses: actions/deploy-pages@v3 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | $RECYCLE.BIN/ 2 | **/*.rs.bk 3 | **/env_backup 4 | *-prefix/ 5 | *.a 6 | *.app 7 | *.cab 8 | *.d 9 | *.dll 10 | *.dylib 11 | *.exe 12 | *.gch 13 | *.icloud 14 | *.iws 15 | *.la 16 | *.lai 17 | *.lcov 18 | *.lib 19 | *.lnk 20 | *.lo 21 | *.log 22 | *.mod 23 | *.msi 24 | *.msix 25 | *.msm 26 | *.msp 27 | *.o 28 | *.obj 29 | *.out 30 | *.pch 31 | *.pdb 32 | *.pid 33 | *.pid.lock 34 | *.seed 35 | *.slo 36 | *.smod 37 | *.so 38 | *.stackdump 39 | *.tgz 40 | *.tsbuildinfo 41 | *~ 42 | **/*.*.swp 43 | .swp 44 | .AppleDB 45 | .AppleDesktop 46 | .AppleDouble 47 | .DS_Store 48 | .DocumentRevisions-V100 49 | .LSOverride 50 | .Spotlight-V100 51 | .TemporaryItems 52 | .Trash-* 53 | .Trashes 54 | .VolumeIcon.icns 55 | ._* 56 | .apdisk 57 | .cache 58 | .cache/ 59 | .com.apple.timemachine.donotpresent 60 | .directory 61 | .docusaurus 62 | .dynamodb/ 63 | .env 64 | .env.development.local 65 | .env.local 66 | .env.production.local 67 | .env.test.local 68 | .eslintcache 69 | .fseventsd 70 | .fuse_hidden* 71 | .fusebox/ 72 | .grunt 73 | .idea/* 74 | .idea/**/aws.xml 75 | __pycache__ 76 | .idea/**/contentModel.xml 77 | .idea/**/dataSources.ids 78 | .idea/**/dataSources.local.xml 79 | .idea/**/dataSources/ 80 | .idea/**/dbnavigator.xml 81 | .idea/**/dictionaries 82 | .idea/**/dynamic.xml 83 | .idea/**/gradle.xml 84 | .idea/**/libraries 85 | .idea/**/mongoSettings.xml 86 | .idea/**/shelf 87 | .idea/**/sqlDataSources.xml 88 | .idea/**/tasks.xml 89 | .idea/**/uiDesigner.xml 90 | .idea/**/usage.statistics.xml 91 | .idea/**/workspace.xml 92 | .idea/caches/build_file_checksums.ser 93 | .idea/httpRequests 94 | .idea/replstate.xml 95 | .idea/sonarlint/ 96 | .idea_modules/ 97 | .lock-wscript 98 | .next 99 | .nfs* 100 | .ninja_deps 101 | .ninja_log 102 | .node_repl_history 103 | .npm 104 | .nuxt 105 | .nyc_output 106 | .parcel-cache 107 | .pnp.* 108 | .pnpm-debug.log* 109 | .rpt2_cache/ 110 | .rts2_cache_cjs/ 111 | .rts2_cache_es/ 112 | .rts2_cache_umd/ 113 | .serverless/ 114 | .stylelintcache 115 | .svelte-kit 116 | .temp 117 | .tern-port 118 | .vscode-test 119 | .vuepress/dist 120 | .webpack/ 121 | .yarn-integrity 122 | .yarn/build-state.yml 123 | .yarn/cache 124 | .yarn/install-state.gz 125 | .yarn/unplugged 126 | CMakeCache.txt 127 | CMakeFiles 128 | CMakeLists.txt.user 129 | CMakeScripts 130 | CTestTestfile.cmake 131 | Icon 132 | Makefile 133 | Network Trash Folder 134 | Temporary Items 135 | Testing 136 | Thumbs.db 137 | Thumbs.db:encryptable 138 | [Dd]esktop.ini 139 | _deps 140 | atlassian-ide-plugin.xml 141 | bower_components 142 | build/Release 143 | cmake-build-*/ 144 | cmake_install.cmake 145 | com_crashlytics_export_strings.xml 146 | compile_commands.json 147 | coverage 148 | crashlytics-build.properties 149 | crashlytics.properties 150 | debug/ 151 | dist 152 | ehthumbs.db 153 | ehthumbs_vista.db 154 | fabric.properties 155 | install_manifest.txt 156 | jspm_packages/ 157 | lerna-debug.log* 158 | lib-cov 159 | logs 160 | node_modules/ 161 | npm-debug.log* 162 | out 163 | out/ 164 | pids 165 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 166 | rust-project.json 167 | target/ 168 | web_modules/ 169 | yarn-debug.log* 170 | yarn-error.log* 171 | 172 | # direnv 173 | .direnv/ 174 | .envrc 175 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "build" 2 | on: 3 | push: 4 | branches: ["main"] 5 | pull_request: 6 | branches: ["main"] 7 | 8 | # This is the example from the readme. 9 | # On each push to the `main` branch it will create or update a GitHub build, build your app, and upload the artifacts to the build. 10 | 11 | jobs: 12 | build: 13 | permissions: 14 | contents: write 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | include: 19 | - name: Linux-x86_64 20 | target: x86_64-unknown-linux-gnu 21 | runner: ubuntu-20.04 22 | 23 | - name: macOS-universal 24 | target: universal-apple-darwin 25 | runner: macos-latest 26 | 27 | - name: Windows-x86_64 28 | target: x86_64-pc-windows-msvc 29 | runner: windows-latest 30 | 31 | name: ${{ matrix.name }} 32 | runs-on: ${{ matrix.runner }} 33 | steps: 34 | - name: "Setup actions/checkout" 35 | uses: actions/checkout@v4 36 | 37 | # setup ubuntu dependencies 38 | - name: Setup Ubuntu dependencies 39 | if: matrix.runner == 'ubuntu-20.04' 40 | run: | 41 | sudo apt-get update 42 | sudo apt-get install -y build-essential curl wget file libssl-dev libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev patchelf 43 | 44 | # install llvm (for llvm-copy) on macos only. For cpp runtimes. 45 | - name: "Setup MacOS dependencies" 46 | if: matrix.runner == 'macos-latest' 47 | run: | 48 | brew update 49 | brew install llvm@17 50 | echo "$(brew --prefix llvm@17)/bin" >> $GITHUB_PATH 51 | 52 | - name: "Setup rust" 53 | uses: actions-rust-lang/setup-rust-toolchain@v1 54 | 55 | - name: Add rust target (macOS) 56 | if: ${{ matrix.runner == 'macos-latest' }} 57 | run: | 58 | rustup target add x86_64-apple-darwin 59 | rustup target add aarch64-apple-darwin 60 | 61 | - name: Add rust target (Other) 62 | if: ${{ matrix.runner != 'macos-latest' }} 63 | run: rustup target add ${{ matrix.target }} 64 | 65 | - name: Install Node.js 66 | uses: actions/setup-node@v3 67 | with: 68 | node-version: 18 69 | 70 | - name: Install pnpm 71 | uses: pnpm/action-setup@v2 72 | with: 73 | version: 8 74 | run_install: false 75 | 76 | - name: Install GUI frontend dependencies 77 | run: cd edgen && pnpm install # change this to npm or pnpm depending on which one you use 78 | 79 | - uses: tauri-apps/tauri-action@dev 80 | env: 81 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 82 | TAURI_PRIVATE_KEY: ${{ secrets.TAURI_KEY }} 83 | RUSTFLAGS: "--cfg tokio_unstable" 84 | with: 85 | args: --target ${{ matrix.target }} 86 | tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version 87 | releaseName: "v__VERSION__" 88 | releaseBody: "See the assets to download this version and install." 89 | releaseDraft: true 90 | prerelease: false 91 | projectPath: ./edgen 92 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | # good nix template: https://srid.ca/rust-nix 2 | 3 | { 4 | inputs = { 5 | nixpkgs.url = "nixpkgs"; 6 | rust-overlay.url = "github:oxalica/rust-overlay"; 7 | flake-utils.url = "github:numtide/flake-utils"; 8 | }; 9 | 10 | outputs = { self, nixpkgs, rust-overlay, flake-utils }: 11 | flake-utils.lib.eachDefaultSystem (system: 12 | let 13 | inherit (nixpkgs) lib; 14 | 15 | overlays = [ (import rust-overlay) ]; 16 | pkgs = import nixpkgs { 17 | inherit system overlays; 18 | }; 19 | # pkgs = nixpkgs.legacyPackages.${system}; 20 | 21 | # The reason for using pkgs.symlinkJoin instead of just pkgs is to consolidate these various Rust-related components into a single symlink. This can be convenient for setting up a development environment or ensuring that specific tools are available in a unified location. It simplifies the management of Rust-related tools and makes it easier to reference them in the rest of the Nix configuration, for example, in the subsequent nativeBuildInputs section of the mkShell environment. 22 | # rust-toolchain = pkgs.symlinkJoin { 23 | # name = "rust-toolchain"; 24 | # paths = [ pkgs.rustc-wasm32 pkgs.cargo pkgs.cargo-watch pkgs.rust-analyzer pkgs.rustPlatform.rustcSrc ]; 25 | # }; 26 | 27 | rust-toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; 28 | llvm = pkgs.llvmPackages_11; 29 | 30 | clangBuildInputs = with llvm; [ 31 | clang 32 | libclang 33 | libcxx 34 | libcxxabi 35 | lld 36 | lldb 37 | ]; 38 | 39 | nativeBuildInputs = with pkgs; [ 40 | pkg-config 41 | rust-toolchain 42 | cmake 43 | vulkan-loader 44 | cudaPackagesGoogle.cudatoolkit 45 | ] ++ clangBuildInputs; 46 | 47 | packages = with pkgs; [ 48 | curl 49 | wget 50 | dbus 51 | openssl_3 52 | glib 53 | gtk3 54 | gdk-pixbuf 55 | libsoup 56 | pango 57 | harfbuzz 58 | at-spi2-atk 59 | cairo 60 | webkitgtk 61 | webkitgtk_4_1 62 | librsvg 63 | libayatana-appindicator 64 | nodejs_18 65 | nodePackages.pnpm 66 | ]; 67 | 68 | libraries = with pkgs;[ 69 | webkitgtk 70 | webkitgtk_4_1 71 | gtk3 72 | libayatana-appindicator 73 | ]; 74 | 75 | buildInputs = packages; 76 | in 77 | rec { 78 | # `nix develop` 79 | devShell = pkgs.mkShell { 80 | inherit buildInputs nativeBuildInputs; 81 | shellHook = '' 82 | # make sure all libraries are added into LD_LIBRARY_PATH 83 | export LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath libraries}:$LD_LIBRARY_PATH 84 | 85 | # For rust-analyzer 'hover' tooltips to work. 86 | export RUST_SRC_PATH=${rust-toolchain} 87 | export RUST_BACKTRACE=1 88 | 89 | # add ~/.cargo/bin to PATH for crates installed with `cargo install` 90 | export PATH=$PATH:$HOME/.cargo/bin 91 | 92 | # clang 93 | export LIBCLANG_PATH="${llvm.libclang.lib}/lib"; 94 | 95 | # tauri 96 | export WEBKIT_DISABLE_COMPOSITING_MODE=1 97 | 98 | # vulkan 99 | export VULKAN_SDK=${pkgs.vulkan-loader} 100 | export CUDA_PATH=${pkgs.cudatoolkit} 101 | ''; 102 | }; 103 | }); 104 | } 105 | -------------------------------------------------------------------------------- /docs/src/components/Feedback.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { forwardRef, Fragment, useState } from 'react' 4 | import { Transition } from '@headlessui/react' 5 | 6 | function CheckIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 7 | return ( 8 | 18 | ) 19 | } 20 | 21 | function FeedbackButton( 22 | props: Omit, 'type' | 'className'>, 23 | ) { 24 | return ( 25 | 98 | 99 | 100 | 101 | ) 102 | }) 103 | -------------------------------------------------------------------------------- /docs/src/components/Logo.tsx: -------------------------------------------------------------------------------- 1 | export function Logo(props: React.ComponentPropsWithoutRef<'svg'>) { 2 | return ( 3 | 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1705309234, 9 | "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "flake-utils_2": { 22 | "inputs": { 23 | "systems": "systems_2" 24 | }, 25 | "locked": { 26 | "lastModified": 1681202837, 27 | "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", 28 | "owner": "numtide", 29 | "repo": "flake-utils", 30 | "rev": "cfacdce06f30d2b68473a46042957675eebb3401", 31 | "type": "github" 32 | }, 33 | "original": { 34 | "owner": "numtide", 35 | "repo": "flake-utils", 36 | "type": "github" 37 | } 38 | }, 39 | "nixpkgs": { 40 | "locked": { 41 | "lastModified": 1706925685, 42 | "narHash": "sha256-hVInjWMmgH4yZgA4ZtbgJM1qEAel72SYhP5nOWX4UIM=", 43 | "owner": "NixOS", 44 | "repo": "nixpkgs", 45 | "rev": "79a13f1437e149dc7be2d1290c74d378dad60814", 46 | "type": "github" 47 | }, 48 | "original": { 49 | "id": "nixpkgs", 50 | "type": "indirect" 51 | } 52 | }, 53 | "nixpkgs_2": { 54 | "locked": { 55 | "lastModified": 1681358109, 56 | "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", 57 | "owner": "NixOS", 58 | "repo": "nixpkgs", 59 | "rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9", 60 | "type": "github" 61 | }, 62 | "original": { 63 | "owner": "NixOS", 64 | "ref": "nixpkgs-unstable", 65 | "repo": "nixpkgs", 66 | "type": "github" 67 | } 68 | }, 69 | "root": { 70 | "inputs": { 71 | "flake-utils": "flake-utils", 72 | "nixpkgs": "nixpkgs", 73 | "rust-overlay": "rust-overlay" 74 | } 75 | }, 76 | "rust-overlay": { 77 | "inputs": { 78 | "flake-utils": "flake-utils_2", 79 | "nixpkgs": "nixpkgs_2" 80 | }, 81 | "locked": { 82 | "lastModified": 1705803528, 83 | "narHash": "sha256-nChqKQPRXxmGBEkHse39LjNpkNKk4U1xPQ4a4oYlUdw=", 84 | "owner": "oxalica", 85 | "repo": "rust-overlay", 86 | "rev": "bd7e8f4e122e11c934a576abc04327764f9bf19b", 87 | "type": "github" 88 | }, 89 | "original": { 90 | "owner": "oxalica", 91 | "repo": "rust-overlay", 92 | "type": "github" 93 | } 94 | }, 95 | "systems": { 96 | "locked": { 97 | "lastModified": 1681028828, 98 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 99 | "owner": "nix-systems", 100 | "repo": "default", 101 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 102 | "type": "github" 103 | }, 104 | "original": { 105 | "owner": "nix-systems", 106 | "repo": "default", 107 | "type": "github" 108 | } 109 | }, 110 | "systems_2": { 111 | "locked": { 112 | "lastModified": 1681028828, 113 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 114 | "owner": "nix-systems", 115 | "repo": "default", 116 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 117 | "type": "github" 118 | }, 119 | "original": { 120 | "owner": "nix-systems", 121 | "repo": "default", 122 | "type": "github" 123 | } 124 | } 125 | }, 126 | "root": "root", 127 | "version": 7 128 | } 129 | -------------------------------------------------------------------------------- /docs/src/app/guides/quickstart/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Quickstart', 3 | description: 4 | 'This guide will get you all set up and ready to use the Protocol API. We’ll cover how to get started an API client and how to make your first API request.', 5 | } 6 | 7 | # Quickstart 8 | 9 | This guide will get you all set up and ready to use the Protocol API. We'll cover how to get started using one of our API clients and how to make your first API request. We'll also look at where to go next to find all the information you need to take full advantage of our powerful REST API. {{ className: 'lead' }} 10 | 11 | 12 | If you're a developer looking into building Edgen from source, please follow [Documentation » Getting Started](/documentation/getting-started). 13 | 14 | 15 | ## Download and install ⚡Edgen 16 | \ 17 | 18 | 19 | ## Choose your client 20 | 21 | Before making your first API request, you need to pick which API client you will use. ⚡Edgen offers clients for Python and Node.js. In the following example, you can see how to install each client. 22 | 23 | {/* TODO: Edit with our published packages */} 24 | 25 | 26 | 27 | ```bash {{ title: 'cURL' }} 28 | # cURL is most likely already installed on your machine. If not, install it 29 | curl --version 30 | ``` 31 | 32 | ```bash {{ language: 'python' }} 33 | # Install the Python API client 34 | pip install edgen 35 | ``` 36 | 37 | ```bash {{ language: 'ts' }} 38 | # Install the Node API client 39 | npm install edgen --save 40 | ``` 41 | 42 | 43 | 44 |
45 | 48 |
49 | 50 | ## Making your first API request 51 | 52 | You are ready to make your first call to the ⚡Edgen API. Below, you can see how to send a GET request to the chat completions endpoint to create a chat response, given an list of input chat messages. 53 | 54 | {/* TODO: Do not hardcode this codegroup. Since it's already defined in /api-reference/chat */} 55 | 56 | 57 | ```bash {{ title: 'cURL' }} 58 | curl http://localhost:33322/v1/chat/completions \ 59 | -H "Content-Type: application/json" \ 60 | -H "Authorization: Bearer no-key-required" \ 61 | -d '{ 62 | "model": "default", 63 | "messages": [ 64 | { 65 | "role": "system", 66 | "content": "You are EdgenChat, a helpful AI assistant." 67 | }, 68 | { 69 | "role": "user", 70 | "content": "Hello!" 71 | } 72 | ], 73 | "stream": true 74 | }' 75 | ``` 76 | 77 | ```python 78 | from edgen import Edgen 79 | client = Edgen() 80 | 81 | completion = client.chat.completions.create( 82 | model="default", 83 | messages=[ 84 | {"role": "system", "content": "You are a helpful assistant."}, 85 | {"role": "user", "content": "Hello!"} 86 | ], 87 | stream=True 88 | ) 89 | 90 | for chunk in completion: 91 | print(chunk.choices[0].delta) 92 | ``` 93 | 94 | ```ts 95 | import Edgen from "edgen"; 96 | 97 | const client = new Edgen(); 98 | 99 | async function main() { 100 | const completion = await client.chat.completions.create({ 101 | model: "default", 102 | messages: [ 103 | {"role": "system", "content": "You are a helpful assistant."}, 104 | {"role": "user", "content": "Hello!"} 105 | ], 106 | stream: true, 107 | }); 108 | 109 | for await (const chunk of completion) { 110 | console.log(chunk.choices[0].delta.content); 111 | } 112 | } 113 | 114 | main(); 115 | ``` 116 | 117 | 118 | 119 |
120 | 123 |
124 | -------------------------------------------------------------------------------- /docs/src/app/api-reference/embeddings/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Embeddings', 3 | description: 'Generate embeddings', 4 | } 5 | 6 | # Embeddings 7 | 8 | Generate embeddings from text. {{ className: 'lead' }} 9 | 10 | --- 11 | 12 | ## Create embeddings {{ tag: 'POST', label: 'http://localhost:33322/v1/embeddings' }} 13 | 14 | 15 | 16 | Given a list of messages belonging to a chat history, generate a response. 17 | 18 | ### Required attributes 19 | 20 | 21 | 22 | One or multiple pieces of text from which embeddings will be generated. For each piece of text, one embedding is generated. 23 | 24 | 25 | 26 | 27 | 28 | The model used for chat completions. 29 |
    30 |
  • 31 | If the model name is "default", the chat model from the configuration is used (see [Documentation » Configuration](/documentation/configuration) for details). 32 |
  • 33 |
  • 34 | If the model name follows the format repo-owner/repo-name/model-name, the indicated model is used and, if it is not present, it will be downloaded from [huggingface](https://huggingface.co/). If it cannot be downloaded, Edgen responds with an error. Example: "nomic-ai/nomic-embed-text-v1.5-GGUF/nomic-embed-text-v1.5.f16.gguf". 35 |
  • 36 |
  • 37 | If the model name contains just a file name, e.g.: "my-model.bin", Edgen will try using the file of this name in the data directory as defined in the configuration. If the the file does not exist there, Edgen responds with an error. 38 |
  • 39 |
40 |
41 |
42 | 43 | ### Optional attributes 44 | 45 | 46 | 47 | The format to return the embeddings in. Can be either `float` or `base64`. 48 | 49 | 50 | 51 | 52 | 53 | The number of dimensions the resulting output embeddings should have. Only supported in some models. 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | ```bash {{ title: 'cURL' }} 63 | curl http://localhost:33322/v1/embeddings \ 64 | -H "Content-Type: application/json" \ 65 | -H "Authorization: Bearer no-key-required" \ 66 | -d '{ 67 | "model": "default", 68 | "input": "Hello World!" 69 | }' 70 | ``` 71 | 72 | ```python 73 | from edgen import Edgen 74 | client = Edgen() 75 | 76 | embeddings = client.embeddings.create( 77 | model="default", 78 | input="Who is John Doe?" 79 | ) 80 | 81 | for item in completion.data: 82 | print(data.embedding) 83 | ``` 84 | 85 | ```ts 86 | import Edgen from "edgen"; 87 | 88 | const client = new Edgen(); 89 | 90 | async function main() { 91 | const embeddings = await client.embeddings.create({ 92 | model: "default", 93 | messages: "Who is Foo Bar?" 94 | }); 95 | 96 | for await (const item of embeddings.data) { 97 | console.log(item.embedding.content); 98 | } 99 | } 100 | 101 | main(); 102 | ``` 103 | 104 | 105 | 106 | ```json {{ title: 'Response' }} 107 | { 108 | "object": "list", 109 | "data": [ 110 | { 111 | "object": "embedding", 112 | "embedding": [ 113 | 0.0023064255, 114 | -0.009327292, 115 | .... 116 | -0.0028842222, 117 | ], 118 | "index": 0 119 | } 120 | ], 121 | "model": "default", 122 | "usage": { 123 | "prompt_tokens": 8, 124 | "total_tokens": 8 125 | } 126 | } 127 | ``` 128 | 129 | 130 |
131 | -------------------------------------------------------------------------------- /docs/src/components/mdx.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import clsx from 'clsx' 3 | 4 | import { Feedback } from '@/components/Feedback' 5 | import { Heading} from '@/components/Heading' 6 | import { Prose } from '@/components/Prose' 7 | 8 | export const a = Link 9 | export { Button } from '@/components/Button' 10 | export { CodeGroup, Code as code, Pre as pre } from '@/components/Code' 11 | export { ButtonRow } from '@/components/ButtonRow' 12 | 13 | export { Eyebrow, HeadingNoEyebrow } from '@/components/Heading' 14 | 15 | export function wrapper({ children }: { children: React.ReactNode }) { 16 | return ( 17 |
18 | {children} 19 | {/*
20 | 21 |
*/} 22 |
23 | ) 24 | } 25 | 26 | export const h2 = function H2( 27 | props: Omit, 'level'>, 28 | ) { 29 | return 30 | } 31 | 32 | function InfoIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 33 | return ( 34 | 45 | ) 46 | } 47 | 48 | export function Note({ children }: { children: React.ReactNode }) { 49 | return ( 50 |
51 | 52 |
53 | {children} 54 |
55 |
56 | ) 57 | } 58 | 59 | export function Row({ children }: { children: React.ReactNode }) { 60 | return ( 61 |
62 | {children} 63 |
64 | ) 65 | } 66 | 67 | export function Col({ 68 | children, 69 | sticky = false, 70 | }: { 71 | children: React.ReactNode 72 | sticky?: boolean 73 | }) { 74 | return ( 75 |
:first-child]:mt-0 [&>:last-child]:mb-0', 78 | sticky && 'xl:sticky xl:top-24', 79 | )} 80 | > 81 | {children} 82 |
83 | ) 84 | } 85 | 86 | export function Properties({ children }: { children: React.ReactNode }) { 87 | return ( 88 |
89 |
    93 | {children} 94 |
95 |
96 | ) 97 | } 98 | 99 | export function Property({ 100 | name, 101 | children, 102 | type, 103 | }: { 104 | name: string 105 | children: React.ReactNode 106 | type?: string 107 | }) { 108 | return ( 109 |
  • 110 |
    111 |
    Name
    112 |
    113 | {name} 114 |
    115 | {type && ( 116 | <> 117 |
    Type
    118 |
    119 | {type} 120 |
    121 | 122 | )} 123 |
    Description
    124 |
    125 | {children} 126 |
    127 |
    128 |
  • 129 | ) 130 | } 131 | -------------------------------------------------------------------------------- /crates/edgen_server/src/whisper.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | use once_cell::sync::Lazy; 14 | use uuid::Uuid; 15 | 16 | use edgen_core::whisper::{TranscriptionArgs, WhisperEndpoint, WhisperEndpointError}; 17 | use edgen_rt_whisper_cpp::WhisperCppEndpoint; 18 | 19 | use crate::model::Model; 20 | 21 | static ENDPOINT: Lazy = Lazy::new(Default::default); 22 | 23 | pub async fn create_transcription( 24 | file: &[u8], 25 | model: Model, 26 | language: Option<&str>, 27 | prompt: Option<&str>, 28 | temperature: Option, 29 | create_session: bool, 30 | session: Option, 31 | ) -> Result<(String, Option), WhisperEndpointError> { 32 | let args = TranscriptionArgs { 33 | file: file.to_vec(), 34 | language: language.map(move |s| s.to_string()), 35 | prompt: prompt.map(move |s| s.to_string()), 36 | temperature, 37 | create_session, 38 | session, 39 | }; 40 | 41 | ENDPOINT 42 | .transcription( 43 | model 44 | .file_path() 45 | .map_err(move |e| WhisperEndpointError::Load(e.to_string()))?, 46 | args, 47 | ) 48 | .await 49 | } 50 | 51 | pub async fn reset_environment() { 52 | ENDPOINT.reset() 53 | } 54 | 55 | #[cfg(test)] 56 | mod tests { 57 | use super::*; 58 | use crate::model::{Model, ModelKind}; 59 | use crate::types::Endpoint; 60 | use edgen_core::settings::SETTINGS; 61 | use levenshtein; 62 | use std::path::PathBuf; 63 | 64 | async fn init_settings_for_test() { 65 | SETTINGS 66 | .write() 67 | .await 68 | .init() 69 | .await 70 | .expect("Failed to initialise settings"); 71 | } 72 | 73 | fn frost() -> String { 74 | " The woods are lovely, dark and deep, \ 75 | but I have promises to keep \ 76 | and miles to go before I sleep, \ 77 | and miles to go before I sleep." 78 | .to_string() 79 | } 80 | 81 | #[tokio::test] 82 | #[ignore] // this test hangs sometimes 83 | async fn test_create_transcription() { 84 | init_settings_for_test().await; 85 | let model_name = "ggml-distil-small.en.bin".to_string(); 86 | let repo = "distil-whisper/distil-small.en".to_string(); 87 | let dir = SETTINGS 88 | .read() 89 | .await 90 | .read() 91 | .await 92 | .audio_transcriptions_models_dir 93 | .to_string(); 94 | let mut model = Model::new(ModelKind::Whisper, &model_name, &repo, &PathBuf::from(&dir)); 95 | assert!(model.preload(Endpoint::AudioTranscriptions).await.is_ok()); 96 | 97 | let sound = include_bytes!("../resources/frost.wav"); 98 | let response = create_transcription(sound, model, None, None, None, true, None).await; 99 | 100 | assert!(response.is_ok(), "cannot create transcription"); 101 | 102 | let expected_text = frost(); 103 | let (actual_text, session) = response.unwrap(); 104 | 105 | println!("{:?}", session); 106 | 107 | // Calculate Levenshtein distance 108 | let distance = levenshtein::levenshtein(&expected_text, &actual_text); 109 | 110 | // Calculate similarity percentage 111 | let similarity_percentage = 112 | 100.0 - ((distance as f64 / expected_text.len() as f64) * 100.0); 113 | 114 | // Assert that the similarity is at least 90% 115 | assert!( 116 | similarity_percentage >= 90.0, 117 | "Text similarity is less than 90%" 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /docs/src/app/api-reference/image/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Image', 3 | description: 'Generate images', 4 | } 5 | 6 | # Image 7 | 8 | Generate images from text. {{ className: 'lead' }} 9 | 10 | --- 11 | 12 | 13 | 14 | 15 | ## Create image {{tag:'POST', label:'http://localhost:33322/v1/image/generations'}} 16 | 17 | Given a text prompt, generate 1 or more images according to the prompt. 18 | 19 | ### Required attributes 20 | 21 | 22 | 23 | A description of the images to be generated. 24 | 25 | 26 | 27 | 28 | 29 | The model used for image generations. (WARNING: At the moment only "stable-diffusion-2-1" is allowed) 30 |
      31 |
    • 32 | If the model name is "default", the chat model from the configuration is used (see [Documentation » Configuration](/documentation/configuration) for details). 33 |
    • 34 |
    • 35 | If the model name is a valid model name recognized by Edgen, it is what is used. 36 |
    • 37 |
    38 | 39 |
    40 |
    41 | 42 | ### Optional attributes 43 | 44 | 45 | 46 | The width of the generated image. 47 | 48 | 49 | 50 | 51 | 52 | The height of the generated image. 53 | 54 | 55 | 56 | 57 | 58 | The optional unconditional prompt. 59 | 60 | 61 | 62 | 63 | 64 | The number of steps to be used in the diffusion process. 65 | 66 | 67 | 68 | 69 | 70 | The number of images to generate. 71 | Default: 1 72 | 73 | 74 | 75 | 76 | 77 | The random number generator seed to use for the generation. 78 | By default, a random seed is used. 79 | 80 | 81 | 82 | 83 | 84 | The guidance scale to use for generation, that is, how much should the model follow the prompt. 85 | Values below 1 disable guidance. (the prompt is ignored) 86 | 87 | 88 | 89 | 90 | 91 | The Variational Auto-Encoder scale to use for generation. 92 | Required if `model` is not a pre-made descriptor name. 93 | This value should probably not be set, if `model` is a pre-made descriptor name. 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 |
    103 | 104 | 105 | ```bash {{ title: 'cURL' }} 106 | curl http://localhost:33322/v1/image/generations \ 107 | -H "Content-Type: application/json" \ 108 | -H "Authorization: Bearer no-key-required" \ 109 | -d '{ 110 | "model": "stable-diffusion-2-1", 111 | "prompt": "A rusty robot" 112 | }' 113 | ``` 114 | 115 | ```python 116 | API NOT DONE YET 117 | ``` 118 | 119 | ```ts 120 | API NOT DONE YET 121 | ``` 122 | 123 | 124 | 125 | ```json {{ title: 'Response' }} 126 | {"images": [[123, 234, ..., 231, 213]]} 127 | ``` 128 |
    129 |
    130 | 131 | 132 |
    133 | -------------------------------------------------------------------------------- /docs/src/mdx/search.mjs: -------------------------------------------------------------------------------- 1 | import { slugifyWithCounter } from '@sindresorhus/slugify' 2 | import glob from 'fast-glob' 3 | import * as fs from 'fs' 4 | import { toString } from 'mdast-util-to-string' 5 | import * as path from 'path' 6 | import { remark } from 'remark' 7 | import remarkMdx from 'remark-mdx' 8 | import { createLoader } from 'simple-functional-loader' 9 | import { filter } from 'unist-util-filter' 10 | import { SKIP, visit } from 'unist-util-visit' 11 | import * as url from 'url' 12 | 13 | const __filename = url.fileURLToPath(import.meta.url) 14 | const processor = remark().use(remarkMdx).use(extractSections) 15 | const slugify = slugifyWithCounter() 16 | 17 | function isObjectExpression(node) { 18 | return ( 19 | node.type === 'mdxTextExpression' && 20 | node.data?.estree?.body?.[0]?.expression?.type === 'ObjectExpression' 21 | ) 22 | } 23 | 24 | function excludeObjectExpressions(tree) { 25 | return filter(tree, (node) => !isObjectExpression(node)) 26 | } 27 | 28 | function extractSections() { 29 | return (tree, { sections }) => { 30 | slugify.reset() 31 | 32 | visit(tree, (node) => { 33 | if (node.type === 'heading' || node.type === 'paragraph') { 34 | let content = toString(excludeObjectExpressions(node)) 35 | if (node.type === 'heading' && node.depth <= 2) { 36 | let hash = node.depth === 1 ? null : slugify(content) 37 | sections.push([content, hash, []]) 38 | } else { 39 | sections.at(-1)?.[2].push(content) 40 | } 41 | return SKIP 42 | } 43 | }) 44 | } 45 | } 46 | 47 | export default function (nextConfig = {}) { 48 | let cache = new Map() 49 | 50 | return Object.assign({}, nextConfig, { 51 | webpack(config, options) { 52 | config.module.rules.push({ 53 | test: __filename, 54 | use: [ 55 | createLoader(function () { 56 | let appDir = path.resolve('./src/app') 57 | this.addContextDependency(appDir) 58 | 59 | let files = glob.sync('**/*.mdx', { cwd: appDir }) 60 | let data = files.map((file) => { 61 | let url = '/' + file.replace(/(^|\/)page\.mdx$/, '') 62 | let mdx = fs.readFileSync(path.join(appDir, file), 'utf8') 63 | 64 | let sections = [] 65 | 66 | if (cache.get(file)?.[0] === mdx) { 67 | sections = cache.get(file)[1] 68 | } else { 69 | let vfile = { value: mdx, sections } 70 | processor.runSync(processor.parse(vfile), vfile) 71 | cache.set(file, [mdx, sections]) 72 | } 73 | 74 | return { url, sections } 75 | }) 76 | 77 | // When this file is imported within the application 78 | // the following module is loaded: 79 | return ` 80 | import FlexSearch from 'flexsearch' 81 | 82 | let sectionIndex = new FlexSearch.Document({ 83 | tokenize: 'full', 84 | document: { 85 | id: 'url', 86 | index: 'content', 87 | store: ['title', 'pageTitle'], 88 | }, 89 | context: { 90 | resolution: 9, 91 | depth: 2, 92 | bidirectional: true 93 | } 94 | }) 95 | 96 | let data = ${JSON.stringify(data)} 97 | 98 | for (let { url, sections } of data) { 99 | for (let [title, hash, content] of sections) { 100 | sectionIndex.add({ 101 | url: url + (hash ? ('#' + hash) : ''), 102 | title, 103 | content: [title, ...content].join('\\n'), 104 | pageTitle: hash ? sections[0][0] : undefined, 105 | }) 106 | } 107 | } 108 | 109 | export function search(query, options = {}) { 110 | let result = sectionIndex.search(query, { 111 | ...options, 112 | enrich: true, 113 | }) 114 | if (result.length === 0) { 115 | return [] 116 | } 117 | return result[0].result.map((item) => ({ 118 | url: item.id, 119 | title: item.doc.title, 120 | pageTitle: item.doc.pageTitle, 121 | })) 122 | } 123 | ` 124 | }), 125 | ], 126 | }) 127 | 128 | if (typeof nextConfig.webpack === 'function') { 129 | return nextConfig.webpack(config, options) 130 | } 131 | 132 | return config 133 | }, 134 | }) 135 | } 136 | -------------------------------------------------------------------------------- /docs/src/components/SectionProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { 4 | createContext, 5 | useContext, 6 | useEffect, 7 | useLayoutEffect, 8 | useState, 9 | } from 'react' 10 | import { type StoreApi, createStore, useStore } from 'zustand' 11 | 12 | import { remToPx } from '@/lib/remToPx' 13 | 14 | export interface Section { 15 | id: string 16 | title: string 17 | offsetRem?: number 18 | tag?: string 19 | headingRef?: React.RefObject 20 | } 21 | 22 | interface SectionState { 23 | sections: Array
    24 | visibleSections: Array 25 | setVisibleSections: (visibleSections: Array) => void 26 | registerHeading: ({ 27 | id, 28 | ref, 29 | offsetRem, 30 | }: { 31 | id: string 32 | ref: React.RefObject 33 | offsetRem: number 34 | }) => void 35 | } 36 | 37 | function createSectionStore(sections: Array
    ) { 38 | return createStore()((set) => ({ 39 | sections, 40 | visibleSections: [], 41 | setVisibleSections: (visibleSections) => 42 | set((state) => 43 | state.visibleSections.join() === visibleSections.join() 44 | ? {} 45 | : { visibleSections }, 46 | ), 47 | registerHeading: ({ id, ref, offsetRem }) => 48 | set((state) => { 49 | return { 50 | sections: state.sections.map((section) => { 51 | if (section.id === id) { 52 | return { 53 | ...section, 54 | headingRef: ref, 55 | offsetRem, 56 | } 57 | } 58 | return section 59 | }), 60 | } 61 | }), 62 | })) 63 | } 64 | 65 | function useVisibleSections(sectionStore: StoreApi) { 66 | let setVisibleSections = useStore(sectionStore, (s) => s.setVisibleSections) 67 | let sections = useStore(sectionStore, (s) => s.sections) 68 | 69 | useEffect(() => { 70 | function checkVisibleSections() { 71 | let { innerHeight, scrollY } = window 72 | let newVisibleSections = [] 73 | 74 | for ( 75 | let sectionIndex = 0; 76 | sectionIndex < sections.length; 77 | sectionIndex++ 78 | ) { 79 | let { id, headingRef, offsetRem = 0 } = sections[sectionIndex] 80 | 81 | if (!headingRef?.current) { 82 | continue 83 | } 84 | 85 | let offset = remToPx(offsetRem) 86 | let top = headingRef.current.getBoundingClientRect().top + scrollY 87 | 88 | if (sectionIndex === 0 && top - offset > scrollY) { 89 | newVisibleSections.push('_top') 90 | } 91 | 92 | let nextSection = sections[sectionIndex + 1] 93 | let bottom = 94 | (nextSection?.headingRef?.current?.getBoundingClientRect().top ?? 95 | Infinity) + 96 | scrollY - 97 | remToPx(nextSection?.offsetRem ?? 0) 98 | 99 | if ( 100 | (top > scrollY && top < scrollY + innerHeight) || 101 | (bottom > scrollY && bottom < scrollY + innerHeight) || 102 | (top <= scrollY && bottom >= scrollY + innerHeight) 103 | ) { 104 | newVisibleSections.push(id) 105 | } 106 | } 107 | 108 | setVisibleSections(newVisibleSections) 109 | } 110 | 111 | let raf = window.requestAnimationFrame(() => checkVisibleSections()) 112 | window.addEventListener('scroll', checkVisibleSections, { passive: true }) 113 | window.addEventListener('resize', checkVisibleSections) 114 | 115 | return () => { 116 | window.cancelAnimationFrame(raf) 117 | window.removeEventListener('scroll', checkVisibleSections) 118 | window.removeEventListener('resize', checkVisibleSections) 119 | } 120 | }, [setVisibleSections, sections]) 121 | } 122 | 123 | const SectionStoreContext = createContext | null>(null) 124 | 125 | const useIsomorphicLayoutEffect = 126 | typeof window === 'undefined' ? useEffect : useLayoutEffect 127 | 128 | export function SectionProvider({ 129 | sections, 130 | children, 131 | }: { 132 | sections: Array
    133 | children: React.ReactNode 134 | }) { 135 | let [sectionStore] = useState(() => createSectionStore(sections)) 136 | 137 | useVisibleSections(sectionStore) 138 | 139 | useIsomorphicLayoutEffect(() => { 140 | sectionStore.setState({ sections }) 141 | }, [sectionStore, sections]) 142 | 143 | return ( 144 | 145 | {children} 146 | 147 | ) 148 | } 149 | 150 | export function useSectionStore(selector: (state: SectionState) => T) { 151 | let store = useContext(SectionStoreContext) 152 | return useStore(store!, selector) 153 | } 154 | -------------------------------------------------------------------------------- /edgen/src-tauri/src/gui.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | use edgen_core::settings; 14 | use edgen_server; 15 | use opener; 16 | use tauri::{ 17 | CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, 18 | }; 19 | use tracing::info; 20 | 21 | // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command 22 | #[tauri::command] 23 | fn greet(name: &str) -> String { 24 | format!("Hello, {}! You've been greeted from Rust!", name) 25 | } 26 | 27 | pub fn run() { 28 | // here `"quit".to_string()` defines the menu item id, and the second parameter is the menu item label. 29 | let menu_item_show = CustomMenuItem::new("show".to_string(), "Show"); 30 | let menu_item_quit = CustomMenuItem::new("quit".to_string(), "Quit"); 31 | let menu_item_edgen_chat = CustomMenuItem::new("edgenchat".to_string(), "EdgenChat"); 32 | let menu_item_config = CustomMenuItem::new("config".to_string(), "Config"); 33 | let menu_item_reset_config = CustomMenuItem::new("reset_config".to_string(), "Reset Config"); 34 | // let show = CustomMenuItem::new("show".to_string(), "Show"); 35 | let tray_menu = SystemTrayMenu::new() 36 | // .add_item(show) 37 | .add_item(menu_item_edgen_chat) 38 | .add_item(menu_item_config) 39 | .add_item(menu_item_reset_config) 40 | .add_native_item(SystemTrayMenuItem::Separator) 41 | .add_item(menu_item_show) 42 | .add_item(menu_item_quit); 43 | 44 | tauri::Builder::default() 45 | .system_tray(SystemTray::new().with_menu(tray_menu)) 46 | .on_system_tray_event(|app, event| match event { 47 | SystemTrayEvent::LeftClick { 48 | position: _, 49 | size: _, 50 | .. 51 | } => { 52 | info!("system tray received a left click"); 53 | let window = app.get_window("main").unwrap(); 54 | window.set_focus().unwrap(); 55 | } 56 | SystemTrayEvent::RightClick { 57 | position: _, 58 | size: _, 59 | .. 60 | } => { 61 | info!("system tray received a right click"); 62 | } 63 | SystemTrayEvent::DoubleClick { 64 | position: _, 65 | size: _, 66 | .. 67 | } => { 68 | info!("system tray received a double click"); 69 | } 70 | 71 | SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { 72 | "show" => { 73 | let window = app.get_window("main").unwrap(); 74 | window.show().unwrap(); 75 | } 76 | "quit" => { 77 | app.exit(0); 78 | } 79 | "edgenchat" => { 80 | if let Err(err) = opener::open("https://chat.edgen.co") { 81 | eprintln!("Error opening website: {:?}", err); 82 | } 83 | } 84 | "config" => { 85 | if let Err(err) = opener::open(settings::get_config_file_path()) { 86 | eprintln!("Error opening config file: {:?}", err); 87 | } 88 | } 89 | "reset_config" => { 90 | if let Err(err) = edgen_server::config_reset() { 91 | eprintln!("Error resetting config: {:?}", err); 92 | } 93 | } 94 | _ => {} 95 | }, 96 | _ => {} 97 | }) 98 | // keep the frontend running in the background 99 | .on_window_event(|event| match event.event() { 100 | tauri::WindowEvent::CloseRequested { api, .. } => { 101 | event.window().hide().unwrap(); 102 | api.prevent_close(); 103 | } 104 | _ => {} 105 | }) 106 | .invoke_handler(tauri::generate_handler![greet]) 107 | .run(tauri::generate_context!()) 108 | .expect("error while running tauri application"); 109 | } 110 | -------------------------------------------------------------------------------- /docs/src/components/Heading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect, useRef } from 'react' 4 | import Link from 'next/link' 5 | import { useInView } from 'framer-motion' 6 | 7 | import { useSectionStore } from '@/components/SectionProvider' 8 | import { Tag } from '@/components/Tag' 9 | import { remToPx } from '@/lib/remToPx' 10 | 11 | function AnchorIcon(props: React.ComponentPropsWithoutRef<'svg'>) { 12 | return ( 13 | 22 | ) 23 | } 24 | 25 | export function Eyebrow({ tag, label }: { tag?: string; label?: string }) { 26 | if (!tag && !label) { 27 | return null 28 | } 29 | 30 | return ( 31 |
    32 | {tag && {tag}} 33 | {tag && label && ( 34 | 35 | )} 36 | {label && ( 37 | {label} 38 | )} 39 |
    40 | ) 41 | } 42 | 43 | function Anchor({ 44 | id, 45 | inView, 46 | children, 47 | }: { 48 | id: string 49 | inView: boolean 50 | children: React.ReactNode 51 | }) { 52 | return ( 53 | 57 | {inView && ( 58 |
    59 |
    60 | 61 |
    62 |
    63 | )} 64 | {children} 65 | 66 | ) 67 | } 68 | 69 | export function Heading({ 70 | children, 71 | tag, 72 | label, 73 | level, 74 | anchor = true, 75 | ...props 76 | }: React.ComponentPropsWithoutRef<`h${Level}`> & { 77 | id: string 78 | tag?: string 79 | label?: string 80 | level?: Level 81 | anchor?: boolean 82 | }) { 83 | level = level ?? (2 as Level) 84 | let Component = `h${level}` as 'h2' | 'h3' 85 | let ref = useRef(null) 86 | let registerHeading = useSectionStore((s) => s.registerHeading) 87 | 88 | let inView = useInView(ref, { 89 | margin: `${remToPx(-3.5)}px 0px 0px 0px`, 90 | amount: 'all', 91 | }) 92 | 93 | useEffect(() => { 94 | if (level === 2) { 95 | registerHeading({ id: props.id, ref, offsetRem: tag || label ? 8 : 6 }) 96 | } 97 | }) 98 | 99 | return ( 100 | <> 101 | 102 | 107 | {anchor ? ( 108 | 109 | {children} 110 | 111 | ) : ( 112 | children 113 | )} 114 | 115 | 116 | ) 117 | } 118 | 119 | export function HeadingNoEyebrow({ 120 | children, 121 | tag, 122 | label, 123 | level, 124 | anchor = true, 125 | ...props 126 | }: React.ComponentPropsWithoutRef<`h${Level}`> & { 127 | id: string 128 | tag?: string 129 | label?: string 130 | level?: Level 131 | anchor?: boolean 132 | }) { 133 | level = level ?? (2 as Level) 134 | let Component = `h${level}` as 'h2' | 'h3' 135 | let ref = useRef(null) 136 | let registerHeading = useSectionStore((s) => s.registerHeading) 137 | 138 | let inView = useInView(ref, { 139 | margin: `${remToPx(-3.5)}px 0px 0px 0px`, 140 | amount: 'all', 141 | }) 142 | 143 | useEffect(() => { 144 | if (level === 2) { 145 | registerHeading({ id: props.id, ref, offsetRem: tag || label ? 8 : 6 }) 146 | } 147 | }) 148 | 149 | return ( 150 | <> 151 | 156 | { 157 | {children} 158 | } 159 | 160 | 161 | ) 162 | } 163 | -------------------------------------------------------------------------------- /docs/src/components/EdgenAI_dark_colored.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 33 | 38 | 43 | 48 | 53 | 58 | 63 | 68 | 73 | 74 | -------------------------------------------------------------------------------- /docs/src/app/documentation/configuration/page.mdx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Configuration', 3 | description: 'Edgen configuration.', 4 | } 5 | 6 | # Configuration 7 | The Edgen configuration. It is read from a file where you can define your models' locations, select which model to use for each endpoint, the number of threads Edgen can use and more. {{ className: 'lead' }} 8 | 9 | | Config Name | Description | Default Value | 10 | | --------------------------------- | ------------------------------------------ | ------------------------------------------------ | 11 | | `threads` | Number of CPU threads for processing | \ -1 | 12 | | `default_uri` | Default URI for communication | http://127.0.0.1:33322 | 13 | | `chat_completions_models_dir` | Directory for chat completions models | `/edgen/models/chat/completions` | 14 | | `chat_completions_model_name` | Name of chat completions model | neural-chat-7b-v3-3.Q4_K_M.gguf | 15 | | `chat_completions_model_repo` | HuggingFace repo for chat completions | TheBloke/neural-chat-7B-v3-3-GGUF | 16 | | `audio_transcriptions_models_dir` | Directory for audio transcriptions models | `/edgen/models/audio/transcriptions` | 17 | | `audio_transcriptions_model_name` | Name of audio transcriptions model | ggml-distil-small.en.bin | 18 | | `audio_transcriptions_model_repo` | HuggingFace repo for audio transcriptions | distil-whisper/distil-small.en | 19 | | `gpu_policy` | Policy to choose how a model gets loaded | !always_device | 20 | | `max_request_size` | Maximum size a request can have | 100 Megabytes | 21 | 22 | ## Configuration Paths for DATA_DIR 23 | 24 | | Platform | Value | Example | 25 | | -------- | ----------------------------------------------------------------- | ------------------------------------------------- | 26 | | Linux | `$XDG_DATA_HOME/_project_path_` or `$HOME/.local/share/_project_path_` | `/home/Alex/.local/share/edgen` | 27 | | macOS | `$HOME/Library/Application Support/_project_path_` | `/Users/Alex/Library/Application Support/com.EdgenAI.Edgen` | 28 | | Windows | `{FOLDERID_RoamingAppData}\_project_path_\data` | `C:\Users\Alex\AppData\Roaming\EdgenAI\Edgen\data` | 29 | 30 | ## Model Name and Repo 31 | 32 | Model name and repo define the model to use and how to obtain it automatically. If you download the model yourself you just have to copy it to the corresponding model directory and set the `model_name` setting to the file name. The repo has only informative character in this case, for instance: 33 | 34 | | Config Name | Your Value | 35 | | --------------------------------- | ------------------------------------------ | 36 | | `chat_completions_models_dir` | `/edgen/models/chat/completions` | 37 | | `chat_completions_model_name` | my-fancy-model | 38 | | `chat_completions_model_repo` | ModelMaster/fancy-model-1.v1-1.GGUF | 39 | 40 | If you prefer to let Edgen manage your models, you need to fill in the correct model name and repo, e.g. 41 | 42 | | Config Name | Your Value | 43 | | --------------------------------- | ------------------------------------------ | 44 | | `chat_completions_models_dir` | `/edgen/models/chat/completions` | 45 | | `chat_completions_model_name` | fancy-model-1.v1-1.gguf | 46 | | `chat_completions_model_repo` | ModelMaster/fancy-model-1.v1-1.GGUF | 47 | 48 | In this case, if the model does not exist in the model directory, Edgen will automatically download for you. You can use the model manager ([API Reference » Models](/api-reference/models)) to inspect and delete automatically downloaded models. 49 | 50 | ## GPU policies 51 | 52 | Edgen supports the following policies, each with their own sub-settings: 53 | 54 | - `!always_device` - Models will always get loaded to a GPU. 55 | - `overflow_to_cpu` - If true, when a model can't be loaded to a GPU, it gets loaded to system memory. Else, Edgen will free GPU memory until the model can be loaded. **WARNING**: neither of these systems are currently implemented. 56 | - `!always_cpu` - Models will always get loaded to system memory. 57 | - `overflow_to_device` - If true, when a model can't be loaded to system memory, it gets loaded to a GPU. Else, Edgen will free system memory until the model can be loaded. **WARNING**: neither of these systems are currently implemented. 58 | 59 | -------------------------------------------------------------------------------- /crates/edgen_async_compat/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* Copyright 2023- The Binedge, Lda team. All rights reserved. 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * Unless required by applicable law or agreed to in writing, software 7 | * distributed under the License is distributed on an "AS IS" BASIS, 8 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | * See the License for the specific language governing permissions and 10 | * limitations under the License. 11 | */ 12 | 13 | //! Shims around [`smol`][smol], [`tokio`][tokio], and [`glommio`] to provide a unified interface 14 | //! for asynchronous programming. 15 | //! 16 | //! This crate exports [`spawn`], [`spawn_local`], and [`unblock`] functions that will 17 | //! defer to the appropriate runtime depending on the feature flags enabled. 18 | //! 19 | //! The following feature flags are available and **mutually exclusive**: 20 | //! 21 | //! - `runtime-smol`: Use [`smol`] as the runtime. 22 | //! - `runtime-tokio`: Use [`tokio`] as the runtime. 23 | //! - `runtime-glommio`: Use [`glommio`] as the runtime. 24 | //! 25 | //! You must enable **exactly one** of these. Failing to enable any, or enabling more than one, 26 | //! will cause the crate to fail to compile. 27 | //! 28 | //! [smol]: https://docs.rs/smol 29 | //! [tokio]: https://docs.rs/tokio 30 | //! [glommio]: https://docs.rs/glommio 31 | 32 | #![forbid(unsafe_code)] 33 | #![warn(missing_docs)] 34 | 35 | use core::future::Future; 36 | 37 | static_assertions::assert_cfg!( 38 | any( 39 | all(feature = "runtime-smol", not(any(feature = "runtime-tokio", feature = "runtime-glommio"))), 40 | all(feature = "runtime-tokio", not(any(feature = "runtime-smol", feature = "runtime-glommio"))), 41 | all(feature = "runtime-glommio", not(any(feature = "runtime-smol", feature = "runtime-tokio"))), 42 | ), 43 | "You must enable exactly one of the `runtime-smol`, `runtime-tokio`, or `runtime-glommio` feature flags." 44 | ); 45 | 46 | /// Spawns a future onto the current executor, causing it to start executing almost immediately. 47 | /// 48 | /// This will automatically select for `smol`, `tokio`, or `glommio` depending on the feature 49 | /// flags enabled. 50 | pub async fn spawn(future: F) 51 | where 52 | F: Future + Send + 'static, 53 | { 54 | cfg_if::cfg_if! { 55 | if #[cfg(feature = "runtime-smol")] { 56 | smol::spawn(future).detach(); 57 | } else if #[cfg(feature = "runtime-tokio")] { 58 | tokio::spawn(future); 59 | } else if #[cfg(feature = "runtime-glommio")] { 60 | glommio::spawn_local(future).detach(); 61 | } else { 62 | unreachable!("No runtime enabled; build should not have succeeded") 63 | } 64 | } 65 | } 66 | 67 | /// Spawns a blocking function onto a thread pool, returning a future that resolves when the 68 | /// thread pool has finished executing the function. 69 | pub async fn unblock(callback: F) -> R 70 | where 71 | F: FnOnce() -> R + Send + 'static, 72 | R: Send + 'static, 73 | { 74 | cfg_if::cfg_if! { 75 | if #[cfg(feature = "runtime-smol")] { 76 | smol::unblock(callback).await 77 | } else if #[cfg(feature = "runtime-tokio")] { 78 | tokio::task::spawn_blocking(callback).await.unwrap() 79 | } else if #[cfg(feature = "runtime-glommio")] { 80 | glommio::executor().spawn_blocking(callback).await 81 | } else { 82 | unreachable!("No runtime enabled; build should not have succeeded") 83 | } 84 | } 85 | } 86 | 87 | /// Blocks the current thread until the provided future completes. 88 | pub fn block_on(future: F) -> R 89 | where 90 | F: Future + Send + 'static, 91 | R: Send + 'static, 92 | { 93 | cfg_if::cfg_if! { 94 | if #[cfg(feature = "runtime-smol")] { 95 | smol::block_on(future) 96 | } else if #[cfg(feature = "runtime-tokio")] { 97 | tokio::runtime::Builder::new_current_thread() 98 | .enable_all() 99 | .build() 100 | .unwrap() 101 | .block_on(future) 102 | } else if #[cfg(feature = "runtime-glommio")] { 103 | // glommio::executor().spawn_local(future) 104 | todo!() 105 | } else { 106 | unreachable!("No runtime enabled; build should not have succeeded") 107 | } 108 | } 109 | } 110 | 111 | #[cfg(test)] 112 | mod test { 113 | use super::*; 114 | 115 | #[test] 116 | fn test_spawn() { 117 | async fn test() { 118 | spawn(async { 119 | println!("Hello, world!"); 120 | }) 121 | .await; 122 | } 123 | 124 | block_on(test()); 125 | } 126 | 127 | #[test] 128 | fn test_spawn_blocking() { 129 | async fn test() { 130 | unblock(|| { 131 | println!("Hello, world!"); 132 | }) 133 | .await; 134 | } 135 | 136 | block_on(test()); 137 | } 138 | } 139 | --------------------------------------------------------------------------------