add schedule and other parameters

This commit is contained in:
Hongbo Wu
2024-04-17 12:16:15 +08:00
parent 6a4faf6f3c
commit 259b778aba
4 changed files with 53 additions and 14 deletions

View File

@ -4,7 +4,11 @@ import { v4 as uuid } from 'uuid'
import { OpenAI } from '@langchain/openai'
import { PromptTemplate } from '@langchain/core/prompts'
import { LibraryItem } from '../../entity/library_item'
import { htmlToSpeechFile, SpeechFile } from '@omnivore/text-to-speech-handler'
import {
htmlToSpeechFile,
SpeechFile,
SSMLOptions,
} from '@omnivore/text-to-speech-handler'
import axios from 'axios'
import { searchLibraryItems } from '../../services/library_item'
import { redisDataSource } from '../../redis_data_source'
@ -15,8 +19,13 @@ import showdown from 'showdown'
import { Digest, writeDigest } from '../../services/digest'
import { TaskState } from '../../generated/graphql'
export type CreateDigestJobSchedule = 'daily' | 'weekly'
export interface CreateDigestJobData {
userId: string
voices?: string[]
language?: string
rate?: string
}
export interface CreateDigestJobResponse {
@ -312,7 +321,10 @@ const summarizeItems = async (
}
// generate speech files from the summaries
const generateSpeechFiles = (rankedItems: RankedItem[]): SpeechFile[] => {
const generateSpeechFiles = (
rankedItems: RankedItem[],
options: SSMLOptions
): SpeechFile[] => {
// convert the summaries from markdown to HTML
const converter = new showdown.Converter({
backslashEscapesHTMLTags: true,
@ -327,7 +339,7 @@ const generateSpeechFiles = (rankedItems: RankedItem[]): SpeechFile[] => {
</div>`
return htmlToSpeechFile({
content: html,
options: {},
options,
})
})
@ -363,7 +375,11 @@ export const createDigestJob = async (jobData: CreateDigestJobData) => {
const filteredSummaries = filterSummaries(summaries)
const speechFiles = generateSpeechFiles(filteredSummaries)
const speechFiles = generateSpeechFiles(filteredSummaries, {
...jobData,
primaryVoice: jobData.voices?.[0],
secondaryVoice: jobData.voices?.[1],
})
const title = generateTitle(summaries)
const digest: Digest = {
id: uuid(),
@ -372,10 +388,12 @@ export const createDigestJob = async (jobData: CreateDigestJobData) => {
urlsToAudio: [],
jobState: TaskState.Succeeded,
speechFiles,
libraryItems: filteredSummaries.map((item) => ({
chapters: filteredSummaries.map((item, index) => ({
title: item.libraryItem.title,
id: item.libraryItem.id,
url: item.libraryItem.originalUrl,
thumbnail: item.libraryItem.thumbnail ?? undefined,
wordCount: speechFiles[index].wordCount,
})),
createdAt: new Date(),
description: generateDescription(summaries),

View File

@ -1,7 +1,10 @@
import cors from 'cors'
import express from 'express'
import { env } from '../env'
import { CREATE_DIGEST_JOB } from '../jobs/ai/create_digest'
import {
CreateDigestJobSchedule,
CREATE_DIGEST_JOB,
} from '../jobs/ai/create_digest'
import { createJobId, getJob, jobStateToTaskState } from '../queue-processor'
import { getDigest } from '../services/digest'
import { findActiveUser } from '../services/user'
@ -32,6 +35,13 @@ const isFeedback = (data: any): data is Feedback => {
)
}
interface CreateDigestRequest {
voices?: string[]
language?: string
rate?: string
schedule?: CreateDigestJobSchedule
}
export function digestRouter() {
const router = express.Router()
@ -72,10 +82,16 @@ export function digestRouter() {
return res.sendStatus(202)
}
const data = req.body as CreateDigestRequest
// enqueue job and return job id
const result = await enqueueCreateDigest({
userId,
})
const result = await enqueueCreateDigest(
{
userId,
...data,
},
data.schedule
)
// return job id
return res.status(201).send(result)

View File

@ -5,11 +5,9 @@ import { TaskState } from '../generated/graphql'
interface Chapter {
title: string
}
interface LibraryItem {
id: string
url: string
wordCount: number
thumbnail?: string
}
@ -26,7 +24,6 @@ export interface Digest {
urlsToAudio?: string[]
speechFiles?: SpeechFile[]
libraryItems?: LibraryItem[]
}
const digestKey = (userId: string) => `digest:${userId}`

View File

@ -19,6 +19,7 @@ import { AISummarizeJobData, AI_SUMMARIZE_JOB_NAME } from '../jobs/ai-summarize'
import {
CreateDigestJobData,
CreateDigestJobResponse,
CreateDigestJobSchedule,
CREATE_DIGEST_JOB,
} from '../jobs/ai/create_digest'
import { BulkActionData, BULK_ACTION_JOB_NAME } from '../jobs/bulk_action'
@ -859,7 +860,8 @@ export const enqueueSendEmail = async (jobData: SendEmailJobData) => {
}
export const enqueueCreateDigest = async (
data: CreateDigestJobData
data: CreateDigestJobData,
schedule?: CreateDigestJobSchedule
): Promise<CreateDigestJobResponse> => {
const queue = await getBackendQueue()
if (!queue) {
@ -873,6 +875,12 @@ export const enqueueCreateDigest = async (
removeOnFail: true,
attempts: 3,
priority: getJobPriority(CREATE_DIGEST_JOB),
repeat: schedule
? {
immediately: true, // run immediately
pattern: schedule === 'daily' ? '0 0 * * *' : '0 0 * * 7', // every day at midnight or every Sunday at midnight
}
: undefined,
})
logger.info('create digest job enqueued', { jobId: job.id })