Skip to content

Commit

Permalink
✨ feat: Add heatmap
Browse files Browse the repository at this point in the history
  • Loading branch information
canisminor1990 authored and arvinxx committed Dec 26, 2024
1 parent 8df6f97 commit bddf790
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 10 deletions.
1 change: 0 additions & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const nextConfig: NextConfig = {
'@icons-pack/react-simple-icons',
'@lobehub/ui',
'gpt-tokenizer',
'chroma-js',
],
webVitalsAttribution: ['CLS', 'LCP'],
},
Expand Down
2 changes: 1 addition & 1 deletion src/app/(main)/profile/stats/Client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const Client = memo<{ mobile?: boolean }>(({ mobile }) => {
</FormGroup>
</Grid>
<FormGroup style={FORM_STYLE.style} title={t('stats.heatmaps.title')} variant={'pure'}>
<Flexbox paddingBlock={16}>
<Flexbox paddingBlock={24}>
<AiHeatmaps />
</Flexbox>
</FormGroup>
Expand Down
40 changes: 39 additions & 1 deletion src/app/(main)/profile/stats/features/AiHeatmaps.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,46 @@
import { Heatmaps } from '@lobehub/charts';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';

import { useClientDataSWR } from '@/libs/swr';
import { messageService } from '@/services/message';

const AiHeatmaps = memo(() => {
return <Heatmaps data={[]} />;
const { t } = useTranslation('auth');
const { data, isLoading } = useClientDataSWR('stats-heatmaps', async () =>
messageService.getHeatmaps(),
);

return (
<Heatmaps
blockSize={14}
data={data || []}
labels={{
legend: {
less: t('heatmaps.legend.less'),
more: t('heatmaps.legend.more'),
},
months: [
t('heatmaps.months.jan'),
t('heatmaps.months.feb'),
t('heatmaps.months.mar'),
t('heatmaps.months.apr'),
t('heatmaps.months.may'),
t('heatmaps.months.jun'),
t('heatmaps.months.jul'),
t('heatmaps.months.aug'),
t('heatmaps.months.sep'),
t('heatmaps.months.oct'),
t('heatmaps.months.nov'),
t('heatmaps.months.dec'),
],
tooltip: t('heatmaps.tooltip'),
totalCount: t('heatmaps.totalCount'),
}}
loading={isLoading}
maxLevel={4}
/>
);
});

export default AiHeatmaps;
2 changes: 1 addition & 1 deletion src/app/(main)/profile/stats/features/AssistantsRank.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const AssistantsRank = memo(() => {
};
}) || []
}
height={420}
height={340}
leftLabel={t('stats.assistantsRank.left')}
loading={isLoading}
onValueChange={(item) => router.push(item.link)}
Expand Down
2 changes: 1 addition & 1 deletion src/app/(main)/profile/stats/features/TopicsRank.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const TopicsRank = memo(() => {
};
}) || []
}
height={420}
height={340}
leftLabel={t('stats.topicsRank.left')}
loading={isLoading}
onValueChange={(item) => router.push(item.link)}
Expand Down
53 changes: 52 additions & 1 deletion src/database/server/models/message.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { count } from 'drizzle-orm';
import type { HeatmapsProps } from '@lobehub/charts';
import dayjs from 'dayjs';
import { count, sql } from 'drizzle-orm';
import { and, asc, desc, eq, inArray, isNull, like } from 'drizzle-orm/expressions';

import { LobeChatDatabase } from '@/database/type';
Expand All @@ -17,6 +19,7 @@ import {
CreateMessageParams,
} from '@/types/message';
import { merge } from '@/utils/merge';
import { today } from '@/utils/time';

