Added a way to use azure openai api.

This commit is contained in:
TDC13 2023-04-29 12:22:25 -05:00
parent f00159d695
commit 213426d58f
3 changed files with 88 additions and 9 deletions

82
main.ts
View file

@ -28,13 +28,14 @@ import * as cohere from "cohere-ai";
import * as fs from "fs";
import GPT3Tokenizer from "gpt3-tokenizer";
import { Configuration, OpenAIApi } from "openai";
import { Configuration as AzureConfiguration, OpenAIApi as AzureOpenAiApi} from "azure-openai";
import { v4 as uuidv4 } from "uuid";
const dialog = require("electron").remote.dialog;
const untildify = require("untildify") as any;
const tokenizer = new GPT3Tokenizer({ type: "codex" }); // TODO depends on model
const PROVIDERS = ["cohere", "textsynth", "ocp", "openai", "openai-chat"];
const PROVIDERS = ["cohere", "textsynth", "ocp", "openai", "openai-chat", "azure", "azure-chat"];
type Provider = (typeof PROVIDERS)[number];
interface LoomSettings {
@ -42,6 +43,10 @@ interface LoomSettings {
cohereApiKey: string;
textsynthApiKey: string;
azureApiKey: string;
azureEndpoint: string;
ocpApiKey: string;
ocpUrl: string;
@ -68,6 +73,9 @@ const DEFAULT_SETTINGS: LoomSettings = {
cohereApiKey: "",
textsynthApiKey: "",
azureApiKey: "",
azureEndpoint: "",
ocpApiKey: "",
ocpUrl: "",
@ -110,6 +118,7 @@ export default class LoomPlugin extends Plugin {
statusBarItem: HTMLElement;
openai: OpenAIApi;
azureopenai: AzureOpenAiApi;
withFile<T>(callback: (file: TFile) => T): T | null {
const file = this.app.workspace.getActiveFile();
@ -152,6 +161,19 @@ export default class LoomPlugin extends Plugin {
cohere.init(this.settings.cohereApiKey);
}
setAzureOpenAI() {
const configuration = new AzureConfiguration({
apiKey: this.settings.azureApiKey,
// add azure info into configuration
azure: {
apiKey: this.settings.azureApiKey,
endpoint: this.settings.azureEndpoint
}
});
this.azureopenai = new AzureOpenAiApi(configuration);
}
async onload() {
await this.loadSettings();
await this.loadState();
@ -160,6 +182,7 @@ export default class LoomPlugin extends Plugin {
this.setOpenAI();
this.setCohere();
this.setAzureOpenAI();
this.statusBarItem = this.addStatusBarItem();
this.statusBarItem.setText("Completing...");
@ -180,6 +203,12 @@ export default class LoomPlugin extends Plugin {
!this.settings.openaiApiKey
)
return false;
if (
["azure", "azure-chat"].includes(this.settings.provider) &&
!this.settings.azureApiKey
)
return false;
if (this.settings.provider === "cohere" && !this.settings.cohereApiKey)
return false;
if (
@ -189,7 +218,7 @@ export default class LoomPlugin extends Plugin {
return false;
if (this.settings.provider === "ocp" && !this.settings.ocpApiKey)
return false;
if (!checking) {
if (file.extension === "md")
this.mdComplete(file);
@ -1067,7 +1096,7 @@ export default class LoomPlugin extends Plugin {
// complete, or visually display an error and return if that fails
let rawCompletions;
try {
if (this.settings.provider === "openai-chat") {
if (["openai-chat"].includes(this.settings.provider)) {
rawCompletions = (
await this.openai.createChatCompletion({
model: this.settings.model,
@ -1078,7 +1107,7 @@ export default class LoomPlugin extends Plugin {
top_p: this.settings.topP,
})
).data.choices.map((choice) => choice.message?.content);
} else if (this.settings.provider === "openai") {
} else if (["openai"].includes(this.settings.provider)) {
rawCompletions = (
await this.openai.createCompletion({
model: this.settings.model,
@ -1089,18 +1118,40 @@ export default class LoomPlugin extends Plugin {
top_p: this.settings.topP,
})
).data.choices.map((choice) => choice.text);
} else if (["azure-chat"].includes(this.settings.provider)) {
rawCompletions = (
await this.azureopenai.createChatCompletion({
model: this.settings.model,
messages: [{ role: "assistant", content: prompt }],
max_tokens: this.settings.maxTokens,
n: this.settings.n,
temperature: this.settings.temperature,
top_p: this.settings.topP,
})
).data.choices.map((choice) => choice.message?.content);
} else if (["azure"].includes(this.settings.provider)) {
rawCompletions = (
await this.azureopenai.createCompletion({
model: this.settings.model,
prompt,
max_tokens: this.settings.maxTokens,
n: this.settings.n,
temperature: this.settings.temperature,
top_p: this.settings.topP,
})
).data.choices.map((choice) => choice.text);
}
} catch (e) {
if (
e.response.status === 401 &&
["openai", "openai-chat"].includes(this.settings.provider)
["openai", "openai-chat", "azure", "azure-chat"].includes(this.settings.provider)
)
new Notice(
"OpenAI API key is invalid. Please provide a valid key in the settings."
);
else if (
e.response.status === 429 &&
["openai", "openai-chat"].includes(this.settings.provider)
["openai", "openai-chat", "azure", "azure-chat"].includes(this.settings.provider)
)
new Notice("OpenAI API rate limit exceeded.");
else new Notice("Unknown API error: " + e.response.data.error.message);
@ -1203,7 +1254,7 @@ export default class LoomPlugin extends Plugin {
completion = completion.replace(/</g, "\\<"); // escape < for obsidian
completion = completion.replace(/\[/g, "\\["); // escape [ for obsidian
if (this.settings.provider === "openai-chat") {
if (["azure-chat", "openai-chat"].includes(this.settings.provider)) {
if (!trailingSpace) completion = " " + completion;
} else if (trailingSpace && completion[0] === " ")
completion = completion.slice(1);
@ -1621,6 +1672,8 @@ class LoomView extends ItemView {
{ name: "OpenAI code-davinci-002 proxy", value: "ocp" },
{ name: "OpenAI (Completion)", value: "openai" },
{ name: "OpenAI (Chat)", value: "openai-chat" },
{ name: "Azure (Completion)", value: "azure" },
{ name: "Azure (Chat)", value: "azure-chat" },
];
providerOptions.forEach((option) => {
const optionEl = providerSelect.createEl("option", {
@ -2238,6 +2291,8 @@ class LoomSettingTab extends PluginSettingTab {
dropdown.addOption("ocp", "OpenAI code-davinci-002 proxy");
dropdown.addOption("openai", "OpenAI (Completion)");
dropdown.addOption("openai-chat", "OpenAI (Chat)");
dropdown.addOption("azure", "Azure (Completion)");
dropdown.addOption("azure-chat", "Azure (Chat)");
dropdown.setValue(this.plugin.settings.provider);
dropdown.onChange(async (value) => {
if (PROVIDERS.find((provider) => provider === value))
@ -2276,6 +2331,19 @@ class LoomSettingTab extends PluginSettingTab {
apiKeySetting("OpenAI", "openaiApiKey");
apiKeySetting("Azure", "azureApiKey")
new Setting(containerEl)
.setName("Azure-Openai Resource Endpoint")
.setDesc("Required if using Azure")
.addText((text) =>
text.setValue(this.plugin.settings.azureEndpoint).onChange(async (value) => {
this.plugin.settings.azureEndpoint = value;
await this.plugin.save();
})
);
// TODO: reduce duplication of other settings
new Setting(containerEl).setName("Model").addText((text) =>

14
package-lock.json generated
View file

@ -1,17 +1,18 @@
{
"name": "obsidian-loom",
"version": "0.1.0",
"version": "1.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "obsidian-loom",
"version": "0.1.0",
"version": "1.3.0",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.9.3",
"@types/lodash": "^4.14.191",
"azure-openai": "^0.9.4",
"cohere-ai": "^6.1.0",
"gpt3-tokenizer": "^1.1.5",
"openai": "^3.2.0",
@ -497,6 +498,15 @@
"follow-redirects": "^1.14.8"
}
},
"node_modules/azure-openai": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/azure-openai/-/azure-openai-0.9.4.tgz",
"integrity": "sha512-7uii4ZInxzu2zjLg45PdvgOaw3ps18tEAw0Yux9mo8anX4PwnCMSS9xdlKNiNQyyEKPogvAcxH2PIufHXFLx6Q==",
"dependencies": {
"axios": "^0.26.0",
"form-data": "^4.0.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",

View file

@ -27,6 +27,7 @@
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.9.3",
"@types/lodash": "^4.14.191",
"azure-openai": "^0.9.4",
"cohere-ai": "^6.1.0",
"gpt3-tokenizer": "^1.1.5",
"openai": "^3.2.0",