askexperts
Version:
AskExperts SDK: build and use AI experts - ask them questions and pay with bitcoin on an open protocol
95 lines • 3.7 kB
JavaScript
import { debugExpert, debugError } from "../common/debug.js";
import { OpenaiProxyExpertBase } from "./OpenaiProxyExpertBase.js";
/**
* OpenAI Expert implementation for NIP-174
* Provides direct access to OpenAI models with pricing based on token usage
*/
export class OpenaiProxyExpert extends OpenaiProxyExpertBase {
/**
* Creates a new OpenaiExpert instance
*
* @param options - Configuration options
*/
constructor(options) {
super(options);
/**
* Interval ID for description update checks
*/
this.descriptionCheckInterval = null;
this.modelVendor = this.model.split("/")[0];
this.modelName = (this.model.split("/")?.[1] || this.model).split(/[\s\p{P}]+/u)[0];
this.systemPrompt = options.systemPrompt;
this.server.hashtags = [this.model, this.modelVendor, this.modelName];
this.server.nickname = this.model;
this.server.onAsk = this.onAsk.bind(this);
if (this.systemPrompt)
this.onGetSystemPrompt = () => Promise.resolve(this.systemPrompt);
}
/**
* Starts the expert
*/
async start() {
// Set initial description
this.server.description = await this.getDescription();
// Set up interval to check for description changes
this.descriptionCheckInterval = setInterval(async () => {
const newDescription = await this.getDescription();
// Only update if description has changed
if (newDescription !== this.server.description) {
this.server.description = newDescription;
}
}, 60000); // Check every minute to react to pricing changes
// Start the server
await super.start();
}
/**
* Disposes of resources when the expert is no longer needed
*/
async [Symbol.asyncDispose]() {
// Call the parent's dispose method
await super[Symbol.asyncDispose]();
// Clear the interval when disposing
if (this.descriptionCheckInterval) {
clearInterval(this.descriptionCheckInterval);
this.descriptionCheckInterval = null;
}
}
async getDescription() {
// Get current pricing, it might change over time
const pricing = await this.openai.pricing(this.model);
let description = `I'm an expert providing direct access to LLM model ${this.model}.`;
// Add pricing information if available
if (pricing) {
description += ` Input token price per million: ${pricing.inputPricePPM} sats, output token price per million ${pricing.outputPricePPM} sats.`;
}
description += ` System prompt: ${this.systemPrompt ? "disallowed" : "allowed"}`;
return description;
}
/**
* Handles ask events
*
* @param ask - The ask event
* @returns Promise resolving to a bid if interested, or undefined to ignore
*/
async onAsk(ask) {
try {
const tags = ask.hashtags;
// if (!tags.includes("llm") && !tags.includes("model")) return;
if (!tags.includes(this.model) &&
!tags.includes(this.modelVendor) &&
!tags.includes(this.modelName))
return;
debugExpert(`Received ask: ${ask.id}`);
// Return the bid with our description as the offer
const description = await this.getDescription();
return {
offer: description,
};
}
catch (error) {
debugError("Error handling ask:", error);
return undefined;
}
}
}
//# sourceMappingURL=OpenaiProxyExpert.js.map