search-api-webui 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
backend/app.py CHANGED
@@ -1,30 +1,45 @@
1
1
  import json
2
2
  import os
3
+ from pathlib import Path
3
4
  from flask import Flask, request, jsonify, send_from_directory
4
5
  from flask_cors import CORS
5
6
  from backend.providers import load_providers
6
7
 
8
+ CURRENT_DIR = Path(__file__).resolve().parent
9
+ STATIC_FOLDER = CURRENT_DIR / 'static'
10
+
7
11
  app = Flask(__name__, static_folder='static')
8
12
  CORS(app)
9
13
 
10
- BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
11
- PROVIDERS_YAML = os.path.join(BASE_DIR, 'providers.yaml')
12
- USER_CONFIG_JSON = os.path.join(BASE_DIR, 'user_config.json')
14
+ PROVIDERS_YAML = CURRENT_DIR / 'providers.yaml'
15
+ USER_CONFIG_DIR = Path.home() / '.search-api-webui'
16
+ USER_CONFIG_JSON = USER_CONFIG_DIR / 'config.json'
17
+
18
+ if not USER_CONFIG_DIR.exists():
19
+ USER_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
13
20
 
14
- provider_map = load_providers(PROVIDERS_YAML)
21
+ if PROVIDERS_YAML.exists():
22
+ provider_map = load_providers(str(PROVIDERS_YAML))
23
+ else:
24
+ print(f"Error: Configuration file not found at {PROVIDERS_YAML}")
25
+ provider_map = {}
15
26
 
16
27
  def get_stored_config():
17
- if not os.path.exists(USER_CONFIG_JSON):
28
+ if not USER_CONFIG_JSON.exists():
18
29
  return {}
19
30
  try:
20
- with open(USER_CONFIG_JSON, 'r') as f:
31
+ with open(USER_CONFIG_JSON, 'r', encoding='utf-8') as f:
21
32
  return json.load(f)
22
- except:
33
+ except Exception as e:
34
+ print(f"Error reading config: {e}")
23
35
  return {}
24
36
 
25
37
  def save_stored_config(config_dict):
26
- with open(USER_CONFIG_JSON, 'w') as f:
27
- json.dump(config_dict, f, indent=2)
38
+ try:
39
+ with open(USER_CONFIG_JSON, 'w', encoding='utf-8') as f:
40
+ json.dump(config_dict, f, indent=2)
41
+ except Exception as e:
42
+ print(f"Error saving config: {e}")
28
43
 
29
44
  @app.route('/api/providers', methods=['GET'])
30
45
  def get_providers_list():
@@ -127,10 +142,10 @@ def search_api():
127
142
  @app.route('/', defaults={'path': ''})
128
143
  @app.route('/<path:path>')
129
144
  def serve(path):
130
- if path != "" and os.path.exists(os.path.join(app.static_folder, path)):
131
- return send_from_directory(app.static_folder, path)
145
+ if path != "" and (STATIC_FOLDER / path).exists():
146
+ return send_from_directory(str(STATIC_FOLDER), path)
132
147
  else:
133
- return send_from_directory(app.static_folder, 'index.html')
148
+ return send_from_directory(str(STATIC_FOLDER), 'index.html')
134
149
 
135
150
  def main():
136
151
  import argparse
@@ -138,7 +153,11 @@ def main():
138
153
  parser.add_argument("--port", type=int, default=8889, help="Port to run the server on")
139
154
  parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to run the server on")
140
155
  args = parser.parse_args()
141
-
156
+
157
+ print(f"Starting Search API WebUI...")
158
+ print(f" - Config Storage: {USER_CONFIG_JSON}")
159
+ print(f" - Serving on: http://{args.host}:{args.port}")
160
+
142
161
  app.run(host=args.host, port=args.port)
143
162
 
144
163
  if __name__ == "__main__":
@@ -26,7 +26,7 @@ def load_providers(file_path='providers.yaml'):
26
26
  provider_type = conf.get('type', 'generic')
27
27
 
28
28
  # Instantiate specific provider based on type or name
