dates
This commit is contained in:
@@ -6,6 +6,7 @@ import { z } from 'zod'
|
||||
import { generateSearchQueries, getDefaultPlatforms } from '@/lib/query-generator'
|
||||
import { executeSearches, scoreOpportunities } from '@/lib/search-executor'
|
||||
import type { EnhancedProductAnalysis, SearchConfig, PlatformConfig } from '@/lib/types'
|
||||
import { logServer } from "@/lib/server-logger";
|
||||
|
||||
const searchSchema = z.object({
|
||||
projectId: z.string(),
|
||||
@@ -23,12 +24,15 @@ const searchSchema = z.object({
|
||||
})),
|
||||
strategies: z.array(z.string()),
|
||||
maxResults: z.number().default(50)
|
||||
minAgeDays: z.number().min(0).max(365).optional(),
|
||||
maxAgeDays: z.number().min(0).max(365).optional()
|
||||
})
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
let jobId: string | undefined
|
||||
try {
|
||||
const requestId = request.headers.get("x-request-id") ?? undefined;
|
||||
if (!(await isAuthenticatedNextjs())) {
|
||||
const redirectUrl = new URL("/auth", request.url);
|
||||
const referer = request.headers.get("referer");
|
||||
@@ -41,9 +45,21 @@ export async function POST(request: NextRequest) {
|
||||
const parsed = searchSchema.parse(body)
|
||||
const { projectId, config } = parsed
|
||||
jobId = parsed.jobId
|
||||
const ageFilters = {
|
||||
minAgeDays: config.minAgeDays,
|
||||
maxAgeDays: config.maxAgeDays,
|
||||
}
|
||||
|
||||
if (!process.env.SERPER_API_KEY) {
|
||||
const errorMessage = "SERPER_API_KEY is not configured. Add it to your environment to run searches."
|
||||
await logServer({
|
||||
level: "warn",
|
||||
message: "Serper API key missing",
|
||||
labels: ["api", "opportunities", "config", "warn"],
|
||||
payload: { projectId },
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
if (jobId) {
|
||||
await fetchMutation(
|
||||
api.searchJobs.update,
|
||||
@@ -84,19 +100,43 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
const analysis = searchContext.context as EnhancedProductAnalysis
|
||||
|
||||
console.log('🔍 Starting opportunity search...')
|
||||
console.log(` Product: ${analysis.productName}`)
|
||||
console.log(` Platforms: ${config.platforms.filter(p => p.enabled).map(p => p.name).join(', ')}`)
|
||||
console.log(` Strategies: ${config.strategies.join(', ')}`)
|
||||
await logServer({
|
||||
level: "info",
|
||||
message: "Starting opportunity search",
|
||||
labels: ["api", "opportunities", "start"],
|
||||
payload: {
|
||||
projectId,
|
||||
productName: analysis.productName,
|
||||
platforms: config.platforms.filter((p) => p.enabled).map((p) => p.name),
|
||||
strategies: config.strategies,
|
||||
filters: ageFilters,
|
||||
},
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
|
||||
// Generate queries
|
||||
console.log(' Generating search queries...')
|
||||
await logServer({
|
||||
level: "info",
|
||||
message: "Generating search queries",
|
||||
labels: ["api", "opportunities", "queries"],
|
||||
payload: { projectId },
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
const enforcedConfig: SearchConfig = {
|
||||
...(config as SearchConfig),
|
||||
maxResults: Math.min((config as SearchConfig).maxResults || 50, 50),
|
||||
}
|
||||
const queries = generateSearchQueries(analysis as EnhancedProductAnalysis, enforcedConfig)
|
||||
console.log(` ✓ Generated ${queries.length} queries`)
|
||||
await logServer({
|
||||
level: "info",
|
||||
message: "Generated search queries",
|
||||
labels: ["api", "opportunities", "queries"],
|
||||
payload: { projectId, count: queries.length },
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
if (jobId) {
|
||||
await fetchMutation(
|
||||
api.searchJobs.update,
|
||||
@@ -106,9 +146,23 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
// Execute searches
|
||||
console.log(' Executing searches...')
|
||||
const searchResults = await executeSearches(queries)
|
||||
console.log(` ✓ Found ${searchResults.length} raw results`)
|
||||
await logServer({
|
||||
level: "info",
|
||||
message: "Executing searches",
|
||||
labels: ["api", "opportunities", "search"],
|
||||
payload: { projectId, queryCount: queries.length },
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
const searchResults = await executeSearches(queries, ageFilters)
|
||||
await logServer({
|
||||
level: "info",
|
||||
message: "Searches complete",
|
||||
labels: ["api", "opportunities", "search"],
|
||||
payload: { projectId, rawResults: searchResults.length },
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
if (jobId) {
|
||||
await fetchMutation(
|
||||
api.searchJobs.update,
|
||||
@@ -130,9 +184,23 @@ export async function POST(request: NextRequest) {
|
||||
const filteredResults = searchResults.filter((result) => !existingSet.has(result.url))
|
||||
|
||||
// Score and rank
|
||||
console.log(' Scoring opportunities...')
|
||||
await logServer({
|
||||
level: "info",
|
||||
message: "Scoring opportunities",
|
||||
labels: ["api", "opportunities", "score"],
|
||||
payload: { projectId, candidateResults: filteredResults.length },
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
const opportunities = scoreOpportunities(filteredResults, analysis as EnhancedProductAnalysis)
|
||||
console.log(` ✓ Scored ${opportunities.length} opportunities`)
|
||||
await logServer({
|
||||
level: "info",
|
||||
message: "Opportunities scored",
|
||||
labels: ["api", "opportunities", "score"],
|
||||
payload: { projectId, scored: opportunities.length },
|
||||
requestId,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
if (jobId) {
|
||||
await fetchMutation(
|
||||
api.searchJobs.update,
|
||||
@@ -179,7 +247,14 @@ export async function POST(request: NextRequest) {
|
||||
} catch (error: any) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : typeof error === "string" ? error : "Search failed"
|
||||
console.error("❌ Opportunity search error:", errorMessage)
|
||||
await logServer({
|
||||
level: "error",
|
||||
message: "Opportunity search error",
|
||||
labels: ["api", "opportunities", "error"],
|
||||
payload: { message: errorMessage },
|
||||
requestId: request.headers.get("x-request-id") ?? undefined,
|
||||
source: "api/opportunities",
|
||||
});
|
||||
|
||||
if (jobId) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user