File size: 4,523 Bytes
f02770e
409c813
5a18aa8
 
ceb6868
5a18aa8
 
 
 
 
 
 
 
 
 
9fe0994
8b21f9c
5a18aa8
23d2217
8b21f9c
 
 
 
 
 
 
 
 
 
 
 
 
 
ceb6868
5a18aa8
 
 
 
 
 
8b21f9c
 
5a18aa8
 
 
8b21f9c
 
436f2c6
8b21f9c
 
 
 
 
 
 
 
5a18aa8
 
8b21f9c
 
 
5a18aa8
 
 
8b21f9c
 
5a18aa8
 
8b21f9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436f2c6
8b21f9c
 
 
 
 
 
 
 
 
 
 
 
 
00536e4
8b21f9c
 
436f2c6
9fe0994
 
8b21f9c
 
 
9fe0994
8b21f9c
 
 
 
 
 
 
 
 
409c813
8b21f9c
f02770e
8b21f9c
f02770e
8b21f9c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import gradio as gr
import requests
from tenacity import retry, wait_exponential, stop_after_attempt, retry_if_exception_type
import json

# Define custom exceptions for clarity
class RateLimitException(Exception):
    pass

# Retry configuration: Retry up to 5 times with exponential backoff
@retry(
    wait=wait_exponential(multiplier=1, min=4, max=10),
    stop=stop_after_attempt(5),
    retry=retry_if_exception_type(RateLimitException)
)
def search_searx(query, instance_url='https://searx.org', categories='general'):
    """
    Perform a search using the Searx API with retry logic.

    :param query: The search query string.
    :param instance_url: The URL of the Searx instance.
    :param categories: Categories to search in (e.g., 'general', 'images', 'videos').
    :return: A list of formatted search results or an error message.
    """
    search_endpoint = f"{instance_url}/search"
    params = {
        'q': query,
        'format': 'json',
        'categories': categories,
        'pageno': 1,          # Page number
        'time_range': '',     # Time range filter
        'engines': '',        # Specify search engines, comma-separated
        'safesearch': '0'     # Safe search (0: off, 1: moderate, 2: strict)
    }
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' +
                      'AppleWebKit/537.36 (KHTML, like Gecko) ' +
                      'Chrome/58.0.3029.110 Safari/537.3'
    }

    try:
        response = requests.get(search_endpoint, params=params, headers=headers, timeout=10)
        if response.status_code == 429:
            raise RateLimitException("Rate limit exceeded. Retrying...")
        response.raise_for_status()  # Raise an error for bad status codes
        data = response.json()
        
        if 'results' not in data or not data['results']:
            return "No results found."

        formatted_results = ""
        for idx, result in enumerate(data['results'], start=1):
            title = result.get('title', 'No Title')
            url = result.get('url', 'No URL')
            snippet = result.get('content', 'No Description')
            # Using Markdown link formatting
            formatted_results += f"**{idx}. [{title}]({url})**\n{snippet}\n\n"

        return formatted_results

    except RateLimitException as e:
        # After retries, if still failing due to rate limits
        return f"Rate limit exceeded. Please try again later.\nError: {e}"
    except requests.exceptions.RequestException as e:
        return f"An error occurred while searching: {e}"
    except json.JSONDecodeError:
        return "Failed to parse the response from the Searx instance."

def create_gradio_interface():
    """
    Creates and returns the Gradio interface.
    """
    with gr.Blocks() as demo:
        gr.Markdown("# 🕵️‍♂️ Private Search with Searx and Gradio")
        gr.Markdown(
            "This application allows you to perform private searches using the [Searx](https://searx.org/) metasearch engine."
        )

        with gr.Row():
            with gr.Column():
                query = gr.Textbox(
                    label="Search Query",
                    placeholder="Enter your search query here...",
                    lines=1
                )
                instance_url = gr.Textbox(
                    label="Searx Instance URL",
                    value="https://searx.org",
                    placeholder="https://searx.instance.url",
                    lines=1
                )
                categories = gr.Textbox(
                    label="Categories",
                    value="general",
                    placeholder="e.g., general, images, videos",
                    lines=1
                )
                search_button = gr.Button("Search")

            with gr.Column():
                results = gr.Markdown("### Search Results will appear here...")

        def perform_search(q, url, cats):
            return search_searx(q, instance_url=url, categories=cats)

        search_button.click(
            perform_search,
            inputs=[query, instance_url, categories],
            outputs=results
        )

        gr.Markdown(
            """
            ---
            **Note:** This application uses the Searx metasearch engine to fetch results from multiple sources while preserving your privacy.
            """
        )

    return demo

iface = create_gradio_interface()

if __name__ == "__main__":
    iface.launch()