mirror of
				https://github.com/searxng/searxng.git
				synced 2025-11-04 03:27:06 -05:00 
			
		
		
		
	[enh] autocompleter server side part
This commit is contained in:
		
							parent
							
								
									20504a0e83
								
							
						
					
					
						commit
						41dd4d9ba3
					
				@ -5,9 +5,6 @@ server:
 | 
				
			|||||||
    request_timeout : 2.0 # seconds
 | 
					    request_timeout : 2.0 # seconds
 | 
				
			||||||
    base_url : False
 | 
					    base_url : False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
client:
 | 
					 | 
				
			||||||
    autocompleter : False # only for developers, no real results yet
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
engines:
 | 
					engines:
 | 
				
			||||||
  - name : wikipedia
 | 
					  - name : wikipedia
 | 
				
			||||||
    engine : wikipedia
 | 
					    engine : wikipedia
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@ if(searx.autocompleter) {
 | 
				
			|||||||
		        timeout: 5   // Correct option?
 | 
							        timeout: 5   // Correct option?
 | 
				
			||||||
		    },
 | 
							    },
 | 
				
			||||||
		    'minLength': 4,
 | 
							    'minLength': 4,
 | 
				
			||||||
		    'selectMode': 'type-ahead',
 | 
							    // 'selectMode': 'type-ahead',
 | 
				
			||||||
		    cache: true,
 | 
							    cache: true,
 | 
				
			||||||
		    delay: 300
 | 
							    delay: 300
 | 
				
			||||||
	    });
 | 
						    });
 | 
				
			||||||
 | 
				
			|||||||
@ -15,14 +15,14 @@
 | 
				
			|||||||
    {% endblock %}
 | 
					    {% endblock %}
 | 
				
			||||||
    <script type="text/javascript">
 | 
					    <script type="text/javascript">
 | 
				
			||||||
        searx = {};
 | 
					        searx = {};
 | 
				
			||||||
        searx.autocompleter = {% if client.autocompleter %}true{% else %}false{% endif %};
 | 
					        searx.autocompleter = {% if autocomplete %}true{% else %}false{% endif %};
 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
<div id="container">
 | 
					<div id="container">
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
{% if client.autocompleter %}
 | 
					{% if autocomplete %}
 | 
				
			||||||
<script src="{{ url_for('static', filename='js/mootools-core-1.4.5-min.js') }}" ></script>
 | 
					<script src="{{ url_for('static', filename='js/mootools-core-1.4.5-min.js') }}" ></script>
 | 
				
			||||||
<script src="{{ url_for('static', filename='js/mootools-autocompleter-1.1.2-min.js') }}" ></script>
 | 
					<script src="{{ url_for('static', filename='js/mootools-autocompleter-1.1.2-min.js') }}" ></script>
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@
 | 
				
			|||||||
        <select name='language'>
 | 
					        <select name='language'>
 | 
				
			||||||
            <option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Automatic') }}</option>
 | 
					            <option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Automatic') }}</option>
 | 
				
			||||||
            {% for lang_id,lang_name,country_name in language_codes %}
 | 
					            {% for lang_id,lang_name,country_name in language_codes %}
 | 
				
			||||||
            <option value={{ lang_id }} {% if lang_id == current_language %}selected="selected"{% endif %}>{{ lang_name}} ({{ country_name }}) - {{ lang_id }}</option>
 | 
					            <option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>{{ lang_name }} ({{ country_name }}) - {{ lang_id }}</option>
 | 
				
			||||||
            {% endfor %}
 | 
					            {% endfor %}
 | 
				
			||||||
        </select>
 | 
					        </select>
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
@ -27,7 +27,18 @@
 | 
				
			|||||||
        <p>
 | 
					        <p>
 | 
				
			||||||
        <select name='locale'>
 | 
					        <select name='locale'>
 | 
				
			||||||
            {% for locale_id,locale_name in locales.items() %}
 | 
					            {% for locale_id,locale_name in locales.items() %}
 | 
				
			||||||
            <option value={{ locale_id }} {% if locale_id == current_locale %}selected="selected"{% endif %}>{{ locale_name}}</option>
 | 
					            <option value="{{ locale_id }}" {% if locale_id == current_locale %}selected="selected"{% endif %}>{{ locale_name }}</option>
 | 
				
			||||||
 | 
					            {% endfor %}
 | 
				
			||||||
 | 
					        </select>
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					    </fieldset>
 | 
				
			||||||
 | 
					    <fieldset>
 | 
				
			||||||
 | 
					        <legend>{{ _('Autocomplete') }}</legend>
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					        <select name="autocomplete">
 | 
				
			||||||
 | 
					            <option value=""> - </option>
 | 
				
			||||||
 | 
					            {% for backend in autocomplete_backends %}
 | 
				
			||||||
 | 
					            <option value="{{ backend }}" {% if backend == autocomplete %}selected="selected"{% endif %}>{{ backend }}</option>
 | 
				
			||||||
            {% endfor %}
 | 
					            {% endfor %}
 | 
				
			||||||
        </select>
 | 
					        </select>
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
 | 
				
			|||||||