import {
MessageItem,
Expand Down Expand Up @@ -299,6 +302,54 @@ export class MessageModel {
return result[0].count;
};

getHeatmaps = async (): Promise<HeatmapsProps['data']> => {
const startDate = today().subtract(1, 'year').startOf('day');
const endDate = today().endOf('day');

const result = await this.db
.select({
count: count(messages.id),
date: sql`DATE(${messages.createdAt})`.as('heatmaps_date'),
})
.from(messages)
.where(
genWhere([
eq(messages.userId, this.userId),
genRangeWhere(
[startDate.format('YYYY-MM-DD'), endDate.add(1, 'day').format('YYYY-MM-DD')],
messages.createdAt,
(date) => date.toDate(),
),
]),
)
.groupBy(sql`heatmaps_date`)
.orderBy(desc(sql`heatmaps_date`));

const heatmapData: HeatmapsProps['data'] = [];
let currentDate = startDate;

while (currentDate.isBefore(endDate) || currentDate.isSame(endDate, 'day')) {
const formattedDate = currentDate.format('YYYY-MM-DD');
const matchingResult = result.find(
(r) => r?.date && dayjs(r.date as string).format('YYYY-MM-DD') === formattedDate,
);

const count = matchingResult ? matchingResult.count : 0;
const levelCount = count > 0 ? Math.floor(count / 5) : 0;
const level = levelCount > 4 ? 4 : levelCount;

heatmapData.push({
count,
date: formattedDate,
level,
});

currentDate = currentDate.add(1, 'day');
}

return heatmapData;
};

hasMoreThanN = async (n: number): Promise<boolean> => {
const result = await this.db
.select({ id: messages.id })
Expand Down
2 changes: 1 addition & 1 deletion src/database/server/models/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export class SessionModel {
.leftJoin(agents, eq(agentsToSessions.agentId, agents.id))
.groupBy(sessions.id, agentsToSessions.agentId, agents.id)
.orderBy(desc(sql`count`))
.limit(10);
.limit(8);
};

hasMoreThanN = async (n: number): Promise<boolean> => {
Expand Down
2 changes: 1 addition & 1 deletion src/database/server/models/topic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export class TopicModel {
.leftJoin(messages, eq(topics.id, messages.topicId))
.groupBy(topics.id)
.orderBy(desc(sql`count`))
.limit(10);
.limit(8);
};

// **************** Create *************** //
Expand Down
24 changes: 23 additions & 1 deletion src/locales/default/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ export default {
desc: '管理您的账户信息。',
title: '账户',
},
heatmaps: {
legend: {
less: '不活跃',
more: '活跃',
},
months: {
apr: '四月',
aug: '八月',
dec: '十二月',
feb: '二月',
jan: '一月',
jul: '七月',
jun: '六月',
mar: '三月',
may: '五月',
nov: '十一月',
oct: '十月',
sep: '九月',
},
tooltip: '{{date}} 当日发送 {{count}} 条消息',
totalCount: '过去一年共发送 {{count}} 条消息',
},
login: '登录',
loginOrSignup: '登录 / 注册',
profile: {
Expand All @@ -24,7 +46,7 @@ export default {
title: '助手使用率',
},
heatmaps: {
title: 'AI 指数',
title: '创作指数',
},
messages: '消息数',
topics: '话题数',
Expand Down
4 changes: 4 additions & 0 deletions src/server/routers/lambda/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export const messageRouter = router({
return ctx.messageModel.queryBySessionId(input.sessionId);
}),

getHeatmaps: messageProcedure.query(async ({ ctx }) => {
return ctx.messageModel.getHeatmaps();
}),

// TODO: 未来这部分方法也需要使用 authedProcedure
getMessages: publicProcedure
.input(
Expand Down
5 changes: 5 additions & 0 deletions src/services/message/_deprecated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export class ClientService implements IMessageService {
return MessageModel.count();
}

// @ts-ignore
async getHeatmaps() {
throw new Error('Method not implemented.');
}

async countTodayMessages() {
const topics = await MessageModel.queryAll();
return topics.filter(
Expand Down
4 changes: 4 additions & 0 deletions src/services/message/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ export class ClientService extends BaseClientService implements IMessageService
return this.messageModel.count(params);
};

getHeatmaps: IMessageService['getHeatmaps'] = async () => {
return this.messageModel.getHeatmaps();
};

getAllMessagesInSession: IMessageService['getAllMessagesInSession'] = async (sessionId) => {
const data = this.messageModel.queryBySessionId(this.toDbSessionId(sessionId));

Expand Down
4 changes: 4 additions & 0 deletions src/services/message/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export class ServerService implements IMessageService {
return lambdaClient.message.count.query(params);
};

getHeatmaps: IMessageService['getHeatmaps'] = async () => {
return lambdaClient.message.getHeatmaps.query();
};

updateMessageError: IMessageService['updateMessageError'] = async (id, error) => {
return lambdaClient.message.update.mutate({ id, value: { error } });
};
Expand Down
4 changes: 3 additions & 1 deletion src/services/message/type.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { HeatmapsProps } from '@lobehub/charts';

import { MessageItem } from '@/database/schemas';
import {
ChatMessage,
Expand All @@ -21,7 +23,7 @@ export interface IMessageService {
range?: [string, string];
startDate?: string;
}): Promise<number>;

getHeatmaps(): Promise<HeatmapsProps['data']>;
updateMessageError(id: string, error: ChatMessageError): Promise<any>;
updateMessage(id: string, message: Partial<MessageItem>): Promise<any>;
updateMessageTTS(id: string, tts: Partial<ChatTTS> | false): Promise<any>;
Expand Down

0 comments on commit bddf790

Please sign in to comment.