Skip to content

Commit a0aab03

Browse files
mohdamirducanh-ho2296marcusschiesser
authored
T-System's LLMHUB is added as model provider backend. (#139)
--------- Co-authored-by: Duc Anh Ho <[email protected]> Co-authored-by: Marcus Schiesser <[email protected]>
1 parent a807306 commit a0aab03

File tree

9 files changed

+290
-13
lines changed

9 files changed

+290
-13
lines changed

.changeset/silent-buses-dance.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"create-llama": patch
3+
---
4+
5+
Add T-System's LLMHUB as a model provider

helpers/env-variables.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
TemplateVectorDB,
99
} from "./types";
1010

11+
import { TSYSTEMS_LLMHUB_API_URL } from "./providers/llmhub";
12+
1113
export type EnvVar = {
1214
name?: string;
1315
description?: string;
@@ -262,6 +264,21 @@ const getModelEnvs = (modelConfig: ModelConfig): EnvVar[] => {
262264
},
263265
]
264266
: []),
267+
...(modelConfig.provider === "t-systems"
268+
? [
269+
{
270+
name: "T_SYSTEMS_LLMHUB_BASE_URL",
271+
description:
272+
"The base URL for the T-Systems AI Foundation Model API. Eg: http://localhost:11434",
273+
value: TSYSTEMS_LLMHUB_API_URL,
274+
},
275+
{
276+
name: "T_SYSTEMS_LLMHUB_API_KEY",
277+
description: "API Key for T-System's AI Foundation Model.",
278+
value: modelConfig.apiKey,
279+
},
280+
]
281+
: []),
265282
];
266283
};
267284

helpers/providers/index.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import ciInfo from "ci-info";
22
import prompts from "prompts";
33
import { questionHandlers } from "../../questions";
4-
import { ModelConfig, ModelProvider } from "../types";
4+
import { ModelConfig, ModelProvider, TemplateFramework } from "../types";
55
import { askAnthropicQuestions } from "./anthropic";
66
import { askGeminiQuestions } from "./gemini";
77
import { askGroqQuestions } from "./groq";
8+
import { askLLMHubQuestions } from "./llmhub";
89
import { askOllamaQuestions } from "./ollama";
910
import { askOpenAIQuestions } from "./openai";
1011

@@ -13,31 +14,35 @@ const DEFAULT_MODEL_PROVIDER = "openai";
1314
export type ModelConfigQuestionsParams = {
1415
openAiKey?: string;
1516
askModels: boolean;
17+
framework?: TemplateFramework;
1618
};
1719

1820
export type ModelConfigParams = Omit<ModelConfig, "provider">;
1921

