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
144 lines
3.4 KiB
Go
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")
|
|
}
|
|
}
|