fix: enrichment pipeline reliability + loading page gradient + button click area
- generate-report: filter empty strings from AI social handles, add saveError logging - useReport: 3-level fallback for social handles (report > clinicInfo > scrape_data) - useEnrichment: always trigger enrichment if clinicName exists (not just IG/YT handles) - Hero: pointer-events-none on decorative blobs (were blocking button clicks) - AnalysisLoadingPage: warm gradient on INFINITH logo text (#fff3eb → #e4cfff → #f5f9ff) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>claude/bold-hawking
parent
72ea8f4a2d
commit
ad625e08ee
|
|
@ -79,9 +79,9 @@ export default function Hero() {
|
|||
</div>
|
||||
|
||||
{/* Decorative elements */}
|
||||
<div className="absolute top-1/4 left-10 w-64 h-64 bg-purple-300 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob"></div>
|
||||
<div className="absolute top-1/3 right-10 w-64 h-64 bg-pink-300 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-2000"></div>
|
||||
<div className="absolute -bottom-8 left-1/2 -translate-x-1/2 w-64 h-64 bg-indigo-300 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-4000"></div>
|
||||
<div className="absolute top-1/4 left-10 w-64 h-64 bg-purple-300 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob pointer-events-none"></div>
|
||||
<div className="absolute top-1/3 right-10 w-64 h-64 bg-pink-300 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-2000 pointer-events-none"></div>
|
||||
<div className="absolute -bottom-8 left-1/2 -translate-x-1/2 w-64 h-64 bg-indigo-300 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-4000 pointer-events-none"></div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ export function useEnrichment(
|
|||
|
||||
useEffect(() => {
|
||||
if (!baseReport || !params?.reportId || hasTriggered.current) return;
|
||||
// Don't enrich if no social handles are available
|
||||
if (!params.instagramHandle && !params.instagramHandles?.length && !params.youtubeChannelId) return;
|
||||
// Always enrich if clinicName exists — Naver, 강남언니, Google Maps work with name alone
|
||||
|
||||
hasTriggered.current = true;
|
||||
setStatus('loading');
|
||||
|
|
|
|||
|
|
@ -76,21 +76,30 @@ export function useReport(id: string | undefined): UseReportResult {
|
|||
},
|
||||
);
|
||||
|
||||
// Recover social handles: report.socialHandles > scrape_data.clinic.socialMedia
|
||||
let handles = (reportJson.socialHandles as Record<string, string | null>) || null;
|
||||
if (!handles && scrapeData) {
|
||||
const clinic = scrapeData.clinic as Record<string, unknown> | undefined;
|
||||
const socialMedia = clinic?.socialMedia as Record<string, string> | undefined;
|
||||
if (socialMedia) {
|
||||
// Recover social handles: report.socialHandles > AI clinicInfo.socialMedia > scrape_data
|
||||
let handles = (reportJson.socialHandles as Record<string, string | null | string[]>) || null;
|
||||
if (!handles) {
|
||||
// Try AI-generated socialMedia in clinicInfo
|
||||
const aiSocial = (reportJson.clinicInfo as Record<string, unknown>)?.socialMedia as Record<string, unknown> | undefined;
|
||||
const scrapeSocial = scrapeData
|
||||
? (scrapeData.clinic as Record<string, unknown>)?.socialMedia as Record<string, string> | undefined
|
||||
: undefined;
|
||||
|
||||
const igSource = aiSocial?.instagramAccounts || aiSocial?.instagram || scrapeSocial?.instagram;
|
||||
const ytSource = (aiSocial?.youtube as string) || scrapeSocial?.youtube;
|
||||
|
||||
if (igSource || ytSource) {
|
||||
handles = {
|
||||
instagram: normalizeInstagramHandle(socialMedia.instagram),
|
||||
youtube: socialMedia.youtube || null,
|
||||
facebook: socialMedia.facebook || null,
|
||||
blog: socialMedia.blog || null,
|
||||
instagram: Array.isArray(igSource)
|
||||
? igSource.map((h: string) => normalizeInstagramHandle(h)).filter(Boolean)
|
||||
: normalizeInstagramHandle(igSource as string),
|
||||
youtube: ytSource || null,
|
||||
facebook: (aiSocial?.facebook as string) || scrapeSocial?.facebook || null,
|
||||
blog: (aiSocial?.naverBlog as string) || scrapeSocial?.blog || null,
|
||||
};
|
||||
}
|
||||
}
|
||||
setSocialHandles(handles);
|
||||
setSocialHandles(handles as Record<string, string | null> | null);
|
||||
|
||||
// If channelEnrichment already exists in DB, merge it immediately
|
||||
const enrichment = reportJson.channelEnrichment as EnrichmentData | undefined;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,12 @@ export default function AnalysisLoadingPage() {
|
|||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="text-4xl md:text-5xl font-serif font-bold text-gradient mb-4"
|
||||
className="text-4xl md:text-5xl font-serif font-bold mb-4"
|
||||
style={{
|
||||
background: 'linear-gradient(to right, #fff3eb, #e4cfff, #f5f9ff)',
|
||||
WebkitBackgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
}}
|
||||
>
|
||||
INFINITH
|
||||
</motion.h1>
|
||||
|
|
|
|||
|
|
@ -187,11 +187,15 @@ ${JSON.stringify(analyzeResult.data?.analysis || {}, null, 2)}
|
|||
.filter((h): h is string => h !== null)
|
||||
)];
|
||||
|
||||
// Filter out empty strings — AI sometimes returns "" instead of null
|
||||
const pickNonEmpty = (...vals: (string | null | undefined)[]): string | null =>
|
||||
vals.find(v => v && v.trim().length > 0) || null;
|
||||
|
||||
const normalizedHandles = {
|
||||
instagram: igHandles.length > 0 ? igHandles : null, // array of handles
|
||||
youtube: aiSocial.youtube || scrapeSocial.youtube || null,
|
||||
facebook: aiSocial.facebook || scrapeSocial.facebook || null,
|
||||
blog: aiSocial.naverBlog || scrapeSocial.blog || null,
|
||||
instagram: igHandles.length > 0 ? igHandles : null,
|
||||
youtube: pickNonEmpty(aiSocial.youtube, scrapeSocial.youtube),
|
||||
facebook: pickNonEmpty(aiSocial.facebook, scrapeSocial.facebook),
|
||||
blog: pickNonEmpty(aiSocial.naverBlog, scrapeSocial.blog),
|
||||
};
|
||||
|
||||
// Embed normalized handles in report for DB persistence
|
||||
|
|
@ -211,6 +215,10 @@ ${JSON.stringify(analyzeResult.data?.analysis || {}, null, 2)}
|
|||
.select("id")
|
||||
.single();
|
||||
|
||||
if (saveError) {
|
||||
console.error("DB save error:", saveError);
|
||||
}
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
|
|
@ -226,6 +234,7 @@ ${JSON.stringify(analyzeResult.data?.analysis || {}, null, 2)}
|
|||
aiGeneration: !report.parseError,
|
||||
},
|
||||
socialHandles: normalizedHandles,
|
||||
saveError: saveError?.message || null,
|
||||
address,
|
||||
services,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue