feat: mistral inference engine extension (#2569)
* Add new feat: Inference Mistral extension * change settings * nitpicking fix * fix model position and add mistral registerModel * remove irrelevant changes * change desc of mistral medium Co-authored-by: Louis <louis@jan.ai> * change desc of mistral small Co-authored-by: Louis <louis@jan.ai> * change desc of mistral large Co-authored-by: Louis <louis@jan.ai> * remove unpopular mistral model * replace placeholder * sort remaining models using size --------- Co-authored-by: Jack Tri Le <Jack> Co-authored-by: Louis <louis@jan.ai>
This commit is contained in:
parent
c0c038f4f7
commit
1244f03f66
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
.vscode
|
||||
.idea
|
||||
.env
|
||||
.idea
|
||||
|
||||
|
||||
79
extensions/inference-mistral-extension/README.md
Normal file
79
extensions/inference-mistral-extension/README.md
Normal file
@ -0,0 +1,79 @@
|
||||
# Mistral Engine Extension
|
||||
|
||||
Created using Jan extension example
|
||||
|
||||
# Create a Jan Extension using Typescript
|
||||
|
||||
Use this template to bootstrap the creation of a TypeScript Jan extension. 🚀
|
||||
|
||||
## Create Your Own Extension
|
||||
|
||||
To create your own extension, you can use this repository as a template! Just follow the below instructions:
|
||||
|
||||
1. Click the Use this template button at the top of the repository
|
||||
2. Select Create a new repository
|
||||
3. Select an owner and name for your new repository
|
||||
4. Click Create repository
|
||||
5. Clone your new repository
|
||||
|
||||
## Initial Setup
|
||||
|
||||
After you've cloned the repository to your local machine or codespace, you'll need to perform some initial setup steps before you can develop your extension.
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> You'll need to have a reasonably modern version of
|
||||
> [Node.js](https://nodejs.org) handy. If you are using a version manager like
|
||||
> [`nodenv`](https://github.com/nodenv/nodenv) or
|
||||
> [`nvm`](https://github.com/nvm-sh/nvm), you can run `nodenv install` in the
|
||||
> root of your repository to install the version specified in
|
||||
> [`package.json`](./package.json). Otherwise, 20.x or later should work!
|
||||
|
||||
1. :hammer_and_wrench: Install the dependencies
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
1. :building_construction: Package the TypeScript for distribution
|
||||
|
||||
```bash
|
||||
npm run bundle
|
||||
```
|
||||
|
||||
1. :white_check_mark: Check your artifact
|
||||
|
||||
There will be a tgz file in your extension directory now
|
||||
|
||||
## Update the Extension Metadata
|
||||
|
||||
The [`package.json`](package.json) file defines metadata about your extension, such as
|
||||
extension name, main entry, description and version.
|
||||
|
||||
When you copy this repository, update `package.json` with the name, description for your extension.
|
||||
|
||||
## Update the Extension Code
|
||||
|
||||
The [`src/`](./src/) directory is the heart of your extension! This contains the
|
||||
source code that will be run when your extension functions are invoked. You can replace the
|
||||
contents of this directory with your own code.
|
||||
|
||||
There are a few things to keep in mind when writing your extension code:
|
||||
|
||||
- Most Jan Extension functions are processed asynchronously.
|
||||
In `index.ts`, you will see that the extension function will return a `Promise<any>`.
|
||||
|
||||
```typescript
|
||||
import { events, MessageEvent, MessageRequest } from '@janhq/core'
|
||||
|
||||
function onStart(): Promise<any> {
|
||||
return events.on(MessageEvent.OnMessageSent, (data: MessageRequest) =>
|
||||
this.inference(data)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
For more information about the Jan Extension Core module, see the
|
||||
[documentation](https://github.com/janhq/jan/blob/main/core/README.md).
|
||||
|
||||
So, what are you waiting for? Go ahead and start customizing your extension!
|
||||
42
extensions/inference-mistral-extension/package.json
Normal file
42
extensions/inference-mistral-extension/package.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@janhq/inference-mistral-extension",
|
||||
"version": "1.0.0",
|
||||
"description": "This extension enables Mistral chat completion API calls",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/module.js",
|
||||
"engine": "mistral",
|
||||
"author": "Jan <service@jan.ai>",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
"build": "tsc -b . && webpack --config webpack.config.js",
|
||||
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install"
|
||||
},
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./main": "./dist/module.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cpx": "^1.5.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"webpack": "^5.88.2",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"ts-loader": "^9.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@janhq/core": "file:../../core",
|
||||
"fetch-retry": "^5.0.6",
|
||||
"path-browserify": "^1.0.1",
|
||||
"ulidx": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist/*",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"bundleDependencies": [
|
||||
"fetch-retry"
|
||||
]
|
||||
}
|
||||
85
extensions/inference-mistral-extension/resources/models.json
Normal file
85
extensions/inference-mistral-extension/resources/models.json
Normal file
@ -0,0 +1,85 @@
|
||||
[
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://docs.mistral.ai/api/"
|
||||
}
|
||||
],
|
||||
"id": "mistral-small-latest",
|
||||
"object": "model",
|
||||
"name": "Mistral Small",
|
||||
"version": "1.0",
|
||||
"description": "Mistral Small is the ideal choice for simpe tasks that one can do in builk - like Classification, Customer Support, or Text Generation. It offers excellent performance at an affordable price point.",
|
||||
"format": "api",
|
||||
"settings": {},
|
||||
"parameters": {
|
||||
"max_tokens": 4096,
|
||||
"temperature": 0.7
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Mistral",
|
||||
"tags": [
|
||||
"Classification",
|
||||
"Customer Support",
|
||||
"Text Generation"
|
||||
]
|
||||
},
|
||||
"engine": "mistral"
|
||||
},
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://docs.mistral.ai/api/"
|
||||
}
|
||||
],
|
||||
"id": "mistral-medium-latest",
|
||||
"object": "model",
|
||||
"name": "Mistral Medium",
|
||||
"version": "1.0",
|
||||
"description": "Mistral Medium is the ideal for intermediate tasks that require moderate reasoning - like Data extraction, Summarizing a Document, Writing a Job Description, or Writing Product Descriptions. Mistral Medium strikes a balance between performance and capability, making it suitable for a wide range of tasks that only require language transformaion",
|
||||
"format": "api",
|
||||
"settings": {},
|
||||
"parameters": {
|
||||
"max_tokens": 4096,
|
||||
"temperature": 0.7
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Mistral",
|
||||
"tags": [
|
||||
"Data extraction",
|
||||
"Summarizing a Document",
|
||||
"Writing a Job Description",
|
||||
"Writing Product Descriptions"
|
||||
]
|
||||
},
|
||||
"engine": "mistral"
|
||||
},
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://docs.mistral.ai/api/"
|
||||
}
|
||||
],
|
||||
"id": "mistral-large-latest",
|
||||
"object": "model",
|
||||
"name": "Mistral Large",
|
||||
"version": "1.0",
|
||||
"description": "Mistral Large is ideal for complex tasks that require large reasoning capabilities or are highly specialized - like Synthetic Text Generation, Code Generation, RAG, or Agents.",
|
||||
"format": "api",
|
||||
"settings": {},
|
||||
"parameters": {
|
||||
"max_tokens": 4096,
|
||||
"temperature": 0.7
|
||||
},
|
||||
"metadata": {
|
||||
"author": "Mistral",
|
||||
"tags": [
|
||||
"Text Generation",
|
||||
"Code Generation",
|
||||
"RAG",
|
||||
"Agents"
|
||||
]
|
||||
},
|
||||
"engine": "mistral"
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"key": "chat-completions-endpoint",
|
||||
"title": "Chat Completions Endpoint",
|
||||
"description": "The endpoint to use for chat completions. See the [Mistral API documentation](https://docs.mistral.ai/api/#operation/createChatCompletion) for more information.",
|
||||
"controllerType": "input",
|
||||
"controllerProps": {
|
||||
"placeholder": "Chat Completions Endpoint",
|
||||
"value": "https://api.mistral.ai/v1/chat/completions"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "mistral-api-key",
|
||||
"title": "API Key",
|
||||
"description": "The Mistral API uses API keys for authentication. Visit your [API Keys](https://console.mistral.ai/api-keys/) page to retrieve the API key you'll use in your requests.",
|
||||
"controllerType": "input",
|
||||
"controllerProps": {
|
||||
"placeholder": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"value": "",
|
||||
"type": "password"
|
||||
}
|
||||
}
|
||||
]
|
||||
48
extensions/inference-mistral-extension/src/index.ts
Normal file
48
extensions/inference-mistral-extension/src/index.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file This file exports a class that implements the InferenceExtension interface from the @janhq/core package.
|
||||
* The class provides methods for initializing and stopping a model, and for making inference requests.
|
||||
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
|
||||
* @version 1.0.0
|
||||
* @module inference-mistral-extension/src/index
|
||||
*/
|
||||
|
||||
import { RemoteOAIEngine } from '@janhq/core'
|
||||
|
||||
declare const SETTINGS: Array<any>
|
||||
declare const MODELS: Array<any>
|
||||
|
||||
enum Settings {
|
||||
apiKey = 'mistral-api-key',
|
||||
chatCompletionsEndPoint = 'chat-completions-endpoint',
|
||||
}
|
||||
/**
|
||||
* A class that implements the InferenceExtension interface from the @janhq/core package.
|
||||
* The class provides methods for initializing and stopping a model, and for making inference requests.
|
||||
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
|
||||
*/
|
||||
export default class JanInferenceMistralExtension extends RemoteOAIEngine {
|
||||
inferenceUrl: string = ''
|
||||
provider: string = 'mistral'
|
||||
|
||||
override async onLoad(): Promise<void> {
|
||||
super.onLoad()
|
||||
|
||||
// Register Settings
|
||||
this.registerSettings(SETTINGS)
|
||||
this.registerModels(MODELS)
|
||||
|
||||
this.apiKey = await this.getSetting<string>(Settings.apiKey, '')
|
||||
this.inferenceUrl = await this.getSetting<string>(
|
||||
Settings.chatCompletionsEndPoint,
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
onSettingUpdate<T>(key: string, value: T): void {
|
||||
if (key === Settings.apiKey) {
|
||||
this.apiKey = value as string
|
||||
} else if (key === Settings.chatCompletionsEndPoint) {
|
||||
this.inferenceUrl = value as string
|
||||
}
|
||||
}
|
||||
}
|
||||
14
extensions/inference-mistral-extension/tsconfig.json
Normal file
14
extensions/inference-mistral-extension/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2016",
|
||||
"module": "ES6",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": false,
|
||||
"skipLibCheck": true,
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
||||
42
extensions/inference-mistral-extension/webpack.config.js
Normal file
42
extensions/inference-mistral-extension/webpack.config.js
Normal file
@ -0,0 +1,42 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const packageJson = require('./package.json')
|
||||
const settingJson = require('./resources/settings.json')
|
||||
const modelsJson = require('./resources/models.json')
|
||||
|
||||
module.exports = {
|
||||
experiments: { outputModule: true },
|
||||
entry: './src/index.ts', // Adjust the entry point to match your project's main file
|
||||
mode: 'production',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
SETTINGS: JSON.stringify(settingJson),
|
||||
ENGINE: JSON.stringify(packageJson.engine),
|
||||
MODELS: JSON.stringify(modelsJson),
|
||||
}),
|
||||
],
|
||||
output: {
|
||||
filename: 'index.js', // Adjust the output file name as needed
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
library: { type: 'module' }, // Specify ESM output format
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js'],
|
||||
fallback: {
|
||||
path: require.resolve('path-browserify'),
|
||||
},
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
},
|
||||
// Add loaders and other configuration as needed for your project
|
||||
}
|
||||
@ -30,10 +30,10 @@ const ExploreModelList: React.FC<Props> = ({ models }) => {
|
||||
remainingModels.push(m)
|
||||
}
|
||||
})
|
||||
featuredModels.sort((m1, m2) => m1.name.localeCompare(m2.name))
|
||||
featuredModels.sort((m1, m2) => m1.metadata.size - m2.metadata.size)
|
||||
remoteModels.sort((m1, m2) => m1.name.localeCompare(m2.name))
|
||||
localModels.sort((m1, m2) => m1.name.localeCompare(m2.name))
|
||||
remainingModels.sort((m1, m2) => m1.name.localeCompare(m2.name))
|
||||
localModels.sort((m1, m2) => m1.metadata.size - m2.metadata.size)
|
||||
remainingModels.sort((m1, m2) => m1.metadata.size - m2.metadata.size)
|
||||
return [
|
||||
...featuredModels,
|
||||
...remoteModels,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user