- Replace `any` types with proper interfaces (QuestDetailResponse, etc.) - Remove unused imports (createUser, findUserByTelegramId, updatePointContent) - Use `unknown` in catch blocks with instanceof narrowing - Type Express handlers with Request/Response/NextFunction - Add argsIgnorePattern for underscore-prefixed params in ESLint config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
151 lines
3.9 KiB
TypeScript
151 lines
3.9 KiB
TypeScript
import {
|
|
createQuest, createQuestDay, createQuestPoint,
|
|
updateQuestStatus, updateDayStatus,
|
|
getActiveDayForQuest, getPointsForDay,
|
|
} from '../../api/_lib/db.js'
|
|
import { aiService } from './ai.service.js'
|
|
|
|
interface OnboardingData {
|
|
userId: string
|
|
cityId: string
|
|
cityName: string
|
|
days: number
|
|
companions: string
|
|
pace: string
|
|
userComment?: string
|
|
lang: string
|
|
}
|
|
|
|
export async function createQuestFromOnboarding(data: OnboardingData) {
|
|
try {
|
|
// Generate quest plan via AI
|
|
const plan = await aiService.generateQuestPlan({
|
|
city: data.cityName,
|
|
days: data.days,
|
|
companions: data.companions,
|
|
pace: data.pace,
|
|
userComment: data.userComment,
|
|
lang: data.lang,
|
|
})
|
|
|
|
// Create quest in DB
|
|
const quest = await createQuest({
|
|
city_id: data.cityId,
|
|
user_id: data.userId,
|
|
title: plan.title,
|
|
description: plan.description,
|
|
number_of_days: data.days,
|
|
pace: data.pace,
|
|
companions: data.companions,
|
|
user_comment: data.userComment,
|
|
})
|
|
|
|
// Create day skeletons
|
|
const days = []
|
|
for (let i = 0; i < data.days; i++) {
|
|
const day = await createQuestDay({
|
|
quest_id: quest.id,
|
|
day_number: i + 1,
|
|
theme: plan.dayThemes[i] || undefined,
|
|
})
|
|
days.push(day)
|
|
}
|
|
|
|
// Start the quest and first day
|
|
await updateQuestStatus(quest.id, 'in_progress')
|
|
await updateDayStatus(days[0].id, 'in_progress')
|
|
|
|
// Generate first point
|
|
const firstPoint = await aiService.generatePoint({
|
|
city: data.cityName,
|
|
dayNumber: 1,
|
|
totalDays: data.days,
|
|
dayTheme: plan.dayThemes[0] || '',
|
|
pace: data.pace,
|
|
companions: data.companions,
|
|
userComment: data.userComment,
|
|
previousPoints: [],
|
|
lang: data.lang,
|
|
})
|
|
|
|
await createQuestPoint({
|
|
day_id: days[0].id,
|
|
title: firstPoint.title,
|
|
location_lat: firstPoint.locationLat,
|
|
location_lon: firstPoint.locationLon,
|
|
teaser_text: firstPoint.teaserText,
|
|
order_in_day: 1,
|
|
status: 'active',
|
|
})
|
|
|
|
return {
|
|
questId: quest.id,
|
|
title: plan.title,
|
|
description: plan.description,
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to create quest from onboarding:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
export async function generateNextPoint(questId: string, questContext: {
|
|
city: string
|
|
dayNumber: number
|
|
totalDays: number
|
|
dayTheme: string
|
|
pace: string
|
|
companions: string
|
|
userComment?: string
|
|
lang: string
|
|
}) {
|
|
try {
|
|
const day = await getActiveDayForQuest(questId)
|
|
if (!day) return null
|
|
|
|
const existingPoints = await getPointsForDay(day.id)
|
|
const previousPoints = existingPoints.map((p: { title: string }) => p.title)
|
|
const maxOrder = existingPoints.reduce((max: number, p: { order_in_day?: number }) => Math.max(max, p.order_in_day || 0), 0)
|
|
const nextOrder = maxOrder + 1
|
|
|
|
const point = await aiService.generatePoint({
|
|
...questContext,
|
|
previousPoints,
|
|
})
|
|
|
|
const created = await createQuestPoint({
|
|
day_id: day.id,
|
|
title: point.title,
|
|
location_lat: point.locationLat,
|
|
location_lon: point.locationLon,
|
|
teaser_text: point.teaserText,
|
|
order_in_day: nextOrder,
|
|
status: 'active',
|
|
})
|
|
|
|
return { point: created, isLastOfDay: point.isLastPointOfDay }
|
|
} catch (error) {
|
|
console.error('Failed to generate next point:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
export async function generatePointContent(pointId: string, context: {
|
|
city: string
|
|
pointTitle: string
|
|
dayNumber: number
|
|
companions: string
|
|
pace: string
|
|
lang: string
|
|
}) {
|
|
try {
|
|
const content = await aiService.generatePointContent(context)
|
|
const { updatePointContent } = await import('../../api/_lib/db.js')
|
|
await updatePointContent(pointId, content.contentText)
|
|
return content
|
|
} catch (error) {
|
|
console.error('Failed to generate point content:', error)
|
|
return null
|
|
}
|
|
}
|