feat: whyrating - initial project from turbostarter boilerplate
This commit is contained in:
100
packages/ai/src/modules/chat/utils.ts
Normal file
100
packages/ai/src/modules/chat/utils.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
import { generateObject } from "ai";
|
||||
import * as z from "zod";
|
||||
|
||||
import { Credits } from "../credits/utils";
|
||||
|
||||
import { MODELS, PROMPTS } from "./constants";
|
||||
|
||||
import type {
|
||||
ChatMessagePartPayload,
|
||||
ChatMessageOptionsPayload,
|
||||
} from "./schema";
|
||||
import type { Message, Part, ChatMessage, ChatMessagePart } from "./types";
|
||||
import type { AnthropicProviderOptions } from "@ai-sdk/anthropic";
|
||||
import type { OpenAIResponsesProviderOptions } from "@ai-sdk/openai";
|
||||
import type { XaiProviderOptions } from "@ai-sdk/xai";
|
||||
|
||||
export const generateChatName = async (content: string) => {
|
||||
const { object } = await generateObject({
|
||||
model: openai.responses("gpt-4.1-mini"),
|
||||
schema: z.object({
|
||||
name: z.string().min(1),
|
||||
}),
|
||||
system: PROMPTS.CHAT_NAME,
|
||||
prompt: `User message: ${content}`,
|
||||
});
|
||||
|
||||
return object.name;
|
||||
};
|
||||
|
||||
export const getProviderOptions = (options: ChatMessageOptionsPayload) => {
|
||||
const model = MODELS.find((model) => model.id === options.model);
|
||||
const reasoning = !!model?.reason && !!options.reason;
|
||||
|
||||
return {
|
||||
anthropic: {
|
||||
thinking: {
|
||||
type: reasoning ? "enabled" : "disabled",
|
||||
budgetTokens: 1200,
|
||||
},
|
||||
} satisfies AnthropicProviderOptions,
|
||||
openai: {
|
||||
...(reasoning
|
||||
? { reasoningEffort: "medium", reasoningSummary: "detailed" }
|
||||
: {}),
|
||||
textVerbosity: "medium",
|
||||
} satisfies OpenAIResponsesProviderOptions,
|
||||
xai: {
|
||||
...(reasoning ? { reasoningEffort: "low" } : {}),
|
||||
} satisfies XaiProviderOptions,
|
||||
};
|
||||
};
|
||||
|
||||
export const getCreditsDeduction = (
|
||||
options: ChatMessageOptionsPayload,
|
||||
parts?: ChatMessagePartPayload[],
|
||||
) => {
|
||||
const model = MODELS.find((model) => model.id === options.model);
|
||||
|
||||
const searchDeduction = options.search
|
||||
? Credits.COST.DEFAULT
|
||||
: Credits.COST.FREE;
|
||||
const reasoningDeduction =
|
||||
options.reason && model?.reason ? Credits.COST.DEFAULT : Credits.COST.FREE;
|
||||
|
||||
const attachments = parts?.filter((part) => part.type === "file");
|
||||
const attachmentDeduction = (attachments?.length ?? 0) * Credits.COST.DEFAULT;
|
||||
|
||||
return (
|
||||
Credits.COST.DEFAULT +
|
||||
searchDeduction +
|
||||
reasoningDeduction +
|
||||
attachmentDeduction
|
||||
);
|
||||
};
|
||||
|
||||
export const toChatMessagePart = ({
|
||||
type,
|
||||
details,
|
||||
}: Part): ChatMessagePart | null => {
|
||||
if (typeof details !== "object" || details === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type,
|
||||
...details,
|
||||
} as ChatMessagePart;
|
||||
};
|
||||
|
||||
export const toChatMessage = (
|
||||
message: Message & {
|
||||
parts?: Part[];
|
||||
},
|
||||
): ChatMessage => {
|
||||
return {
|
||||
...message,
|
||||
parts: message.parts?.map(toChatMessagePart).filter(Boolean) ?? [],
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user