2022
export async function askModelConfig({
2123
askModels,
2224
openAiKey,
25+
framework,
2326
}: ModelConfigQuestionsParams): Promise<ModelConfig> {
2427
let modelProvider: ModelProvider = DEFAULT_MODEL_PROVIDER;
2528
if (askModels && !ciInfo.isCI) {
29+
let choices = [
30+
{ title: "OpenAI", value: "openai" },
31+
{ title: "Groq", value: "groq" },
32+
{ title: "Ollama", value: "ollama" },
33+
{ title: "Anthropic", value: "anthropic" },
34+
{ title: "Gemini", value: "gemini" },
35+
];
36+
37+
if (framework === "fastapi") {
38+
choices.push({ title: "T-Systems", value: "t-systems" });
39+
}
2640
const { provider } = await prompts(
2741
{
2842
type: "select",
2943
name: "provider",
3044
message: "Which model provider would you like to use",
31-
choices: [
32-
{
33-
title: "OpenAI",
34-
value: "openai",
35-
},
36-
{ title: "Groq", value: "groq" },
37-
{ title: "Ollama", value: "ollama" },
38-
{ title: "Anthropic", value: "anthropic" },
39-
{ title: "Gemini", value: "gemini" },
40-
],
45+
choices: choices,
4146
initial: 0,
4247
},
4348
questionHandlers,
@@ -59,6 +64,9 @@ export async function askModelConfig({
5964
case "gemini":
6065
modelConfig = await askGeminiQuestions({ askModels });
6166
break;
67+
case "t-systems":
68+
modelConfig = await askLLMHubQuestions({ askModels });
69+
break;
6270
default:
6371
modelConfig = await askOpenAIQuestions({
6472
openAiKey,

helpers/providers/llmhub.ts

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import ciInfo from "ci-info";
2+
import got from "got";
3+
import ora from "ora";
4+
import { red } from "picocolors";
5+
import prompts from "prompts";
6+
import { ModelConfigParams } from ".";
7+
import { questionHandlers } from "../../questions";
8+
9+
export const TSYSTEMS_LLMHUB_API_URL =
10+
"https://llm-server.llmhub.t-systems.net/v2";
11+
12+
const DEFAULT_MODEL = "gpt-3.5-turbo";
13+
const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-large";
14+
15+
const LLMHUB_MODELS = [
16+
"gpt-35-turbo",
17+
"gpt-4-32k-1",
18+
"gpt-4-32k-canada",
19+
"gpt-4-32k-france",
20+
"gpt-4-turbo-128k-france",
21+
"Llama2-70b-Instruct",
22+
"Llama-3-70B-Instruct",
23+
"Mixtral-8x7B-Instruct-v0.1",
24+
"mistral-large-32k-france",
25+
"CodeLlama-2",
26+
];
27+
const LLMHUB_EMBEDDING_MODELS = [
28+
"text-embedding-ada-002",
29+
"text-embedding-ada-002-france",
30+
"jina-embeddings-v2-base-de",
31+
"jina-embeddings-v2-base-code",
32+
"text-embedding-bge-m3",
33+
];
34+
35+
type LLMHubQuestionsParams = {
36+
apiKey?: string;
37+
askModels: boolean;
38+
};
39+
40+
export async function askLLMHubQuestions({
41+
askModels,
42+
apiKey,
43+
}: LLMHubQuestionsParams): Promise<ModelConfigParams> {
44+
const config: ModelConfigParams = {
45+
apiKey,
46+
model: DEFAULT_MODEL,
47+
embeddingModel: DEFAULT_EMBEDDING_MODEL,
48+
dimensions: getDimensions(DEFAULT_EMBEDDING_MODEL),
49+
isConfigured(): boolean {
50+
if (config.apiKey) {
51+
return true;
52+
}
53+
if (process.env["T_SYSTEMS_LLMHUB_API_KEY"]) {
54+
return true;
55+
}
56+
return false;
57+
},
58+
};
59+
60+
if (!config.apiKey) {
61+
const { key } = await prompts(
62+
{
63+
type: "text",
64+
name: "key",
65+
message: askModels
66+
? "Please provide your LLMHub API key (or leave blank to use T_SYSTEMS_LLMHUB_API_KEY env variable):"
67+
: "Please provide your LLMHub API key (leave blank to skip):",
68+
validate: (value: string) => {
69+
if (askModels && !value) {
70+
if (process.env.T_SYSTEMS_LLMHUB_API_KEY) {
71+
return true;
72+
}
73+
return "T_SYSTEMS_LLMHUB_API_KEY env variable is not set - key is required";
74+
}
75+
return true;
76+
},
77+
},
78+
questionHandlers,
79+
);
80+
config.apiKey = key || process.env.T_SYSTEMS_LLMHUB_API_KEY;
81+
}
82+
83+
// use default model values in CI or if user should not be asked
84+
const useDefaults = ciInfo.isCI || !askModels;
85+
if (!useDefaults) {
86+
const { model } = await prompts(
87+
{
88+
type: "select",
89+
name: "model",
90+
message: "Which LLM model would you like to use?",
91+
choices: await getAvailableModelChoices(false, config.apiKey),
92+
initial: 0,
93+
},
94+
questionHandlers,
95+
);
96+
config.model = model;
97+
98+
const { embeddingModel } = await prompts(
99+
{
100+
type: "select",
101+
name: "embeddingModel",
102+
message: "Which embedding model would you like to use?",
103+
choices: await getAvailableModelChoices(true, config.apiKey),
104+
initial: 0,
105+
},
106+
questionHandlers,
107+
);
108+
config.embeddingModel = embeddingModel;
109+
config.dimensions = getDimensions(embeddingModel);
110+
}
111+
112+
return config;
113+
}
114+
115+
async function getAvailableModelChoices(
116+
selectEmbedding: boolean,
117+
apiKey?: string,
118+
) {
119+
if (!apiKey) {
120+
throw new Error("Need LLMHub key to retrieve model choices");
121+
}
122+
const isLLMModel = (modelId: string) => {
123+
return LLMHUB_MODELS.includes(modelId);
124+
};
125+
126+
const isEmbeddingModel = (modelId: string) => {
127+
return LLMHUB_EMBEDDING_MODELS.includes(modelId);
128+
};
129+
130+
const spinner = ora("Fetching available models").start();
131+
try {
132+
const response = await got(`${TSYSTEMS_LLMHUB_API_URL}/models`, {
133+
headers: {
134+
Authorization: "Bearer " + apiKey,
135+
},
136+
timeout: 5000,
137+
responseType: "json",
138+
});
139+
const data: any = await response.body;
140+
spinner.stop();
141+
return data.data
142+
.filter((model: any) =>
143+
selectEmbedding ? isEmbeddingModel(model.id) : isLLMModel(model.id),
144+
)
145+
.map((el: any) => {
146+
return {
147+
title: el.id,
148+
value: el.id,
149+
};
150+
});
151+
} catch (error) {
152+
spinner.stop();
153+
if ((error as any).response?.statusCode === 401) {
154+
console.log(
155+
red(
156+
"Invalid LLMHub API key provided! Please provide a valid key and try again!",
157+
),
158+
);
159+
} else {
160+
console.log(red("Request failed: " + error));
161+
}
162+
process.exit(1);
163+
}
164+
}
165+
166+
function getDimensions(modelName: string) {
167+
// Assuming dimensions similar to OpenAI for simplicity. Update if different.
168+
return modelName === "text-embedding-004" ? 768 : 1536;
169+
}

helpers/python.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ const getAdditionalDependencies = (
173173
version: "0.1.6",
174174
});
175175
break;
176+
case "t-systems":
177+
dependencies.push({
178+
name: "llama-index-agent-openai",
179+
version: "0.2.2",
180+
});
181+
dependencies.push({
182+
name: "llama-index-llms-openai-like",
183+
version: "0.1.3",
184+
});
185+
break;
176186
}
177187

178188
return dependencies;

helpers/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ export type ModelProvider =
66
| "groq"
77
| "ollama"
88
| "anthropic"
9-
| "gemini";
9+
| "gemini"
10+
| "t-systems";
1011
export type ModelConfig = {
1112
provider: ModelProvider;
1213
apiKey?: string;

questions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ export const askQuestions = async (
484484
const modelConfig = await askModelConfig({
485485
openAiKey,
486486
askModels: program.askModels ?? false,
487+
framework: program.framework,
487488
});
488489
program.modelConfig = modelConfig;
489490
preferences.modelConfig = modelConfig;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from llama_index.embeddings.openai import OpenAIEmbedding
2+
from llama_index.core.settings import Settings
3+
from typing import Dict
4+
import os
5+
6+
DEFAULT_MODEL = "gpt-3.5-turbo"
7+
DEFAULT_EMBEDDING_MODEL = "text-embedding-3-large"
8+
9+
class TSIEmbedding(OpenAIEmbedding):
10+
def __init__(self, **kwargs):
11+
super().__init__(**kwargs)
12+
self._query_engine = self._text_engine = self.model_name
13+
14+
def llm_config_from_env() -> Dict:
15+
from llama_index.core.constants import DEFAULT_TEMPERATURE
16+
17+
model = os.getenv("MODEL", DEFAULT_MODEL)
18+
temperature = os.getenv("LLM_TEMPERATURE", DEFAULT_TEMPERATURE)
19+
max_tokens = os.getenv("LLM_MAX_TOKENS")
20+
api_key = os.getenv("T_SYSTEMS_LLMHUB_API_KEY")
21+
api_base = os.getenv("T_SYSTEMS_LLMHUB_BASE_URL")
22+
23+
config = {
24+
"model": model,
25+
"api_key": api_key,
26+
"api_base": api_base,
27+
"temperature": float(temperature),
28+
"max_tokens": int(max_tokens) if max_tokens is not None else None,
29+
}
30+
return config
31+
32+
33+
def embedding_config_from_env() -> Dict:
34+
from llama_index.core.constants import DEFAULT_EMBEDDING_DIM
35+
36+
model = os.getenv("EMBEDDING_MODEL", DEFAULT_EMBEDDING_MODEL)
37+
dimension = os.getenv("EMBEDDING_DIM", DEFAULT_EMBEDDING_DIM)
38+
api_key = os.getenv("T_SYSTEMS_LLMHUB_API_KEY")
39+
api_base = os.getenv("T_SYSTEMS_LLMHUB_BASE_URL")
40+
41+
config = {
42+
"model_name": model,
43+
"dimension": int(dimension) if dimension is not None else None,
44+
"api_key": api_key,
45+
"api_base": api_base,
46+
}
47+
return config
48+
49+
def init_llmhub():
50+
from llama_index.llms.openai_like import OpenAILike
51+
52+
llm_configs = llm_config_from_env()
53+
embedding_configs = embedding_config_from_env()
54+
55+
Settings.embed_model = TSIEmbedding(**embedding_configs)
56+
Settings.llm = OpenAILike(
57+
**llm_configs,
58+
is_chat_model=True,
59+
is_function_calling_model=False,
60+
context_window=4096,
61+
)

0 commit comments

Comments
 (0)