deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
10
packages/ai-hugging-face/.eslintrc.js
Normal file
10
packages/ai-hugging-face/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: [
|
||||
'../../configs/build.eslintrc.json'
|
||||
],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: 'tsconfig.json'
|
||||
}
|
||||
};
|
||||
33
packages/ai-hugging-face/README.md
Normal file
33
packages/ai-hugging-face/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
<div align='center'>
|
||||
|
||||
<br />
|
||||
|
||||
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
|
||||
|
||||
<h2>ECLIPSE THEIA - HUGGING FACE AI EXTENSION</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
The `@theia/ai-huggingface` integrates Hugging Face's models with Theia AI.
|
||||
The Hugging Face API key and the models to use can be configured via preferences.
|
||||
Alternatively, the Hugging Face API key can also be provided via the `HUGGINGFACE_API_KEY` environment variable.
|
||||
|
||||
## Additional Information
|
||||
|
||||
- [API documentation for `@theia/ai-huggingface`](https://eclipse-theia.github.io/theia/docs/next/modules/_theia_ai-huggingface.html)
|
||||
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
||||
- [Theia - Website](https://theia-ide.org/)
|
||||
|
||||
## License
|
||||
|
||||
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
|
||||
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
|
||||
|
||||
## Trademark
|
||||
|
||||
"Theia" is a trademark of the Eclipse Foundation
|
||||
<https://www.eclipse.org/theia>
|
||||
50
packages/ai-hugging-face/package.json
Normal file
50
packages/ai-hugging-face/package.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@theia/ai-huggingface",
|
||||
"version": "1.68.0",
|
||||
"description": "Theia - Hugging Face Integration",
|
||||
"dependencies": {
|
||||
"@huggingface/inference": "^4.13.10",
|
||||
"@theia/ai-core": "1.68.0",
|
||||
"@theia/core": "1.68.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"theiaExtensions": [
|
||||
{
|
||||
"frontend": "lib/browser/huggingface-frontend-module",
|
||||
"backend": "lib/node/huggingface-backend-module"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"theia-extension"
|
||||
],
|
||||
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/eclipse-theia/theia.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/eclipse-theia/theia/issues"
|
||||
},
|
||||
"homepage": "https://github.com/eclipse-theia/theia",
|
||||
"files": [
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "theiaext build",
|
||||
"clean": "theiaext clean",
|
||||
"compile": "theiaext compile",
|
||||
"lint": "theiaext lint",
|
||||
"test": "theiaext test",
|
||||
"watch": "theiaext watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/ext-scripts": "1.68.0"
|
||||
},
|
||||
"nyc": {
|
||||
"extends": "../../configs/nyc.json"
|
||||
},
|
||||
"gitHead": "21358137e41342742707f660b8e222f940a27652"
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { HuggingFaceLanguageModelsManager, HuggingFaceModelDescription } from '../common';
|
||||
import { API_KEY_PREF, MODELS_PREF } from '../common/huggingface-preferences';
|
||||
import { PreferenceService } from '@theia/core';
|
||||
|
||||
const HUGGINGFACE_PROVIDER_ID = 'huggingface';
|
||||
@injectable()
|
||||
export class HuggingFaceFrontendApplicationContribution implements FrontendApplicationContribution {
|
||||
|
||||
@inject(PreferenceService)
|
||||
protected preferenceService: PreferenceService;
|
||||
|
||||
@inject(HuggingFaceLanguageModelsManager)
|
||||
protected manager: HuggingFaceLanguageModelsManager;
|
||||
|
||||
protected prevModels: string[] = [];
|
||||
|
||||
onStart(): void {
|
||||
this.preferenceService.ready.then(() => {
|
||||
const apiKey = this.preferenceService.get<string>(API_KEY_PREF, undefined);
|
||||
this.manager.setApiKey(apiKey);
|
||||
|
||||
const models = this.preferenceService.get<string[]>(MODELS_PREF, []);
|
||||
this.manager.createOrUpdateLanguageModels(...models.map(modelId => this.createHuggingFaceModelDescription(modelId)));
|
||||
this.prevModels = [...models];
|
||||
|
||||
this.preferenceService.onPreferenceChanged(event => {
|
||||
if (event.preferenceName === API_KEY_PREF) {
|
||||
const newApiKey = this.preferenceService.get<string>(API_KEY_PREF, undefined);
|
||||
this.manager.setApiKey(newApiKey);
|
||||
this.handleKeyChange(newApiKey);
|
||||
} else if (event.preferenceName === MODELS_PREF) {
|
||||
this.handleModelChanges(this.preferenceService.get<string[]>(MODELS_PREF, []));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected handleModelChanges(newModels: string[]): void {
|
||||
const oldModels = new Set(this.prevModels);
|
||||
const updatedModels = new Set(newModels);
|
||||
|
||||
const modelsToRemove = [...oldModels].filter(model => !updatedModels.has(model));
|
||||
const modelsToAdd = [...updatedModels].filter(model => !oldModels.has(model));
|
||||
|
||||
this.manager.removeLanguageModels(...modelsToRemove.map(model => `${HUGGINGFACE_PROVIDER_ID}/${model}`));
|
||||
this.manager.createOrUpdateLanguageModels(...modelsToAdd.map(modelId => this.createHuggingFaceModelDescription(modelId)));
|
||||
this.prevModels = newModels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API key changes. Updates all HuggingFace models on the manager to ensure the new key is used.
|
||||
*/
|
||||
protected handleKeyChange(newApiKey: string | undefined): void {
|
||||
if (this.prevModels && this.prevModels.length > 0) {
|
||||
this.manager.createOrUpdateLanguageModels(...this.prevModels.map(modelId => this.createHuggingFaceModelDescription(modelId)));
|
||||
}
|
||||
}
|
||||
|
||||
protected createHuggingFaceModelDescription(
|
||||
modelId: string
|
||||
): HuggingFaceModelDescription {
|
||||
const id = `${HUGGINGFACE_PROVIDER_ID}/${modelId}`;
|
||||
return {
|
||||
id: id,
|
||||
model: modelId
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import { HuggingFacePreferencesSchema } from '../common/huggingface-preferences';
|
||||
import { FrontendApplicationContribution, RemoteConnectionProvider, ServiceConnectionProvider } from '@theia/core/lib/browser';
|
||||
import { HuggingFaceFrontendApplicationContribution } from './huggingface-frontend-application-contribution';
|
||||
import { HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH, HuggingFaceLanguageModelsManager } from '../common';
|
||||
import { PreferenceContribution } from '@theia/core';
|
||||
|
||||
export default new ContainerModule(bind => {
|
||||
bind(PreferenceContribution).toConstantValue({ schema: HuggingFacePreferencesSchema });
|
||||
bind(HuggingFaceFrontendApplicationContribution).toSelf().inSingletonScope();
|
||||
bind(FrontendApplicationContribution).toService(HuggingFaceFrontendApplicationContribution);
|
||||
bind(HuggingFaceLanguageModelsManager).toDynamicValue(ctx => {
|
||||
const provider = ctx.container.get<ServiceConnectionProvider>(RemoteConnectionProvider);
|
||||
return provider.createProxy<HuggingFaceLanguageModelsManager>(HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH);
|
||||
}).inSingletonScope();
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
export const HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH = '/services/huggingface/language-model-manager';
|
||||
export const HuggingFaceLanguageModelsManager = Symbol('HuggingFaceLanguageModelsManager');
|
||||
|
||||
export interface HuggingFaceModelDescription {
|
||||
/**
|
||||
* The identifier of the model which will be shown in the UI.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The model ID as used by the Hugging Face API.
|
||||
*/
|
||||
model: string;
|
||||
}
|
||||
|
||||
export interface HuggingFaceLanguageModelsManager {
|
||||
apiKey: string | undefined;
|
||||
setApiKey(key: string | undefined): void;
|
||||
createOrUpdateLanguageModels(...models: HuggingFaceModelDescription[]): Promise<void>;
|
||||
removeLanguageModels(...modelIds: string[]): void;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { AI_CORE_PREFERENCES_TITLE } from '@theia/ai-core/lib/common/ai-core-preferences';
|
||||
import { nls, PreferenceSchema } from '@theia/core';
|
||||
|
||||
export const API_KEY_PREF = 'ai-features.huggingFace.apiKey';
|
||||
export const MODELS_PREF = 'ai-features.huggingFace.models';
|
||||
|
||||
export const HuggingFacePreferencesSchema: PreferenceSchema = {
|
||||
properties: {
|
||||
[API_KEY_PREF]: {
|
||||
type: 'string',
|
||||
markdownDescription: nls.localize('theia/ai/huggingFace/apiKey/mdDescription',
|
||||
'Enter an API Key for your Hugging Face Account. **Please note:** By using this preference the Hugging Face API key will be stored in clear text\
|
||||
on the machine running Theia. Use the environment variable `HUGGINGFACE_API_KEY` to set the key securely.'),
|
||||
title: AI_CORE_PREFERENCES_TITLE,
|
||||
tags: ['experimental']
|
||||
},
|
||||
[MODELS_PREF]: {
|
||||
type: 'array',
|
||||
markdownDescription: nls.localize('theia/ai/huggingFace/models/mdDescription',
|
||||
'Hugging Face models to use. **Please note:** Only models supporting the chat completion API are supported \
|
||||
(instruction-tuned models like `*-Instruct`) currently. Some models may require accepting license terms on the Hugging Face website.'),
|
||||
title: AI_CORE_PREFERENCES_TITLE,
|
||||
default: ['meta-llama/Llama-3.2-3B-Instruct', 'meta-llama/Llama-3.1-8B-Instruct'],
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
tags: ['experimental']
|
||||
}
|
||||
}
|
||||
};
|
||||
16
packages/ai-hugging-face/src/common/index.ts
Normal file
16
packages/ai-hugging-face/src/common/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
export * from './huggingface-language-models-manager';
|
||||
@@ -0,0 +1,38 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import { HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH, HuggingFaceLanguageModelsManager } from '../common/huggingface-language-models-manager';
|
||||
import { ConnectionHandler, PreferenceContribution, RpcConnectionHandler } from '@theia/core';
|
||||
import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
|
||||
import { HuggingFaceLanguageModelsManagerImpl } from './huggingface-language-models-manager-impl';
|
||||
import { HuggingFacePreferencesSchema } from '../common/huggingface-preferences';
|
||||
|
||||
export const HuggingFaceModelFactory = Symbol('HuggingFaceModelFactory');
|
||||
|
||||
// We use a connection module to handle AI services separately for each frontend.
|
||||
const huggingfaceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService, bindFrontendService }) => {
|
||||
bind(HuggingFaceLanguageModelsManagerImpl).toSelf().inSingletonScope();
|
||||
bind(HuggingFaceLanguageModelsManager).toService(HuggingFaceLanguageModelsManagerImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(ctx =>
|
||||
new RpcConnectionHandler(HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH, () => ctx.container.get(HuggingFaceLanguageModelsManager))
|
||||
).inSingletonScope();
|
||||
});
|
||||
|
||||
export default new ContainerModule(bind => {
|
||||
bind(PreferenceContribution).toConstantValue({ schema: HuggingFacePreferencesSchema });
|
||||
bind(ConnectionContainerModule).toConstantValue(huggingfaceConnectionModule);
|
||||
});
|
||||
148
packages/ai-hugging-face/src/node/huggingface-language-model.ts
Normal file
148
packages/ai-hugging-face/src/node/huggingface-language-model.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import {
|
||||
LanguageModel,
|
||||
LanguageModelRequest,
|
||||
LanguageModelMessage,
|
||||
LanguageModelResponse,
|
||||
LanguageModelStreamResponsePart,
|
||||
LanguageModelTextResponse,
|
||||
MessageActor,
|
||||
LanguageModelStatus
|
||||
} from '@theia/ai-core';
|
||||
import { CancellationToken } from '@theia/core';
|
||||
import { InferenceClient } from '@huggingface/inference';
|
||||
|
||||
export const HuggingFaceModelIdentifier = Symbol('HuggingFaceModelIdentifier');
|
||||
|
||||
function toRole(actor: MessageActor): 'user' | 'assistant' | 'system' {
|
||||
switch (actor) {
|
||||
case 'user':
|
||||
return 'user';
|
||||
case 'ai':
|
||||
return 'assistant';
|
||||
case 'system':
|
||||
return 'system';
|
||||
default:
|
||||
return 'user';
|
||||
}
|
||||
}
|
||||
|
||||
function toChatMessages(messages: LanguageModelMessage[]): Array<{ role: 'user' | 'assistant' | 'system'; content: string }> {
|
||||
return messages
|
||||
.filter(LanguageModelMessage.isTextMessage)
|
||||
.map(message => ({
|
||||
role: toRole(message.actor),
|
||||
content: message.text
|
||||
}));
|
||||
}
|
||||
|
||||
export class HuggingFaceModel implements LanguageModel {
|
||||
|
||||
/**
|
||||
* @param id the unique id for this language model. It will be used to identify the model in the UI.
|
||||
* @param model the model id as it is used by the Hugging Face API
|
||||
* @param apiKey function to retrieve the API key for Hugging Face
|
||||
*/
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
public model: string,
|
||||
public status: LanguageModelStatus,
|
||||
public apiKey: () => string | undefined,
|
||||
public readonly name?: string,
|
||||
public readonly vendor?: string,
|
||||
public readonly version?: string,
|
||||
public readonly family?: string,
|
||||
public readonly maxInputTokens?: number,
|
||||
public readonly maxOutputTokens?: number
|
||||
) { }
|
||||
|
||||
async request(request: LanguageModelRequest, cancellationToken?: CancellationToken): Promise<LanguageModelResponse> {
|
||||
const hfInference = this.initializeInferenceClient();
|
||||
if (this.isStreamingSupported(this.model)) {
|
||||
return this.handleStreamingRequest(hfInference, request, cancellationToken);
|
||||
} else {
|
||||
return this.handleNonStreamingRequest(hfInference, request);
|
||||
}
|
||||
}
|
||||
|
||||
protected getSettings(request: LanguageModelRequest): Record<string, unknown> {
|
||||
return request.settings ?? {};
|
||||
}
|
||||
|
||||
protected async handleNonStreamingRequest(hfInference: InferenceClient, request: LanguageModelRequest): Promise<LanguageModelTextResponse> {
|
||||
const settings = this.getSettings(request);
|
||||
|
||||
const response = await hfInference.chatCompletion({
|
||||
model: this.model,
|
||||
messages: toChatMessages(request.messages),
|
||||
...settings
|
||||
});
|
||||
|
||||
const text = response.choices[0]?.message?.content ?? '';
|
||||
|
||||
return {
|
||||
text
|
||||
};
|
||||
}
|
||||
|
||||
protected async handleStreamingRequest(
|
||||
hfInference: InferenceClient,
|
||||
request: LanguageModelRequest,
|
||||
cancellationToken?: CancellationToken
|
||||
): Promise<LanguageModelResponse> {
|
||||
|
||||
const settings = this.getSettings(request);
|
||||
|
||||
const stream = hfInference.chatCompletionStream({
|
||||
model: this.model,
|
||||
messages: toChatMessages(request.messages),
|
||||
...settings
|
||||
});
|
||||
|
||||
const asyncIterator = {
|
||||
async *[Symbol.asyncIterator](): AsyncIterator<LanguageModelStreamResponsePart> {
|
||||
for await (const chunk of stream) {
|
||||
const content = chunk.choices[0]?.delta?.content;
|
||||
|
||||
if (content !== undefined) {
|
||||
yield { content };
|
||||
}
|
||||
|
||||
if (cancellationToken?.isCancellationRequested) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { stream: asyncIterator };
|
||||
}
|
||||
|
||||
protected isStreamingSupported(model: string): boolean {
|
||||
// Assuming all models support streaming for now; can be refined if needed
|
||||
return true;
|
||||
}
|
||||
|
||||
private initializeInferenceClient(): InferenceClient {
|
||||
const token = this.apiKey();
|
||||
if (!token) {
|
||||
throw new Error('Please provide a Hugging Face API token.');
|
||||
}
|
||||
return new InferenceClient(token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { LanguageModelRegistry, LanguageModelStatus } from '@theia/ai-core';
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { HuggingFaceModel } from './huggingface-language-model';
|
||||
import { HuggingFaceLanguageModelsManager, HuggingFaceModelDescription } from '../common';
|
||||
|
||||
@injectable()
|
||||
export class HuggingFaceLanguageModelsManagerImpl implements HuggingFaceLanguageModelsManager {
|
||||
|
||||
protected _apiKey: string | undefined;
|
||||
|
||||
@inject(LanguageModelRegistry)
|
||||
protected readonly languageModelRegistry: LanguageModelRegistry;
|
||||
|
||||
get apiKey(): string | undefined {
|
||||
return this._apiKey ?? process.env.HUGGINGFACE_API_KEY;
|
||||
}
|
||||
|
||||
protected calculateStatus(apiKey: string | undefined): LanguageModelStatus {
|
||||
return apiKey ? { status: 'ready' } : { status: 'unavailable', message: 'No Hugging Face API key set' };
|
||||
}
|
||||
|
||||
async createOrUpdateLanguageModels(...modelDescriptions: HuggingFaceModelDescription[]): Promise<void> {
|
||||
for (const modelDescription of modelDescriptions) {
|
||||
const model = await this.languageModelRegistry.getLanguageModel(modelDescription.id);
|
||||
const apiKeyProvider = () => this.apiKey;
|
||||
const status = this.calculateStatus(this.apiKey);
|
||||
|
||||
if (model) {
|
||||
if (!(model instanceof HuggingFaceModel)) {
|
||||
console.warn(`Hugging Face: model ${modelDescription.id} is not a Hugging Face model`);
|
||||
continue;
|
||||
}
|
||||
await this.languageModelRegistry.patchLanguageModel(modelDescription.id, { status });
|
||||
} else {
|
||||
this.languageModelRegistry.addLanguageModels([
|
||||
new HuggingFaceModel(
|
||||
modelDescription.id,
|
||||
modelDescription.model,
|
||||
status,
|
||||
apiKeyProvider,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeLanguageModels(...modelIds: string[]): void {
|
||||
this.languageModelRegistry.removeLanguageModels(modelIds);
|
||||
}
|
||||
|
||||
setApiKey(apiKey: string | undefined): void {
|
||||
this._apiKey = apiKey || undefined;
|
||||
}
|
||||
}
|
||||
28
packages/ai-hugging-face/src/package.spec.ts
Normal file
28
packages/ai-hugging-face/src/package.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2024 EclipseSource GmbH and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
/* note: this bogus test file is required so that
|
||||
we are able to run mocha unit tests on this
|
||||
package, without having any actual unit tests in it.
|
||||
This way a coverage report will be generated,
|
||||
showing 0% coverage, instead of no report.
|
||||
This file can be removed once we have real unit
|
||||
tests in place. */
|
||||
|
||||
describe('ai-huggingface package', () => {
|
||||
|
||||
it('support code coverage statistics', () => true);
|
||||
});
|
||||
19
packages/ai-hugging-face/tsconfig.json
Normal file
19
packages/ai-hugging-face/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../configs/base.tsconfig",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../ai-core"
|
||||
},
|
||||
{
|
||||
"path": "../core"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user