Skip to content

Commit ded6884

Browse files
authored
Merge pull request #1973 from Stijnus/feat/openai-like-api-models
feat: add support for OPENAI_LIKE_API_MODELS
2 parents 37217a5 + 9e01e5c commit ded6884

File tree

5 files changed

+111
-12
lines changed

5 files changed

+111
-12
lines changed

app/lib/modules/llm/providers/openai-like.ts

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default class OpenAILikeProvider extends BaseProvider {
1010
config = {
1111
baseUrlKey: 'OPENAI_LIKE_API_BASE_URL',
1212
apiTokenKey: 'OPENAI_LIKE_API_KEY',
13+
modelsKey: 'OPENAI_LIKE_API_MODELS',
1314
};
1415

1516
staticModels: ModelInfo[] = [];
@@ -31,20 +32,114 @@ export default class OpenAILikeProvider extends BaseProvider {
3132
return [];
3233
}
3334

34-
const response = await fetch(`${baseUrl}/models`, {
35-
headers: {
36-
Authorization: `Bearer ${apiKey}`,
37-
},
38-
});
35+
try {
36+
const response = await fetch(`${baseUrl}/models`, {
37+
headers: {
38+
Authorization: `Bearer ${apiKey}`,
39+
},
40+
});
41+
42+
if (!response.ok) {
43+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
44+
}
45+
46+
const res = (await response.json()) as any;
47+
48+
return res.data.map((model: any) => ({
49+
name: model.id,
50+
label: model.id,
51+
provider: this.name,
52+
maxTokenAllowed: 8000,
53+
}));
54+
} catch (error) {
55+
console.log(`${this.name}: Not allowed to GET /models endpoint for provider`, error);
56+
57+
// Fallback to OPENAI_LIKE_API_MODELS if available
58+
// eslint-disable-next-line dot-notation
59+
const modelsEnv = serverEnv['OPENAI_LIKE_API_MODELS'] || settings?.OPENAI_LIKE_API_MODELS;
60+
61+
if (modelsEnv) {
62+
console.log(`${this.name}: OPENAI_LIKE_API_MODELS=${modelsEnv}`);
63+
return this._parseModelsFromEnv(modelsEnv);
64+
}
65+
66+
return [];
67+
}
68+
}
69+
70+
/**
71+
* Parse OPENAI_LIKE_API_MODELS environment variable
72+
* Format: path/to/model1:limit;path/to/model2:limit;path/to/model3:limit
73+
*/
74+
private _parseModelsFromEnv(modelsEnv: string): ModelInfo[] {
75+
if (!modelsEnv) {
76+
return [];
77+
}
78+
79+
try {
80+
const models: ModelInfo[] = [];
81+
const modelEntries = modelsEnv.split(';');
82+
83+
for (const entry of modelEntries) {
84+
const trimmedEntry = entry.trim();
3985

40-
const res = (await response.json()) as any;
86+
if (!trimmedEntry) {
87+
continue;
88+
}
89+
90+
const [modelPath, limitStr] = trimmedEntry.split(':');
91+
92+
if (!modelPath) {
93+
continue;
94+
}
95+
96+
const limit = limitStr ? parseInt(limitStr.trim(), 10) : 8000;
97+
const modelName = modelPath.trim();
98+
99+
// Generate a readable label from the model path
100+
const label = this._generateModelLabel(modelName);
101+
102+
models.push({
103+
name: modelName,
104+
label,
105+
provider: this.name,
106+
maxTokenAllowed: limit,
107+
});
108+
}
109+
110+
console.log(`${this.name}: Parsed Models:`, models);
111+
112+
return models;
113+
} catch (error) {
114+
console.error(`${this.name}: Error parsing OPENAI_LIKE_API_MODELS:`, error);
115+
return [];
116+
}
117+
}
118+
119+
/**
120+
* Generate a readable label from model path
121+
*/
122+
private _generateModelLabel(modelPath: string): string {
123+
// Extract the last part of the path and clean it up
124+
const parts = modelPath.split('/');
125+
const lastPart = parts[parts.length - 1];
126+
127+
// Remove common prefixes and clean up the name
128+
let label = lastPart
129+
.replace(/^accounts\//, '')
130+
.replace(/^fireworks\/models\//, '')
131+
.replace(/^models\//, '')
132+
// Capitalize first letter of each word
133+
.replace(/\b\w/g, (l) => l.toUpperCase())
134+
// Replace spaces with hyphens for a cleaner look
135+
.replace(/\s+/g, '-');
136+
137+
// Add provider suffix if not already present
138+
if (!label.includes('Fireworks') && !label.includes('OpenAI')) {
139+
label += ' (OpenAI Compatible)';
140+
}
41141

42-
return res.data.map((model: any) => ({
43-
name: model.id,
44-
label: model.id,
45-
provider: this.name,
46-
maxTokenAllowed: 8000,
47-
}));
142+
return label;
48143
}
49144

50145
getModelInstance(options: {

app/types/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type ProviderInfo = {
1717
export interface IProviderSetting {
1818
enabled?: boolean;
1919
baseUrl?: string;
20+
OPENAI_LIKE_API_MODELS?: string;
2021
}
2122

2223
export type IProviderConfig = ProviderInfo & {

vite-electron.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export default defineConfig((config) => {
6060
envPrefix: [
6161
'VITE_',
6262
'OPENAI_LIKE_API_BASE_URL',
63+
'OPENAI_LIKE_API_MODELS',
6364
'OLLAMA_API_BASE_URL',
6465
'LMSTUDIO_API_BASE_URL',
6566
'TOGETHER_API_BASE_URL',

vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export default defineConfig((config) => {
6060
envPrefix: [
6161
'VITE_',
6262
'OPENAI_LIKE_API_BASE_URL',
63+
'OPENAI_LIKE_API_MODELS',
6364
'OLLAMA_API_BASE_URL',
6465
'LMSTUDIO_API_BASE_URL',
6566
'TOGETHER_API_BASE_URL',

worker-configuration.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface Env {
99
OLLAMA_API_BASE_URL: string;
1010
OPENAI_LIKE_API_KEY: string;
1111
OPENAI_LIKE_API_BASE_URL: string;
12+
OPENAI_LIKE_API_MODELS: string;
1213
TOGETHER_API_KEY: string;
1314
TOGETHER_API_BASE_URL: string;
1415
DEEPSEEK_API_KEY: string;

0 commit comments

Comments
 (0)