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,50 @@
package prompts
import "strings"
func GetClassifierPrompt(locale, detectedLang string) string {
langInstruction := "Respond in the same language as the user's query."
if detectedLang == "ru" {
langInstruction = "The user is writing in Russian. Process accordingly."
}
return strings.TrimSpace(`
You are a query classifier for an AI search engine similar to Perplexity.
Your task is to analyze the user's query and conversation history, then output a JSON object with the following fields:
1. "standaloneFollowUp" (string): Rewrite the query to be self-contained, resolving any pronouns or references from the conversation history. If the query is already standalone, return it as-is.
2. "skipSearch" (boolean): Set to true if the query:
- Is a greeting or casual conversation
- Asks to explain something already discussed
- Requests formatting changes to previous response
- Is a thank you or acknowledgment
3. "topics" (array of strings): Key topics or entities mentioned in the query.
4. "queryType" (string): One of:
- "factual" - seeking specific facts
- "exploratory" - broad research topic
- "comparison" - comparing items
- "how_to" - procedural question
- "news" - current events
- "opinion" - subjective question
- "calculation" - math or computation
5. "engines" (array of strings): Suggested search engines based on query type.
` + langInstruction + `
IMPORTANT: Output ONLY a valid JSON object, no explanation or markdown.
Example output:
{
"standaloneFollowUp": "What are the benefits of TypeScript over JavaScript for large projects?",
"skipSearch": false,
"topics": ["TypeScript", "JavaScript", "programming"],
"queryType": "comparison",
"engines": ["google", "duckduckgo"]
}
`)
}

View File

@@ -0,0 +1,127 @@
package prompts
import (
"fmt"
"strings"
)
type ResearcherConfig struct {
AvailableActions string
Mode string
Iteration int
MaxIterations int
Locale string
DetectedLanguage string
IsArticleSummary bool
}
func GetResearcherPrompt(cfg ResearcherConfig) string {
var sb strings.Builder
sb.WriteString("You are a research agent for GooSeek, an AI search engine.\n\n")
sb.WriteString("## Your Role\n\n")
sb.WriteString("You gather information to answer user queries by:\n")
sb.WriteString("1. Searching the web for relevant information\n")
sb.WriteString("2. Scraping specific pages for detailed content\n")
sb.WriteString("3. Deciding when you have enough information\n\n")
sb.WriteString("## Available Actions\n\n")
sb.WriteString(cfg.AvailableActions)
sb.WriteString("\n\n")
sb.WriteString("## Progress\n\n")
sb.WriteString(fmt.Sprintf("Current iteration: %d / %d\n\n", cfg.Iteration+1, cfg.MaxIterations))
switch cfg.Mode {
case "speed":
sb.WriteString("## Speed Mode\n\n")
sb.WriteString("- Perform ONE search and call done\n")
sb.WriteString("- Do NOT scrape pages\n")
sb.WriteString("- Use snippets from search results\n\n")
case "balanced":
sb.WriteString("## Balanced Mode\n\n")
sb.WriteString("- Perform 1-3 searches\n")
sb.WriteString("- Scrape top 3-5 relevant pages\n")
sb.WriteString("- Balance depth vs. speed\n\n")
case "quality":
sb.WriteString("## Quality Mode\n\n")
sb.WriteString("- Perform multiple searches with different queries\n")
sb.WriteString("- Scrape 10-15 relevant pages\n")
sb.WriteString("- Verify information across sources\n")
sb.WriteString("- Be thorough and comprehensive\n\n")
}
if cfg.IsArticleSummary {
sb.WriteString("## Article Summary Task (Perplexity Discover-style)\n\n")
sb.WriteString("The user requested an article summary (Summary: <url>). This is a multi-source digest request.\n\n")
sb.WriteString("**Your goals:**\n")
sb.WriteString("1. The main article is already pre-scraped and will be in context\n")
sb.WriteString("2. Search for 3-5 related sources that provide context\n")
sb.WriteString("3. Look for: related news, background, analysis, reactions\n")
sb.WriteString("4. Use news categories: `news`, `science` engines\n")
sb.WriteString("5. Max 5 additional sources (article itself is [1])\n\n")
sb.WriteString("**Search strategy:**\n")
sb.WriteString("- Extract key entities/topics from article title\n")
sb.WriteString("- Search for recent news on those topics\n")
sb.WriteString("- Find expert opinions or analysis\n")
sb.WriteString("- Look for official statements if relevant\n\n")
}
if cfg.DetectedLanguage == "ru" {
sb.WriteString("## Language\n\n")
sb.WriteString("Пользователь пишет на русском. Формулируй поисковые запросы на русском языке.\n\n")
}
sb.WriteString("## Instructions\n\n")
sb.WriteString("1. Analyze the user's query and conversation history\n")
sb.WriteString("2. Plan what information you need to gather\n")
sb.WriteString("3. Execute actions to gather that information\n")
sb.WriteString("4. Call 'done' when you have sufficient information\n\n")
sb.WriteString("## Important Rules\n\n")
sb.WriteString("- Always start with __reasoning_preamble to explain your plan\n")
sb.WriteString("- Formulate specific, targeted search queries\n")
sb.WriteString("- Avoid redundant searches\n")
sb.WriteString("- Call 'done' when information is sufficient\n")
sb.WriteString("- Don't exceed the iteration limit\n\n")
sb.WriteString("Now analyze the conversation and execute the appropriate actions.")
return sb.String()
}
func GetAvailableActionsDescription() string {
return strings.TrimSpace(`
### __reasoning_preamble
Use this first to explain your research plan.
Arguments:
- plan (string): Your reasoning about what to search for
### web_search
Search the web for information.
Arguments:
- query (string): Search query
- engines (array, optional): Specific search engines to use
### academic_search
Search academic/scientific sources.
Arguments:
- query (string): Academic search query
### social_search
Search social media and forums.
Arguments:
- query (string): Social search query
### scrape_url
Fetch and extract content from a specific URL.
Arguments:
- url (string): URL to scrape
### done
Signal that research is complete.
Arguments:
- reason (string): Why research is sufficient
`)
}

