feat(share): refactor page and enhance thumbnail extraction
- Extract 8 reusable components from monolithic share page - Add LLM health indicator with 30s polling - Implement stealth thumbnail extraction with 4-method cascade - Integrate real-time thumbnail preview component - Reduce share page from 306 to ~140 lines - Add comprehensive outcome documentation Components: - UrlInputSection: URL input and extraction trigger - ProgressIndicator: Loading state display - ExtractedTextViewer: Collapsible text preview - RecipeCard: Recipe display with Tandoor integration - ErrorState: Error handling UI - LogViewer: System logs with color coding - LlmHealthIndicator: LLM status with polling - ThumbnailPreview: Real-time thumbnail display Thumbnail Methods: 1. Meta tag extraction (og:image, twitter:image) 2. Video poster attribute 3. Instagram embedded JSON data 4. Screenshot fallback Stories Completed: - Story 1: Component extraction and refactoring - Story 2: LLM health status indicator - Story 3: Enhanced stealth thumbnail extraction - Story 4: Thumbnail preview integration Closes: RefactorSharePageAndEnhanceThumbnails
This commit is contained in:
58
src/routes/share/components/LlmHealthIndicator.svelte
Normal file
58
src/routes/share/components/LlmHealthIndicator.svelte
Normal file
@@ -0,0 +1,58 @@
|
||||
<script lang="ts">
|
||||
interface HealthState {
|
||||
status: 'checking' | 'healthy' | 'unhealthy' | 'error';
|
||||
message: string;
|
||||
lastChecked: Date | null;
|
||||
}
|
||||
|
||||
let { pollInterval = 30000 } = $props<{
|
||||
pollInterval?: number;
|
||||
}>();
|
||||
|
||||
let health = $state<HealthState>({
|
||||
status: 'checking',
|
||||
message: '',
|
||||
lastChecked: null
|
||||
});
|
||||
|
||||
async function checkHealth() {
|
||||
try {
|
||||
const res = await fetch('/api/llm-health');
|
||||
const data = await res.json();
|
||||
health = {
|
||||
status: data.status === 'healthy' ? 'healthy' : 'unhealthy',
|
||||
message: data.message,
|
||||
lastChecked: new Date()
|
||||
};
|
||||
} catch (e) {
|
||||
health = {
|
||||
status: 'error',
|
||||
message: e instanceof Error ? e.message : 'Network error',
|
||||
lastChecked: new Date()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
checkHealth(); // Initial check
|
||||
const interval = setInterval(checkHealth, pollInterval);
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<div class="flex items-center gap-1">
|
||||
{#if health.status === 'checking'}
|
||||
🟡 <span>Checking LLM...</span>
|
||||
{:else if health.status === 'healthy'}
|
||||
🟢 <span class="text-green-600">LLM Ready</span>
|
||||
{:else if health.status === 'unhealthy'}
|
||||
🔴 <span class="text-red-600">LLM Unavailable</span>
|
||||
{:else}
|
||||
🔴 <span class="text-red-600">LLM Error</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500" title={health.message}>
|
||||
{health.lastChecked ? `Last: ${health.lastChecked.toLocaleTimeString()}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user