29
- if name == 'querit' or provider_type == 'querit_sdk':
29
+ if provider_type == 'querit_sdk':
30
30
  providers[name] = QueritSdkProvider(conf)
31
31
  else:
32
32
  providers[name] = GenericProvider(conf)
@@ -17,6 +17,9 @@ class GenericProvider(BaseProvider):
17
17
  config (dict): Configuration containing url, headers, params, and mapping rules.
18
18
  """
19
19
  self.config = config
20
+ self.session = requests.Session() # Persistent connection session
21
+ self._connection_ready = False # Connection ready status
22
+ self._last_url = None # Last used URL tracker
20
23
 
21
24
  def _fill_template(self, template_obj, **kwargs):
22
25
  """
@@ -42,6 +45,31 @@ class GenericProvider(BaseProvider):
42
45
  return {k: self._fill_template(v, **kwargs) for k, v in template_obj.items()}
43
46
  return template_obj
44
47
 
48
+ def _ensure_connection(self, url, headers):
49
+ """
50
+ Pre-warm HTTPS connection and verify availability.
51
+ Uses lightweight HEAD request to verify connection without fetching response body.
52
+
53
+ Args:
54
+ url (str): Target URL
55
+ headers (dict): Request headers
56
+
57
+ Returns:
58
+ bool: Whether connection is ready
59
+ """
60
+ # Re-warm if URL changed or connection not ready
61
+ if url != self._last_url or not self._connection_ready:
62
+ try:
63
+ # Verify connection using HEAD request (no response body)
64
+ self.session.head(url, headers=headers, timeout=5)
65
+ self._connection_ready = True
66
+ self._last_url = url
67
+ print(f' [Connection Pool] Connected to: {url}')
68
+ except Exception as e:
69
+ self._connection_ready = False
70
+ print(f' [Connection Pool] Connection warm-up failed: {e}')
71
+ raise
72
+
45
73
  def search(self, query, api_key, **kwargs):
46
74
  # 1. Extract parameters with defaults
47
75
  limit = kwargs.get('limit', '10')
@@ -69,6 +97,18 @@ class GenericProvider(BaseProvider):
69
97
  print(f'[{self.config.get("name", "Unknown")}] Search:')
70
98
  print(f' URL: {url} | Method: {method}')
71
99
 
100
+ # Ensure connection is pre-warmed (use HEAD request to verify availability)
101
+ # Pre-warming is not counted in request latency, only verifies connection
102
+ try:
103
+ self._ensure_connection(url, headers)
104
+ except Exception as e:
105
+ print(f"Connection Warm-up Error: {e}")
106
+ return {
107
+ "error": f"Connection failed: {str(e)}",
108
+ "results": [],
109
+ "metrics": {"latency_ms": 0, "size_bytes": 0}
110
+ }
111
+
72
112
  start_time = time.time()
73
113
 
74
114
  try:
@@ -78,10 +118,11 @@ class GenericProvider(BaseProvider):
78
118
  if json_body:
79
119
  req_args['json'] = json_body
80
120
 
121
+ # Use Session to send request (connection is reused)
81
122
  if method.upper() == 'GET':
82
- response = requests.get(url, **req_args)
123
+ response = self.session.get(url, **req_args)
83
124
  else:
84
- response = requests.post(url, **req_args)
125
+ response = self.session.post(url, **req_args)
85
126
 
86
127
  response.raise_for_status()
87
128
  except Exception as e:
backend/providers.yaml CHANGED
@@ -1,7 +1,18 @@
1
1
  querit:
2
- type: "querit_sdk"
3
- description: "Official Querit Search via Python SDK"
4
- default_limit: 10
2
+ url: "https://api.querit.ai/v1/search"
3
+ method: "POST"
4
+ headers:
5
+ "Accept": "application/json"
6
+ "Authorization": "Bearer {api_key}"
7
+ "Content-Type": "application/json"
8
+ payload:
9
+ query: "{query}"
10
+ response_mapping:
11
+ root_path: "results.result"
12
+ fields:
13
+ title: "title"
14
+ url: "url"
15
+ snippet: "snippet"
5
16
 
