Skip to content

Commit 1867eab

Browse files
authored
feat: weekly report (#177)
* feat: weekly report * fix: timeout
1 parent 42ed5b4 commit 1867eab

6 files changed

Lines changed: 105 additions & 2 deletions

File tree

apps/web-app/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ NUXT_AI_MODEL=
2424
NUXT_AI_MODEL_PRO=
2525
NUXT_AI_SERVICE_TOKEN=
2626
NUXT_AI_DAILY_REPORT_PROMPT=
27+
NUXT_AI_WEEKLY_REPORT_PROMPT=
2728

2829
# Telegram
2930
NUXT_TELEGRAM_LOCAL_BOT_API_SERVER_URL=

apps/web-app/nuxt.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default defineNuxtConfig({
1919
apiKey: '',
2020
serviceToken: '',
2121
dailyReportPrompt: '',
22+
weeklyReportPrompt: '',
2223
},
2324
telegram: {
2425
localBotApiServerUrl: '',
@@ -81,6 +82,7 @@ export default defineNuxtConfig({
8182
'0 * * * *': ['kitchen:revenue-update'], // Every hour
8283
'0 0 * * *': ['kitchen:rating-update'], // Every day
8384
'0 17 * * 1-5': ['ai:daily-report'], // Mon-Fri 17:00
85+
'30 17 * * 5': ['ai:weekly-report'], // Friday 17:30
8486
},
8587
},
8688
tiptap: {

apps/web-app/server/tasks/ai/daily-report.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const logger = useLogger('task:ai:daily-report')
99
export default defineTask({
1010
meta: {
1111
name: 'ai:daily-report',
12-
description: 'Prepare and post daily report to Telegram group',
12+
description: 'Prepare and post daily report',
1313
},
1414
async run() {
1515
if (process.env.NODE_ENV !== 'production') {
@@ -31,6 +31,8 @@ export default defineTask({
3131
const client = new OpenAI({
3232
apiKey: ai.apiKey,
3333
baseURL: ai.baseUrl,
34+
timeout: 120000,
35+
maxRetries: 2,
3436
})
3537

3638
const response = await client.chat.completions.create({
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import process from 'node:process'
2+
import { repository } from '@roll-stack/database'
3+
import { format } from 'date-fns'
4+
import { ru } from 'date-fns/locale/ru'
5+
import OpenAI from 'openai'
6+
7+
const logger = useLogger('task:ai:weekly-report')
8+
9+
export default defineTask({
10+
meta: {
11+
name: 'ai:weekly-report',
12+
description: 'Prepare and post weekly report',
13+
},
14+
async run() {
15+
if (process.env.NODE_ENV !== 'production') {
16+
logger.info('Skipping task in non-production environment')
17+
return { result: true }
18+
}
19+
20+
try {
21+
const { ai } = useRuntimeConfig()
22+
23+
const tasks = await repository.task.listCompletedThisWeek()
24+
const staff = await repository.user.findStaff()
25+
26+
function preparePerformer(performerId: string | null) {
27+
const user = staff.find((user) => user.id === performerId)
28+
if (!user) {
29+
return null
30+
}
31+
32+
return {
33+
name: user?.name,
34+
surname: user?.surname,
35+
caption: user?.caption,
36+
completedTasksCount: tasks.filter((task) => task.performerId === user?.id).length,
37+
}
38+
}
39+
40+
const preparedTasks = tasks.map((task) => {
41+
const performer = preparePerformer(task.performerId)
42+
43+
return {
44+
completedAt: task.completedAt,
45+
name: task.name,
46+
description: task.description,
47+
report: task.report,
48+
performer,
49+
}
50+
})
51+
52+
const client = new OpenAI({
53+
apiKey: ai.apiKey,
54+
baseURL: ai.baseUrl,
55+
timeout: 120000,
56+
maxRetries: 2,
57+
})
58+
59+
const response = await client.chat.completions.create({
60+
model: ai.modelPro,
61+
messages: [
62+
{
63+
role: 'system',
64+
content: ai.weeklyReportPrompt,
65+
},
66+
{
67+
role: 'user',
68+
content: JSON.stringify(preparedTasks),
69+
},
70+
],
71+
})
72+
73+
const finalMessage = response.choices[0].message.content
74+
if (!finalMessage) {
75+
return { result: true }
76+
}
77+
78+
// Flow item
79+
const week = format(new Date(), 'w', { locale: ru })
80+
await repository.flow.createItem({
81+
type: 'weekly_task_report',
82+
title: `Задачи за неделю ${week}`,
83+
description: finalMessage,
84+
})
85+
} catch (error) {
86+
errorResolver(error)
87+
}
88+
89+
return { result: true }
90+
},
91+
})

packages/database/src/repository/task.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ export class Task {
7474
})
7575
}
7676

77+
static async listCompletedThisWeek() {
78+
return useDatabase().query.tasks.findMany({
79+
where: (tasks, { gte }) => gte(tasks.completedAt, sql`now() - interval '6 day'`),
80+
orderBy: (tasks, { desc }) => desc(tasks.updatedAt),
81+
})
82+
}
83+
7784
static async autoCreatorsList() {
7885
return useDatabase().query.taskAutoCreators.findMany()
7986
}

packages/database/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export type TimeZone = '+00:00'
3636
| '+11:00'
3737
| '+12:00'
3838

39-
export type FlowItemType = 'daily_task_report'
39+
export type FlowItemType = 'daily_task_report' | 'weekly_task_report'
4040

4141
export type Permission = InferSelectModel<typeof tables.permissions>
4242
export type PermissionDraft = InferInsertModel<typeof tables.permissions>

0 commit comments

Comments
 (0)