91 lines
2.3 KiB
TypeScript
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");
|
|
}
|