Spaces:
Sleeping
Sleeping
| import { config } from "$lib/server/config"; | |
| import { generateFromDefaultEndpoint } from "$lib/server/generateFromDefaultEndpoint"; | |
| import { logger } from "$lib/server/logger"; | |
| import { MessageUpdateType, type MessageUpdate } from "$lib/types/MessageUpdate"; | |
| import type { Conversation } from "$lib/types/Conversation"; | |
| import { getReturnFromGenerator } from "$lib/utils/getReturnFromGenerator"; | |
| import { stripThinkBlocks } from "$lib/utils/stripThinkBlocks"; | |
| export async function* generateTitleForConversation( | |
| conv: Conversation, | |
| opts?: { apiKey?: string } | |
| ): AsyncGenerator<MessageUpdate, undefined, undefined> { | |
| try { | |
| const userMessage = conv.messages.find((m) => m.from === "user"); | |
| // HACK: detect if the conversation is new | |
| if (conv.title !== "New Chat" || !userMessage) return; | |
| const prompt = userMessage.content; | |
| const modelForTitle = config.TASK_MODEL?.trim() ? config.TASK_MODEL : conv.model; | |
| const title = | |
| (await generateTitle(prompt, modelForTitle, { apiKey: opts?.apiKey })) ?? "New Chat"; | |
| yield { | |
| type: MessageUpdateType.Title, | |
| title: stripThinkBlocks(title).trim() || "New Chat", | |
| }; | |
| } catch (cause) { | |
| logger.error(Error("Failed whilte generating title for conversation", { cause })); | |
| } | |
| } | |
| export async function generateTitle(prompt: string, modelId?: string, opts?: { apiKey?: string }) { | |
| if (config.LLM_SUMMARIZATION !== "true") { | |
| // When summarization is disabled, use the first five words without adding emojis | |
| const firstFive = prompt.split(/\s+/g).slice(0, 5).join(" "); | |
| const stripped = stripThinkBlocks(firstFive).trim(); | |
| return stripped || firstFive; | |
| } | |
| // Tools removed: no tool-based title path | |
| return await getReturnFromGenerator( | |
| generateFromDefaultEndpoint({ | |
| messages: [{ from: "user", content: `Prompt to craft the title from: "${prompt}"` }], | |
| preprompt: `You are a titling assistant. | |
| Create a natural, concise title (max 4 words) that reflects the user's request. | |
| Use the same language as the user. | |
| Never answer the request. | |
| NEVER respond with the words “summary,” “summarize,” “prompt,” or any synonyms in the title. | |
| No quotes, emojis, hashtags, or trailing punctuation. | |
| Return only the title text.`, | |
| generateSettings: { | |
| max_tokens: 30, | |
| }, | |
| modelId, | |
| apiKey: opts?.apiKey, | |
| }) | |
| ) | |
| .then((summary) => { | |
| const firstFive = prompt.split(/\s+/g).slice(0, 5).join(" "); | |
| const trimmed = stripThinkBlocks(String(summary ?? "")).trim(); | |
| // Fallback: if empty, return first five words only (no emoji) | |
| return trimmed || stripThinkBlocks(firstFive).trim() || firstFive; | |
| }) | |
| .catch((e) => { | |
| logger.error(e); | |
| const firstFive = prompt.split(/\s+/g).slice(0, 5).join(" "); | |
| return stripThinkBlocks(firstFive).trim() || firstFive; | |
| }); | |
| } | |