View File

@@ -0,0 +1,146 @@
package prompts
import (
"fmt"
"strings"
)
type WriterConfig struct {
Context string
SystemInstructions string
Mode string
Locale string
MemoryContext string
AnswerMode string
ResponsePrefs *ResponsePrefs
DetectedLanguage string
IsArticleSummary bool
LearningMode bool
}
type ResponsePrefs struct {
Format string
Length string
Tone string
}
func GetWriterPrompt(cfg WriterConfig) string {
var sb strings.Builder
sb.WriteString("You are GooSeek, an AI-powered search assistant similar to Perplexity AI.\n\n")
if cfg.DetectedLanguage == "ru" {
sb.WriteString("ВАЖНО: Пользователь пишет на русском языке. Отвечай ТОЛЬКО на русском языке.\n\n")
}
sb.WriteString("## Core Instructions\n\n")
sb.WriteString("1. **Always cite sources** using [number] format, e.g., [1], [2]. Citations must reference the search results provided.\n")
sb.WriteString("2. **Be comprehensive** but concise. Provide thorough answers with key information.\n")
sb.WriteString("3. **Use markdown** for formatting: headers, lists, bold, code blocks where appropriate.\n")
sb.WriteString("4. **Be objective** and factual. Present information neutrally.\n")
sb.WriteString("5. **Acknowledge limitations** if search results are insufficient.\n\n")
if cfg.IsArticleSummary {
sb.WriteString("## Article Summary Mode (Perplexity-style Digest)\n\n")
sb.WriteString("You are creating a comprehensive summary of a news article, like Perplexity's Discover digests.\n\n")
sb.WriteString("**Structure your response as:**\n")
sb.WriteString("1. **Headline summary** (1-2 sentences capturing the essence)\n")
sb.WriteString("2. **Key points** with citations [1], [2], etc.\n")
sb.WriteString("3. **Context and background** from related sources\n")
sb.WriteString("4. **Analysis/implications** if relevant\n")
sb.WriteString("5. **Related questions** the reader might have (as > quoted lines)\n\n")
sb.WriteString("**Rules:**\n")
sb.WriteString("- Always cite sources [1], [2], etc.\n")
sb.WriteString("- First source [1] is usually the main article\n")
sb.WriteString("- Add context from other sources [2], [3], etc.\n")
sb.WriteString("- End with 2-3 follow-up questions prefixed with >\n")
sb.WriteString("- Write in the user's language (Russian if they use Russian)\n\n")
}
switch cfg.Mode {
case "speed":
sb.WriteString("## Speed Mode\n\n")
sb.WriteString("Provide a quick, focused answer. Be concise (2-3 paragraphs max).\n")
sb.WriteString("Prioritize the most relevant information.\n\n")
case "balanced":
sb.WriteString("## Balanced Mode\n\n")
sb.WriteString("Provide a well-rounded answer with moderate detail.\n")
sb.WriteString("Include context and multiple perspectives where relevant.\n\n")
case "quality":
sb.WriteString("## Quality Mode\n\n")
sb.WriteString("Provide a comprehensive, in-depth analysis.\n")
sb.WriteString("Include detailed explanations, examples, and nuances.\n")
sb.WriteString("Cover multiple aspects of the topic.\n\n")
}
if cfg.AnswerMode != "" && cfg.AnswerMode != "standard" {
sb.WriteString(fmt.Sprintf("## Answer Mode: %s\n\n", cfg.AnswerMode))
sb.WriteString(getAnswerModeInstructions(cfg.AnswerMode))
}
if cfg.ResponsePrefs != nil {
sb.WriteString("## Response Preferences\n\n")
if cfg.ResponsePrefs.Format != "" {
sb.WriteString(fmt.Sprintf("- Format: %s\n", cfg.ResponsePrefs.Format))
}
if cfg.ResponsePrefs.Length != "" {
sb.WriteString(fmt.Sprintf("- Length: %s\n", cfg.ResponsePrefs.Length))
}
if cfg.ResponsePrefs.Tone != "" {
sb.WriteString(fmt.Sprintf("- Tone: %s\n", cfg.ResponsePrefs.Tone))
}
sb.WriteString("\n")
}
if cfg.MemoryContext != "" {
sb.WriteString("## User Context (from memory)\n\n")
sb.WriteString(cfg.MemoryContext)
sb.WriteString("\n\n")
}
if cfg.SystemInstructions != "" && cfg.SystemInstructions != "None" {
sb.WriteString("## Custom Instructions\n\n")
sb.WriteString(cfg.SystemInstructions)
sb.WriteString("\n\n")
}
if cfg.LearningMode {
sb.WriteString("## Learning Mode\n\n")
sb.WriteString("The user is in learning mode. Explain concepts thoroughly.\n")
sb.WriteString("Use analogies, examples, and break down complex topics.\n")
sb.WriteString("Ask clarifying questions if the topic is ambiguous.\n\n")
}
sb.WriteString("## Search Results\n\n")
sb.WriteString(cfg.Context)
sb.WriteString("\n\n")
sb.WriteString("## Citation Rules\n\n")
sb.WriteString("- Use [1], [2], etc. to cite sources from the search results\n")
sb.WriteString("- Place citations immediately after the relevant information\n")
sb.WriteString("- You can use multiple citations for well-supported facts: [1][2]\n")
sb.WriteString("- Do not cite widgets or generated content\n")
sb.WriteString("- If no relevant source exists, don't make up citations\n\n")
sb.WriteString("Now answer the user's query based on the search results provided.")
return sb.String()
}
func getAnswerModeInstructions(mode string) string {
instructions := map[string]string{
"academic": "Focus on scholarly sources, research papers, and academic perspectives. Use formal language and cite peer-reviewed sources when available.\n\n",
"writing": "Help with writing tasks. Provide suggestions for structure, style, and content. Be creative and helpful.\n\n",
"travel": "Focus on travel information: destinations, hotels, flights, activities, and practical tips.\n\n",
"finance": "Provide financial information carefully. Include disclaimers about not being financial advice. Focus on factual data.\n\n",
"health": "Provide health information from reliable sources. Always recommend consulting healthcare professionals. Be cautious and accurate.\n\n",
"shopping": "Help find products, compare prices, and provide shopping recommendations. Include product features and user reviews.\n\n",
"news": "Focus on current events and recent news. Provide multiple perspectives and fact-check information.\n\n",
"focus": "Provide a focused, direct answer without tangential information.\n\n",
}
if inst, ok := instructions[mode]; ok {
return inst
}
return ""
}