Files
home 06fe57c765 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
2026-02-27 04:15:32 +03:00

144 lines
3.4 KiB
Go

package main
import (
"context"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gooseek/backend/internal/search"
"github.com/gooseek/backend/pkg/config"
)
func main() {
cfg, err := config.Load()
if err != nil {
log.Fatal("Failed to load config:", err)
}
searchClient := search.NewSearXNGClient(cfg)
app := fiber.New(fiber.Config{
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 60 * time.Second,
})
app.Use(logger.New())
app.Use(cors.New())
app.Get("/health", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "ok"})
})
app.Get("/api/v1/search", func(c *fiber.Ctx) error {
query := c.Query("q")
if query == "" {
return c.Status(400).JSON(fiber.Map{"error": "Query parameter 'q' is required"})
}
opts := &search.SearchOptions{}
if engines := c.Query("engines"); engines != "" {
opts.Engines = strings.Split(engines, ",")
}
if categories := c.Query("categories"); categories != "" {
opts.Categories = strings.Split(categories, ",")
}
if pageno := c.QueryInt("pageno", 1); pageno > 0 {
opts.PageNo = pageno
}
if lang := c.Query("language"); lang != "" {
opts.Language = lang
}
ctx, cancel := context.WithTimeout(context.Background(), cfg.SearchTimeout)
defer cancel()
result, err := searchClient.Search(ctx, query, opts)
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(result)
})
app.Get("/api/v1/search/images", func(c *fiber.Ctx) error {
query := c.Query("q")
if query == "" {
return c.Status(400).JSON(fiber.Map{"error": "Query parameter 'q' is required"})
}
ctx, cancel := context.WithTimeout(context.Background(), cfg.SearchTimeout)
defer cancel()
result, err := searchClient.Search(ctx, query, &search.SearchOptions{
Categories: []string{"images"},
PageNo: 1,
})
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(result)
})
app.Get("/api/v1/search/videos", func(c *fiber.Ctx) error {
query := c.Query("q")
if query == "" {
return c.Status(400).JSON(fiber.Map{"error": "Query parameter 'q' is required"})
}
ctx, cancel := context.WithTimeout(context.Background(), cfg.SearchTimeout)
defer cancel()
result, err := searchClient.Search(ctx, query, &search.SearchOptions{
Categories: []string{"videos"},
PageNo: 1,
})
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(result)
})
app.Get("/api/v1/search/media", func(c *fiber.Ctx) error {
query := c.Query("q")
if query == "" {
return c.Status(400).JSON(fiber.Map{"error": "Query parameter 'q' is required"})
}
maxImages := c.QueryInt("maxImages", 8)
maxVideos := c.QueryInt("maxVideos", 6)
ctx, cancel := context.WithTimeout(context.Background(), cfg.SearchTimeout*2)
defer cancel()
result, err := searchClient.SearchMedia(ctx, query, &search.MediaSearchOptions{
MaxImages: maxImages,
MaxVideos: maxVideos,
})
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(result)
})
port := cfg.SearchSvcPort
log.Printf("search-svc listening on :%d", port)
log.Fatal(app.Listen(fmt.Sprintf(":%d", port)))
}
func init() {
if os.Getenv("PORT") == "" {
os.Setenv("PORT", "3001")
}
}