mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-03 15:01:00 +02:00
Enforce strict Effect tsgo migrations
This commit is contained in:
parent
64fb23e7d0
commit
f6878d4dd7
49 changed files with 5547 additions and 3250 deletions
|
|
@ -4,11 +4,13 @@
|
|||
* Python reference: trustgraph-flow/trustgraph/embeddings/ollama/processor.py
|
||||
*/
|
||||
|
||||
import { Effect, Layer } from "effect";
|
||||
import { Config, Effect, Layer } from "effect";
|
||||
import * as O from "effect/Option";
|
||||
import * as S from "effect/Schema";
|
||||
import {
|
||||
Embeddings,
|
||||
embeddingsError,
|
||||
EmbeddingsError,
|
||||
errorMessage,
|
||||
makeEmbeddingsService,
|
||||
makeEmbeddingsSpecs,
|
||||
type EmbeddingsServiceShape,
|
||||
|
|
@ -22,18 +24,58 @@ export interface OllamaEmbeddingsConfig extends ProcessorConfig {
|
|||
fetch?: typeof fetch;
|
||||
}
|
||||
|
||||
interface OllamaEmbedResponse {
|
||||
embeddings: number[][];
|
||||
const EmbeddingVector = S.Array(S.Number);
|
||||
|
||||
const OllamaEmbedResponse = S.Struct({
|
||||
embeddings: S.Array(EmbeddingVector),
|
||||
});
|
||||
|
||||
type OllamaEmbedResponse = typeof OllamaEmbedResponse.Type;
|
||||
|
||||
interface ResolvedOllamaEmbeddingsConfig {
|
||||
readonly defaultModel: string;
|
||||
readonly ollamaHost: string;
|
||||
readonly fetchImpl: typeof fetch;
|
||||
}
|
||||
|
||||
const ollamaEmbeddingsError = (operation: string, cause: unknown): EmbeddingsError =>
|
||||
EmbeddingsError.make({
|
||||
operation,
|
||||
message: errorMessage(cause),
|
||||
provider: "ollama",
|
||||
});
|
||||
|
||||
const ollamaEmbeddingsMessageError = (operation: string, message: string): EmbeddingsError =>
|
||||
EmbeddingsError.make({
|
||||
operation,
|
||||
message,
|
||||
provider: "ollama",
|
||||
});
|
||||
|
||||
const optionalStringConfig = Effect.fn("OllamaEmbeddings.optionalStringConfig")(function*(name: string) {
|
||||
return O.getOrUndefined(yield* Config.string(name).pipe(Config.option));
|
||||
});
|
||||
|
||||
const loadOllamaEmbeddingsConfig = Effect.fn("OllamaEmbeddings.loadConfig")(function*(
|
||||
config: OllamaEmbeddingsConfig,
|
||||
) {
|
||||
return {
|
||||
defaultModel: config.model ?? "mxbai-embed-large",
|
||||
ollamaHost:
|
||||
config.ollamaHost ??
|
||||
(yield* optionalStringConfig("OLLAMA_URL")) ??
|
||||
(yield* optionalStringConfig("OLLAMA_HOST")) ??
|
||||
"http://localhost:11434",
|
||||
fetchImpl: config.fetch ?? globalThis.fetch,
|
||||
} satisfies ResolvedOllamaEmbeddingsConfig;
|
||||
});
|
||||
|
||||
export function makeOllamaEmbeddings(config: OllamaEmbeddingsConfig): EmbeddingsServiceShape {
|
||||
const defaultModel = config.model ?? "mxbai-embed-large";
|
||||
const ollamaHost =
|
||||
config.ollamaHost ??
|
||||
process.env.OLLAMA_URL ??
|
||||
process.env.OLLAMA_HOST ??
|
||||
"http://localhost:11434";
|
||||
const fetchImpl = config.fetch ?? globalThis.fetch;
|
||||
const {
|
||||
defaultModel,
|
||||
ollamaHost,
|
||||
fetchImpl,
|
||||
} = Effect.runSync(loadOllamaEmbeddingsConfig(config)) satisfies ResolvedOllamaEmbeddingsConfig;
|
||||
|
||||
return {
|
||||
embed: Effect.fn("OllamaEmbeddings.embed")((texts: ReadonlyArray<string>, model?: string) => {
|
||||
|
|
@ -49,29 +91,38 @@ export function makeOllamaEmbeddings(config: OllamaEmbeddingsConfig): Embeddings
|
|||
model: useModel,
|
||||
input: Array.from(texts),
|
||||
}).pipe(
|
||||
Effect.mapError((error) => embeddingsError("ollama.encode-request", error, "ollama")),
|
||||
Effect.mapError((error) => ollamaEmbeddingsError("ollama.encode-request", error))
|
||||
);
|
||||
|
||||
return yield* Effect.tryPromise({
|
||||
try: async () => {
|
||||
const response = await fetchImpl(url, {
|
||||
const response = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
fetchImpl(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
throw new Error(
|
||||
`Ollama embeddings request failed (${response.status}): ${errorBody}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as OllamaEmbedResponse;
|
||||
return data.embeddings;
|
||||
},
|
||||
catch: (error) => embeddingsError("ollama.embed", error, "ollama"),
|
||||
}),
|
||||
catch: (error) => ollamaEmbeddingsError("ollama.fetch", error),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = yield* Effect.tryPromise({
|
||||
try: () => response.text(),
|
||||
catch: (error) => ollamaEmbeddingsError("ollama.error-body", error),
|
||||
});
|
||||
return yield* ollamaEmbeddingsMessageError(
|
||||
"ollama.embed",
|
||||
`Ollama embeddings request failed (${response.status}): ${errorBody}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = yield* Effect.tryPromise({
|
||||
try: () => response.json() as Promise<unknown>,
|
||||
catch: (error) => ollamaEmbeddingsError("ollama.response-json", error),
|
||||
});
|
||||
const decoded = yield* S.decodeUnknownEffect(OllamaEmbedResponse)(data).pipe(
|
||||
Effect.mapError((error) => ollamaEmbeddingsError("ollama.decode-response", error))
|
||||
);
|
||||
return Array.from(decoded.embeddings, (vector) => Array.from(vector));
|
||||
});
|
||||
}),
|
||||
};
|
||||
|
|
@ -88,9 +139,10 @@ export type OllamaEmbeddingsProcessor = ReturnType<typeof makeOllamaEmbeddingsPr
|
|||
|
||||
export function makeOllamaEmbeddingsProcessor(config: OllamaEmbeddingsConfig) {
|
||||
const embeddings = makeOllamaEmbeddings(config);
|
||||
console.log(
|
||||
`[OllamaEmbeddings] Initialized (host=${config.ollamaHost ?? process.env.OLLAMA_URL ?? process.env.OLLAMA_HOST ?? "http://localhost:11434"}, model=${config.model ?? "mxbai-embed-large"})`,
|
||||
);
|
||||
const resolved = Effect.runSync(loadOllamaEmbeddingsConfig(config)) satisfies ResolvedOllamaEmbeddingsConfig;
|
||||
Effect.runSync(Effect.log(
|
||||
`[OllamaEmbeddings] Initialized (host=${resolved.ollamaHost}, model=${resolved.defaultModel})`,
|
||||
));
|
||||
return makeEmbeddingsService(config, embeddings);
|
||||
}
|
||||
|
||||
|
|
@ -102,6 +154,6 @@ export const program = makeFlowProcessorProgram<OllamaEmbeddingsConfig, never, E
|
|||
layer: (config) => OllamaEmbeddingsLive(config),
|
||||
});
|
||||
|
||||
export async function run(): Promise<void> {
|
||||
await Effect.runPromise(program);
|
||||
export function run(): Promise<void> {
|
||||
return Effect.runPromise(program);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue