refactor(chat): reorganize helper functions and update imports
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { type ChatSendResponse, type UiMessage } from "@/data/dto/chat";
|
||||
import type { ChatLockDetailData } from "@/data/schemas/chat";
|
||||
import { todayString } from "@/utils/date";
|
||||
|
||||
/**
|
||||
* ChatMessage[] -> UiMessage[].
|
||||
* Business fact: `role === "assistant"` means the message is from AI.
|
||||
*/
|
||||
export function localMessagesToUi(
|
||||
records: readonly {
|
||||
id?: string;
|
||||
type?: string;
|
||||
content: string;
|
||||
role: string;
|
||||
createdAt: string;
|
||||
audioUrl?: string | null;
|
||||
image?: { type: string | null; url: string | null };
|
||||
lockDetail?: ChatLockDetailData;
|
||||
}[],
|
||||
): UiMessage[] {
|
||||
return records.map((m) => ({
|
||||
...(m.id ? { id: m.id } : {}),
|
||||
content: getAiMessageDisplayContent({
|
||||
content: m.content,
|
||||
isFromAI: m.role === "assistant",
|
||||
hasImage: Boolean(m.image?.url),
|
||||
}),
|
||||
isFromAI: m.role === "assistant",
|
||||
date: messageDateFromCreatedAt(m.createdAt),
|
||||
...(m.audioUrl && m.lockDetail?.locked !== true
|
||||
? { audioUrl: m.audioUrl }
|
||||
: {}),
|
||||
...deriveUiLockFields(m.lockDetail, m.image?.url),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* ChatSendResponse -> UiMessage.
|
||||
* Business fact: the backend response is the AI reply.
|
||||
*/
|
||||
export function sendResponseToUiMessage(response: ChatSendResponse): UiMessage {
|
||||
return {
|
||||
...(response.messageId ? { id: response.messageId } : {}),
|
||||
content: getAiMessageDisplayContent({
|
||||
content: response.reply,
|
||||
isFromAI: true,
|
||||
hasImage: Boolean(response.image.url),
|
||||
}),
|
||||
isFromAI: true,
|
||||
date: todayString(new Date(response.timestamp)),
|
||||
...(response.audioUrl && !response.lockDetail.locked
|
||||
? { audioUrl: response.audioUrl }
|
||||
: {}),
|
||||
...deriveUiLockFields(response.lockDetail, response.image.url),
|
||||
};
|
||||
}
|
||||
|
||||
function messageDateFromCreatedAt(createdAt: string): string {
|
||||
const parsed = new Date(createdAt);
|
||||
if (Number.isNaN(parsed.getTime())) return todayString();
|
||||
return todayString(parsed);
|
||||
}
|
||||
|
||||
function getAiMessageDisplayContent(input: {
|
||||
content: string;
|
||||
isFromAI: boolean;
|
||||
hasImage?: boolean;
|
||||
}): string {
|
||||
return input.isFromAI && input.hasImage ? "" : input.content;
|
||||
}
|
||||
|
||||
function deriveUiLockFields(
|
||||
lockDetail: ChatLockDetailData | undefined,
|
||||
imageUrl?: string | null,
|
||||
): Partial<UiMessage> {
|
||||
const lockReason = lockDetail?.reason ?? null;
|
||||
const isLocked = lockDetail?.locked === true;
|
||||
const isPrivateMessage = isLocked && lockReason === "private_message";
|
||||
const isLockedImage =
|
||||
isLocked && (lockReason === "image_paywall" || lockReason === "image");
|
||||
return {
|
||||
...(imageUrl ? { imageUrl } : {}),
|
||||
...(imageUrl && isLockedImage ? { imagePaywalled: true } : {}),
|
||||
...(lockDetail ? { locked: lockDetail.locked, lockReason } : {}),
|
||||
...(isPrivateMessage ? { isPrivate: true } : {}),
|
||||
...(isPrivateMessage ? { lockedPrivate: true } : {}),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user