feats: new interactive mode, language preference and time injection, more provider flexibility and clarity, more configuration options
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
"""
|
||||
AI Answers Plugin - One-Shot Test
|
||||
Comprehensive test that outputs everything: config, injection, LLM response.
|
||||
|
||||
Usage: python test.py
|
||||
Requires: pip install flask flask-babel python-dotenv
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import logging
|
||||
from types import ModuleType
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Suppress Flask noise during test
|
||||
logging.getLogger('werkzeug').setLevel(logging.ERROR)
|
||||
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
||||
|
||||
# Mock SearXNG modules
|
||||
searx = ModuleType("searx")
|
||||
searx_plugins = ModuleType("searx.plugins")
|
||||
searx_results = ModuleType("searx.result_types")
|
||||
|
||||
class MockPlugin:
|
||||
def __init__(self, cfg):
|
||||
self.active = getattr(cfg, 'active', True)
|
||||
|
||||
class MockPluginInfo:
|
||||
def __init__(self, **kwargs):
|
||||
self.meta = kwargs
|
||||
|
||||
class MockEngineResults:
|
||||
def __init__(self):
|
||||
self.types = ModuleType("types")
|
||||
self.types.Answer = lambda *args, **kwargs: kwargs.get('answer', args[0] if args else "")
|
||||
self._results = []
|
||||
|
||||
def add(self, res):
|
||||
self._results.append(res)
|
||||
|
||||
searx_plugins.Plugin = MockPlugin
|
||||
searx_plugins.PluginInfo = MockPluginInfo
|
||||
searx_results.EngineResults = MockEngineResults
|
||||
|
||||
sys.modules["searx"] = searx
|
||||
sys.modules["searx.plugins"] = searx_plugins
|
||||
sys.modules["searx.result_types"] = searx_results
|
||||
|
||||
from flask import Flask
|
||||
from flask_babel import Babel
|
||||
from ai_answers import SXNGPlugin
|
||||
|
||||
def run_tests():
|
||||
print()
|
||||
print("=" * 60)
|
||||
print(" AI Answers Plugin - Comprehensive Test")
|
||||
print("=" * 60)
|
||||
|
||||
# === CONFIG TEST ===
|
||||
print("\n[1/4] Configuration")
|
||||
print("-" * 40)
|
||||
|
||||
app = Flask(__name__)
|
||||
Babel(app)
|
||||
|
||||
class MockConfig:
|
||||
active = True
|
||||
|
||||
plugin = SXNGPlugin(MockConfig())
|
||||
plugin.init(app)
|
||||
|
||||
print(f" Provider: {plugin.provider or 'NOT SET'}")
|
||||
print(f" Model: {plugin.model or 'N/A'}")
|
||||
print(f" API Key: {'[OK]' if plugin.api_key else '[MISSING]'}")
|
||||
print(f" Max Tokens: {getattr(plugin, 'max_tokens', 'N/A')}")
|
||||
print(f" Temperature: {getattr(plugin, 'temperature', 'N/A')}")
|
||||
print(f" Context Count: {getattr(plugin, 'context_count', 'N/A')}")
|
||||
print(f" Allowed Tabs: {getattr(plugin, 'allowed_tabs', 'N/A')}")
|
||||
|
||||
if not plugin.api_key:
|
||||
print("\n" + "=" * 60)
|
||||
print(" SKIPPED: No LLM_KEY configured")
|
||||
print(" Set LLM_PROVIDER and LLM_KEY in .env to run full test")
|
||||
print("=" * 60)
|
||||
return False
|
||||
|
||||
# === INJECTION TEST ===
|
||||
print("\n[2/4] HTML Injection")
|
||||
print("-" * 40)
|
||||
|
||||
class MockSearchQuery:
|
||||
pageno = 1
|
||||
query = "why is the sky blue"
|
||||
lang = 'en'
|
||||
categories = ['general']
|
||||
|
||||
class MockSearch:
|
||||
search_query = MockSearchQuery()
|
||||
class MockResultContainer:
|
||||
def __init__(self):
|
||||
self.answers = set()
|
||||
def get_ordered_results(self):
|
||||
return [
|
||||
{"title": "Wikipedia", "content": "The sky appears blue due to Rayleigh scattering.", "url": "https://example.com/1", "publishedDate": "2026-01-15"},
|
||||
{"title": "NASA", "content": "Blue wavelengths scatter more than red.", "url": "https://example.com/2", "publishedDate": "2026-01-10"},
|
||||
]
|
||||
result_container = MockResultContainer()
|
||||
|
||||
search = MockSearch()
|
||||
plugin.post_search(None, search)
|
||||
|
||||
if not search.result_container.answers:
|
||||
print(" FAIL: No HTML injected")
|
||||
return False
|
||||
|
||||
html = str(list(search.result_container.answers)[0])
|
||||
|
||||
has_box = 'id="sxng-stream-box"' in html
|
||||
has_endpoint = '/ai-stream' in html
|
||||
|
||||
token_match = re.search(r'const tk = "(.*?)";', html)
|
||||
has_token = bool(token_match)
|
||||
|
||||
print(f" Stream box: {'[OK]' if has_box else '[FAIL]'}")
|
||||
print(f" Endpoint ref: {'[OK]' if has_endpoint else '[FAIL]'}")
|
||||
print(f" Auth token: {'[OK]' if has_token else '[FAIL]'}")
|
||||
print(f" HTML size: {len(html):,} bytes")
|
||||
|
||||
if not (has_box and has_endpoint and has_token):
|
||||
print(" FAIL: Missing required elements")
|
||||
return False
|
||||
|
||||
# === STREAM ENDPOINT TEST ===
|
||||
print("\n[3/4] Stream Endpoint")
|
||||
print("-" * 40)
|
||||
|
||||
with app.test_client() as client:
|
||||
payload = {
|
||||
"q": "why is the sky blue",
|
||||
"context": "[1] Wikipedia: The sky appears blue due to Rayleigh scattering.",
|
||||
"lang": "en",
|
||||
"tk": token_match.group(1)
|
||||
}
|
||||
|
||||
start = time.time()
|
||||
response = client.post('/ai-stream', json=payload)
|
||||
elapsed = time.time() - start
|
||||
|
||||
print(f" Status: {response.status_code}")
|
||||
print(f" Time: {elapsed:.2f}s")
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f" FAIL: Expected 200, got {response.status_code}")
|
||||
return False
|
||||
|
||||
# === LLM RESPONSE TEST ===
|
||||
print("\n[4/4] LLM Response")
|
||||
print("-" * 40)
|
||||
|
||||
data = response.data.decode('utf-8')
|
||||
print(f" Bytes: {len(data):,}")
|
||||
print(f" Words: ~{len(data.split())}")
|
||||
|
||||
if len(data) < 10:
|
||||
print(" FAIL: Response too short (API error?)")
|
||||
return False
|
||||
|
||||
print("\n --- Response Preview ---")
|
||||
preview = data[:500] + ("..." if len(data) > 500 else "")
|
||||
for line in preview.split('\n'):
|
||||
print(f" {line}")
|
||||
print(" --- End Preview ---")
|
||||
|
||||
# === SUMMARY ===
|
||||
print("\n" + "=" * 60)
|
||||
print(" ALL TESTS PASSED")
|
||||
print("=" * 60)
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = run_tests()
|
||||
sys.exit(0 if success else 1)
|
||||
Reference in New Issue
Block a user