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:
102
backend/internal/types/blocks.go
Normal file
102
backend/internal/types/blocks.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package types
|
||||
|
||||
type BlockType string
|
||||
|
||||
const (
|
||||
BlockTypeText BlockType = "text"
|
||||
BlockTypeResearch BlockType = "research"
|
||||
BlockTypeSource BlockType = "source"
|
||||
BlockTypeWidget BlockType = "widget"
|
||||
BlockTypeThinking BlockType = "thinking"
|
||||
)
|
||||
|
||||
type Block struct {
|
||||
ID string `json:"id"`
|
||||
Type BlockType `json:"type"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type TextBlock struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
type ResearchBlock struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Data ResearchData `json:"data"`
|
||||
}
|
||||
|
||||
type ResearchData struct {
|
||||
SubSteps []ResearchSubStep `json:"subSteps"`
|
||||
}
|
||||
|
||||
type ResearchSubStep struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Reasoning string `json:"reasoning,omitempty"`
|
||||
Searching []string `json:"searching,omitempty"`
|
||||
Reading []Chunk `json:"reading,omitempty"`
|
||||
}
|
||||
|
||||
type SourceBlock struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Data []Chunk `json:"data"`
|
||||
}
|
||||
|
||||
type WidgetBlock struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Data WidgetData `json:"data"`
|
||||
}
|
||||
|
||||
type WidgetData struct {
|
||||
WidgetType string `json:"widgetType"`
|
||||
Params interface{} `json:"params"`
|
||||
}
|
||||
|
||||
type StreamEvent struct {
|
||||
Type string `json:"type"`
|
||||
Block *Block `json:"block,omitempty"`
|
||||
BlockID string `json:"blockId,omitempty"`
|
||||
Chunk string `json:"chunk,omitempty"`
|
||||
Patch interface{} `json:"patch,omitempty"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func NewTextBlock(id, content string) *Block {
|
||||
return &Block{
|
||||
ID: id,
|
||||
Type: BlockTypeText,
|
||||
Data: content,
|
||||
}
|
||||
}
|
||||
|
||||
func NewResearchBlock(id string) *Block {
|
||||
return &Block{
|
||||
ID: id,
|
||||
Type: BlockTypeResearch,
|
||||
Data: ResearchData{SubSteps: []ResearchSubStep{}},
|
||||
}
|
||||
}
|
||||
|
||||
func NewSourceBlock(id string, chunks []Chunk) *Block {
|
||||
return &Block{
|
||||
ID: id,
|
||||
Type: BlockTypeSource,
|
||||
Data: chunks,
|
||||
}
|
||||
}
|
||||
|
||||
func NewWidgetBlock(id, widgetType string, params interface{}) *Block {
|
||||
return &Block{
|
||||
ID: id,
|
||||
Type: BlockTypeWidget,
|
||||
Data: WidgetData{
|
||||
WidgetType: widgetType,
|
||||
Params: params,
|
||||
},
|
||||
}
|
||||
}
|
||||
75
backend/internal/types/chunks.go
Normal file
75
backend/internal/types/chunks.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package types
|
||||
|
||||
type Chunk struct {
|
||||
Content string `json:"content"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type SearchResult struct {
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Thumbnail string `json:"thumbnail,omitempty"`
|
||||
ImgSrc string `json:"img_src,omitempty"`
|
||||
ThumbnailSrc string `json:"thumbnail_src,omitempty"`
|
||||
IframeSrc string `json:"iframe_src,omitempty"`
|
||||
Author string `json:"author,omitempty"`
|
||||
PublishedDate string `json:"publishedDate,omitempty"`
|
||||
Engine string `json:"engine,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
Score float64 `json:"score,omitempty"`
|
||||
Price string `json:"price,omitempty"`
|
||||
Currency string `json:"currency,omitempty"`
|
||||
Duration interface{} `json:"duration,omitempty"`
|
||||
Views interface{} `json:"views,omitempty"`
|
||||
}
|
||||
|
||||
type SearchResponse struct {
|
||||
Results []SearchResult `json:"results"`
|
||||
Suggestions []string `json:"suggestions,omitempty"`
|
||||
}
|
||||
|
||||
type ContentCategory string
|
||||
|
||||
const (
|
||||
CategoryProduct ContentCategory = "product"
|
||||
CategoryVideo ContentCategory = "video"
|
||||
CategoryProfile ContentCategory = "profile"
|
||||
CategoryPromo ContentCategory = "promo"
|
||||
CategoryImage ContentCategory = "image"
|
||||
CategoryArticle ContentCategory = "article"
|
||||
)
|
||||
|
||||
func (r *SearchResult) ToChunk() Chunk {
|
||||
metadata := map[string]string{
|
||||
"title": r.Title,
|
||||
"url": r.URL,
|
||||
}
|
||||
if r.Thumbnail != "" {
|
||||
metadata["thumbnail"] = r.Thumbnail
|
||||
}
|
||||
if r.Author != "" {
|
||||
metadata["author"] = r.Author
|
||||
}
|
||||
if r.PublishedDate != "" {
|
||||
metadata["publishedDate"] = r.PublishedDate
|
||||
}
|
||||
|
||||
content := r.Content
|
||||
if content == "" {
|
||||
content = r.Title
|
||||
}
|
||||
|
||||
return Chunk{
|
||||
Content: content,
|
||||
Metadata: metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func SearchResultsToChunks(results []SearchResult) []Chunk {
|
||||
chunks := make([]Chunk, 0, len(results))
|
||||
for _, r := range results {
|
||||
chunks = append(chunks, r.ToChunk())
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
145
backend/internal/types/widgets.go
Normal file
145
backend/internal/types/widgets.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package types
|
||||
|
||||
type WidgetType string
|
||||
|
||||
const (
|
||||
WidgetWeather WidgetType = "weather"
|
||||
WidgetCalculator WidgetType = "calculator"
|
||||
WidgetProducts WidgetType = "products"
|
||||
WidgetVideos WidgetType = "videos"
|
||||
WidgetProfiles WidgetType = "profiles"
|
||||
WidgetPromos WidgetType = "promos"
|
||||
WidgetImageGallery WidgetType = "image_gallery"
|
||||
WidgetVideoEmbed WidgetType = "video_embed"
|
||||
WidgetKnowledge WidgetType = "knowledge_card"
|
||||
)
|
||||
|
||||
type ProductData struct {
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
Price float64 `json:"price"`
|
||||
OldPrice float64 `json:"oldPrice,omitempty"`
|
||||
Currency string `json:"currency"`
|
||||
Discount int `json:"discount,omitempty"`
|
||||
Rating float64 `json:"rating,omitempty"`
|
||||
ReviewCount int `json:"reviewCount,omitempty"`
|
||||
ImageURL string `json:"imageUrl,omitempty"`
|
||||
Marketplace string `json:"marketplace"`
|
||||
InStock bool `json:"inStock"`
|
||||
Badges []Badge `json:"badges,omitempty"`
|
||||
}
|
||||
|
||||
type VideoData struct {
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
Thumbnail string `json:"thumbnail,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
Views int `json:"views,omitempty"`
|
||||
Likes int `json:"likes,omitempty"`
|
||||
Author string `json:"author,omitempty"`
|
||||
Platform string `json:"platform"`
|
||||
EmbedURL string `json:"embedUrl,omitempty"`
|
||||
}
|
||||
|
||||
type ProfileData struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username,omitempty"`
|
||||
URL string `json:"url"`
|
||||
AvatarURL string `json:"avatarUrl,omitempty"`
|
||||
Bio string `json:"bio,omitempty"`
|
||||
Followers int `json:"followers,omitempty"`
|
||||
Following int `json:"following,omitempty"`
|
||||
Platform string `json:"platform"`
|
||||
Verified bool `json:"verified"`
|
||||
IsOnline bool `json:"isOnline,omitempty"`
|
||||
LastOnline string `json:"lastOnline,omitempty"`
|
||||
}
|
||||
|
||||
type PromoData struct {
|
||||
Code string `json:"code"`
|
||||
Description string `json:"description"`
|
||||
Discount string `json:"discount"`
|
||||
Store string `json:"store"`
|
||||
StoreURL string `json:"storeUrl"`
|
||||
LogoURL string `json:"logoUrl,omitempty"`
|
||||
ExpiresAt string `json:"expiresAt,omitempty"`
|
||||
Conditions string `json:"conditions,omitempty"`
|
||||
Verified bool `json:"verified"`
|
||||
}
|
||||
|
||||
type ImageData struct {
|
||||
URL string `json:"url"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Source string `json:"source,omitempty"`
|
||||
SourceURL string `json:"sourceUrl,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
}
|
||||
|
||||
type Badge struct {
|
||||
Text string `json:"text"`
|
||||
Type string `json:"type"`
|
||||
Color string `json:"color,omitempty"`
|
||||
}
|
||||
|
||||
type KnowledgeCardData struct {
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Content interface{} `json:"content"`
|
||||
}
|
||||
|
||||
type ComparisonTable struct {
|
||||
Headers []string `json:"headers"`
|
||||
Rows [][]string `json:"rows"`
|
||||
}
|
||||
|
||||
type StatCard struct {
|
||||
Label string `json:"label"`
|
||||
Value string `json:"value"`
|
||||
Change float64 `json:"change,omitempty"`
|
||||
Unit string `json:"unit,omitempty"`
|
||||
}
|
||||
|
||||
type Timeline struct {
|
||||
Events []TimelineEvent `json:"events"`
|
||||
}
|
||||
|
||||
type TimelineEvent struct {
|
||||
Date string `json:"date"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
type WeatherParams struct {
|
||||
Location string `json:"location"`
|
||||
Current WeatherCurrent `json:"current"`
|
||||
Forecast []WeatherDay `json:"forecast,omitempty"`
|
||||
LastUpdated string `json:"lastUpdated,omitempty"`
|
||||
}
|
||||
|
||||
type WeatherCurrent struct {
|
||||
Temp float64 `json:"temp"`
|
||||
FeelsLike float64 `json:"feelsLike"`
|
||||
Humidity int `json:"humidity"`
|
||||
WindSpeed float64 `json:"windSpeed"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
|
||||
type WeatherDay struct {
|
||||
Date string `json:"date"`
|
||||
TempMax float64 `json:"tempMax"`
|
||||
TempMin float64 `json:"tempMin"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
|
||||
type CalculatorParams struct {
|
||||
Expression string `json:"expression"`
|
||||
Result float64 `json:"result"`
|
||||
Steps []Step `json:"steps,omitempty"`
|
||||
}
|
||||
|
||||
type Step struct {
|
||||
Description string `json:"description"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
Reference in New Issue
Block a user