@ -41,6 +41,7 @@ from searx.engines import (
 | 
				
			|||||||
from searx.utils import UnicodeWriter, highlight_content, html_to_text
 | 
					from searx.utils import UnicodeWriter, highlight_content, html_to_text
 | 
				
			||||||
from searx.languages import language_codes
 | 
					from searx.languages import language_codes
 | 
				
			||||||
from searx.search import Search
 | 
					from searx.search import Search
 | 
				
			||||||
 | 
					from searx.autocomplete import backends as autocomplete_backends
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app = Flask(
 | 
					app = Flask(
 | 
				
			||||||
@ -91,16 +92,25 @@ def get_base_url():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def render(template_name, **kwargs):
 | 
					def render(template_name, **kwargs):
 | 
				
			||||||
    blocked_engines = request.cookies.get('blocked_engines', '').split(',')
 | 
					    blocked_engines = request.cookies.get('blocked_engines', '').split(',')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    autocomplete = request.cookies.get('autocomplete')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if autocomplete not in autocomplete_backends:
 | 
				
			||||||
 | 
					        autocomplete = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nonblocked_categories = (engines[e].categories
 | 
					    nonblocked_categories = (engines[e].categories
 | 
				
			||||||
                             for e in engines
 | 
					                             for e in engines
 | 
				
			||||||
                             if e not in blocked_engines)
 | 
					                             if e not in blocked_engines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nonblocked_categories = set(chain.from_iterable(nonblocked_categories))
 | 
					    nonblocked_categories = set(chain.from_iterable(nonblocked_categories))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not 'categories' in kwargs:
 | 
					    if not 'categories' in kwargs:
 | 
				
			||||||
        kwargs['categories'] = ['general']
 | 
					        kwargs['categories'] = ['general']
 | 
				
			||||||
        kwargs['categories'].extend(x for x in
 | 
					        kwargs['categories'].extend(x for x in
 | 
				
			||||||
                                    sorted(categories.keys())
 | 
					                                    sorted(categories.keys())
 | 
				
			||||||
                                    if x != 'general'
 | 
					                                    if x != 'general'
 | 
				
			||||||
                                    and x in nonblocked_categories)
 | 
					                                    and x in nonblocked_categories)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not 'selected_categories' in kwargs:
 | 
					    if not 'selected_categories' in kwargs:
 | 
				
			||||||
        kwargs['selected_categories'] = []
 | 
					        kwargs['selected_categories'] = []
 | 
				
			||||||
        cookie_categories = request.cookies.get('categories', '').split(',')
 | 
					        cookie_categories = request.cookies.get('categories', '').split(',')
 | 
				
			||||||
@ -109,6 +119,10 @@ def render(template_name, **kwargs):
 | 
				
			|||||||
                kwargs['selected_categories'].append(ccateg)
 | 
					                kwargs['selected_categories'].append(ccateg)
 | 
				
			||||||
        if not kwargs['selected_categories']:
 | 
					        if not kwargs['selected_categories']:
 | 
				
			||||||
            kwargs['selected_categories'] = ['general']
 | 
					            kwargs['selected_categories'] = ['general']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not 'autocomplete' in kwargs:
 | 
				
			||||||
 | 
					        kwargs['autocomplete'] = autocomplete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return render_template(template_name, **kwargs)
 | 
					    return render_template(template_name, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -122,7 +136,6 @@ def index():
 | 
				
			|||||||
    if not request.args and not request.form:
 | 
					    if not request.args and not request.form:
 | 
				
			||||||
        return render(
 | 
					        return render(
 | 
				
			||||||
            'index.html',
 | 
					            'index.html',
 | 
				
			||||||
            client=settings.get('client', None)
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@ -130,7 +143,6 @@ def index():
 | 
				
			|||||||
    except:
 | 
					    except:
 | 
				
			||||||
        return render(
 | 
					        return render(
 | 
				
			||||||
            'index.html',
 | 
					            'index.html',
 | 
				
			||||||
            client=settings.get('client', None)
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # TODO moar refactor - do_search integration into Search class
 | 
					    # TODO moar refactor - do_search integration into Search class
 | 
				
			||||||
@ -212,7 +224,6 @@ def index():
 | 
				
			|||||||
    return render(
 | 
					    return render(
 | 
				
			||||||
        'results.html',
 | 
					        'results.html',
 | 
				
			||||||
        results=search.results,
 | 
					        results=search.results,
 | 
				
			||||||
        client=settings.get('client', None),
 | 
					 | 
				
			||||||
        q=search.request_data['q'],
 | 
					        q=search.request_data['q'],
 | 
				
			||||||
        selected_categories=search.categories,
 | 
					        selected_categories=search.categories,
 | 
				
			||||||
        paging=search.paging,
 | 
					        paging=search.paging,
 | 
				
			||||||
@ -227,7 +238,6 @@ def about():
 | 
				
			|||||||
    """Render about page"""
 | 
					    """Render about page"""
 | 
				
			||||||
    return render(
 | 
					    return render(
 | 
				
			||||||
        'about.html',
 | 
					        'about.html',
 | 
				
			||||||
        client=settings.get('client', None)
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -235,27 +245,35 @@ def about():
 | 
				
			|||||||
def autocompleter():
 | 
					def autocompleter():
 | 
				
			||||||
    """Return autocompleter results"""
 | 
					    """Return autocompleter results"""
 | 
				
			||||||
    request_data = {}
 | 
					    request_data = {}
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    if request.method == 'POST':
 | 
					    if request.method == 'POST':
 | 
				
			||||||
        request_data = request.form
 | 
					        request_data = request.form
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        request_data = request.args
 | 
					        request_data = request.args
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    # TODO fix XSS-vulnerability
 | 
					    # TODO fix XSS-vulnerability
 | 
				
			||||||
    autocompleter.querry = request_data.get('q')
 | 
					    query = request_data.get('q')
 | 
				
			||||||
    autocompleter.results = []
 | 
					
 | 
				
			||||||
    
 | 
					    if not query:
 | 
				
			||||||
    if settings['client']['autocompleter']:
 | 
					        return
 | 
				
			||||||
        #TODO remove test code and add real autocompletion
 | 
					
 | 
				
			||||||
        if autocompleter.querry:
 | 
					    completer = autocomplete_backends.get(request.cookies.get('autocomplete'))
 | 
				
			||||||
            autocompleter.results = [autocompleter.querry + " result-1",autocompleter.querry + " result-2",autocompleter.querry + " result-3",autocompleter.querry + " result-4"]
 | 
					
 | 
				
			||||||
    
 | 
					    if not completer:
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        results = completer(query)
 | 
				
			||||||
 | 
					    except Exception, e:
 | 
				
			||||||
 | 
					        print e
 | 
				
			||||||
 | 
					        results = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if request_data.get('format') == 'x-suggestions':
 | 
					    if request_data.get('format') == 'x-suggestions':
 | 
				
			||||||
        return Response(json.dumps([autocompleter.querry,autocompleter.results]),
 | 
					        return Response(json.dumps([query, results]),
 | 
				
			||||||
                                   mimetype='application/json')
 | 
					                        mimetype='application/json')
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return Response(json.dumps(autocompleter.results),
 | 
					        return Response(json.dumps(results),
 | 
				
			||||||
                                   mimetype='application/json')
 | 
					                        mimetype='application/json')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route('/preferences', methods=['GET', 'POST'])
 | 
					@app.route('/preferences', methods=['GET', 'POST'])
 | 
				
			||||||
@ -276,6 +294,7 @@ def preferences():
 | 
				
			|||||||
    else:
 | 
					    else:
 | 
				
			||||||
        selected_categories = []
 | 
					        selected_categories = []
 | 
				
			||||||
        locale = None
 | 
					        locale = None
 | 
				
			||||||
 | 
					        autocomplete = ''
 | 
				
			||||||
        for pd_name, pd in request.form.items():
 | 
					        for pd_name, pd in request.form.items():
 | 
				
			||||||
            if pd_name.startswith('category_'):
 | 
					            if pd_name.startswith('category_'):
 | 
				
			||||||
                category = pd_name[9:]
 | 
					                category = pd_name[9:]
 | 
				
			||||||
@ -284,6 +303,8 @@ def preferences():
 | 
				
			|||||||
                selected_categories.append(category)
 | 
					                selected_categories.append(category)
 | 
				
			||||||
            elif pd_name == 'locale' and pd in settings['locales']:
 | 
					            elif pd_name == 'locale' and pd in settings['locales']:
 | 
				
			||||||
                locale = pd
 | 
					                locale = pd
 | 
				
			||||||
 | 
					            elif pd_name == 'autocomplete':
 | 
				
			||||||
 | 
					                autocomplete = pd
 | 
				
			||||||
            elif pd_name == 'language' and (pd == 'all' or
 | 
					            elif pd_name == 'language' and (pd == 'all' or
 | 
				
			||||||
                                            pd in (x[0] for
 | 
					                                            pd in (x[0] for
 | 
				
			||||||
                                                   x in language_codes)):
 | 
					                                                   x in language_codes)):
 | 
				
			||||||
@ -319,8 +340,14 @@ def preferences():
 | 
				
			|||||||
            # cookie max age: 4 weeks
 | 
					            # cookie max age: 4 weeks
 | 
				
			||||||
            resp.set_cookie(
 | 
					            resp.set_cookie(
 | 
				
			||||||
                'categories', ','.join(selected_categories),
 | 
					                'categories', ','.join(selected_categories),
 | 
				
			||||||
                max_age=60 * 60 * 24 * 7 * 4
 | 
					                max_age=cookie_max_age
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            resp.set_cookie(
 | 
				
			||||||
 | 
					                'autocomplete', autocomplete,
 | 
				
			||||||
 | 
					                max_age=cookie_max_age
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return resp
 | 
					        return resp
 | 
				
			||||||
    return render('preferences.html',
 | 
					    return render('preferences.html',
 | 
				
			||||||
                  client=settings.get('client', None),
 | 
					                  client=settings.get('client', None),
 | 
				
			||||||
@ -330,6 +357,7 @@ def preferences():
 | 
				
			|||||||
                  language_codes=language_codes,
 | 
					                  language_codes=language_codes,
 | 
				
			||||||
                  categs=categories.items(),
 | 
					                  categs=categories.items(),
 | 
				
			||||||
                  blocked_engines=blocked_engines,
 | 
					                  blocked_engines=blocked_engines,
 | 
				
			||||||
 | 
					                  autocomplete_backends=autocomplete_backends,
 | 
				
			||||||
                  shortcuts={y: x for x, y in engine_shortcuts.items()})
 | 
					                  shortcuts={y: x for x, y in engine_shortcuts.items()})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -361,7 +389,12 @@ def opensearch():
 | 
				
			|||||||
    # chrome/chromium only supports HTTP GET....
 | 
					    # chrome/chromium only supports HTTP GET....
 | 
				
			||||||
    if request.headers.get('User-Agent', '').lower().find('webkit') >= 0:
 | 
					    if request.headers.get('User-Agent', '').lower().find('webkit') >= 0:
 | 
				
			||||||
        method = 'get'
 | 
					        method = 'get'
 | 
				
			||||||
    ret = render('opensearch.xml', method=method, host=get_base_url(),client=settings['client'])
 | 
					
 | 
				
			||||||
 | 
					    ret = render('opensearch.xml',
 | 
				
			||||||
 | 
					                 method=method,
 | 
				
			||||||
 | 
					                 host=get_base_url(),
 | 
				
			||||||
 | 
					                 client=settings['client'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    resp = Response(response=ret,
 | 
					    resp = Response(response=ret,
 | 
				
			||||||
                    status=200,
 | 
					                    status=200,
 | 
				
			||||||
                    mimetype="application/xml")
 | 
					                    mimetype="application/xml")
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user