feat: Go backend, enhanced search, new widgets, Docker deploy

Major changes:
- Add Go backend (backend/) with microservices architecture
- Enhanced master-agents-svc: reranker, content-classifier, stealth-crawler,
  proxy-manager, media-search, fastClassifier, language detection
- New web-svc widgets: KnowledgeCard, ProductCard, ProfileCard, VideoCard,
  UnifiedCard, CardGallery, InlineImageGallery, SourcesPanel, RelatedQuestions
- Improved discover-svc with discover-db integration
- Docker deployment improvements (Caddyfile, vendor.sh, BUILD.md)
- Library-svc: project_id schema migration
- Remove deprecated finance-svc and travel-svc
- Localization improvements across services

Made-with: Cursor
This commit is contained in:
home
2026-02-27 04:15:32 +03:00
parent 328d968f3f
commit 06fe57c765
285 changed files with 53132 additions and 1871 deletions

View File

@@ -0,0 +1,146 @@
'use client';
import { ExternalLink } from 'lucide-react';
import * as Tooltip from '@radix-ui/react-tooltip';
import type { Citation as CitationType } from '@/lib/types';
interface CitationProps {
citation: CitationType;
compact?: boolean;
}
export function Citation({ citation, compact }: CitationProps) {
if (compact) {
return (
<a
href={citation.url}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center w-5 h-5 text-2xs font-medium bg-cream-300/10 hover:bg-cream-300/20 text-cream-300 border border-cream-400/20 rounded transition-colors"
>
{citation.index}
</a>
);
}
return (
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<a
href={citation.url}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-2.5 py-1.5 bg-navy-800/40 hover:bg-navy-800/60 border border-navy-700/30 hover:border-cream-400/20 rounded-lg transition-all group"
>
<span className="w-4 h-4 rounded bg-cream-300/10 text-cream-300 flex items-center justify-center text-2xs font-medium">
{citation.index}
</span>
{citation.favicon && (
<img
src={citation.favicon}
alt=""
className="w-3.5 h-3.5 rounded"
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
}}
/>
)}
<span className="text-xs text-cream-400/80 group-hover:text-cream-200 max-w-[120px] truncate transition-colors">
{citation.domain}
</span>
<ExternalLink className="w-2.5 h-2.5 text-cream-500/50 group-hover:text-cream-400/70 transition-colors" />
</a>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
side="top"
className="max-w-[300px] p-4 bg-navy-800/95 backdrop-blur-xl border border-navy-700/50 rounded-xl shadow-xl z-50"
sideOffset={8}
>
<p className="font-medium text-sm text-cream-100 line-clamp-2 mb-2">
{citation.title}
</p>
{citation.snippet && (
<p className="text-xs text-cream-400/70 line-clamp-3 mb-3">
{citation.snippet}
</p>
)}
<div className="flex items-center gap-2 text-2xs text-cream-500/60">
{citation.favicon && (
<img
src={citation.favicon}
alt=""
className="w-3 h-3 rounded"
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
}}
/>
)}
<span className="truncate">{citation.domain}</span>
</div>
<Tooltip.Arrow className="fill-navy-800" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
);
}
interface CitationListProps {
citations: CitationType[];
maxVisible?: number;
}
export function CitationList({ citations, maxVisible = 6 }: CitationListProps) {
if (!citations || citations.length === 0) return null;
const visible = citations.slice(0, maxVisible);
const remaining = citations.length - maxVisible;
return (
<div className="flex flex-wrap gap-2">
{visible.map((citation) => (
<Citation key={citation.index} citation={citation} />
))}
{remaining > 0 && (
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<button className="text-xs text-cream-500/70 hover:text-cream-300 px-2.5 py-1.5 rounded-lg hover:bg-navy-800/30 transition-colors">
+{remaining} ещё
</button>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
side="top"
className="max-w-[320px] p-3 bg-navy-800/95 backdrop-blur-xl border border-navy-700/50 rounded-xl shadow-xl z-50"
sideOffset={8}
>
<div className="space-y-2">
{citations.slice(maxVisible).map((citation) => (
<a
key={citation.index}
href={citation.url}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2 rounded-lg hover:bg-navy-700/50 transition-colors"
>
<span className="w-4 h-4 rounded bg-cream-300/10 text-cream-300 flex items-center justify-center text-2xs font-medium flex-shrink-0">
{citation.index}
</span>
<span className="text-xs text-cream-200 truncate">
{citation.title}
</span>
</a>
))}
</div>
<Tooltip.Arrow className="fill-navy-800" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
)}
</div>
);
}