entari-plugin-hyw 4.0.0rc7__py3-none-any.whl → 4.0.0rc8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of entari-plugin-hyw might be problematic. Click here for more details.
- entari_plugin_hyw/Untitled-1 +1865 -0
- entari_plugin_hyw/__init__.py +726 -394
- entari_plugin_hyw/history.py +26 -13
- entari_plugin_hyw/misc.py +3 -0
- entari_plugin_hyw/search_cache.py +154 -0
- {entari_plugin_hyw-4.0.0rc7.dist-info → entari_plugin_hyw-4.0.0rc8.dist-info}/METADATA +3 -1
- entari_plugin_hyw-4.0.0rc8.dist-info/RECORD +68 -0
- {entari_plugin_hyw-4.0.0rc7.dist-info → entari_plugin_hyw-4.0.0rc8.dist-info}/WHEEL +1 -1
- {entari_plugin_hyw-4.0.0rc7.dist-info → entari_plugin_hyw-4.0.0rc8.dist-info}/top_level.txt +1 -0
- hyw_core/__init__.py +94 -0
- hyw_core/browser_control/__init__.py +65 -0
- hyw_core/browser_control/assets/card-dist/index.html +409 -0
- hyw_core/browser_control/assets/index.html +5691 -0
- hyw_core/browser_control/engines/__init__.py +17 -0
- {entari_plugin_hyw/browser → hyw_core/browser_control}/engines/duckduckgo.py +42 -8
- {entari_plugin_hyw/browser → hyw_core/browser_control}/engines/google.py +1 -1
- {entari_plugin_hyw/browser → hyw_core/browser_control}/manager.py +15 -8
- entari_plugin_hyw/render_vue.py → hyw_core/browser_control/renderer.py +29 -14
- {entari_plugin_hyw/browser → hyw_core/browser_control}/service.py +287 -112
- hyw_core/config.py +154 -0
- hyw_core/core.py +322 -0
- hyw_core/definitions.py +83 -0
- entari_plugin_hyw/modular_pipeline.py → hyw_core/pipeline.py +121 -97
- {entari_plugin_hyw → hyw_core}/search.py +19 -14
- hyw_core/stages/__init__.py +21 -0
- entari_plugin_hyw/stage_base.py → hyw_core/stages/base.py +2 -2
- entari_plugin_hyw/stage_summary.py → hyw_core/stages/summary.py +34 -11
- entari_plugin_hyw/assets/card-dist/index.html +0 -387
- entari_plugin_hyw/browser/__init__.py +0 -10
- entari_plugin_hyw/browser/engines/bing.py +0 -95
- entari_plugin_hyw/card-ui/.gitignore +0 -24
- entari_plugin_hyw/card-ui/README.md +0 -5
- entari_plugin_hyw/card-ui/index.html +0 -16
- entari_plugin_hyw/card-ui/package-lock.json +0 -2342
- entari_plugin_hyw/card-ui/package.json +0 -31
- entari_plugin_hyw/card-ui/public/logos/anthropic.svg +0 -1
- entari_plugin_hyw/card-ui/public/logos/cerebras.svg +0 -9
- entari_plugin_hyw/card-ui/public/logos/deepseek.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/gemini.svg +0 -1
- entari_plugin_hyw/card-ui/public/logos/google.svg +0 -1
- entari_plugin_hyw/card-ui/public/logos/grok.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/huggingface.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/microsoft.svg +0 -15
- entari_plugin_hyw/card-ui/public/logos/minimax.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/mistral.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/nvida.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/openai.svg +0 -1
- entari_plugin_hyw/card-ui/public/logos/openrouter.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/perplexity.svg +0 -24
- entari_plugin_hyw/card-ui/public/logos/qwen.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/xai.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/xiaomi.png +0 -0
- entari_plugin_hyw/card-ui/public/logos/zai.png +0 -0
- entari_plugin_hyw/card-ui/public/vite.svg +0 -1
- entari_plugin_hyw/card-ui/src/App.vue +0 -787
- entari_plugin_hyw/card-ui/src/assets/vue.svg +0 -1
- entari_plugin_hyw/card-ui/src/components/HelloWorld.vue +0 -41
- entari_plugin_hyw/card-ui/src/components/MarkdownContent.vue +0 -382
- entari_plugin_hyw/card-ui/src/components/SectionCard.vue +0 -41
- entari_plugin_hyw/card-ui/src/components/StageCard.vue +0 -240
- entari_plugin_hyw/card-ui/src/main.ts +0 -5
- entari_plugin_hyw/card-ui/src/style.css +0 -29
- entari_plugin_hyw/card-ui/src/test_regex.js +0 -103
- entari_plugin_hyw/card-ui/src/types.ts +0 -61
- entari_plugin_hyw/card-ui/tsconfig.app.json +0 -16
- entari_plugin_hyw/card-ui/tsconfig.json +0 -7
- entari_plugin_hyw/card-ui/tsconfig.node.json +0 -26
- entari_plugin_hyw/card-ui/vite.config.ts +0 -16
- entari_plugin_hyw/definitions.py +0 -174
- entari_plugin_hyw/stage_instruct.py +0 -355
- entari_plugin_hyw/stage_instruct_deepsearch.py +0 -104
- entari_plugin_hyw/stage_vision.py +0 -113
- entari_plugin_hyw-4.0.0rc7.dist-info/RECORD +0 -102
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/anthropic.svg +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/cerebras.svg +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/deepseek.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/gemini.svg +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/google.svg +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/grok.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/huggingface.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/microsoft.svg +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/minimax.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/mistral.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/nvida.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/openai.svg +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/openrouter.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/perplexity.svg +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/qwen.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/xai.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/xiaomi.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/logos/zai.png +0 -0
- {entari_plugin_hyw → hyw_core/browser_control}/assets/card-dist/vite.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/anthropic.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/cerebras.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/deepseek.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/gemini.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/google.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/grok.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/huggingface.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/microsoft.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/minimax.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/mistral.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/nvida.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/openai.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/openrouter.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/perplexity.svg +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/qwen.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/xai.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/xiaomi.png +0 -0
- {entari_plugin_hyw/assets/icon → hyw_core/browser_control/assets/logos}/zai.png +0 -0
- {entari_plugin_hyw/browser → hyw_core/browser_control}/engines/base.py +0 -0
- {entari_plugin_hyw/browser → hyw_core/browser_control}/engines/default.py +0 -0
- {entari_plugin_hyw/browser → hyw_core/browser_control}/landing.html +0 -0
- {entari_plugin_hyw → hyw_core}/image_cache.py +0 -0
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, computed } from 'vue'
|
|
3
|
-
import { Icon } from '@iconify/vue'
|
|
4
|
-
import type { Stage } from '../types'
|
|
5
|
-
|
|
6
|
-
const props = defineProps<{
|
|
7
|
-
stage: Stage
|
|
8
|
-
isFirst?: boolean
|
|
9
|
-
isLast?: boolean
|
|
10
|
-
prevStageName?: string
|
|
11
|
-
refOffset?: number
|
|
12
|
-
hideRefs?: boolean
|
|
13
|
-
}>()
|
|
14
|
-
|
|
15
|
-
const failedImages = ref<Record<string, boolean>>({})
|
|
16
|
-
const imageHeights = ref<Record<string, number>>({})
|
|
17
|
-
|
|
18
|
-
function handleImageError(url: string) {
|
|
19
|
-
failedImages.value[url] = true
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function handleImageLoad(url: string, event: Event) {
|
|
23
|
-
const img = event.target as HTMLImageElement
|
|
24
|
-
if (img.naturalWidth && img.naturalHeight) {
|
|
25
|
-
// Store aspect ratio as height per unit width
|
|
26
|
-
imageHeights.value[url] = img.naturalHeight / img.naturalWidth
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Compute two columns for masonry layout
|
|
31
|
-
const imageColumns = computed(() => {
|
|
32
|
-
const images = props.stage.image_references || []
|
|
33
|
-
const leftColumn: typeof images = []
|
|
34
|
-
const rightColumn: typeof images = []
|
|
35
|
-
let leftHeight = 0
|
|
36
|
-
let rightHeight = 0
|
|
37
|
-
|
|
38
|
-
for (const img of images) {
|
|
39
|
-
if (failedImages.value[img.url]) continue
|
|
40
|
-
|
|
41
|
-
// Get aspect ratio (default to 1 if not loaded yet)
|
|
42
|
-
const aspectRatio = imageHeights.value[img.url] || 1
|
|
43
|
-
|
|
44
|
-
// Add to shorter column
|
|
45
|
-
if (leftHeight <= rightHeight) {
|
|
46
|
-
leftColumn.push(img)
|
|
47
|
-
leftHeight += aspectRatio
|
|
48
|
-
} else {
|
|
49
|
-
rightColumn.push(img)
|
|
50
|
-
rightHeight += aspectRatio
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return { leftColumn, rightColumn }
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
function getDomain(url: string): string {
|
|
62
|
-
try {
|
|
63
|
-
const urlObj = new URL(url)
|
|
64
|
-
const hostname = urlObj.hostname.replace('www.', '')
|
|
65
|
-
const pathname = urlObj.pathname === '/' ? '' : urlObj.pathname
|
|
66
|
-
return hostname + pathname
|
|
67
|
-
} catch {
|
|
68
|
-
return url
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function getFavicon(url: string): string {
|
|
73
|
-
const domain = getDomain(url)
|
|
74
|
-
return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function formatTime(seconds: number): string {
|
|
78
|
-
return `${seconds.toFixed(2)}s`
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function formatCost(dollars: number): string {
|
|
82
|
-
return dollars > 0 ? `$${dollars.toFixed(6)}` : '$0'
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function getModelShort(model: string): string {
|
|
86
|
-
const short = model.includes('/') ? model.split('/').pop() || model : model
|
|
87
|
-
return short.length > 25 ? short.slice(0, 23) + '…' : short
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function getStageTheme(name?: string) {
|
|
91
|
-
if (!name) return themes['default']
|
|
92
|
-
const key = name.toLowerCase()
|
|
93
|
-
|
|
94
|
-
if (key.includes('search')) return themes['search']
|
|
95
|
-
if (key.includes('crawl') || key.includes('page')) return themes['crawler']
|
|
96
|
-
if (key.includes('agent')) return themes['agent']
|
|
97
|
-
if (key.includes('instruct')) return themes['instruct']
|
|
98
|
-
if (key.includes('vision')) return themes['vision']
|
|
99
|
-
|
|
100
|
-
return themes['default']
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const themes: Record<string, any> = {
|
|
104
|
-
'search': { color: 'text-blue-600', bg: 'bg-blue-50', iconBg: 'bg-blue-100/50', icon: 'mdi:magnify' },
|
|
105
|
-
'crawler': { color: 'text-orange-600', bg: 'bg-orange-50', iconBg: 'bg-orange-100/50', icon: 'mdi:web' },
|
|
106
|
-
'agent': { color: 'text-purple-600', bg: 'bg-purple-50', iconBg: 'bg-white/80', icon: 'mdi:robot' },
|
|
107
|
-
'instruct': { color: 'text-red-600', bg: 'bg-red-50', iconBg: 'bg-white/80', icon: 'mdi:lightning-bolt' },
|
|
108
|
-
'vision': { color: 'text-purple-600', bg: 'bg-purple-50', iconBg: 'bg-white/80', icon: 'mdi:eye' },
|
|
109
|
-
'default': { color: 'text-gray-600', bg: 'bg-gray-50', iconBg: 'bg-gray-100/50', icon: 'mdi:circle' }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function getIcon(name: string): string {
|
|
113
|
-
const key = name.toLowerCase()
|
|
114
|
-
if (key.includes('search')) return 'mdi:magnify'
|
|
115
|
-
if (key.includes('crawl') || key.includes('page')) return 'mdi:web'
|
|
116
|
-
if (key.includes('agent')) return 'mdi:robot'
|
|
117
|
-
if (key.includes('instruct')) return 'mdi:lightning-bolt'
|
|
118
|
-
if (key.includes('vision')) return 'mdi:eye'
|
|
119
|
-
return 'mdi:circle'
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function getModelLogo(model: string): string | undefined {
|
|
123
|
-
if (!model) return undefined
|
|
124
|
-
const m = model.toLowerCase()
|
|
125
|
-
if (m.includes('openai') || m.includes('gpt')) return 'logos/openai.svg'
|
|
126
|
-
if (m.includes('claude') || m.includes('anthropic')) return 'logos/anthropic.svg'
|
|
127
|
-
if (m.includes('gemini') || m.includes('google')) return 'logos/google.svg'
|
|
128
|
-
if (m.includes('deepseek')) return 'logos/deepseek.png'
|
|
129
|
-
if (m.includes('huggingface')) return 'logos/huggingface.png'
|
|
130
|
-
if (m.includes('mistral')) return 'logos/mistral.png'
|
|
131
|
-
if (m.includes('perplexity')) return 'logos/perplexity.svg'
|
|
132
|
-
if (m.includes('cerebras')) return 'logos/cerebras.svg'
|
|
133
|
-
if (m.includes('grok')) return 'logos/grok.png'
|
|
134
|
-
if (m.includes('qwen')) return 'logos/qwen.png'
|
|
135
|
-
if (m.includes('minimax')) return 'logos/minimax.png'
|
|
136
|
-
if (m.includes('nvidia') || m.includes('nvida')) return 'logos/nvida.png'
|
|
137
|
-
if (m.includes('azure') || m.includes('microsoft')) return 'logos/microsoft.svg'
|
|
138
|
-
if (m.includes('xai')) return 'logos/xai.png'
|
|
139
|
-
if (m.includes('xiaomi')) return 'logos/xiaomi.png'
|
|
140
|
-
if (m.includes('zai')) return 'logos/zai.png'
|
|
141
|
-
return undefined
|
|
142
|
-
}
|
|
143
|
-
</script>
|
|
144
|
-
|
|
145
|
-
<template>
|
|
146
|
-
<div class="relative">
|
|
147
|
-
<!-- Content -->
|
|
148
|
-
<div class="flex-1 min-w-0 pl-2">
|
|
149
|
-
<div class="rounded-none overflow-hidden bg-white">
|
|
150
|
-
|
|
151
|
-
<!-- Header -->
|
|
152
|
-
<div :class="['bg-white px-4 py-2.5 flex items-center justify-between gap-3']">
|
|
153
|
-
<div class="flex items-center gap-3">
|
|
154
|
-
<div :class="['w-8 h-8 flex items-center justify-center shrink-0 overflow-hidden border border-gray-100', getStageTheme(stage.name).iconBg, getStageTheme(stage.name).color]">
|
|
155
|
-
<img v-if="getModelLogo(stage.model)" :src="getModelLogo(stage.model)" class="w-5 h-5 object-contain" />
|
|
156
|
-
<Icon v-else :icon="getIcon(stage.name)" class="text-lg" />
|
|
157
|
-
</div>
|
|
158
|
-
<div class="flex flex-col">
|
|
159
|
-
<span class="font-black text-[18px] text-gray-800 uppercase tracking-tight">{{ stage.name }}</span>
|
|
160
|
-
<span class="text-[15.5px] font-mono tabular-nums tracking-tighter" style="color: var(--text-muted)">{{ getModelShort(stage.model) }}</span>
|
|
161
|
-
</div>
|
|
162
|
-
</div>
|
|
163
|
-
<div v-if="stage.time > 0 || stage.cost > 0" class="text-[15.5px] font-mono flex items-center justify-end gap-2 leading-tight min-w-[120px]" style="color: var(--text-muted)">
|
|
164
|
-
<span v-if="stage.cost > 0">{{ formatCost(stage.cost) }}</span>
|
|
165
|
-
<span v-if="stage.time > 0 && stage.cost > 0" class="text-gray-300">·</span>
|
|
166
|
-
<span v-if="stage.time > 0">{{ formatTime(stage.time) }}</span>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
<div v-if="stage.description" class="px-5 py-3 text-[14.5px] text-gray-600 bg-gray-50/40 border-y border-gray-100 italic leading-relaxed font-sans">
|
|
172
|
-
<span class="mr-1 text-[var(--theme-color)] not-italic opacity-50">✦</span> {{ stage.description }}
|
|
173
|
-
</div>
|
|
174
|
-
|
|
175
|
-
<div v-if="stage.references?.length || stage.image_references?.length || stage.crawled_pages?.length || stage.tasks?.length" class="bg-white pl-11 relative">
|
|
176
|
-
|
|
177
|
-
<!-- Tasks List -->
|
|
178
|
-
<div v-if="stage.tasks?.length" class="pr-3 py-3 relative z-10 border-b border-gray-50 last:border-0">
|
|
179
|
-
<div v-for="(task, idx) in stage.tasks" :key="idx" class="flex items-start gap-2.5 mb-2 last:mb-0">
|
|
180
|
-
<div class="w-4 h-4 rounded-full border border-[var(--theme-color)] flex items-center justify-center shrink-0 mt-0.5 bg-[var(--theme-color)]/10">
|
|
181
|
-
<Icon icon="mdi:check" class="text-[10px] text-[var(--theme-color)]" />
|
|
182
|
-
</div>
|
|
183
|
-
<span class="text-[15px] text-gray-700 font-medium leading-tight select-text">{{ task }}</span>
|
|
184
|
-
</div>
|
|
185
|
-
</div>
|
|
186
|
-
|
|
187
|
-
<!-- Image Search Results - True Masonry Layout -->
|
|
188
|
-
<div v-if="stage.image_references?.length && !hideRefs" class="pr-3 py-3 relative z-10">
|
|
189
|
-
<div class="flex gap-2">
|
|
190
|
-
<!-- Left Column -->
|
|
191
|
-
<div class="flex-1 flex flex-col gap-2">
|
|
192
|
-
<a v-for="(img, idx) in imageColumns.leftColumn" :key="`left-${img.url}-${idx}`"
|
|
193
|
-
:href="img.url" target="_blank"
|
|
194
|
-
class="relative overflow-hidden transition-all hover:opacity-90 group block">
|
|
195
|
-
<img :src="img.thumbnail || img.url"
|
|
196
|
-
@load="handleImageLoad(img.url, $event)"
|
|
197
|
-
@error="handleImageError(img.url)"
|
|
198
|
-
class="w-full h-auto block group-hover:scale-[1.02] transition-transform">
|
|
199
|
-
</a>
|
|
200
|
-
</div>
|
|
201
|
-
<!-- Right Column -->
|
|
202
|
-
<div class="flex-1 flex flex-col gap-2">
|
|
203
|
-
<a v-for="(img, idx) in imageColumns.rightColumn" :key="`right-${img.url}-${idx}`"
|
|
204
|
-
:href="img.url" target="_blank"
|
|
205
|
-
class="relative overflow-hidden transition-all hover:opacity-90 group block">
|
|
206
|
-
<img :src="img.thumbnail || img.url"
|
|
207
|
-
@load="handleImageLoad(img.url, $event)"
|
|
208
|
-
@error="handleImageError(img.url)"
|
|
209
|
-
class="w-full h-auto block group-hover:scale-[1.02] transition-transform">
|
|
210
|
-
</a>
|
|
211
|
-
</div>
|
|
212
|
-
</div>
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
<div v-if="stage.crawled_pages?.length && !hideRefs" class="divide-y divide-gray-50 relative z-10">
|
|
216
|
-
<div v-for="(page, idx) in stage.crawled_pages" :key="idx" class="pr-3 py-3 hover:bg-gray-50 transition-colors group">
|
|
217
|
-
<!-- Header Row: Title & Link -->
|
|
218
|
-
<a :href="page.url" target="_blank" class="flex items-start gap-3 block">
|
|
219
|
-
<img :src="getFavicon(page.url)" class="w-4 h-4 rounded-none shrink-0 object-contain mt-[4px]">
|
|
220
|
-
<div class="flex-1 min-w-0 flex flex-col">
|
|
221
|
-
<div class="flex items-center gap-2">
|
|
222
|
-
<span class="flex-1 text-[18px] font-bold text-gray-700 truncate leading-tight tracking-tight group-hover:text-[var(--theme-color)] transition-colors">{{ page.title }}</span>
|
|
223
|
-
<!-- Square Badge with Shadow -->
|
|
224
|
-
<span class="shrink-0 w-[18px] h-[18px] text-[11px] font-bold flex items-center justify-center" style="background-color: var(--theme-color); color: var(--header-text-color); box-shadow: 0 1px 3px 0 rgba(0,0,0,0.15)">{{ (refOffset || 0) + (stage.references?.length || 0) + idx + 1 }}</span>
|
|
225
|
-
</div>
|
|
226
|
-
<div class="text-[15.5px] font-mono truncate mt-0.5 tracking-tighter" style="color: var(--text-muted)">{{ getDomain(page.url) }}</div>
|
|
227
|
-
</div>
|
|
228
|
-
</a>
|
|
229
|
-
|
|
230
|
-
<!-- Description Sub-container -->
|
|
231
|
-
<div v-if="page.description" class="ml-7 mt-2.5 p-3 bg-gray-100/80 text-[14px] text-gray-600 leading-snug font-sans border-l-[3px] border-[var(--theme-color)] rounded-r-sm">
|
|
232
|
-
{{ page.description }}
|
|
233
|
-
</div>
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
</div>
|
|
240
|
-
</template>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
@plugin "daisyui";
|
|
3
|
-
@plugin "@tailwindcss/typography";
|
|
4
|
-
|
|
5
|
-
/* Custom styles */
|
|
6
|
-
body {
|
|
7
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/* Premium reading color scheme - applies to all prose elements */
|
|
11
|
-
.prose {
|
|
12
|
-
color: var(--text-body, #3a3a3c) !important;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
|
|
16
|
-
color: var(--text-primary, #2c2c2e) !important;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.prose p, .prose li, .prose td, .prose th {
|
|
20
|
-
color: var(--text-body, #3a3a3c) !important;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.prose strong, .prose b {
|
|
24
|
-
color: var(--text-primary, #2c2c2e) !important;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.prose code {
|
|
28
|
-
color: var(--text-body, #3a3a3c) !important;
|
|
29
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const stripPrefixBeforeH1 = (text) => {
|
|
3
|
-
const h1Match = text.match(/^#\s+/m)
|
|
4
|
-
if (h1Match && h1Match.index !== undefined) {
|
|
5
|
-
return text.substring(h1Match.index)
|
|
6
|
-
}
|
|
7
|
-
return text
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const dedent = (text) => {
|
|
11
|
-
const lines = text.split('\n')
|
|
12
|
-
// Find minimum indentation of non-empty lines
|
|
13
|
-
let minIndent = Infinity
|
|
14
|
-
for (const line of lines) {
|
|
15
|
-
if (line.trim().length === 0) continue
|
|
16
|
-
const leadingSpace = line.match(/^\s*/)?.[0].length || 0
|
|
17
|
-
if (leadingSpace < minIndent) minIndent = leadingSpace
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (minIndent === Infinity || minIndent === 0) return text
|
|
21
|
-
|
|
22
|
-
return lines.map(line => {
|
|
23
|
-
if (line.trim().length === 0) return ''
|
|
24
|
-
return line.substring(minIndent)
|
|
25
|
-
}).join('\n')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const parse = (rawMd) => {
|
|
29
|
-
if (!rawMd) return []
|
|
30
|
-
|
|
31
|
-
const md = stripPrefixBeforeH1(rawMd)
|
|
32
|
-
|
|
33
|
-
let content = md.replace(/^#\s+.+$/m, '')
|
|
34
|
-
content = content.replace(/(?:^|\n)\s*(?:#{1,3}|\*\*)\s*(?:References|Citations|Sources)[\s\S]*$/i, '')
|
|
35
|
-
content = content.trim()
|
|
36
|
-
|
|
37
|
-
const sections = []
|
|
38
|
-
|
|
39
|
-
const combinedRegex = /(```[\s\S]*?```|((?:^|\n)\|[^\n]*\|(?:\n\|[^\n]*\|)*)|<summary>[\s\S]*?<\/summary>)/
|
|
40
|
-
|
|
41
|
-
let remaining = content
|
|
42
|
-
|
|
43
|
-
while (remaining) {
|
|
44
|
-
const match = remaining.match(combinedRegex)
|
|
45
|
-
if (!match) {
|
|
46
|
-
if (remaining.trim()) {
|
|
47
|
-
sections.push({ type: 'markdown', content: remaining.trim() })
|
|
48
|
-
}
|
|
49
|
-
break
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const index = match.index
|
|
53
|
-
const matchedStr = match[0]
|
|
54
|
-
const preText = remaining.substring(0, index)
|
|
55
|
-
|
|
56
|
-
if (preText.trim()) {
|
|
57
|
-
sections.push({ type: 'markdown', content: preText.trim() })
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const isCode = matchedStr.startsWith('```')
|
|
61
|
-
const isSummary = matchedStr.startsWith('<summary>')
|
|
62
|
-
const isTable = !isCode && !isSummary && matchedStr.trim().startsWith('|')
|
|
63
|
-
|
|
64
|
-
if (isCode || isTable || isSummary) {
|
|
65
|
-
let language = ''
|
|
66
|
-
let content = matchedStr.trim()
|
|
67
|
-
|
|
68
|
-
if (isCode) {
|
|
69
|
-
const match = matchedStr.match(/^```(\w+)/)
|
|
70
|
-
if (match && match[1]) language = match[1]
|
|
71
|
-
} else if (isSummary) {
|
|
72
|
-
content = content.replace(/^<summary>/, '').replace(/<\/summary>$/, '')
|
|
73
|
-
content = dedent(content)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
sections.push({
|
|
77
|
-
type: 'card',
|
|
78
|
-
title: isCode ? 'Code' : (isSummary ? 'Summary' : 'Table'),
|
|
79
|
-
content: content,
|
|
80
|
-
contentType: isCode ? 'code' : (isSummary ? 'summary' : 'table'),
|
|
81
|
-
language: language
|
|
82
|
-
})
|
|
83
|
-
} else {
|
|
84
|
-
sections.push({ type: 'markdown', content: matchedStr })
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
remaining = remaining.substring(index + matchedStr.length)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return sections
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const test1 = `
|
|
94
|
-
# Title
|
|
95
|
-
|
|
96
|
-
<summary>
|
|
97
|
-
Indented text.
|
|
98
|
-
It might become code block.
|
|
99
|
-
</summary>
|
|
100
|
-
`
|
|
101
|
-
|
|
102
|
-
console.log("\n--- Test 2 (After Fix) ---")
|
|
103
|
-
console.log(JSON.stringify(parse(test1), null, 2))
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// Type definitions for render data
|
|
2
|
-
// Python only passes raw data, all processing happens in frontend
|
|
3
|
-
|
|
4
|
-
export interface Stage {
|
|
5
|
-
name: string
|
|
6
|
-
model: string
|
|
7
|
-
provider: string
|
|
8
|
-
icon_name?: string // Icon identifier (e.g., "google", "openai")
|
|
9
|
-
icon_config?: string // Config key for icon (e.g. "openai")
|
|
10
|
-
time: number // Time in seconds (raw number)
|
|
11
|
-
cost: number // Cost in dollars (raw number)
|
|
12
|
-
usage?: any // Token usage stats
|
|
13
|
-
references?: Reference[]
|
|
14
|
-
image_references?: ImageReference[]
|
|
15
|
-
crawled_pages?: CrawledPage[]
|
|
16
|
-
description?: string // Brief intro or thought for this stage
|
|
17
|
-
tasks?: string[]
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Reference {
|
|
21
|
-
title: string
|
|
22
|
-
url: string
|
|
23
|
-
is_fetched?: boolean
|
|
24
|
-
snippet?: string
|
|
25
|
-
type?: string
|
|
26
|
-
images?: string[] // Extracted images (base64)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ImageReference {
|
|
30
|
-
title: string
|
|
31
|
-
url: string
|
|
32
|
-
thumbnail?: string
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface CrawledPage {
|
|
36
|
-
title: string
|
|
37
|
-
url: string
|
|
38
|
-
description?: string
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface Stats {
|
|
42
|
-
total_time?: number
|
|
43
|
-
vision_duration?: number
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface Flags {
|
|
47
|
-
has_vision: boolean
|
|
48
|
-
has_search: boolean
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Raw data from Python - minimal processing
|
|
52
|
-
export interface RenderData {
|
|
53
|
-
markdown: string // Raw markdown content
|
|
54
|
-
stages: Stage[]
|
|
55
|
-
references: Reference[] // All references for citation
|
|
56
|
-
page_references: Reference[]
|
|
57
|
-
image_references: ImageReference[]
|
|
58
|
-
stats: Stats
|
|
59
|
-
total_time: number
|
|
60
|
-
theme_color?: string // Configurable theme color (hex)
|
|
61
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
5
|
-
"types": ["vite/client"],
|
|
6
|
-
|
|
7
|
-
/* Linting */
|
|
8
|
-
"strict": true,
|
|
9
|
-
"noUnusedLocals": true,
|
|
10
|
-
"noUnusedParameters": true,
|
|
11
|
-
"erasableSyntaxOnly": true,
|
|
12
|
-
"noFallthroughCasesInSwitch": true,
|
|
13
|
-
"noUncheckedSideEffectImports": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
|
16
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
-
"target": "ES2023",
|
|
5
|
-
"lib": ["ES2023"],
|
|
6
|
-
"module": "ESNext",
|
|
7
|
-
"types": ["node"],
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"verbatimModuleSyntax": true,
|
|
14
|
-
"moduleDetection": "force",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
/* Linting */
|
|
18
|
-
"strict": true,
|
|
19
|
-
"noUnusedLocals": true,
|
|
20
|
-
"noUnusedParameters": true,
|
|
21
|
-
"erasableSyntaxOnly": true,
|
|
22
|
-
"noFallthroughCasesInSwitch": true,
|
|
23
|
-
"noUncheckedSideEffectImports": true
|
|
24
|
-
},
|
|
25
|
-
"include": ["vite.config.ts"]
|
|
26
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite'
|
|
2
|
-
import vue from '@vitejs/plugin-vue'
|
|
3
|
-
import tailwindcss from '@tailwindcss/vite'
|
|
4
|
-
import { viteSingleFile } from 'vite-plugin-singlefile'
|
|
5
|
-
|
|
6
|
-
export default defineConfig({
|
|
7
|
-
plugins: [
|
|
8
|
-
vue(),
|
|
9
|
-
tailwindcss(),
|
|
10
|
-
viteSingleFile(),
|
|
11
|
-
],
|
|
12
|
-
build: {
|
|
13
|
-
outDir: '../assets/card-dist',
|
|
14
|
-
emptyOutDir: true,
|
|
15
|
-
},
|
|
16
|
-
})
|