Merge branch 'dev' into main
This commit is contained in:
commit
63a2f22414
7
.github/ISSUE_TEMPLATE/bug_report.md
vendored
7
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -25,16 +25,13 @@ If applicable, add screenshots to help explain your issue.
|
|||||||
|
|
||||||
**Environment details**
|
**Environment details**
|
||||||
- Operating System: [Specify your OS. e.g., MacOS Sonoma 14.2.1, Windows 11, Ubuntu 22, etc]
|
- Operating System: [Specify your OS. e.g., MacOS Sonoma 14.2.1, Windows 11, Ubuntu 22, etc]
|
||||||
- Jan Version: [e.g., 0.4.3]
|
- Jan Version: [e.g., 0.4.xxx nightly or manual]
|
||||||
- Processor: [e.g., Apple M1, Intel Core i7, AMD Ryzen 5, etc]
|
- Processor: [e.g., Apple M1, Intel Core i7, AMD Ryzen 5, etc]
|
||||||
- RAM: [e.g., 8GB, 16GB]
|
- RAM: [e.g., 8GB, 16GB]
|
||||||
- Any additional relevant hardware specifics: [e.g., Graphics card, SSD/HDD]
|
- Any additional relevant hardware specifics: [e.g., Graphics card, SSD/HDD]
|
||||||
|
|
||||||
**Logs**
|
**Logs**
|
||||||
If the cause of the error is not clear, kindly provide your usage logs:
|
If the cause of the error is not clear, kindly provide your usage logs: https://jan.ai/docs/troubleshooting#how-to-get-error-logs
|
||||||
- `tail -n 50 ~/jan/logs/app.log` if you are using the UI
|
|
||||||
- `tail -n 50 ~/jan/logs/server.log` if you are using the local api server
|
|
||||||
Making sure to redact any private information.
|
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context or information that could be helpful in diagnosing the problem.
|
Add any other context or information that could be helpful in diagnosing the problem.
|
||||||
|
|||||||
@ -1,12 +1,6 @@
|
|||||||
name: Jan Build Electron App Nightly or Manual
|
name: Electron Builder - Nightly / Manual
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths-ignore:
|
|
||||||
- 'README.md'
|
|
||||||
- 'docs/**'
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 20 * * 1,2,3' # At 8 PM UTC on Monday, Tuesday, and Wednesday which is 3 AM UTC+7 Tuesday, Wednesday, and Thursday
|
- cron: '0 20 * * 1,2,3' # At 8 PM UTC on Monday, Tuesday, and Wednesday which is 3 AM UTC+7 Tuesday, Wednesday, and Thursday
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|||||||
2
.github/workflows/jan-electron-build.yml
vendored
2
.github/workflows/jan-electron-build.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Jan Build Electron App
|
name: Electron Builder - Tag
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
name: Jan Electron Linter & Test
|
name: Test - Linter & Playwright
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
|
|||||||
90
.github/workflows/jan-openai-api-test.yml
vendored
Normal file
90
.github/workflows/jan-openai-api-test.yml
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
name: Test - OpenAI API Pytest collection
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
- release/**
|
||||||
|
paths:
|
||||||
|
- "docs/**"
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
- release/**
|
||||||
|
paths:
|
||||||
|
- "docs/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
openai-python-tests:
|
||||||
|
runs-on: [self-hosted, Linux, ubuntu-desktop]
|
||||||
|
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||||
|
steps:
|
||||||
|
- name: Getting the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Installing node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: "Cleanup cache"
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
rm -rf ~/jan
|
||||||
|
make clean
|
||||||
|
|
||||||
|
- name: install dependencies
|
||||||
|
run: |
|
||||||
|
npm install -g @stoplight/prism-cli
|
||||||
|
|
||||||
|
- name: create python virtual environment and run test
|
||||||
|
run: |
|
||||||
|
python3 -m venv /tmp/jan
|
||||||
|
source /tmp/jan/bin/activate
|
||||||
|
# Clone openai-api-python repo
|
||||||
|
OPENAI_API_PYTHON_TAG=$(cat docs/openapi/version.txt)
|
||||||
|
git clone https://github.com/openai/openai-python.git
|
||||||
|
cd openai-python
|
||||||
|
git checkout $OPENAI_API_PYTHON_TAG
|
||||||
|
|
||||||
|
python3 -m venv /tmp/jan
|
||||||
|
source /tmp/jan/bin/activate
|
||||||
|
pip install -r requirements-dev.lock
|
||||||
|
pip install pytest-reportportal pytest-html
|
||||||
|
|
||||||
|
# Create pytest.ini file with content
|
||||||
|
cat ../docs/tests/pytest.ini >> pytest.ini
|
||||||
|
echo "rp_api_key = ${{ secrets.REPORT_PORTAL_API_KEY }}" >> pytest.ini
|
||||||
|
echo "rp_endpoint = ${{ secrets.REPORT_PORTAL_URL_PYTEST }}" >> pytest.ini
|
||||||
|
cat pytest.ini
|
||||||
|
|
||||||
|
# Append to conftest.py
|
||||||
|
cat ../docs/tests/conftest.py >> tests/conftest.py
|
||||||
|
|
||||||
|
# start mock server and run test then stop mock server
|
||||||
|
prism mock ../docs/openapi/jan.yaml > prism.log & prism_pid=$! && pytest --reportportal --html=report.html && kill $prism_pid
|
||||||
|
deactivate
|
||||||
|
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: report
|
||||||
|
path: |
|
||||||
|
openai-python/report.html
|
||||||
|
openai-python/assets
|
||||||
|
openai-python/prism.log
|
||||||
|
|
||||||
|
- name: clean up
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
rm -rf /tmp/jan
|
||||||
|
rm -rf openai-python
|
||||||
|
rm -rf report.html
|
||||||
|
rm -rf report.zip
|
||||||
|
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
name: Jan Build Docker Nightly or Manual
|
name: Docker Builder - Nightly / Manual
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|||||||
2
.github/workflows/jan-server-build.yml
vendored
2
.github/workflows/jan-server-build.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Jan Build Docker
|
name: Docker Builder - Tag
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|||||||
@ -31,6 +31,12 @@ export abstract class OAIEngine extends AIEngine {
|
|||||||
// The loaded model instance
|
// The loaded model instance
|
||||||
loadedModel: Model | undefined
|
loadedModel: Model | undefined
|
||||||
|
|
||||||
|
// Transform the payload
|
||||||
|
transformPayload?: Function
|
||||||
|
|
||||||
|
// Transform the response
|
||||||
|
transformResponse?: Function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On extension load, subscribe to events.
|
* On extension load, subscribe to events.
|
||||||
*/
|
*/
|
||||||
@ -78,13 +84,23 @@ export abstract class OAIEngine extends AIEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const header = await this.headers()
|
const header = await this.headers()
|
||||||
|
let requestBody = {
|
||||||
|
messages: data.messages ?? [],
|
||||||
|
model: model.id,
|
||||||
|
stream: true,
|
||||||
|
...model.parameters,
|
||||||
|
}
|
||||||
|
if (this.transformPayload) {
|
||||||
|
requestBody = this.transformPayload(requestBody)
|
||||||
|
}
|
||||||
|
|
||||||
requestInference(
|
requestInference(
|
||||||
this.inferenceUrl,
|
this.inferenceUrl,
|
||||||
data.messages ?? [],
|
requestBody,
|
||||||
model,
|
model,
|
||||||
this.controller,
|
this.controller,
|
||||||
header
|
header,
|
||||||
|
this.transformResponse
|
||||||
).subscribe({
|
).subscribe({
|
||||||
next: (content: any) => {
|
next: (content: any) => {
|
||||||
const messageContent: ThreadContent = {
|
const messageContent: ThreadContent = {
|
||||||
|
|||||||
@ -7,21 +7,16 @@ import { ErrorCode, ModelRuntimeParams } from '../../../../types'
|
|||||||
*/
|
*/
|
||||||
export function requestInference(
|
export function requestInference(
|
||||||
inferenceUrl: string,
|
inferenceUrl: string,
|
||||||
recentMessages: any[],
|
requestBody: any,
|
||||||
model: {
|
model: {
|
||||||
id: string
|
id: string
|
||||||
parameters: ModelRuntimeParams
|
parameters: ModelRuntimeParams
|
||||||
},
|
},
|
||||||
controller?: AbortController,
|
controller?: AbortController,
|
||||||
headers?: HeadersInit
|
headers?: HeadersInit,
|
||||||
|
transformResponse?: Function
|
||||||
): Observable<string> {
|
): Observable<string> {
|
||||||
return new Observable((subscriber) => {
|
return new Observable((subscriber) => {
|
||||||
const requestBody = JSON.stringify({
|
|
||||||
messages: recentMessages,
|
|
||||||
model: model.id,
|
|
||||||
stream: true,
|
|
||||||
...model.parameters,
|
|
||||||
})
|
|
||||||
fetch(inferenceUrl, {
|
fetch(inferenceUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -30,17 +25,17 @@ export function requestInference(
|
|||||||
'Accept': model.parameters.stream ? 'text/event-stream' : 'application/json',
|
'Accept': model.parameters.stream ? 'text/event-stream' : 'application/json',
|
||||||
...headers,
|
...headers,
|
||||||
},
|
},
|
||||||
body: requestBody,
|
body: JSON.stringify(requestBody),
|
||||||
signal: controller?.signal,
|
signal: controller?.signal,
|
||||||
})
|
})
|
||||||
.then(async (response) => {
|
.then(async (response) => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
let errorCode = ErrorCode.Unknown;
|
let errorCode = ErrorCode.Unknown
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
errorCode = data.error.code ?? data.error.type ?? ErrorCode.Unknown
|
errorCode = data.error.code ?? data.error.type ?? ErrorCode.Unknown
|
||||||
} else if (response.status === 401) {
|
} else if (response.status === 401) {
|
||||||
errorCode = ErrorCode.InvalidApiKey;
|
errorCode = ErrorCode.InvalidApiKey
|
||||||
}
|
}
|
||||||
const error = {
|
const error = {
|
||||||
message: data.error?.message ?? 'Error occurred.',
|
message: data.error?.message ?? 'Error occurred.',
|
||||||
@ -52,7 +47,11 @@ export function requestInference(
|
|||||||
}
|
}
|
||||||
if (model.parameters.stream === false) {
|
if (model.parameters.stream === false) {
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
if (transformResponse) {
|
||||||
|
subscriber.next(transformResponse(data))
|
||||||
|
} else {
|
||||||
subscriber.next(data.choices[0]?.message?.content ?? '')
|
subscriber.next(data.choices[0]?.message?.content ?? '')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const stream = response.body
|
const stream = response.body
|
||||||
const decoder = new TextDecoder('utf-8')
|
const decoder = new TextDecoder('utf-8')
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { ChatCompletionMessage } from '../inference'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Native Route APIs
|
* Native Route APIs
|
||||||
* @description Enum of all the routes exposed by the app
|
* @description Enum of all the routes exposed by the app
|
||||||
@ -154,3 +156,8 @@ export const APIEvents = [
|
|||||||
...Object.values(DownloadEvent),
|
...Object.values(DownloadEvent),
|
||||||
...Object.values(LocalImportModelEvent),
|
...Object.values(LocalImportModelEvent),
|
||||||
]
|
]
|
||||||
|
export type PayloadType = {
|
||||||
|
messages: ChatCompletionMessage[]
|
||||||
|
model: string
|
||||||
|
stream: Boolean
|
||||||
|
}
|
||||||
|
|||||||
1
docs/openapi/version.txt
Normal file
1
docs/openapi/version.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
v1.23.2
|
||||||
6
docs/tests/conftest.py
Normal file
6
docs/tests/conftest.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
def pytest_collection_modifyitems(items):
|
||||||
|
for item in items:
|
||||||
|
# add the name of the file (without extension) as a marker
|
||||||
|
filename = item.nodeid.split("::")[0].split("/")[-1].replace(".py", "")
|
||||||
|
marker = pytest.mark.file(filename)
|
||||||
|
item.add_marker(marker)
|
||||||
8
docs/tests/pytest.ini
Normal file
8
docs/tests/pytest.ini
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[pytest]
|
||||||
|
rp_project = openai-api-test
|
||||||
|
rp_launch = OpenAI Collection Test
|
||||||
|
rp_launch_description = Full collection to ensure compatibility with OpenAI API
|
||||||
|
rp_launch_attributes = 'CI'
|
||||||
|
filterwarnings = ignore::pytest.PytestUnknownMarkWarning
|
||||||
|
log_format = %(asctime)s %(levelname)s %(message)s
|
||||||
|
log_date_format = %Y-%m-%d %H:%M:%S
|
||||||
79
extensions/inference-cohere-extension/README.md
Normal file
79
extensions/inference-cohere-extension/README.md
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# Cohere 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!
|
||||||
43
extensions/inference-cohere-extension/package.json
Normal file
43
extensions/inference-cohere-extension/package.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "@janhq/inference-cohere-extension",
|
||||||
|
"productName": "Cohere Inference Engine",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "This extension enables Cohere chat completion API calls",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/module.js",
|
||||||
|
"engine": "cohere",
|
||||||
|
"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",
|
||||||
|
"sync:core": "cd ../.. && yarn build:core && cd extensions && rm yarn.lock && cd inference-cohere-extension && yarn && yarn build:publish"
|
||||||
|
},
|
||||||
|
"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",
|
||||||
|
"ulidx": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/*",
|
||||||
|
"package.json",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"bundleDependencies": [
|
||||||
|
"fetch-retry"
|
||||||
|
]
|
||||||
|
}
|
||||||
26
extensions/inference-cohere-extension/resources/models.json
Normal file
26
extensions/inference-cohere-extension/resources/models.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"url": "https://cohere.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "command-r-plus",
|
||||||
|
"object": "model",
|
||||||
|
"name": "Command R+",
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "Command R+ is an instruction-following conversational model that performs language tasks at a higher quality, more reliably, and with a longer context than previous models. It is best suited for complex RAG workflows and multi-step tool use.",
|
||||||
|
"format": "api",
|
||||||
|
"settings": {},
|
||||||
|
"parameters": {
|
||||||
|
"max_tokens": 128000,
|
||||||
|
"temperature": 0.7,
|
||||||
|
"stream": false
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "Cohere",
|
||||||
|
"tags": ["General", "Big Context Length"]
|
||||||
|
},
|
||||||
|
"engine": "cohere"
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "chat-completions-endpoint",
|
||||||
|
"title": "Chat Completions Endpoint",
|
||||||
|
"description": "The endpoint to use for chat completions. See the [Cohere API documentation](https://docs.cohere.com/reference/chat) for more information.",
|
||||||
|
"controllerType": "input",
|
||||||
|
"controllerProps": {
|
||||||
|
"placeholder": "https://api.cohere.ai/v1/chat",
|
||||||
|
"value": "https://api.cohere.ai/v1/chat"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "cohere-api-key",
|
||||||
|
"title": "API Key",
|
||||||
|
"description": "The Cohere API uses API keys for authentication. Visit your [API Keys](https://platform.openai.com/account/api-keys) page to retrieve the API key you'll use in your requests.",
|
||||||
|
"controllerType": "input",
|
||||||
|
"controllerProps": {
|
||||||
|
"placeholder": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||||
|
"value": "",
|
||||||
|
"type": "password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
110
extensions/inference-cohere-extension/src/index.ts
Normal file
110
extensions/inference-cohere-extension/src/index.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* @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-openai-extension/src/index
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RemoteOAIEngine } from '@janhq/core'
|
||||||
|
import { PayloadType } from '@janhq/core'
|
||||||
|
import { ChatCompletionRole } from '@janhq/core'
|
||||||
|
|
||||||
|
declare const SETTINGS: Array<any>
|
||||||
|
declare const MODELS: Array<any>
|
||||||
|
|
||||||
|
enum Settings {
|
||||||
|
apiKey = 'cohere-api-key',
|
||||||
|
chatCompletionsEndPoint = 'chat-completions-endpoint',
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RoleType {
|
||||||
|
user = 'USER',
|
||||||
|
chatbot = 'CHATBOT',
|
||||||
|
system = 'SYSTEM',
|
||||||
|
}
|
||||||
|
|
||||||
|
type CoherePayloadType = {
|
||||||
|
chat_history?: Array<{ role: RoleType; message: string }>
|
||||||
|
message?: string,
|
||||||
|
preamble?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 JanInferenceCohereExtension extends RemoteOAIEngine {
|
||||||
|
inferenceUrl: string = ''
|
||||||
|
provider: string = 'cohere'
|
||||||
|
|
||||||
|
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,
|
||||||
|
''
|
||||||
|
)
|
||||||
|
if (this.inferenceUrl.length === 0) {
|
||||||
|
SETTINGS.forEach((setting) => {
|
||||||
|
if (setting.key === Settings.chatCompletionsEndPoint) {
|
||||||
|
this.inferenceUrl = setting.controllerProps.value as string
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSettingUpdate<T>(key: string, value: T): void {
|
||||||
|
if (key === Settings.apiKey) {
|
||||||
|
this.apiKey = value as string
|
||||||
|
} else if (key === Settings.chatCompletionsEndPoint) {
|
||||||
|
if (typeof value !== 'string') return
|
||||||
|
|
||||||
|
if (value.trim().length === 0) {
|
||||||
|
SETTINGS.forEach((setting) => {
|
||||||
|
if (setting.key === Settings.chatCompletionsEndPoint) {
|
||||||
|
this.inferenceUrl = setting.controllerProps.value as string
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.inferenceUrl = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transformPayload = (payload: PayloadType): CoherePayloadType => {
|
||||||
|
if (payload.messages.length === 0) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
const convertedData:CoherePayloadType = {
|
||||||
|
chat_history: [],
|
||||||
|
message: '',
|
||||||
|
}
|
||||||
|
payload.messages.forEach((item, index) => {
|
||||||
|
// Assign the message of the last item to the `message` property
|
||||||
|
if (index === payload.messages.length - 1) {
|
||||||
|
convertedData.message = item.content as string
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (item.role === ChatCompletionRole.User) {
|
||||||
|
convertedData.chat_history.push({ role: RoleType.user, message: item.content as string})
|
||||||
|
} else if (item.role === ChatCompletionRole.Assistant) {
|
||||||
|
convertedData.chat_history.push({
|
||||||
|
role: RoleType.chatbot,
|
||||||
|
message: item.content as string,
|
||||||
|
})
|
||||||
|
} else if (item.role === ChatCompletionRole.System) {
|
||||||
|
convertedData.preamble = item.content as string
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return convertedData
|
||||||
|
}
|
||||||
|
|
||||||
|
transformResponse = (data: any) => data.text
|
||||||
|
}
|
||||||
14
extensions/inference-cohere-extension/tsconfig.json
Normal file
14
extensions/inference-cohere-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"]
|
||||||
|
}
|
||||||
37
extensions/inference-cohere-extension/webpack.config.js
Normal file
37
extensions/inference-cohere-extension/webpack.config.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
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({
|
||||||
|
MODELS: JSON.stringify(modelsJson),
|
||||||
|
SETTINGS: JSON.stringify(settingJson),
|
||||||
|
ENGINE: JSON.stringify(packageJson.engine),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
filename: 'index.js', // Adjust the output file name as needed
|
||||||
|
library: { type: 'module' }, // Specify ESM output format
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.js'],
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: false,
|
||||||
|
},
|
||||||
|
// Add loaders and other configuration as needed for your project
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-gguf/resolve/main/Phi-3-mini-4k-instruct-q4.gguf",
|
||||||
|
"filename": "Phi-3-mini-4k-instruct-q4.gguf"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "phi3-3.8b",
|
||||||
|
"object": "model",
|
||||||
|
"name": "Phi-3 Mini",
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "Phi-3 Mini is Microsoft's newest, compact model designed for mobile use.",
|
||||||
|
"format": "gguf",
|
||||||
|
"settings": {
|
||||||
|
"ctx_len": 4096,
|
||||||
|
"prompt_template": "<|system|>\n{system_message}<|end|>\n<|user|>\n{prompt}<|end|>\n<|assistant|>\n",
|
||||||
|
"llama_model_path": "Phi-3-mini-4k-instruct-q4.gguf"
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"max_tokens": 4096,
|
||||||
|
"stop": ["<|end|>"]
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "Microsoft",
|
||||||
|
"tags": [
|
||||||
|
"3B",
|
||||||
|
"Finetuned"
|
||||||
|
],
|
||||||
|
"size": 2320000000
|
||||||
|
},
|
||||||
|
"engine": "nitro"
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user