mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Pre-fetch realistic voice only if user is opted in
This commit is contained in:
parent
f3e5076a29
commit
b0938ee96c
5 changed files with 49 additions and 10 deletions
|
|
@ -40,7 +40,7 @@ export const optInFeatureResolver = authorized<
|
|||
}
|
||||
}
|
||||
|
||||
const token = signFeatureToken(optIn)
|
||||
const token = signFeatureToken(optIn, claims.uid)
|
||||
|
||||
return {
|
||||
feature: {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { enqueueTextToSpeech } from '../utils/createTask'
|
|||
import { htmlToSpeechFile } from '@omnivore/text-to-speech-handler'
|
||||
import { UserPersonalization } from '../entity/user_personalization'
|
||||
import { ArticleSavingRequestStatus } from '../elastic/types'
|
||||
import { FeatureName, getFeature } from '../services/features'
|
||||
|
||||
const logger = buildLogger('app.dispatch')
|
||||
|
||||
|
|
@ -80,6 +81,11 @@ export function textToSpeechRouter() {
|
|||
},
|
||||
})
|
||||
|
||||
const feature = await getFeature(
|
||||
FeatureName.UltraRealisticVoice,
|
||||
userId
|
||||
)
|
||||
|
||||
for (const utterance of speechFile.utterances) {
|
||||
// enqueue a task to convert text to speech
|
||||
const taskName = await enqueueTextToSpeech({
|
||||
|
|
@ -91,6 +97,8 @@ export function textToSpeechRouter() {
|
|||
isUltraRealisticVoice: true,
|
||||
language: speechFile.language,
|
||||
rate: userPersonalization?.speechRate || '1.1',
|
||||
featureName: feature?.name,
|
||||
grantedAt: feature?.grantedAt,
|
||||
})
|
||||
logger.info('Start Text to speech task', { taskName })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import * as jwt from 'jsonwebtoken'
|
|||
import { env } from '../env'
|
||||
import { IsNull, Not } from 'typeorm'
|
||||
|
||||
enum FeatureName {
|
||||
export enum FeatureName {
|
||||
UltraRealisticVoice = 'ultra-realistic-voice',
|
||||
}
|
||||
|
||||
|
|
@ -56,10 +56,16 @@ const optInUltraRealisticVoice = async (uid: string): Promise<Feature> => {
|
|||
})
|
||||
}
|
||||
|
||||
export const signFeatureToken = (feature: Feature): string => {
|
||||
export const signFeatureToken = (
|
||||
feature: {
|
||||
name?: string
|
||||
grantedAt?: Date | null
|
||||
},
|
||||
userId: string
|
||||
): string => {
|
||||
return jwt.sign(
|
||||
{
|
||||
uid: feature.user.id,
|
||||
uid: userId,
|
||||
featureName: feature.name,
|
||||
grantedAt: feature.grantedAt ? feature.grantedAt.getTime() / 1000 : null,
|
||||
},
|
||||
|
|
@ -67,3 +73,26 @@ export const signFeatureToken = (feature: Feature): string => {
|
|||
{ expiresIn: '1y' }
|
||||
)
|
||||
}
|
||||
|
||||
export const isOptedIn = async (
|
||||
name: FeatureName,
|
||||
uid: string
|
||||
): Promise<boolean> => {
|
||||
const feature = await getRepository(Feature).findOneBy({
|
||||
user: { id: uid },
|
||||
name,
|
||||
grantedAt: Not(IsNull()),
|
||||
})
|
||||
|
||||
return !!feature
|
||||
}
|
||||
|
||||
export const getFeature = async (
|
||||
name: FeatureName,
|
||||
uid: string
|
||||
): Promise<Feature | null> => {
|
||||
return getRepository(Feature).findOneBy({
|
||||
user: { id: uid },
|
||||
name,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { searchPages } from '../elastic/pages'
|
||||
import { Page, PageType } from '../elastic/types'
|
||||
import { SortBy, SortOrder } from '../utils/search'
|
||||
import { FeatureName, isOptedIn } from './features'
|
||||
|
||||
/*
|
||||
* We should not synthesize the page when:
|
||||
|
|
@ -16,7 +17,7 @@ export const shouldSynthesize = async (
|
|||
return false
|
||||
}
|
||||
|
||||
if (process.env.TEXT_TO_SPEECH_BETA_TEST) {
|
||||
if (await isOptedIn(FeatureName.UltraRealisticVoice, userId)) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { google } from '@google-cloud/tasks/build/protos/protos'
|
|||
import { IntegrationType } from '../entity/integration'
|
||||
import { promisify } from 'util'
|
||||
import * as jwt from 'jsonwebtoken'
|
||||
import { signFeatureToken } from '../services/features'
|
||||
import View = google.cloud.tasks.v2.Task.View
|
||||
|
||||
const logger = buildLogger('app.dispatch')
|
||||
|
|
@ -347,6 +348,8 @@ export const enqueueTextToSpeech = async ({
|
|||
isUltraRealisticVoice = false,
|
||||
language,
|
||||
rate,
|
||||
featureName,
|
||||
grantedAt,
|
||||
}: {
|
||||
userId: string
|
||||
speechId: string
|
||||
|
|
@ -360,6 +363,8 @@ export const enqueueTextToSpeech = async ({
|
|||
isUltraRealisticVoice?: boolean
|
||||
language?: string
|
||||
rate?: string
|
||||
featureName?: string
|
||||
grantedAt?: Date | null
|
||||
}): Promise<string> => {
|
||||
const { GOOGLE_CLOUD_PROJECT } = process.env
|
||||
const payload = {
|
||||
|
|
@ -372,11 +377,7 @@ export const enqueueTextToSpeech = async ({
|
|||
language,
|
||||
rate,
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const token = await signToken({ uid: userId }, env.server.jwtSecret, {
|
||||
expiresIn: '1h',
|
||||
})
|
||||
const token = signFeatureToken({ name: featureName, grantedAt }, userId)
|
||||
const taskHandlerUrl = `${env.queue.textToSpeechTaskHandlerUrl}?token=${token}`
|
||||
// If there is no Google Cloud Project Id exposed, it means that we are in local environment
|
||||
if (env.dev.isLocal || !GOOGLE_CLOUD_PROJECT) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue