Files

1 line
68 KiB
JSON

{"repo": "aldotobing/neurogo", "files": {"cmd/server/main.go": {"36e66763d10a480523ee5edaefe64879c37a5cfc": {"t": 1785745626.6245806, "n": 31716, "h": "e179539cedc4fefb", "c": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/joho/godotenv\"\n\t\"github.com/rs/cors\"\n\n\t\"github.com/aldotobing/neurogo/config\"\n\t\"github.com/aldotobing/neurogo/providers\"\n\t\"github.com/aldotobing/neurogo/router\"\n\t\"github.com/aldotobing/neurogo/server\"\n)\n\n// Global provider registry and current provider\nvar providerRegistry = make(map[string]providers.Provider)\nvar currentProvider = \"\"\n\nfunc main() {\n\t// Debug: Print current working directory and file existence\n\tif cwd, err := os.Getwd(); err == nil {\n\t\tlog.Printf(\"🔍 Current working directory: %s\", cwd)\n\t}\n\n\t// Check if web files exist\n\twebFiles := []string{\"../../web/docs.html\", \"../../web/index.html\", \"../../web/static/app.js\", \"../../web/static/style.css\"}\n\tfor _, file := range webFiles {\n\t\tif _, err := os.Stat(file); err == nil {\n\t\t\tlog.Printf(\"✅ Found: %s\", file)\n\t\t} else {\n\t\t\tlog.Printf(\"❌ Missing: %s\", file)\n\t\t}\n\t}\n\n\t// Load environment variables with better error handling\n\tloadEnvironment()\n\n\t// Initialize the NeuroGO router\n\tneuroRouter := router.New()\n\n\t// Configure providers\n\tsetupProviders(neuroRouter)\n\n\t// Setup universal routes (works with any provider)\n\tsetupUniversalRoutes(neuroRouter)\n\n\t// Setup provider switching routes\n\tsetupProviderSwitchingRoutes(neuroRouter)\n\n\t// Setup example routes\n\tsetupExampleRoutes(neuroRouter)\n\n\t// Create HTTP server\n\thttpRouter := mux.NewRouter()\n\n\t// Setup API routes\n\tapi := httpRouter.PathPrefix(\"/api\").Subrouter()\n\tserver.SetupAPIRoutes(api, neuroRouter)\n\n\t// Setup WebSocket for real-time communication\n\tserver.SetupWebSocket(httpRouter, neuroRouter)\n\n\t// Serve static files for the playground\n\tsetupStaticFiles(httpRouter)\n\n\t// Setup CORS\n\tc := cors.New(cors.Options{\n\t\tAllowedOrigins: []string{\"*\"},\n\t\tAllowedMethods: []string{\"GET\", \"POST\", \"PUT\", \"DELETE\", \"OPTIONS\"},\n\t\tAllowedHeaders: []string{\"*\"},\n\t})\n\n\thandler := c.Handler(httpRouter)\n\n\tport := os.Getenv(\"PORT\")\n\tif port == \"\" {\n\t\tport = \"8080\"\n\t}\n\n\tfmt.Printf(\"🚀 NeuroGO server starting on port %s\\n\", port)\n\tfmt.Printf(\"📱 Playground UI: http://localhost:%s\\n\", port)\n\tfmt.Printf(\"📚 API Documentation: http://localhost:%s/docs\\n\", port)\n\tfmt.Printf(\"🔗 API Endpoint: http://localhost:%s/api\\n\", port)\n\n\tlog.Fatal(http.ListenAndServe(\":\"+port, handler))\n}\n\n// loadEnvironment loads environment variables with better error handling\nfunc loadEnvironment() {\n\t// Try to load .env file from current directory\n\tif err := godotenv.Load(); err != nil {\n\t\t// Try to load from parent directory (in case we're in cmd/server)\n\t\tif err := godotenv.Load(\"../../.env\"); err != nil {\n\t\t\tlog.Println(\"No .env file found, using system environment variables\")\n\t\t} else {\n\t\t\tlog.Println(\"✅ Loaded .env file from parent directory\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"✅ Loaded .env file successfully\")\n\t}\n\n\t// Debug: Print which environment variables are set\n\tdebugEnvironmentVariables()\n}\n\n// debugEnvironmentVariables prints which environment variables are detected\nfunc debugEnvironmentVariables() {\n\tenvVars := []string{\n\t\t\"OPENAI_API_KEY\",\n\t\t\"DEEPSEEK_API_KEY\",\n\t\t\"GEMINI_API_KEY\",\n\t\t\"HUGGINGFACE_API_KEY\",\n\t\t\"OLLAMA_HOST\",\n\t}\n\n\tlog.Println(\"🔍 Environment Variables Status:\")\n\tfor _, envVar := range envVars {\n\t\tvalue := os.Getenv(envVar)\n\t\tif value != \"\" {\n\t\t\t// Don't print the full API key for security\n\t\t\tif len(value) > 10 {\n\t\t\t\tlog.Printf(\" ✅ %s: %s...%s\", envVar, value[:4], value[len(value)-4:])\n\t\t\t} else {\n\t\t\t\tlog.Printf(\" ✅ %s: %s\", envVar, value)\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Printf(\" ❌ %s: not set\", envVar)\n\t\t}\n\t}\n}\n\n// getCurrentProvider returns the currently selected provider or the best available one\nfunc getCurrentProvider(taskType string) providers.Provider {\n\t// If a specific provider is selected, use it\n\tif currentProvider != \"\" {\n\t\tif provider, exists := providerRegistry[currentProvider]; exists {\n\t\t\treturn provider\n\t\t}\n\t}\n\n\t// Otherwise, use the best provider for the task type\n\treturn getBestProvider(taskType)\n}\n\n// getBestProvider returns the best available provider for a given task type\nfunc getBestProvider(taskType string) providers.Provider {\n\t// Provider preferences for different task types\n\tpreferences := map[string][]string{\n\t\t\"translation\": {\"Gemini\", \"OpenAI\", \"DeepSeek\", \"Ollama\"},\n\t\t\"reasoning\": {\"DeepSeek\", \"OpenAI\", \"Gemini\", \"Ollama\"},\n\t\t\"coding\": {\"Ollama\", \"OpenAI\", \"DeepSeek\", \"Gemini\"},\n\t\t\"summary\": {\"OpenAI\", \"DeepSeek\", \"Gemini\", \"Ollama\"},\n\t\t\"general\": {\"OpenAI\", \"DeepSeek\", \"Gemini\", \"Ollama\"},\n\t}\n\n\tproviderList, exists := preferences[taskType]\n\tif !exists {\n\t\tproviderList = preferences[\"general\"]\n\t}\n\n\t// Return the first available provider from the preference list\n\tfor _, providerName := range providerList {\n\t\tif provider, exists := providerRegistry[providerName]; exists {\n\t\t\treturn provider\n\t\t}\n\t}\n\n\t// Fallback: return any available provider\n\tfor _, provider := range providerRegistry {\n\t\treturn provider\n\t}\n\n\treturn nil\n}\n\n// getProviderList returns a list of available provider names\nfunc getProviderList() []string {\n\tvar providers []string\n\tfor name := range providerRegistry {\n\t\tproviders = append(providers, name)\n\t}\n\treturn providers\n}\n\nfunc setupProviders(r *router.Router) {\n\tavailableProviders := []string{}\n\n\t// OpenAI Provider\n\tif apiKey := os.Getenv(\"OPENAI_API_KEY\"); apiKey != \"\" {\n\t\topenAIProvider := providers.NewOpenAI(apiKey)\n\t\tif openAIProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"OpenAI\"] = openAIProvider\n\t\t\tavailableProviders = append(availableProviders, \"OpenAI\")\n\t\t\tlog.Println(\"✅ OpenAI provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ OpenAI provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ OpenAI API key not provided\")\n\t}\n\n\t// DeepSeek Provider\n\tif apiKey := os.Getenv(\"DEEPSEEK_API_KEY\"); apiKey != \"\" {\n\t\tdeepSeekProvider := providers.NewDeepSeek(apiKey)\n\t\tif deepSeekProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"DeepSeek\"] = deepSeekProvider\n\t\t\tavailableProviders = append(availableProviders, \"DeepSeek\")\n\t\t\tlog.Println(\"✅ DeepSeek provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ DeepSeek provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ DeepSeek API key not provided\")\n\t}\n\n\t// Gemini Provider\n\tif apiKey := os.Getenv(\"GEMINI_API_KEY\"); apiKey != \"\" {\n\t\tgeminiProvider := providers.NewGemini(apiKey)\n\t\tif geminiProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"Gemini\"] = geminiProvider\n\t\t\tavailableProviders = append(availableProviders, \"Gemini\")\n\t\t\tlog.Println(\"✅ Gemini provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ Gemini provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ Gemini API key not provided\")\n\t}\n\n\t// Ollama Provider\n\tollamaHost := os.Getenv(\"OLLAMA_HOST\")\n\tif ollamaHost == \"\" {\n\t\tollamaHost = \"http://localhost:11434\"\n\t}\n\n\tlog.Printf(\"🔍 Checking Ollama at: %s\", ollamaHost)\n\tollamaProvider := providers.NewOllama(ollamaHost)\n\tif ollamaProvider.IsAvailable() {\n\t\tproviderRegistry[\"Ollama\"] = ollamaProvider\n\t\tavailableProviders = append(availableProviders, \"Ollama\")\n\t\tlog.Println(\"✅ Ollama provider configured\")\n\t} else {\n\t\tlog.Printf(\"⚠️ Ollama not available - make sure Ollama is running on %s\", ollamaHost)\n\t}\n\n\t// HuggingFace Provider\n\tif apiKey := os.Getenv(\"HUGGINGFACE_API_KEY\"); apiKey != \"\" {\n\t\thfProvider := providers.NewHuggingFace(apiKey)\n\t\tif hfProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"HuggingFace\"] = hfProvider\n\t\t\tavailableProviders = append(availableProviders, \"HuggingFace\")\n\t\t\tlog.Println(\"✅ HuggingFace provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ HuggingFace provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ HuggingFace API key not provided\")\n\t}\n\n\t// Set default provider to the first available one\n\tif len(availableProviders) > 0 && currentProvider == \"\" {\n\t\tcurrentProvider = availableProviders[0]\n\t\tlog.Printf(\"🎯 Default provider set to: %s\", currentProvider)\n\t}\n\n\t// Log summary\n\tif len(availableProviders) == 0 {\n\t\tlog.Println(\"⚠️ No AI providers configured. Only basic commands will work.\")\n\t\tlog.Println(\"💡 To get started with Ollama: run 'ollama serve' and 'ollama pull llama2'\")\n\t\tlog.Println(\"💡 Or add API keys to your .env file for cloud providers\")\n\t} else {\n\t\tlog.Printf(\"🎉 Configured providers: %v\", availableProviders)\n\t}\n}\n\n// setupProviderSwitchingRoutes creates routes for switching between providers\nfunc setupProviderSwitchingRoutes(r *router.Router) {\n\t// Switch to a specific provider\n\tr.Handle(\"use *\", func(ctx *router.Context) error {\n\t\tproviderName := normalizeProviderName(ctx.Captures[0])\n\n\t\tif _, exists := providerRegistry[providerName]; exists {\n\t\t\tcurrentProvider = providerName\n\t\t\tctx.Response = fmt.Sprintf(\"✅ Switched to %s provider. All subsequent commands will use %s.\", providerName, providerName)\n\t\t} else {\n\t\t\tavailableProviders := getProviderList()\n\t\t\tctx.Response = fmt.Sprintf(\"❌ Provider '%s' not available. Available providers: %s\",\n\t\t\t\tctx.Captures[0], strings.Join(availableProviders, \", \"))\n\t\t}\n\t\treturn nil\n\t})\n\n\t// Switch to auto mode (best provider for each task)\n\tr.Handle(\"use auto\", func(ctx *router.Context) error {\n\t\tcurrentProvider = \"\"\n\t\tctx.Response = \"✅ Switched to auto mode. The system will automatically choose the best provider for each task.\"\n\t\treturn nil\n\t})\n\n\t// Show current provider\n\tr.Handle(\"current provider\", func(ctx *router.Context) error {\n\t\tif currentProvider == \"\" {\n\t\t\tctx.Response = \"🤖 Currently in auto mode - the system chooses the best provider for each task.\"\n\t\t} else {\n\t\t\tctx.Response = fmt.Sprintf(\"🎯 Currently using: %s\", currentProvider)\n\t\t}\n\t\treturn nil\n\t})\n\n\t// List all available providers\n\tr.Handle(\"list providers\", func(ctx *router.Context) error {\n\t\tproviders := getProviderList()\n\t\tif len(providers) == 0 {\n\t\t\tctx.Response = \"❌ No providers configured.\"\n\t\t\treturn nil\n\t\t}\n\n\t\tresponse := \"📋 Available providers:\\n\\n\"\n\t\tfor _, name := range providers {\n\t\t\tif name == currentProvider {\n\t\t\t\tresponse += fmt.Sprintf(\"🎯 %s (currently selected)\\n\", name)\n\t\t\t} else {\n\t\t\t\tresponse += fmt.Sprintf(\" %s\\n\", name)\n\t\t\t}\n\t\t}\n\n\t\tresponse += \"\\n💡 Commands:\\n\"\n\t\tresponse += \"• 'use [provider]' - Switch to specific provider\\n\"\n\t\tresponse += \"• 'use auto' - Auto-select best provider for each task\\n\"\n\t\tresponse += \"• 'current provider' - Show current provider\\n\"\n\t\tresponse += \"• 'list providers' - Show this list\\n\"\n\n\t\tctx.Response = response\n\t\treturn nil\n\t})\n\n\t// Provider-specific commands (force use of specific provider)\n\tr.Handle(\"with * *\", func(ctx *router.Context) error {\n\t\tproviderName := normalizeProviderName(ctx.Captures[0])\n\t\tcommand := ctx.Captures[1]\n\n\t\tprovider, exists := providerRegistry[providerName]\n\t\tif !exists {\n\t\t\tavailableProviders := getProviderList()\n\t\t\tctx.Response = fmt.Sprintf(\"❌ Provider '%s' not available. Available providers: %s\",\n\t\t\t\tctx.Captures[0], strings.Join(availableProviders, \", \"))\n\t\t\treturn nil\n\t\t}\n\n\t\t// Execute the command with the specified provider\n\t\tresponse, err := provider.Complete(command, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tctx.Response = fmt.Sprintf(\"[Using %s]\\n\\n%s\", providerName, response)\n\t\treturn nil\n\t})\n}\n\n// normalizeProviderName converts provider names to the correct case\nfunc normalizeProviderName(name string) string {\n\tswitch strings.ToLower(name) {\n\tcase \"openai\":\n\t\treturn \"OpenAI\"\n\tcase \"deepseek\":\n\t\treturn \"DeepSeek\"\n\tcase \"gemini\":\n\t\treturn \"Gemini\"\n\tcase \"ollama\":\n\t\treturn \"Ollama\"\n\tcase \"huggingface\":\n\t\treturn \"HuggingFace\"\n\tdefault:\n\t\treturn strings.Title(strings.ToLower(name))\n\t}\n}\n\n// setupUniversalRoutes creates routes that work with any available provider\nfunc setupUniversalRoutes(r *router.Router) {\n\t// Translation route - works with any provider\n\tr.Handle(\"translate * to *\", func(ctx *router.Context) error {\n\t\ttext := ctx.Captures[0]\n\t\tlanguage := ctx.Captures[1]\n\n\t\tprovider := getCurrentProvider(\"translation\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Translate the following text to %s: %s\", language, text)\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a professional translator. Provide accurate translations.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Summarization route - works with any provider\n\tr.Handle(\"summarize *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"summary\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tresponse, err := provider.Complete(ctx.Captures[0], config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a summarization expert. Provide concise, clear summaries.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Reasoning route - works with any provider\n\tr.Handle(\"think about *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"reasoning\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tresponse, err := provider.Complete(ctx.Captures[0], config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a deep thinking AI. Provide thoughtful, analytical responses.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Step-by-step reasoning\n\tr.Handle(\"reason through *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"reasoning\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Please reason through this step by step: %s\", ctx.Captures[0])\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are an expert at logical reasoning. Break down problems step by step.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Code generation route\n\tr.Handle(\"generate code for *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"coding\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Write clean, well-documented code for: %s\", ctx.Captures[0])\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are an expert programmer. Write clean, efficient, and well-documented code.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// General chat route\n\tr.Handle(\"chat *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"general\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tresponse, err := provider.Complete(ctx.Captures[0], config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Sentiment analysis\n\tr.Handle(\"analyze sentiment of *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"general\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Analyze the sentiment of this text and explain your reasoning: %s\", ctx.Captures[0])\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a sentiment analysis expert. Analyze text sentiment and provide detailed explanations.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n}\n\n// getModelForProvider returns the appropriate model name for each provider\nfunc getModelForProvider(provider providers.Provider) string {\n\tswitch provider.GetName() {\n\tcase \"OpenAI\":\n\t\treturn \"gpt-3.5-turbo\"\n\tcase \"DeepSeek\":\n\t\treturn \"deepseek-chat\"\n\tcase \"Gemini\":\n\t\treturn \"gemini-pro\"\n\tcase \"Ollama\":\n\t\treturn \"llama2\"\n\tcase \"HuggingFace\":\n\t\treturn \"gpt2\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc setupExampleRoutes(r *router.Router) {\n\t// Enhanced help command\n\tr.Handle(\"help\", func(ctx *router.Context) error {\n\t\thelp := `\n🧠 NeuroGO Framework - Available Commands:\n\n📋 General Commands:\n- \"help\" - Show this help message\n- \"status\" - Show system status and configured providers\n\n🔄 Provider Management:\n- \"list providers\" - Show all available providers\n- \"use [provider]\" - Switch to specific provider (e.g., \"use deepseek\")\n- \"use auto\" - Auto-select best provider for each task\n- \"current provider\" - Show currently selected provider\n- \"with [provider] [command]\" - Run one command with specific provider\n\n🌟 Universal Commands (work with any provider):\n- \"translate [text] to [language]\" - Translate text\n- \"summarize [text]\" - Summarize content\n- \"think about [topic]\" - Deep analysis\n- \"reason through [problem]\" - Step-by-step reasoning\n- \"generate code for [task]\" - Generate code\n- \"chat [message]\" - General conversation\n- \"analyze sentiment of [text]\" - Sentiment analysis\n\n💡 Examples:\n- \"use deepseek\" → \"translate hello to Spanish\"\n- \"with openai explain quantum computing\"\n- \"list providers\"\n- \"current provider\"\n\n🔧 Your configured providers: `\n\n\t\tvar configuredProviders []string\n\t\tfor name := range providerRegistry {\n\t\t\tconfiguredProviders = append(configuredProviders, name)\n\t\t}\n\n\t\tif len(configuredProviders) > 0 {\n\t\t\thelp += strings.Join(configuredProviders, \", \")\n\t\t} else {\n\t\t\thelp += \"None\"\n\t\t}\n\n\t\tif currentProvider != \"\" {\n\t\t\thelp += fmt.Sprintf(\"\\n🎯 Currently using: %s\", currentProvider)\n\t\t} else {\n\t\t\thelp += \"\\n🤖 Currently in auto mode\"\n\t\t}\n\n\t\thelp += `\n\n🚀 Switch providers anytime to compare responses!\n\t\t`\n\n\t\tctx.Response = help\n\t\treturn nil\n\t})\n\n\t// Enhanced status command\n\tr.Handle(\"status\", func(ctx *router.Context) error {\n\t\tstatus := map[string]interface{}{\n\t\t\t\"framework\": \"NeuroGO\",\n\t\t\t\"version\": \"1.0.0\",\n\t\t\t\"status\": \"running\",\n\t\t\t\"providers\": map[string]interface{}{\n\t\t\t\t\"configured\": []string{},\n\t\t\t\t\"available\": []string{},\n\t\t\t\t\"current\": currentProvider,\n\t\t\t\t\"mode\": \"auto\",\n\t\t\t\t\"total\": 0,\n\t\t\t},\n\t\t}\n\n\t\tvar configured []string\n\t\tfor name := range providerRegistry {\n\t\t\tconfigured = append(configured, name)\n\t\t}\n\n\t\tif currentProvider != \"\" {\n\t\t\tstatus[\"providers\"].(map[string]interface{})[\"mode\"] = \"manual\"\n\t\t}\n\n\t\tstatus[\"providers\"].(map[string]interface{})[\"configured\"] = configured\n\t\tstatus[\"providers\"].(map[string]interface{})[\"available\"] = configured\n\t\tstatus[\"providers\"].(map[string]interface{})[\"total\"] = len(configured)\n\n\t\tif len(configured) == 0 {\n\t\t\tstatus[\"message\"] = \"No providers configured. Install Ollama or add API keys to get started.\"\n\t\t} else {\n\t\t\tif currentProvider != \"\" {\n\t\t\t\tstatus[\"message\"] = fmt.Sprintf(\"Ready! Using %s provider. %d total provider(s) available.\", currentProvider, len(configured))\n\t\t\t} else {\n\t\t\t\tstatus[\"message\"] = fmt.Sprintf(\"Ready! Auto mode - %d provider(s) available: %s\", len(configured), strings.Join(configured, \", \"))\n\t\t\t}\n\t\t}\n\n\t\tjsonData, _ := json.MarshalIndent(status, \"\", \" \")\n\t\tctx.Response = string(jsonData)\n\t\treturn nil\n\t})\n}\n\nfunc setupStaticFiles(r *mux.Router) {\n\t// Serve static files\n\tstaticDir := \"../../web/static/\"\n\n\tr.PathPrefix(\"/static/\").Handler(http.StripPrefix(\"/static/\", http.FileServer(http.Dir(staticDir))))\n\n\t// API Documentation endpoint\n\tr.HandleFunc(\"/docs\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\n\t\t// Try multiple possible paths for docs.html\n\t\tdocsPaths := []string{\n\t\t\t\"../../web/docs.html\",\n\t\t\t\"../../web/docs.html\",\n\t\t\t\"docs.html\",\n\t\t}\n\n\t\tfor _, docsPath := range docsPaths {\n\t\t\tif _, err := os.Stat(docsPath); err == nil {\n\t\t\t\tlog.Printf(\"✅ Serving docs from: %s\", docsPath)\n\t\t\t\thttp.ServeFile(w, r, docsPath)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// If no file found, log and serve fallback\n\t\tlog.Println(\"⚠️ docs.html file not found, serving embedded fallback\")\n\t\tfmt.Fprint(w, getEmbeddedDocsHTML())\n\t})\n\n\t// Serve the playground UI\n\tr.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\t// Try multiple possible paths for index.html\n\t\tindexPaths := []string{\n\t\t\t\"../../web/index.html\",\n\t\t\t\"../../web/index.html\",\n\t\t\t\"index.html\",\n\t\t}\n\n\t\tfor _, indexPath := range indexPaths {\n\t\t\tif _, err := os.Stat(indexPath); err == nil {\n\t\t\t\tlog.Printf(\"✅ Serving index from: %s\", indexPath)\n\t\t\t\thttp.ServeFile(w, r, indexPath)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// If no file found, serve fallback\n\t\tlog.Println(\"⚠️ index.html file not found, serving embedded fallback\")\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\tfmt.Fprint(w, getEmbeddedHTML())\n\t})\n}\n\nfunc getEmbeddedHTML() string {\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>NeuroGO Playground</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }\n .container { max-width: 1200px; margin: 0 auto; padding: 20px; }\n .header { text-align: center; margin-bottom: 30px; }\n .header h1 { color: #333; margin-bottom: 10px; }\n .header p { color: #666; }\n .nav { text-align: center; margin-bottom: 20px; }\n .nav a { display: inline-block; margin: 0 10px; padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; }\n .nav a:hover { background: #0056b3; }\n .playground { background: white; border-radius: 10px; padding: 30px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }\n .input-section { margin-bottom: 20px; }\n .input-section label { display: block; margin-bottom: 5px; font-weight: 600; color: #333; }\n .input-section input, .input-section select { width: 100%; padding: 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 16px; }\n .input-section input:focus, .input-section select:focus { outline: none; border-color: #007bff; }\n .button { background: #007bff; color: white; padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; font-size: 16px; font-weight: 600; }\n .button:hover { background: #0056b3; }\n .button:disabled { background: #ccc; cursor: not-allowed; }\n .response { margin-top: 20px; padding: 20px; background: #f8f9fa; border-radius: 6px; border-left: 4px solid #007bff; }\n .response pre { white-space: pre-wrap; word-wrap: break-word; }\n .examples { margin-top: 30px; }\n .examples h3 { margin-bottom: 15px; color: #333; }\n .example { background: #e9ecef; padding: 10px; margin: 5px 0; border-radius: 4px; cursor: pointer; }\n .example:hover { background: #dee2e6; }\n .loading { display: none; text-align: center; margin: 20px 0; }\n .spinner { border: 3px solid #f3f3f3; border-top: 3px solid #007bff; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 0 auto; }\n @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n .provider-section { background: #e3f2fd; padding: 15px; border-radius: 6px; margin-bottom: 20px; }\n .provider-section h4 { color: #1565c0; margin-bottom: 10px; }\n .api-info { background: #f0f8ff; padding: 15px; border-radius: 6px; margin-bottom: 20px; border-left: 4px solid #007bff; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>🧠 NeuroGO Playground</h1>\n <p>Test your AI command router with natural language prompts</p>\n </div>\n \n <div class=\"nav\">\n <a href=\"/docs\">📚 API Documentation</a>\n <a href=\"/api/health\">🔍 Health Check</a>\n <a href=\"/api/routes\">🛣️ Routes</a>\n </div>\n \n <div class=\"playground\">\n <div class=\"api-info\">\n <h4>🔗 Available Endpoints:</h4>\n <p><strong>REST API:</strong> /api/process, /api/health, /api/routes</p>\n <p><strong>WebSocket:</strong> /ws</p>\n <p><strong>Documentation:</strong> <a href=\"/docs\">/docs</a> (Full API testing interface)</p>\n </div>\n \n <div class=\"provider-section\">\n <h4>🔄 Provider Management</h4>\n <p>Switch between AI providers or let the system auto-select the best one for each task.</p>\n </div>\n \n <div class=\"input-section\">\n <label for=\"prompt\">Enter your prompt:</label>\n <input type=\"text\" id=\"prompt\" placeholder=\"e.g., use deepseek, translate hello to Spanish\" />\n </div>\n \n <button class=\"button\" onclick=\"processPrompt()\">Process Prompt</button>\n \n <div class=\"loading\" id=\"loading\">\n <div class=\"spinner\"></div>\n <p>Processing your request...</p>\n </div>\n \n <div class=\"response\" id=\"response\" style=\"display: none;\">\n <h3>Response:</h3>\n <pre id=\"responseText\"></pre>\n </div>\n \n <div class=\"examples\">\n <h3>Example Commands:</h3>\n \n <h4>🔄 Provider Management:</h4>\n <div class=\"example\" onclick=\"setPrompt('list providers')\">list providers</div>\n <div class=\"example\" onclick=\"setPrompt('current provider')\">current provider</div>\n <div class=\"example\" onclick=\"setPrompt('use deepseek')\">use deepseek</div>\n <div class=\"example\" onclick=\"setPrompt('use auto')\">use auto</div>\n \n <h4>🌟 Universal Commands:</h4>\n <div class=\"example\" onclick=\"setPrompt('translate hello world to Spanish')\">translate hello world to Spanish</div>\n <div class=\"example\" onclick=\"setPrompt('think about artificial intelligence')\">think about artificial intelligence</div>\n <div class=\"example\" onclick=\"setPrompt('summarize the benefits of renewable energy')\">summarize the benefits of renewable energy</div>\n <div class=\"example\" onclick=\"setPrompt('generate code for a simple calculator')\">generate code for a simple calculator</div>\n \n <h4>🎯 Provider-Specific Commands:</h4>\n <div class=\"example\" onclick=\"setPrompt('with deepseek explain quantum computing')\">with deepseek explain quantum computing</div>\n <div class=\"example\" onclick=\"setPrompt('with openai write a poem about nature')\">with openai write a poem about nature</div>\n \n <h4>📋 System Commands:</h4>\n <div class=\"example\" onclick=\"setPrompt('help')\">help</div>\n <div class=\"example\" onclick=\"setPrompt('status')\">status</div>\n </div>\n </div>\n </div>\n\n <script>\n function setPrompt(text) {\n document.getElementById('prompt').value = text;\n }\n\n async function processPrompt() {\n const prompt = document.getElementById('prompt').value.trim();\n if (!prompt) {\n alert('Please enter a prompt');\n return;\n }\n\n const loading = document.getElementById('loading');\n const response = document.getElementById('response');\n const responseText = document.getElementById('responseText');\n\n loading.style.display = 'block';\n response.style.display = 'none';\n\n try {\n const res = await fetch('/api/process', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ prompt: prompt })\n });\n\n const data = await res.json();\n \n if (data.error) {\n responseText.textContent = 'Error: ' + data.error;\n } else {\n responseText.textContent = data.response;\n }\n \n response.style.display = 'block';\n } catch (error) {\n responseText.textContent = 'Error: ' + error.message;\n response.style.display = 'block';\n } finally {\n loading.style.display = 'none';\n }\n }\n\n // Allow Enter key to submit\n document.getElementById('prompt').addEventListener('keypress', function(e) {\n if (e.key === 'Enter') {\n processPrompt();\n }\n });\n </script>\n</body>\n</html>`\n}\n\n// getEmbeddedDocsHTML returns a minimal fallback for docs if file doesn't exist\nfunc getEmbeddedDocsHTML() string {\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>NeuroGO API Documentation</title>\n <style>\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 40px; }\n .container { max-width: 800px; margin: 0 auto; }\n h1 { color: #333; }\n .error { background: #f8d7da; color: #721c24; padding: 15px; border-radius: 5px; margin: 20px 0; }\n .nav { margin: 20px 0; }\n .nav a { display: inline-block; margin-right: 15px; padding: 10px 15px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>🧠 NeuroGO API Documentation</h1>\n <div class=\"error\">\n <strong>Documentation file not found.</strong><br>\n The docs.html file is missing. Please ensure web/docs.html exists.\n </div>\n <div class=\"nav\">\n <a href=\"/\">← Back to Playground</a>\n <a href=\"/api/health\">Health Check</a>\n <a href=\"/api/routes\">API Routes</a>\n </div>\n <p>For now, you can use the main playground interface or access the API endpoints directly.</p>\n </div>\n</body>\n</html>`\n}\n"}, "e020db6345d007d9b7bf69b1f066c6ec63674315": {"t": 1785755007.0740845, "n": 31716, "h": "e179539cedc4fefb", "c": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/joho/godotenv\"\n\t\"github.com/rs/cors\"\n\n\t\"github.com/aldotobing/neurogo/config\"\n\t\"github.com/aldotobing/neurogo/providers\"\n\t\"github.com/aldotobing/neurogo/router\"\n\t\"github.com/aldotobing/neurogo/server\"\n)\n\n// Global provider registry and current provider\nvar providerRegistry = make(map[string]providers.Provider)\nvar currentProvider = \"\"\n\nfunc main() {\n\t// Debug: Print current working directory and file existence\n\tif cwd, err := os.Getwd(); err == nil {\n\t\tlog.Printf(\"🔍 Current working directory: %s\", cwd)\n\t}\n\n\t// Check if web files exist\n\twebFiles := []string{\"../../web/docs.html\", \"../../web/index.html\", \"../../web/static/app.js\", \"../../web/static/style.css\"}\n\tfor _, file := range webFiles {\n\t\tif _, err := os.Stat(file); err == nil {\n\t\t\tlog.Printf(\"✅ Found: %s\", file)\n\t\t} else {\n\t\t\tlog.Printf(\"❌ Missing: %s\", file)\n\t\t}\n\t}\n\n\t// Load environment variables with better error handling\n\tloadEnvironment()\n\n\t// Initialize the NeuroGO router\n\tneuroRouter := router.New()\n\n\t// Configure providers\n\tsetupProviders(neuroRouter)\n\n\t// Setup universal routes (works with any provider)\n\tsetupUniversalRoutes(neuroRouter)\n\n\t// Setup provider switching routes\n\tsetupProviderSwitchingRoutes(neuroRouter)\n\n\t// Setup example routes\n\tsetupExampleRoutes(neuroRouter)\n\n\t// Create HTTP server\n\thttpRouter := mux.NewRouter()\n\n\t// Setup API routes\n\tapi := httpRouter.PathPrefix(\"/api\").Subrouter()\n\tserver.SetupAPIRoutes(api, neuroRouter)\n\n\t// Setup WebSocket for real-time communication\n\tserver.SetupWebSocket(httpRouter, neuroRouter)\n\n\t// Serve static files for the playground\n\tsetupStaticFiles(httpRouter)\n\n\t// Setup CORS\n\tc := cors.New(cors.Options{\n\t\tAllowedOrigins: []string{\"*\"},\n\t\tAllowedMethods: []string{\"GET\", \"POST\", \"PUT\", \"DELETE\", \"OPTIONS\"},\n\t\tAllowedHeaders: []string{\"*\"},\n\t})\n\n\thandler := c.Handler(httpRouter)\n\n\tport := os.Getenv(\"PORT\")\n\tif port == \"\" {\n\t\tport = \"8080\"\n\t}\n\n\tfmt.Printf(\"🚀 NeuroGO server starting on port %s\\n\", port)\n\tfmt.Printf(\"📱 Playground UI: http://localhost:%s\\n\", port)\n\tfmt.Printf(\"📚 API Documentation: http://localhost:%s/docs\\n\", port)\n\tfmt.Printf(\"🔗 API Endpoint: http://localhost:%s/api\\n\", port)\n\n\tlog.Fatal(http.ListenAndServe(\":\"+port, handler))\n}\n\n// loadEnvironment loads environment variables with better error handling\nfunc loadEnvironment() {\n\t// Try to load .env file from current directory\n\tif err := godotenv.Load(); err != nil {\n\t\t// Try to load from parent directory (in case we're in cmd/server)\n\t\tif err := godotenv.Load(\"../../.env\"); err != nil {\n\t\t\tlog.Println(\"No .env file found, using system environment variables\")\n\t\t} else {\n\t\t\tlog.Println(\"✅ Loaded .env file from parent directory\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"✅ Loaded .env file successfully\")\n\t}\n\n\t// Debug: Print which environment variables are set\n\tdebugEnvironmentVariables()\n}\n\n// debugEnvironmentVariables prints which environment variables are detected\nfunc debugEnvironmentVariables() {\n\tenvVars := []string{\n\t\t\"OPENAI_API_KEY\",\n\t\t\"DEEPSEEK_API_KEY\",\n\t\t\"GEMINI_API_KEY\",\n\t\t\"HUGGINGFACE_API_KEY\",\n\t\t\"OLLAMA_HOST\",\n\t}\n\n\tlog.Println(\"🔍 Environment Variables Status:\")\n\tfor _, envVar := range envVars {\n\t\tvalue := os.Getenv(envVar)\n\t\tif value != \"\" {\n\t\t\t// Don't print the full API key for security\n\t\t\tif len(value) > 10 {\n\t\t\t\tlog.Printf(\" ✅ %s: %s...%s\", envVar, value[:4], value[len(value)-4:])\n\t\t\t} else {\n\t\t\t\tlog.Printf(\" ✅ %s: %s\", envVar, value)\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Printf(\" ❌ %s: not set\", envVar)\n\t\t}\n\t}\n}\n\n// getCurrentProvider returns the currently selected provider or the best available one\nfunc getCurrentProvider(taskType string) providers.Provider {\n\t// If a specific provider is selected, use it\n\tif currentProvider != \"\" {\n\t\tif provider, exists := providerRegistry[currentProvider]; exists {\n\t\t\treturn provider\n\t\t}\n\t}\n\n\t// Otherwise, use the best provider for the task type\n\treturn getBestProvider(taskType)\n}\n\n// getBestProvider returns the best available provider for a given task type\nfunc getBestProvider(taskType string) providers.Provider {\n\t// Provider preferences for different task types\n\tpreferences := map[string][]string{\n\t\t\"translation\": {\"Gemini\", \"OpenAI\", \"DeepSeek\", \"Ollama\"},\n\t\t\"reasoning\": {\"DeepSeek\", \"OpenAI\", \"Gemini\", \"Ollama\"},\n\t\t\"coding\": {\"Ollama\", \"OpenAI\", \"DeepSeek\", \"Gemini\"},\n\t\t\"summary\": {\"OpenAI\", \"DeepSeek\", \"Gemini\", \"Ollama\"},\n\t\t\"general\": {\"OpenAI\", \"DeepSeek\", \"Gemini\", \"Ollama\"},\n\t}\n\n\tproviderList, exists := preferences[taskType]\n\tif !exists {\n\t\tproviderList = preferences[\"general\"]\n\t}\n\n\t// Return the first available provider from the preference list\n\tfor _, providerName := range providerList {\n\t\tif provider, exists := providerRegistry[providerName]; exists {\n\t\t\treturn provider\n\t\t}\n\t}\n\n\t// Fallback: return any available provider\n\tfor _, provider := range providerRegistry {\n\t\treturn provider\n\t}\n\n\treturn nil\n}\n\n// getProviderList returns a list of available provider names\nfunc getProviderList() []string {\n\tvar providers []string\n\tfor name := range providerRegistry {\n\t\tproviders = append(providers, name)\n\t}\n\treturn providers\n}\n\nfunc setupProviders(r *router.Router) {\n\tavailableProviders := []string{}\n\n\t// OpenAI Provider\n\tif apiKey := os.Getenv(\"OPENAI_API_KEY\"); apiKey != \"\" {\n\t\topenAIProvider := providers.NewOpenAI(apiKey)\n\t\tif openAIProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"OpenAI\"] = openAIProvider\n\t\t\tavailableProviders = append(availableProviders, \"OpenAI\")\n\t\t\tlog.Println(\"✅ OpenAI provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ OpenAI provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ OpenAI API key not provided\")\n\t}\n\n\t// DeepSeek Provider\n\tif apiKey := os.Getenv(\"DEEPSEEK_API_KEY\"); apiKey != \"\" {\n\t\tdeepSeekProvider := providers.NewDeepSeek(apiKey)\n\t\tif deepSeekProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"DeepSeek\"] = deepSeekProvider\n\t\t\tavailableProviders = append(availableProviders, \"DeepSeek\")\n\t\t\tlog.Println(\"✅ DeepSeek provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ DeepSeek provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ DeepSeek API key not provided\")\n\t}\n\n\t// Gemini Provider\n\tif apiKey := os.Getenv(\"GEMINI_API_KEY\"); apiKey != \"\" {\n\t\tgeminiProvider := providers.NewGemini(apiKey)\n\t\tif geminiProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"Gemini\"] = geminiProvider\n\t\t\tavailableProviders = append(availableProviders, \"Gemini\")\n\t\t\tlog.Println(\"✅ Gemini provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ Gemini provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ Gemini API key not provided\")\n\t}\n\n\t// Ollama Provider\n\tollamaHost := os.Getenv(\"OLLAMA_HOST\")\n\tif ollamaHost == \"\" {\n\t\tollamaHost = \"http://localhost:11434\"\n\t}\n\n\tlog.Printf(\"🔍 Checking Ollama at: %s\", ollamaHost)\n\tollamaProvider := providers.NewOllama(ollamaHost)\n\tif ollamaProvider.IsAvailable() {\n\t\tproviderRegistry[\"Ollama\"] = ollamaProvider\n\t\tavailableProviders = append(availableProviders, \"Ollama\")\n\t\tlog.Println(\"✅ Ollama provider configured\")\n\t} else {\n\t\tlog.Printf(\"⚠️ Ollama not available - make sure Ollama is running on %s\", ollamaHost)\n\t}\n\n\t// HuggingFace Provider\n\tif apiKey := os.Getenv(\"HUGGINGFACE_API_KEY\"); apiKey != \"\" {\n\t\thfProvider := providers.NewHuggingFace(apiKey)\n\t\tif hfProvider.IsAvailable() {\n\t\t\tproviderRegistry[\"HuggingFace\"] = hfProvider\n\t\t\tavailableProviders = append(availableProviders, \"HuggingFace\")\n\t\t\tlog.Println(\"✅ HuggingFace provider configured\")\n\t\t} else {\n\t\t\tlog.Println(\"❌ HuggingFace provider configuration failed\")\n\t\t}\n\t} else {\n\t\tlog.Println(\"⚠️ HuggingFace API key not provided\")\n\t}\n\n\t// Set default provider to the first available one\n\tif len(availableProviders) > 0 && currentProvider == \"\" {\n\t\tcurrentProvider = availableProviders[0]\n\t\tlog.Printf(\"🎯 Default provider set to: %s\", currentProvider)\n\t}\n\n\t// Log summary\n\tif len(availableProviders) == 0 {\n\t\tlog.Println(\"⚠️ No AI providers configured. Only basic commands will work.\")\n\t\tlog.Println(\"💡 To get started with Ollama: run 'ollama serve' and 'ollama pull llama2'\")\n\t\tlog.Println(\"💡 Or add API keys to your .env file for cloud providers\")\n\t} else {\n\t\tlog.Printf(\"🎉 Configured providers: %v\", availableProviders)\n\t}\n}\n\n// setupProviderSwitchingRoutes creates routes for switching between providers\nfunc setupProviderSwitchingRoutes(r *router.Router) {\n\t// Switch to a specific provider\n\tr.Handle(\"use *\", func(ctx *router.Context) error {\n\t\tproviderName := normalizeProviderName(ctx.Captures[0])\n\n\t\tif _, exists := providerRegistry[providerName]; exists {\n\t\t\tcurrentProvider = providerName\n\t\t\tctx.Response = fmt.Sprintf(\"✅ Switched to %s provider. All subsequent commands will use %s.\", providerName, providerName)\n\t\t} else {\n\t\t\tavailableProviders := getProviderList()\n\t\t\tctx.Response = fmt.Sprintf(\"❌ Provider '%s' not available. Available providers: %s\",\n\t\t\t\tctx.Captures[0], strings.Join(availableProviders, \", \"))\n\t\t}\n\t\treturn nil\n\t})\n\n\t// Switch to auto mode (best provider for each task)\n\tr.Handle(\"use auto\", func(ctx *router.Context) error {\n\t\tcurrentProvider = \"\"\n\t\tctx.Response = \"✅ Switched to auto mode. The system will automatically choose the best provider for each task.\"\n\t\treturn nil\n\t})\n\n\t// Show current provider\n\tr.Handle(\"current provider\", func(ctx *router.Context) error {\n\t\tif currentProvider == \"\" {\n\t\t\tctx.Response = \"🤖 Currently in auto mode - the system chooses the best provider for each task.\"\n\t\t} else {\n\t\t\tctx.Response = fmt.Sprintf(\"🎯 Currently using: %s\", currentProvider)\n\t\t}\n\t\treturn nil\n\t})\n\n\t// List all available providers\n\tr.Handle(\"list providers\", func(ctx *router.Context) error {\n\t\tproviders := getProviderList()\n\t\tif len(providers) == 0 {\n\t\t\tctx.Response = \"❌ No providers configured.\"\n\t\t\treturn nil\n\t\t}\n\n\t\tresponse := \"📋 Available providers:\\n\\n\"\n\t\tfor _, name := range providers {\n\t\t\tif name == currentProvider {\n\t\t\t\tresponse += fmt.Sprintf(\"🎯 %s (currently selected)\\n\", name)\n\t\t\t} else {\n\t\t\t\tresponse += fmt.Sprintf(\" %s\\n\", name)\n\t\t\t}\n\t\t}\n\n\t\tresponse += \"\\n💡 Commands:\\n\"\n\t\tresponse += \"• 'use [provider]' - Switch to specific provider\\n\"\n\t\tresponse += \"• 'use auto' - Auto-select best provider for each task\\n\"\n\t\tresponse += \"• 'current provider' - Show current provider\\n\"\n\t\tresponse += \"• 'list providers' - Show this list\\n\"\n\n\t\tctx.Response = response\n\t\treturn nil\n\t})\n\n\t// Provider-specific commands (force use of specific provider)\n\tr.Handle(\"with * *\", func(ctx *router.Context) error {\n\t\tproviderName := normalizeProviderName(ctx.Captures[0])\n\t\tcommand := ctx.Captures[1]\n\n\t\tprovider, exists := providerRegistry[providerName]\n\t\tif !exists {\n\t\t\tavailableProviders := getProviderList()\n\t\t\tctx.Response = fmt.Sprintf(\"❌ Provider '%s' not available. Available providers: %s\",\n\t\t\t\tctx.Captures[0], strings.Join(availableProviders, \", \"))\n\t\t\treturn nil\n\t\t}\n\n\t\t// Execute the command with the specified provider\n\t\tresponse, err := provider.Complete(command, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tctx.Response = fmt.Sprintf(\"[Using %s]\\n\\n%s\", providerName, response)\n\t\treturn nil\n\t})\n}\n\n// normalizeProviderName converts provider names to the correct case\nfunc normalizeProviderName(name string) string {\n\tswitch strings.ToLower(name) {\n\tcase \"openai\":\n\t\treturn \"OpenAI\"\n\tcase \"deepseek\":\n\t\treturn \"DeepSeek\"\n\tcase \"gemini\":\n\t\treturn \"Gemini\"\n\tcase \"ollama\":\n\t\treturn \"Ollama\"\n\tcase \"huggingface\":\n\t\treturn \"HuggingFace\"\n\tdefault:\n\t\treturn strings.Title(strings.ToLower(name))\n\t}\n}\n\n// setupUniversalRoutes creates routes that work with any available provider\nfunc setupUniversalRoutes(r *router.Router) {\n\t// Translation route - works with any provider\n\tr.Handle(\"translate * to *\", func(ctx *router.Context) error {\n\t\ttext := ctx.Captures[0]\n\t\tlanguage := ctx.Captures[1]\n\n\t\tprovider := getCurrentProvider(\"translation\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Translate the following text to %s: %s\", language, text)\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a professional translator. Provide accurate translations.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Summarization route - works with any provider\n\tr.Handle(\"summarize *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"summary\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tresponse, err := provider.Complete(ctx.Captures[0], config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a summarization expert. Provide concise, clear summaries.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Reasoning route - works with any provider\n\tr.Handle(\"think about *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"reasoning\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tresponse, err := provider.Complete(ctx.Captures[0], config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a deep thinking AI. Provide thoughtful, analytical responses.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Step-by-step reasoning\n\tr.Handle(\"reason through *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"reasoning\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Please reason through this step by step: %s\", ctx.Captures[0])\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are an expert at logical reasoning. Break down problems step by step.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Code generation route\n\tr.Handle(\"generate code for *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"coding\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Write clean, well-documented code for: %s\", ctx.Captures[0])\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are an expert programmer. Write clean, efficient, and well-documented code.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// General chat route\n\tr.Handle(\"chat *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"general\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tresponse, err := provider.Complete(ctx.Captures[0], config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n\n\t// Sentiment analysis\n\tr.Handle(\"analyze sentiment of *\", func(ctx *router.Context) error {\n\t\tprovider := getCurrentProvider(\"general\")\n\t\tif provider == nil {\n\t\t\treturn fmt.Errorf(\"no AI providers available\")\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"Analyze the sentiment of this text and explain your reasoning: %s\", ctx.Captures[0])\n\t\tresponse, err := provider.Complete(prompt, config.CompletionOptions{\n\t\t\tModel: getModelForProvider(provider),\n\t\t\tSystemPrompt: \"You are a sentiment analysis expert. Analyze text sentiment and provide detailed explanations.\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tproviderInfo := \"\"\n\t\tif currentProvider == \"\" {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Auto-selected: %s]\\n\\n\", provider.GetName())\n\t\t} else {\n\t\t\tproviderInfo = fmt.Sprintf(\"[Using: %s]\\n\\n\", provider.GetName())\n\t\t}\n\n\t\tctx.Response = providerInfo + response\n\t\treturn nil\n\t})\n}\n\n// getModelForProvider returns the appropriate model name for each provider\nfunc getModelForProvider(provider providers.Provider) string {\n\tswitch provider.GetName() {\n\tcase \"OpenAI\":\n\t\treturn \"gpt-3.5-turbo\"\n\tcase \"DeepSeek\":\n\t\treturn \"deepseek-chat\"\n\tcase \"Gemini\":\n\t\treturn \"gemini-pro\"\n\tcase \"Ollama\":\n\t\treturn \"llama2\"\n\tcase \"HuggingFace\":\n\t\treturn \"gpt2\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc setupExampleRoutes(r *router.Router) {\n\t// Enhanced help command\n\tr.Handle(\"help\", func(ctx *router.Context) error {\n\t\thelp := `\n🧠 NeuroGO Framework - Available Commands:\n\n📋 General Commands:\n- \"help\" - Show this help message\n- \"status\" - Show system status and configured providers\n\n🔄 Provider Management:\n- \"list providers\" - Show all available providers\n- \"use [provider]\" - Switch to specific provider (e.g., \"use deepseek\")\n- \"use auto\" - Auto-select best provider for each task\n- \"current provider\" - Show currently selected provider\n- \"with [provider] [command]\" - Run one command with specific provider\n\n🌟 Universal Commands (work with any provider):\n- \"translate [text] to [language]\" - Translate text\n- \"summarize [text]\" - Summarize content\n- \"think about [topic]\" - Deep analysis\n- \"reason through [problem]\" - Step-by-step reasoning\n- \"generate code for [task]\" - Generate code\n- \"chat [message]\" - General conversation\n- \"analyze sentiment of [text]\" - Sentiment analysis\n\n💡 Examples:\n- \"use deepseek\" → \"translate hello to Spanish\"\n- \"with openai explain quantum computing\"\n- \"list providers\"\n- \"current provider\"\n\n🔧 Your configured providers: `\n\n\t\tvar configuredProviders []string\n\t\tfor name := range providerRegistry {\n\t\t\tconfiguredProviders = append(configuredProviders, name)\n\t\t}\n\n\t\tif len(configuredProviders) > 0 {\n\t\t\thelp += strings.Join(configuredProviders, \", \")\n\t\t} else {\n\t\t\thelp += \"None\"\n\t\t}\n\n\t\tif currentProvider != \"\" {\n\t\t\thelp += fmt.Sprintf(\"\\n🎯 Currently using: %s\", currentProvider)\n\t\t} else {\n\t\t\thelp += \"\\n🤖 Currently in auto mode\"\n\t\t}\n\n\t\thelp += `\n\n🚀 Switch providers anytime to compare responses!\n\t\t`\n\n\t\tctx.Response = help\n\t\treturn nil\n\t})\n\n\t// Enhanced status command\n\tr.Handle(\"status\", func(ctx *router.Context) error {\n\t\tstatus := map[string]interface{}{\n\t\t\t\"framework\": \"NeuroGO\",\n\t\t\t\"version\": \"1.0.0\",\n\t\t\t\"status\": \"running\",\n\t\t\t\"providers\": map[string]interface{}{\n\t\t\t\t\"configured\": []string{},\n\t\t\t\t\"available\": []string{},\n\t\t\t\t\"current\": currentProvider,\n\t\t\t\t\"mode\": \"auto\",\n\t\t\t\t\"total\": 0,\n\t\t\t},\n\t\t}\n\n\t\tvar configured []string\n\t\tfor name := range providerRegistry {\n\t\t\tconfigured = append(configured, name)\n\t\t}\n\n\t\tif currentProvider != \"\" {\n\t\t\tstatus[\"providers\"].(map[string]interface{})[\"mode\"] = \"manual\"\n\t\t}\n\n\t\tstatus[\"providers\"].(map[string]interface{})[\"configured\"] = configured\n\t\tstatus[\"providers\"].(map[string]interface{})[\"available\"] = configured\n\t\tstatus[\"providers\"].(map[string]interface{})[\"total\"] = len(configured)\n\n\t\tif len(configured) == 0 {\n\t\t\tstatus[\"message\"] = \"No providers configured. Install Ollama or add API keys to get started.\"\n\t\t} else {\n\t\t\tif currentProvider != \"\" {\n\t\t\t\tstatus[\"message\"] = fmt.Sprintf(\"Ready! Using %s provider. %d total provider(s) available.\", currentProvider, len(configured))\n\t\t\t} else {\n\t\t\t\tstatus[\"message\"] = fmt.Sprintf(\"Ready! Auto mode - %d provider(s) available: %s\", len(configured), strings.Join(configured, \", \"))\n\t\t\t}\n\t\t}\n\n\t\tjsonData, _ := json.MarshalIndent(status, \"\", \" \")\n\t\tctx.Response = string(jsonData)\n\t\treturn nil\n\t})\n}\n\nfunc setupStaticFiles(r *mux.Router) {\n\t// Serve static files\n\tstaticDir := \"../../web/static/\"\n\n\tr.PathPrefix(\"/static/\").Handler(http.StripPrefix(\"/static/\", http.FileServer(http.Dir(staticDir))))\n\n\t// API Documentation endpoint\n\tr.HandleFunc(\"/docs\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\n\t\t// Try multiple possible paths for docs.html\n\t\tdocsPaths := []string{\n\t\t\t\"../../web/docs.html\",\n\t\t\t\"../../web/docs.html\",\n\t\t\t\"docs.html\",\n\t\t}\n\n\t\tfor _, docsPath := range docsPaths {\n\t\t\tif _, err := os.Stat(docsPath); err == nil {\n\t\t\t\tlog.Printf(\"✅ Serving docs from: %s\", docsPath)\n\t\t\t\thttp.ServeFile(w, r, docsPath)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// If no file found, log and serve fallback\n\t\tlog.Println(\"⚠️ docs.html file not found, serving embedded fallback\")\n\t\tfmt.Fprint(w, getEmbeddedDocsHTML())\n\t})\n\n\t// Serve the playground UI\n\tr.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\t// Try multiple possible paths for index.html\n\t\tindexPaths := []string{\n\t\t\t\"../../web/index.html\",\n\t\t\t\"../../web/index.html\",\n\t\t\t\"index.html\",\n\t\t}\n\n\t\tfor _, indexPath := range indexPaths {\n\t\t\tif _, err := os.Stat(indexPath); err == nil {\n\t\t\t\tlog.Printf(\"✅ Serving index from: %s\", indexPath)\n\t\t\t\thttp.ServeFile(w, r, indexPath)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// If no file found, serve fallback\n\t\tlog.Println(\"⚠️ index.html file not found, serving embedded fallback\")\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\tfmt.Fprint(w, getEmbeddedHTML())\n\t})\n}\n\nfunc getEmbeddedHTML() string {\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>NeuroGO Playground</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }\n .container { max-width: 1200px; margin: 0 auto; padding: 20px; }\n .header { text-align: center; margin-bottom: 30px; }\n .header h1 { color: #333; margin-bottom: 10px; }\n .header p { color: #666; }\n .nav { text-align: center; margin-bottom: 20px; }\n .nav a { display: inline-block; margin: 0 10px; padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; }\n .nav a:hover { background: #0056b3; }\n .playground { background: white; border-radius: 10px; padding: 30px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }\n .input-section { margin-bottom: 20px; }\n .input-section label { display: block; margin-bottom: 5px; font-weight: 600; color: #333; }\n .input-section input, .input-section select { width: 100%; padding: 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 16px; }\n .input-section input:focus, .input-section select:focus { outline: none; border-color: #007bff; }\n .button { background: #007bff; color: white; padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; font-size: 16px; font-weight: 600; }\n .button:hover { background: #0056b3; }\n .button:disabled { background: #ccc; cursor: not-allowed; }\n .response { margin-top: 20px; padding: 20px; background: #f8f9fa; border-radius: 6px; border-left: 4px solid #007bff; }\n .response pre { white-space: pre-wrap; word-wrap: break-word; }\n .examples { margin-top: 30px; }\n .examples h3 { margin-bottom: 15px; color: #333; }\n .example { background: #e9ecef; padding: 10px; margin: 5px 0; border-radius: 4px; cursor: pointer; }\n .example:hover { background: #dee2e6; }\n .loading { display: none; text-align: center; margin: 20px 0; }\n .spinner { border: 3px solid #f3f3f3; border-top: 3px solid #007bff; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 0 auto; }\n @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n .provider-section { background: #e3f2fd; padding: 15px; border-radius: 6px; margin-bottom: 20px; }\n .provider-section h4 { color: #1565c0; margin-bottom: 10px; }\n .api-info { background: #f0f8ff; padding: 15px; border-radius: 6px; margin-bottom: 20px; border-left: 4px solid #007bff; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>🧠 NeuroGO Playground</h1>\n <p>Test your AI command router with natural language prompts</p>\n </div>\n \n <div class=\"nav\">\n <a href=\"/docs\">📚 API Documentation</a>\n <a href=\"/api/health\">🔍 Health Check</a>\n <a href=\"/api/routes\">🛣️ Routes</a>\n </div>\n \n <div class=\"playground\">\n <div class=\"api-info\">\n <h4>🔗 Available Endpoints:</h4>\n <p><strong>REST API:</strong> /api/process, /api/health, /api/routes</p>\n <p><strong>WebSocket:</strong> /ws</p>\n <p><strong>Documentation:</strong> <a href=\"/docs\">/docs</a> (Full API testing interface)</p>\n </div>\n \n <div class=\"provider-section\">\n <h4>🔄 Provider Management</h4>\n <p>Switch between AI providers or let the system auto-select the best one for each task.</p>\n </div>\n \n <div class=\"input-section\">\n <label for=\"prompt\">Enter your prompt:</label>\n <input type=\"text\" id=\"prompt\" placeholder=\"e.g., use deepseek, translate hello to Spanish\" />\n </div>\n \n <button class=\"button\" onclick=\"processPrompt()\">Process Prompt</button>\n \n <div class=\"loading\" id=\"loading\">\n <div class=\"spinner\"></div>\n <p>Processing your request...</p>\n </div>\n \n <div class=\"response\" id=\"response\" style=\"display: none;\">\n <h3>Response:</h3>\n <pre id=\"responseText\"></pre>\n </div>\n \n <div class=\"examples\">\n <h3>Example Commands:</h3>\n \n <h4>🔄 Provider Management:</h4>\n <div class=\"example\" onclick=\"setPrompt('list providers')\">list providers</div>\n <div class=\"example\" onclick=\"setPrompt('current provider')\">current provider</div>\n <div class=\"example\" onclick=\"setPrompt('use deepseek')\">use deepseek</div>\n <div class=\"example\" onclick=\"setPrompt('use auto')\">use auto</div>\n \n <h4>🌟 Universal Commands:</h4>\n <div class=\"example\" onclick=\"setPrompt('translate hello world to Spanish')\">translate hello world to Spanish</div>\n <div class=\"example\" onclick=\"setPrompt('think about artificial intelligence')\">think about artificial intelligence</div>\n <div class=\"example\" onclick=\"setPrompt('summarize the benefits of renewable energy')\">summarize the benefits of renewable energy</div>\n <div class=\"example\" onclick=\"setPrompt('generate code for a simple calculator')\">generate code for a simple calculator</div>\n \n <h4>🎯 Provider-Specific Commands:</h4>\n <div class=\"example\" onclick=\"setPrompt('with deepseek explain quantum computing')\">with deepseek explain quantum computing</div>\n <div class=\"example\" onclick=\"setPrompt('with openai write a poem about nature')\">with openai write a poem about nature</div>\n \n <h4>📋 System Commands:</h4>\n <div class=\"example\" onclick=\"setPrompt('help')\">help</div>\n <div class=\"example\" onclick=\"setPrompt('status')\">status</div>\n </div>\n </div>\n </div>\n\n <script>\n function setPrompt(text) {\n document.getElementById('prompt').value = text;\n }\n\n async function processPrompt() {\n const prompt = document.getElementById('prompt').value.trim();\n if (!prompt) {\n alert('Please enter a prompt');\n return;\n }\n\n const loading = document.getElementById('loading');\n const response = document.getElementById('response');\n const responseText = document.getElementById('responseText');\n\n loading.style.display = 'block';\n response.style.display = 'none';\n\n try {\n const res = await fetch('/api/process', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ prompt: prompt })\n });\n\n const data = await res.json();\n \n if (data.error) {\n responseText.textContent = 'Error: ' + data.error;\n } else {\n responseText.textContent = data.response;\n }\n \n response.style.display = 'block';\n } catch (error) {\n responseText.textContent = 'Error: ' + error.message;\n response.style.display = 'block';\n } finally {\n loading.style.display = 'none';\n }\n }\n\n // Allow Enter key to submit\n document.getElementById('prompt').addEventListener('keypress', function(e) {\n if (e.key === 'Enter') {\n processPrompt();\n }\n });\n </script>\n</body>\n</html>`\n}\n\n// getEmbeddedDocsHTML returns a minimal fallback for docs if file doesn't exist\nfunc getEmbeddedDocsHTML() string {\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>NeuroGO API Documentation</title>\n <style>\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 40px; }\n .container { max-width: 800px; margin: 0 auto; }\n h1 { color: #333; }\n .error { background: #f8d7da; color: #721c24; padding: 15px; border-radius: 5px; margin: 20px 0; }\n .nav { margin: 20px 0; }\n .nav a { display: inline-block; margin-right: 15px; padding: 10px 15px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>🧠 NeuroGO API Documentation</h1>\n <div class=\"error\">\n <strong>Documentation file not found.</strong><br>\n The docs.html file is missing. Please ensure web/docs.html exists.\n </div>\n <div class=\"nav\">\n <a href=\"/\">← Back to Playground</a>\n <a href=\"/api/health\">Health Check</a>\n <a href=\"/api/routes\">API Routes</a>\n </div>\n <p>For now, you can use the main playground interface or access the API endpoints directly.</p>\n </div>\n</body>\n</html>`\n}\n"}}}}