Files
comparaison/src/lib/llm/index.ts

91 lines
2.3 KiB
TypeScript

import type {
ComparisonRequest,
ComparisonResult,
ResearchProgress,
} from "./types";
import { searchItem, type SearchResult } from "./providers/tavily";
import { generateComparisonWithResearch } from "./providers/openai";
import { getActiveProvider } from "./providers";
export type {
ComparisonRequest,
ComparisonResult,
ResearchProgress,
} from "./types";
export async function* runResearch(
request: ComparisonRequest
): AsyncGenerator<ResearchProgress> {
yield { stage: "parsing", message: "Analyzing comparison request..." };
if (!request.items || request.items.length < 2) {
yield {
stage: "error",
error: "At least 2 items are required for comparison",
};
return;
}
const provider = getActiveProvider();
const searchResults: Record<string, SearchResult[]> = {};
if (provider.hasSearch) {
for (let i = 0; i < request.items.length; i++) {
const item = request.items[i];
const results = await searchItem(item, request.query);
searchResults[item] = results;
yield {
stage: "searching",
item,
results: results.length,
};
yield {
stage: "researching",
item,
progress: Math.round(((i + 1) / request.items.length) * 50),
};
}
} else {
for (let i = 0; i < request.items.length; i++) {
yield {
stage: "researching",
item: request.items[i],
progress: Math.round(((i + 0.5) / request.items.length) * 80),
};
}
}
yield {
stage: "synthesizing",
message: `Synthesizing research into structured comparison using ${provider.name}...`,
};
try {
const result = await provider.synthesize(request, searchResults);
yield { stage: "complete", result };
} catch (error) {
yield {
stage: "error",
error:
error instanceof Error ? error.message : "Research failed unexpectedly",
};
}
}
export async function executeResearch(
request: ComparisonRequest
): Promise<ComparisonResult> {
for await (const progress of runResearch(request)) {
if (progress.stage === "complete") {
return progress.result;
}
if (progress.stage === "error") {
throw new Error(progress.error);
}
}
throw new Error("Research completed without producing a result");
}