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

@@ -3,76 +3,244 @@ import dynamic from 'next/dynamic';
import { Widget } from '../ChatWindow';
import Weather from './Weather';
import Calculation from './Calculation';
import CardGallery from './CardGallery';
import KnowledgeCard from './KnowledgeCard';
import InlineImageGallery from './InlineImageGallery';
import VideoEmbed from './VideoEmbed';
import ProductCard from './ProductCard';
import VideoCard from './VideoCard';
import ProfileCard from './ProfileCard';
import PromoCard from './PromoCard';
const Stock = dynamic(() => import('./Stock'), { ssr: false });
const Renderer = ({ widgets }: { widgets: Widget[] }) => {
return widgets.map((widget, index) => {
switch (widget.widgetType) {
case 'weather':
return (
<Weather
key={index}
location={widget.params.location}
current={widget.params.current}
daily={widget.params.daily}
timezone={widget.params.timezone}
/>
);
case 'calculation_result':
return (
<Calculation
expression={widget.params.expression}
result={widget.params.result}
key={index}
/>
);
case 'stock':
return (
<Stock
key={index}
symbol={widget.params.symbol}
shortName={widget.params.shortName}
longName={widget.params.longName}
exchange={widget.params.exchange}
currency={widget.params.currency}
marketState={widget.params.marketState}
regularMarketPrice={widget.params.regularMarketPrice}
regularMarketChange={widget.params.regularMarketChange}
regularMarketChangePercent={
widget.params.regularMarketChangePercent
}
regularMarketPreviousClose={
widget.params.regularMarketPreviousClose
}
regularMarketOpen={widget.params.regularMarketOpen}
regularMarketDayHigh={widget.params.regularMarketDayHigh}
regularMarketDayLow={widget.params.regularMarketDayLow}
regularMarketVolume={widget.params.regularMarketVolume}
averageDailyVolume3Month={widget.params.averageDailyVolume3Month}
marketCap={widget.params.marketCap}
fiftyTwoWeekLow={widget.params.fiftyTwoWeekLow}
fiftyTwoWeekHigh={widget.params.fiftyTwoWeekHigh}
trailingPE={widget.params.trailingPE}
forwardPE={widget.params.forwardPE}
dividendYield={widget.params.dividendYield}
earningsPerShare={widget.params.earningsPerShare}
website={widget.params.website}
postMarketPrice={widget.params.postMarketPrice}
postMarketChange={widget.params.postMarketChange}
postMarketChangePercent={widget.params.postMarketChangePercent}
preMarketPrice={widget.params.preMarketPrice}
preMarketChange={widget.params.preMarketChange}
preMarketChangePercent={widget.params.preMarketChangePercent}
chartData={widget.params.chartData}
comparisonData={widget.params.comparisonData}
error={widget.params.error}
/>
);
default:
return <div key={index}>Unknown widget type: {widget.widgetType}</div>;
}
});
return (
<div className="space-y-4">
{widgets.map((widget, index) => {
switch (widget.widgetType) {
case 'weather':
return (
<Weather
key={index}
location={widget.params.location}
current={widget.params.current}
daily={widget.params.daily}
timezone={widget.params.timezone}
/>
);
case 'calculation_result':
return (
<Calculation
key={index}
expression={widget.params.expression}
result={widget.params.result}
/>
);
case 'stock':
return (
<Stock
key={index}
symbol={widget.params.symbol}
shortName={widget.params.shortName}
longName={widget.params.longName}
exchange={widget.params.exchange}
currency={widget.params.currency}
marketState={widget.params.marketState}
regularMarketPrice={widget.params.regularMarketPrice}
regularMarketChange={widget.params.regularMarketChange}
regularMarketChangePercent={widget.params.regularMarketChangePercent}
regularMarketPreviousClose={widget.params.regularMarketPreviousClose}
regularMarketOpen={widget.params.regularMarketOpen}
regularMarketDayHigh={widget.params.regularMarketDayHigh}
regularMarketDayLow={widget.params.regularMarketDayLow}
regularMarketVolume={widget.params.regularMarketVolume}
averageDailyVolume3Month={widget.params.averageDailyVolume3Month}
marketCap={widget.params.marketCap}
fiftyTwoWeekLow={widget.params.fiftyTwoWeekLow}
fiftyTwoWeekHigh={widget.params.fiftyTwoWeekHigh}
trailingPE={widget.params.trailingPE}
forwardPE={widget.params.forwardPE}
dividendYield={widget.params.dividendYield}
earningsPerShare={widget.params.earningsPerShare}
website={widget.params.website}
postMarketPrice={widget.params.postMarketPrice}
postMarketChange={widget.params.postMarketChange}
postMarketChangePercent={widget.params.postMarketChangePercent}
preMarketPrice={widget.params.preMarketPrice}
preMarketChange={widget.params.preMarketChange}
preMarketChangePercent={widget.params.preMarketChangePercent}
chartData={widget.params.chartData}
comparisonData={widget.params.comparisonData}
error={widget.params.error}
/>
);
case 'products':
return (
<CardGallery
key={index}
type="product"
items={widget.params.items}
title={widget.params.title}
/>
);
case 'videos':
return (
<CardGallery
key={index}
type="video"
items={widget.params.items}
title={widget.params.title}
/>
);
case 'profiles':
return (
<CardGallery
key={index}
type="profile"
items={widget.params.items}
title={widget.params.title}
/>
);
case 'promos':
return (
<CardGallery
key={index}
type="promo"
items={widget.params.items}
title={widget.params.title}
/>
);
case 'knowledge_card':
return (
<KnowledgeCard
key={index}
title={widget.params.card.title}
data={widget.params.card.data}
source={widget.params.card.source}
sourceUrl={widget.params.card.sourceUrl}
lastUpdated={widget.params.card.lastUpdated}
/>
);
case 'image_gallery':
return (
<InlineImageGallery
key={index}
images={widget.params.images}
layout={widget.params.layout || 'grid'}
/>
);
case 'video_embed':
return (
<VideoEmbed
key={index}
platform={widget.params.video.platform}
videoId={widget.params.video.id}
url={widget.params.video.url}
embedUrl={widget.params.video.embedUrl}
thumbnail={widget.params.video.thumbnail}
title={widget.params.video.title}
duration={widget.params.video.duration}
views={widget.params.video.views}
likes={widget.params.video.likes}
author={widget.params.video.author}
authorUrl={widget.params.video.authorUrl}
publishedAt={widget.params.video.publishedAt}
autoplay={widget.params.autoplay}
/>
);
case 'product':
return (
<ProductCard
key={index}
title={widget.params.title}
price={widget.params.price}
currency={widget.params.currency}
oldPrice={widget.params.oldPrice}
discount={widget.params.discount}
image={widget.params.image}
url={widget.params.url}
rating={widget.params.rating}
reviewCount={widget.params.reviewCount}
seller={widget.params.seller}
marketplace={widget.params.marketplace}
inStock={widget.params.inStock}
deliveryInfo={widget.params.deliveryInfo}
badges={widget.params.badges}
/>
);
case 'video':
return (
<VideoCard
key={index}
title={widget.params.title}
thumbnail={widget.params.thumbnail}
url={widget.params.url}
duration={widget.params.duration}
views={widget.params.views}
likes={widget.params.likes}
author={widget.params.author}
authorUrl={widget.params.authorUrl}
authorAvatar={widget.params.authorAvatar}
platform={widget.params.platform}
publishedAt={widget.params.publishedAt}
description={widget.params.description}
/>
);
case 'profile':
return (
<ProfileCard
key={index}
name={widget.params.name}
username={widget.params.username}
avatar={widget.params.avatar}
url={widget.params.url}
platform={widget.params.platform}
followers={widget.params.followers}
following={widget.params.following}
verified={widget.params.verified}
description={widget.params.description}
isOnline={widget.params.isOnline}
/>
);
case 'promo':
return (
<PromoCard
key={index}
code={widget.params.code}
discount={widget.params.discount}
discountType={widget.params.discountType}
discountValue={widget.params.discountValue}
store={widget.params.store}
storeLogo={widget.params.storeLogo}
storeUrl={widget.params.storeUrl}
url={widget.params.url}
expiresAt={widget.params.expiresAt}
conditions={widget.params.conditions}
minOrderAmount={widget.params.minOrderAmount}
verified={widget.params.verified}
/>
);
default:
return null;
}
})}
</div>
);
};
export default Renderer;