- 添加formatBeijingTime函数,将所有时间显示转换为北京时间(UTC+8) - 更新相册、管理后台、精选页面的时间显示 - 图像拓展功能改为直接发送图片URL而不是base64 - 优化API性能,减少数据传输量
154 lines
4.1 KiB
TypeScript
154 lines
4.1 KiB
TypeScript
import type {
|
||
CoreAssistantMessage,
|
||
CoreToolMessage,
|
||
UIMessage,
|
||
UIMessagePart,
|
||
} from 'ai';
|
||
import { type ClassValue, clsx } from 'clsx';
|
||
import { formatISO } from 'date-fns';
|
||
import { twMerge } from 'tailwind-merge';
|
||
import type { DBMessage, Document } from '@/lib/db/schema';
|
||
import { ChatSDKError, type ErrorCode } from './errors';
|
||
import type { ChatMessage, ChatTools, CustomUIDataTypes } from './types';
|
||
|
||
export function cn(...inputs: ClassValue[]) {
|
||
return twMerge(clsx(inputs));
|
||
}
|
||
|
||
export const fetcher = async (url: string) => {
|
||
const response = await fetch(url);
|
||
|
||
if (!response.ok) {
|
||
const { code, cause } = await response.json();
|
||
throw new ChatSDKError(code as ErrorCode, cause);
|
||
}
|
||
|
||
return response.json();
|
||
};
|
||
|
||
export async function fetchWithErrorHandlers(
|
||
input: RequestInfo | URL,
|
||
init?: RequestInit,
|
||
) {
|
||
try {
|
||
const response = await fetch(input, init);
|
||
|
||
if (!response.ok) {
|
||
const { code, cause } = await response.json();
|
||
throw new ChatSDKError(code as ErrorCode, cause);
|
||
}
|
||
|
||
return response;
|
||
} catch (error: unknown) {
|
||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||
throw new ChatSDKError('offline:chat');
|
||
}
|
||
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
export function getLocalStorage(key: string) {
|
||
if (typeof window !== 'undefined') {
|
||
return JSON.parse(localStorage.getItem(key) || '[]');
|
||
}
|
||
return [];
|
||
}
|
||
|
||
export function generateUUID(): string {
|
||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||
const r = (Math.random() * 16) | 0;
|
||
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
||
return v.toString(16);
|
||
});
|
||
}
|
||
|
||
type ResponseMessageWithoutId = CoreToolMessage | CoreAssistantMessage;
|
||
type ResponseMessage = ResponseMessageWithoutId & { id: string };
|
||
|
||
export function getMostRecentUserMessage(messages: UIMessage[]) {
|
||
const userMessages = messages.filter((message) => message.role === 'user');
|
||
return userMessages.at(-1);
|
||
}
|
||
|
||
export function getDocumentTimestampByIndex(
|
||
documents: Document[],
|
||
index: number,
|
||
) {
|
||
if (!documents) { return new Date(); }
|
||
if (index > documents.length) { return new Date(); }
|
||
|
||
return documents[index].createdAt;
|
||
}
|
||
|
||
export function getTrailingMessageId({
|
||
messages,
|
||
}: {
|
||
messages: ResponseMessage[];
|
||
}): string | null {
|
||
const trailingMessage = messages.at(-1);
|
||
|
||
if (!trailingMessage) { return null; }
|
||
|
||
return trailingMessage.id;
|
||
}
|
||
|
||
export function sanitizeText(text: string) {
|
||
return text.replace('<has_function_call>', '');
|
||
}
|
||
|
||
export function convertToUIMessages(messages: DBMessage[]): ChatMessage[] {
|
||
return messages.map((message) => ({
|
||
id: message.id,
|
||
role: message.role as 'user' | 'assistant' | 'system',
|
||
parts: message.parts as UIMessagePart<CustomUIDataTypes, ChatTools>[],
|
||
metadata: {
|
||
createdAt: formatISO(message.createdAt),
|
||
},
|
||
}));
|
||
}
|
||
|
||
export function getTextFromMessage(message: ChatMessage | UIMessage): string {
|
||
return message.parts
|
||
.filter((part) => part.type === 'text')
|
||
.map((part) => (part as { type: 'text'; text: string}).text)
|
||
.join('');
|
||
}
|
||
|
||
/**
|
||
* 将UTC时间转换为北京时间(UTC+8)
|
||
* @param date - Date对象或时间字符串
|
||
* @returns 北京时间对应的Date对象
|
||
*/
|
||
export function toBeijingTime(date: Date | string): Date {
|
||
const d = typeof date === "string" ? new Date(date) : date;
|
||
// 获取UTC时间戳
|
||
const utcTime = d.getTime() + (d.getTimezoneOffset() * 60 * 1000);
|
||
// 转换为北京时间(UTC+8)
|
||
const beijingTime = new Date(utcTime + (8 * 60 * 60 * 1000));
|
||
return beijingTime;
|
||
}
|
||
|
||
/**
|
||
* 格式化时间为北京时间字符串
|
||
* @param date - Date对象或时间字符串
|
||
* @param options - Intl.DateTimeFormatOptions 格式化选项
|
||
* @returns 格式化后的北京时间字符串
|
||
*/
|
||
export function formatBeijingTime(
|
||
date: Date | string,
|
||
options?: Intl.DateTimeFormatOptions
|
||
): string {
|
||
const beijingTime = toBeijingTime(date);
|
||
const defaultOptions: Intl.DateTimeFormatOptions = {
|
||
year: "numeric",
|
||
month: "numeric",
|
||
day: "numeric",
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
timeZone: "Asia/Shanghai",
|
||
...options,
|
||
};
|
||
return beijingTime.toLocaleString("zh-CN", defaultOptions);
|
||
}
|