6
17
  ydc_search:
7
18
  url: "https://ydc-index.io/v1/search"
@@ -17,3 +28,8 @@ ydc_search:
17
28
  title: "title"
18
29
  url: "url"
19
30
  snippet: "snippets[0] || description"
31
+
32
+ querit_sdk:
33
+ type: "querit_sdk"
34
+ description: "Official Querit Search via Python SDK"
35
+ default_limit: 10
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: search-api-webui
3
+ Version: 0.1.2
4
+ Summary: A Search API WebUI for Querit, You, and other search providers.
5
+ Project-URL: Homepage, https://github.com/querit-ai/search-api-webui
6
+ Project-URL: Repository, https://github.com/querit-ai/search-api-webui.git
7
+ Project-URL: Issues, https://github.com/querit-ai/search-api-webui/issues
8
+ Author: querit.ai
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,llm,querit,search,tool,webui
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: Flask
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Requires-Python: >=3.7
17
+ Requires-Dist: flask-cors
18
+ Requires-Dist: flask>=2.0.0
19
+ Requires-Dist: jmespath
20
+ Requires-Dist: pyyaml>=6.0
21
+ Requires-Dist: querit
22
+ Requires-Dist: requests>=2.25.0
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Search API WebUI
26
+
27
+ A lightweight, local WebUI for testing and visualizing Search APIs (Querit, YDC, etc.).
28
+
29
+ (images)
30
+
31
+ ## Features
32
+
33
+ **Search**: Support for Querit, You.com, and generic Search APIs via configuration.
34
+ **Performance Metrics**: Real-time display of request latency and payload size.
35
+ **Visual Rendering**: Renders standard search results (Title, Snippet, URL) in a clean card layout.
36
+ **Configurable**: Easy-to-edit providers.yaml to add or modify search providers.
37
+ **Secure**: API Keys are stored locally in user_config.json and never committed.
38
+ ## Installation
39
+
40
+ Use this method if you just want to run the tool without modifying the code.
41
+
42
+ ### Prerequisites
43
+
44
+ Python 3.7+
45
+ ### Install via Pip
46
+
47
+ ```
48
+ pip install search-api-webui
49
+ ```
50
+
51
+ ### Run the Server
52
+
53
+ ```
54
+ search-api-webui
55
+ ```
56
+
57
+ Open your browser at http://localhost:8889.
58
+
59
+ ## Development
60
+
61
+ Use this method if you want to contribute to the code or build from source.
62
+
63
+ ### Prerequisites
64
+
65
+ Python 3.7+
66
+ Node.js & npm (for building the frontend)
67
+ ### Setup Steps
68
+
69
+ **Clone the repository**
70
+ ```
71
+ git clone https://github.com/querit-ai/search-api-webui.git
72
+ cd search-api-webui
73
+ ```
74
+
75
+ **Build Frontend**
76
+ ```
77
+ cd frontend
78
+ npm install
79
+ npm run build
80
+ cd …
81
+ ```
82
+
83
+ **Install Backend (Editable Mode)**
84
+ ```
85
+ pip install -e .
86
+ ```
87
+
88
+ **Run the Server**
89
+ ```
90
+ python -m backend.app
91
+ ```
92
+
93
+ ## Configuration
94
+
95
+ ### Add API Keys
96
+
97
+ Open the WebUI settings page (click the gear icon).
98
+ Enter your API Key for the selected provider (e.g., Querit).
99
+ Keys are saved locally in user_config.json.
100
+ ### Add New Providers
101
+
102
+ Edit providers.yaml in the root directory to add custom API endpoints. The system uses JMESPath to map JSON responses to the UI.
103
+
104
+ ```
105
+ my_custom_search:
106
+ url: “https://api.example.com/search”
107
+ method: “GET”
108
+ headers:
109
+ Authorization: “Bearer {api_key}”
110
+ params:
111
+ q: “{query}”
112
+ response_mapping:
113
+ root_path: “data.items”
114
+ fields:
115
+ title: “title”
116
+ url: “link”
117
+ snippet: “snippet”
118
+ ```
119
+
120
+ ## License
121
+
122
+ MIT License. See LICENSE for details.
@@ -0,0 +1,15 @@
1
+ backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ backend/app.py,sha256=XLW8bJVgap4yZ6MUgAuJ4bxSID_zKM699nCW7L_e3XA,5144
3
+ backend/providers/__init__.py,sha256=1RfIA8eQxDLDjXrUxWzmg3tucZGv7WuZ5pJBsc6fAnQ,1052
4
+ backend/providers/base.py,sha256=_iYcxCxI7VCoxb02D71KqtojAU91D6rc3c5dwKNYJ2o,863
5
+ backend/providers/generic.py,sha256=ztwqko1KjiC2BS2afwZY2heREWLW0Kh2ZivqgLofbXU,6211
6
+ backend/providers/querit.py,sha256=5_vHXcDz59jhqY35w8vaoVH3BqGiQCYEZaekIvTKkak,2688
7
+ backend/providers.yaml,sha256=GMF7-o9eqe1AVXuMHEfdfl4OPeIZInDCqjsvO2tRHp0,752
8
+ backend/static/index.html,sha256=fhLWDY2W-bN-bBq2fmkch-e6gRZpoyqbKvNBzpWHiHk,401
9
+ backend/static/assets/index-CF13bI2g.js,sha256=91wc8meWvRXloy4vzmGN43DvrpHIjMVIdCihXCw9zBU,208926
10
+ backend/static/assets/index-DLyBd1PD.css,sha256=nevUEbN7Fw9cq3aXWV7v_tQpD00d7kr3I64dgZ-e7ys,17914
11
+ search_api_webui-0.1.2.dist-info/METADATA,sha256=0_qkPbasFwqzvM-53fSlgwyAvo8cPwSYZ-nPq3007I0,2827
12
+ search_api_webui-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
13
+ search_api_webui-0.1.2.dist-info/entry_points.txt,sha256=D9R5N6s2Bt8rEKYSINTUB1f45nH-Xc5iIKNPfYYc8ec,54
14
+ search_api_webui-0.1.2.dist-info/licenses/LICENSE,sha256=jHhlLwtvhZRz1yU1G_3cjsPigCTXQGT1qshhyekdmTE,1061
15
+ search_api_webui-0.1.2.dist-info/RECORD,,
@@ -1,93 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: search-api-webui
3
- Version: 0.1.0
4
- Summary: A Search API WebUI for Querit, You, and other search providers.
5
- Project-URL: Homepage, https://github.com/querit-ai/search-api-webui
6
- Project-URL: Repository, https://github.com/querit-ai/search-api-webui.git
7
- Project-URL: Issues, https://github.com/querit-ai/search-api-webui/issues
8
- Author: Search API WebUI Team
9
- License: MIT
10
- License-File: LICENSE
11
- Keywords: api,llm,querit,search,tool,webui
12
- Classifier: Development Status :: 3 - Alpha
13
- Classifier: Framework :: Flask
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Programming Language :: Python :: 3
16
- Requires-Python: >=3.7
17
- Requires-Dist: flask-cors
18
- Requires-Dist: flask>=2.0.0
19
- Requires-Dist: jmespath
20
- Requires-Dist: pyyaml>=6.0
21
- Requires-Dist: querit
22
- Requires-Dist: requests>=2.25.0
23
- Description-Content-Type: text/markdown
24
-
25
- # Search API WebUI
26
-
27
- A lightweight, local WebUI for testing and visualizing Search APIs (Querit, YDC, etc.).
28
-
29
- ## Features
30
-
31
- - 🔍 **Search**: Support for Querit, You.com, and generic Search APIs via configuration.
32
- - ⚡ **Performance Metrics**: Real-time display of request latency and payload size.
33
- - 🎨 **Visual Rendering**: Renders standard search results (Title, Snippet, URL) in a clean card layout.
34
- - 🛠️ **Configurable**: Easy-to-edit `providers.yaml` to add or modify search providers.
35
- - 🔒 **Secure**: API Keys are stored locally in `user_config.json` and never committed.
36
-
37
- ## Quick Start
38
-
39
- ### Prerequisites
40
-
41
- - Python 3.7+
42
- - Node.js & npm (for building the frontend)
43
-
44
- ### Installation
45
-
46
- 1. **Clone the repository**
47
- ```bash
48
- git clone https://github.com/querit-ai/search-api-webui.git
49
- cd search-api-webui
50
- ```
51
- 2. **Build Frontend**
52
- ```bash
53
- cd frontend
54
- npm install
55
- npm run build
56
- cd ..
57
- ```
58
- 3. **Install Backend**
59
- ```bash
60
- pip install -e .
61
- ```
62
-
63
- ### Usage
64
- **Run the server:**
65
- ```bash
66
- python -m backend.app
67
- ```
68
- Or if you installed via pip:
69
- ```bash
70
- search-api-webui
71
- ```
72
-
73
- Open your browser at http://localhost:8889.
74
-
75
- ## Configuration
76
- ### Add API Keys
77
- 1. Open the WebUI settings page.
78
- 2. Enter your API Key for the selected provider (e.g., Querit).
79
- 3. Keys are saved locally in user_config.json.
80
-
81
- ### Add New Providers
82
- Edit providers.yaml to add custom API endpoints. The system uses JMESPath to map JSON responses to the UI.
83
- ```yaml
84
- my_custom_search:
85
- url: "https://api.example.com/search"
86
- method: "GET"
87
- ...
88
- ```
89
- ## Development
90
- Backend: Flask (in backend/)
91
- Frontend: React + Vite (in frontend/)
92
- ## License
93
- MIT License. See LICENSE for details.
@@ -1,15 +0,0 @@
1
- backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- backend/app.py,sha256=J5GB0-rNOPq5Ny0DK5LDO_v0OqvUiMF7MM5Xk29aviM,4540
3
- backend/providers/__init__.py,sha256=l9SCd9sEISWZB-E2Co8ds2hILaxBVoh2S6SSg7MXXIo,1072
4
- backend/providers/base.py,sha256=_iYcxCxI7VCoxb02D71KqtojAU91D6rc3c5dwKNYJ2o,863
5
- backend/providers/generic.py,sha256=3dyx3Hpbo4hlfUcwy1wYt5N5dc2X3fK1iFnOoT3m_Vc,4440
6
- backend/providers/querit.py,sha256=5_vHXcDz59jhqY35w8vaoVH3BqGiQCYEZaekIvTKkak,2688
7
- backend/providers.yaml,sha256=2aRmfT7NmeU9IfUqX7phRjOf_fUACRD5ondYJO2HH4I,400
8
- backend/static/index.html,sha256=fhLWDY2W-bN-bBq2fmkch-e6gRZpoyqbKvNBzpWHiHk,401
9
- backend/static/assets/index-CF13bI2g.js,sha256=91wc8meWvRXloy4vzmGN43DvrpHIjMVIdCihXCw9zBU,208926
10
- backend/static/assets/index-DLyBd1PD.css,sha256=nevUEbN7Fw9cq3aXWV7v_tQpD00d7kr3I64dgZ-e7ys,17914
11
- search_api_webui-0.1.0.dist-info/METADATA,sha256=1xdpdSNV2TPkAGfio11onBkZp8yPjEn6Axk4KiJDAcM,2577
12
- search_api_webui-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
13
- search_api_webui-0.1.0.dist-info/entry_points.txt,sha256=D9R5N6s2Bt8rEKYSINTUB1f45nH-Xc5iIKNPfYYc8ec,54
14
- search_api_webui-0.1.0.dist-info/licenses/LICENSE,sha256=jHhlLwtvhZRz1yU1G_3cjsPigCTXQGT1qshhyekdmTE,1061
15
- search_api_webui-0.1.0.dist-info/RECORD,,