@empiricalrun/llm
Advanced tools
Comparing version 0.9.18 to 0.9.19
# @empiricalrun/llm | ||
## 0.9.19 | ||
### Patch Changes | ||
- 2dafa69: feat: added tracing in llm package | ||
## 0.9.18 | ||
@@ -4,0 +10,0 @@ |
import { Langfuse } from "langfuse"; | ||
export declare const isLangfuseEnabled: string | undefined; | ||
export declare const langfuseInstance: Langfuse; | ||
/** | ||
* This is useful when you want to use langfuse only if it is enabled otherwise silently fail. | ||
*/ | ||
export declare function getLangfuseInstanceIfEnabled(): Langfuse | undefined; | ||
/** | ||
* Flush all traces to trace service. | ||
@@ -5,0 +10,0 @@ * This is useful for debugging purposes. |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.flushAllTraces = exports.langfuseInstance = void 0; | ||
exports.flushAllTraces = exports.getLangfuseInstanceIfEnabled = exports.langfuseInstance = exports.isLangfuseEnabled = void 0; | ||
const langfuse_1 = require("langfuse"); | ||
exports.isLangfuseEnabled = process.env.LANGFUSE_SK && process.env.LANGFUSE_PK; | ||
exports.langfuseInstance = new langfuse_1.Langfuse({ | ||
@@ -12,2 +13,9 @@ secretKey: process.env.LANGFUSE_SK, | ||
/** | ||
* This is useful when you want to use langfuse only if it is enabled otherwise silently fail. | ||
*/ | ||
function getLangfuseInstanceIfEnabled() { | ||
return exports.isLangfuseEnabled ? exports.langfuseInstance : undefined; | ||
} | ||
exports.getLangfuseInstanceIfEnabled = getLangfuseInstanceIfEnabled; | ||
/** | ||
* Flush all traces to trace service. | ||
@@ -22,4 +30,4 @@ * This is useful for debugging purposes. | ||
async function flushAllTraces() { | ||
await exports.langfuseInstance.flushAsync(); | ||
await exports.langfuseInstance?.flushAsync(); | ||
} | ||
exports.flushAllTraces = flushAllTraces; |
import { BoundingBox } from "../types"; | ||
export declare function getBoundingBox(base64Image: string, elementDescription: string, options?: { | ||
debug?: true; | ||
telemetry?: { | ||
tags?: string[]; | ||
}; | ||
}): Promise<BoundingBox>; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -5,2 +5,3 @@ "use strict"; | ||
const __1 = require("../.."); | ||
const trace_1 = require("../../trace"); | ||
const image_1 = require("../image"); | ||
@@ -16,3 +17,35 @@ const utils_1 = require("../utils"); | ||
}); | ||
const content = `You are given a screenshot and a description of an element on the screen. You are an expert vision model that can identify bounding box for the element on the screen. Return the output as an array [y_min, x_min, y_max, x_max]. Return only the array and nothing else.\n\nElement description:`; | ||
const langfuseInstance = (0, trace_1.getLangfuseInstanceIfEnabled)(); | ||
if (options?.telemetry?.tags && !langfuseInstance) { | ||
console.warn("Telemetry keys are not set. Telemetry will not be sent."); | ||
} | ||
const session = (0, utils_1.getSessionDetails)(); | ||
const trace = langfuseInstance?.trace({ | ||
name: "vision-bbox", | ||
sessionId: session.id, | ||
release: session.version, | ||
tags: ["vision", "vision-bbox", ...(options?.telemetry?.tags ?? [])], | ||
}); | ||
trace?.update({ | ||
input: { | ||
base64Image, | ||
elementDescription, | ||
}, | ||
}); | ||
const temperature = 0.5; | ||
const model = "gemini-1.5-pro-latest"; | ||
const content = `You are given a screenshot and a description of an element on the screen. You are an expert vision model that can identify bounding box for the element on the screen. Return the output as an array [y_min, x_min, y_max, x_max]. Return only the array and nothing else.\n\nElement description:\n${elementDescription}`; | ||
const generationTrace = trace?.generation({ | ||
name: "get-bounding-box", | ||
model, | ||
modelParameters: { | ||
temperature, | ||
}, | ||
input: { | ||
systemPrompt: content, | ||
userMessages: { | ||
image: base64Image, | ||
}, | ||
}, | ||
}); | ||
const llmResponse = await llm.createChatCompletion({ | ||
@@ -22,3 +55,3 @@ messages: [ | ||
role: "system", | ||
content: `${content}\n${elementDescription}`, | ||
content, | ||
}, | ||
@@ -37,9 +70,17 @@ { | ||
], | ||
model: "gemini-1.5-pro-latest", | ||
model, | ||
modelParameters: { | ||
temperature: 0.5, | ||
temperature, | ||
}, | ||
}); | ||
trace?.update({ | ||
output: llmResponse?.content, | ||
}); | ||
generationTrace?.end({ | ||
output: { | ||
queryResponse: llmResponse?.content, | ||
}, | ||
}); | ||
if (!llmResponse) { | ||
throw new Error("Failed to get bounding box"); | ||
throw new Error(`Failed to get bounding box. Check the trace for more info: ${trace?.getTraceUrl()}`); | ||
} | ||
@@ -49,3 +90,3 @@ const message = llmResponse.content; | ||
if (!arrayAsString) { | ||
throw new Error(`Failed to find array in LLM response: ${message}`); | ||
throw new Error(`Failed to find array in LLM response: ${message}. Check the trace for more info: ${trace?.getTraceUrl()}`); | ||
} | ||
@@ -58,3 +99,3 @@ let bbox; | ||
catch (e) { | ||
throw new Error(`Failed to parse LLM response: ${message}`); | ||
throw new Error(`Failed to parse LLM response: ${message}. Check the trace for more info: ${trace?.getTraceUrl()}`); | ||
} | ||
@@ -61,0 +102,0 @@ if (options.debug) { |
@@ -0,1 +1,2 @@ | ||
import { TraceClient } from "../.."; | ||
import { Coordinates, Point } from "../types"; | ||
@@ -9,5 +10,8 @@ /** | ||
useCache?: boolean; | ||
telemetry?: { | ||
tags?: string[]; | ||
}; | ||
}): Promise<Coordinates>; | ||
export declare function extractTapCoordinateFromString(inputString: string): Point; | ||
export declare function extractTapCoordinateFromString(inputString: string, trace?: TraceClient): Point; | ||
export declare function getLlmResponse(base64Image: string, prompt: string): Promise<string>; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -8,3 +8,5 @@ "use strict"; | ||
const async_retry_1 = __importDefault(require("async-retry")); | ||
const trace_1 = require("../../trace"); | ||
const image_1 = require("../image"); | ||
const utils_1 = require("../utils"); | ||
const cache_1 = require("./cache"); | ||
@@ -28,4 +30,31 @@ const API_BASE_URL = process.env.VISION_MODEL_ENDPOINT; | ||
if (!scaledPoint) { | ||
const langfuseInstance = (0, trace_1.getLangfuseInstanceIfEnabled)(); | ||
if (options?.telemetry?.tags && !langfuseInstance) { | ||
console.warn("Telemetry keys are not set. Telemetry will not be sent."); | ||
} | ||
const session = (0, utils_1.getSessionDetails)(); | ||
const trace = langfuseInstance?.trace({ | ||
name: "vision-point", | ||
sessionId: session.id, | ||
release: session.version, | ||
}); | ||
trace?.update({ | ||
tags: ["vision", "vision-point", ...(options?.telemetry?.tags ?? [])], | ||
input: { | ||
base64Image, | ||
prompt, | ||
}, | ||
}); | ||
const generationTrace = trace?.generation({ | ||
name: "get-coordinates-for", | ||
model: "Molmo-7B-D-0924", | ||
input: { | ||
userMessages: { | ||
prompt, | ||
image: base64Image, | ||
}, | ||
}, | ||
}); | ||
const llmResponse = await getLlmResponse(base64Image, prompt); | ||
const pointFromLlm = extractTapCoordinateFromString(llmResponse); | ||
const pointFromLlm = extractTapCoordinateFromString(llmResponse, trace); | ||
scaledPoint = scaleForImage(pointFromLlm, base64Image); | ||
@@ -35,2 +64,8 @@ if (options?.useCache) { | ||
} | ||
trace?.update({ | ||
output: scaledPoint, | ||
}); | ||
generationTrace?.end({ | ||
output: scaledPoint, | ||
}); | ||
} | ||
@@ -64,3 +99,3 @@ const annotatedImage = await (0, image_1.drawRedDotAtPoint)(base64Image, scaledPoint); | ||
} | ||
function extractTapCoordinateFromString(inputString) { | ||
function extractTapCoordinateFromString(inputString, trace) { | ||
inputString = inputString.trim(); | ||
@@ -86,3 +121,3 @@ if (inputString.startsWith('"') && inputString.endsWith('"')) { | ||
} | ||
throw new Error(`No valid coordinates found in the input string: ${inputString}`); | ||
throw new Error(`No valid coordinates found in the input string: ${inputString}. ${trace ? `Check the trace for more info: ${trace.getTraceUrl()}` : ""}`); | ||
} | ||
@@ -89,0 +124,0 @@ exports.extractTapCoordinateFromString = extractTapCoordinateFromString; |
@@ -7,4 +7,7 @@ import { z, ZodType } from "zod"; | ||
model?: LLMModel; | ||
telemetry?: { | ||
tags?: string[]; | ||
}; | ||
}): Promise<ExtractType<T>>; | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -6,3 +9,5 @@ exports.query = void 0; | ||
const zod_2 = require("zod"); | ||
const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema")); | ||
const __1 = require("../.."); | ||
const trace_1 = require("../../trace"); | ||
const utils_1 = require("../utils"); | ||
@@ -13,3 +18,8 @@ async function query(base64Image, instruction, options = { | ||
}) { | ||
const { responseFormat = zod_2.z.string(), model = "gpt-4o-mini" } = options; | ||
const mergedOptions = { | ||
responseFormat: zod_2.z.string(), | ||
model: "gpt-4o-mini", | ||
...options, | ||
}; | ||
const { responseFormat, model } = mergedOptions; | ||
const llm = new __1.LLM({ | ||
@@ -35,2 +45,39 @@ provider: "openai", | ||
} | ||
const session = (0, utils_1.getSessionDetails)(); | ||
const langfuseInstance = (0, trace_1.getLangfuseInstanceIfEnabled)(); | ||
if (mergedOptions.telemetry?.tags && !langfuseInstance) { | ||
console.warn("Telemetry keys are not set. Telemetry will not be sent."); | ||
} | ||
const trace = langfuseInstance?.trace({ | ||
name: "vision-query", | ||
sessionId: session.id, | ||
release: session.version, | ||
tags: ["vision", "vision-query", ...(mergedOptions?.telemetry?.tags || [])], | ||
}); | ||
const temperature = 0.5; | ||
const generationTrace = trace?.generation({ | ||
name: "query", | ||
model, | ||
modelParameters: { | ||
temperature, | ||
}, | ||
input: { | ||
responseFormat: (0, zod_to_json_schema_1.default)(extendedResponseFormat, "responseFormat"), | ||
systemPrompt, | ||
userMessages: { | ||
instruction, | ||
image: base64Image, | ||
}, | ||
}, | ||
}); | ||
trace?.update({ | ||
input: { | ||
base64Image, | ||
instruction, | ||
options: { | ||
responseFormat: (0, zod_to_json_schema_1.default)(extendedResponseFormat, "responseFormat"), | ||
model, | ||
}, | ||
}, | ||
}); | ||
const llmResponse = await llm.createChatCompletion({ | ||
@@ -60,3 +107,3 @@ messages: [ | ||
modelParameters: { | ||
temperature: 0.5, | ||
temperature: temperature, | ||
}, | ||
@@ -66,8 +113,19 @@ responseFormat: (0, zod_1.zodResponseFormat)(extendedResponseFormat, "your_response"), | ||
if (!llmResponse || !llmResponse.content) { | ||
throw new Error("Query failed: no response content from LLM"); | ||
throw new Error(`Query failed: no response content from LLM. Check the trace for more info: ${trace?.getTraceUrl()}`); | ||
} | ||
const response = llmResponse.content; | ||
const jsonData = JSON.parse(response); | ||
trace?.update({ | ||
output: jsonData, | ||
}); | ||
generationTrace?.end({ | ||
output: jsonData, | ||
usage: { | ||
input: llm.promptTokens, | ||
output: llm.completionTokens, | ||
unit: "TOKENS", | ||
}, | ||
}); | ||
return responseFormat.parse(jsonData.answer); | ||
} | ||
exports.query = query; |
import { LLMProvider } from ".."; | ||
export declare function imageFormatForProvider(provider: LLMProvider, image: string): string; | ||
export declare const getSessionDetails: () => { | ||
id: `${string}-${string}-${string}-${string}-${string}`; | ||
version: string; | ||
}; | ||
//# sourceMappingURL=utils.d.ts.map |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.imageFormatForProvider = void 0; | ||
exports.getSessionDetails = exports.imageFormatForProvider = void 0; | ||
const package_json_1 = __importDefault(require("../../package.json")); | ||
function imageFormatForProvider(provider, image) { | ||
@@ -14,1 +18,9 @@ let base64Image = image; | ||
exports.imageFormatForProvider = imageFormatForProvider; | ||
const getSessionDetails = () => { | ||
const sessionId = crypto.randomUUID(); | ||
return { | ||
id: sessionId, | ||
version: package_json_1.default.version, | ||
}; | ||
}; | ||
exports.getSessionDetails = getSessionDetails; |
{ | ||
"name": "@empiricalrun/llm", | ||
"version": "0.9.18", | ||
"version": "0.9.19", | ||
"main": "dist/index.js", | ||
@@ -39,3 +39,4 @@ "exports": { | ||
"sharp": "^0.33.5", | ||
"zod": "^3.23.8" | ||
"zod": "^3.23.8", | ||
"zod-to-json-schema": "^3.23.5" | ||
}, | ||
@@ -42,0 +43,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
48759
913
8
9
+ Addedzod-to-json-schema@^3.23.5
+ Addedzod-to-json-schema@3.24.1(transitive)