indoxrouter 0.1.8__py3-none-any.whl → 0.1.11__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.
indoxrouter/client.py CHANGED
@@ -5,6 +5,9 @@ This module provides a client for interacting with the IndoxRouter API, which se
5
5
  interface to multiple AI providers and models. The client handles authentication, rate limiting,
6
6
  error handling, and provides a standardized response format across different AI services.
7
7
 
8
+ IMPORTANT: The IndoxRouter server now supports only cookie-based authentication. This client
9
+ automatically handles authentication by exchanging your API key for a JWT token through the login endpoint.
10
+
8
11
  The Client class offers methods for:
9
12
  - Authentication and session management
10
13
  - Making API requests with automatic token refresh
@@ -71,6 +74,7 @@ from .constants import (
71
74
  IMAGE_ENDPOINT,
72
75
  MODEL_ENDPOINT,
73
76
  USAGE_ENDPOINT,
77
+ USE_COOKIES,
74
78
  )
75
79
 
76
80
  logger = logging.getLogger(__name__)
@@ -84,7 +88,6 @@ class Client:
84
88
  def __init__(
85
89
  self,
86
90
  api_key: Optional[str] = None,
87
- base_url: Optional[str] = None,
88
91
  timeout: int = DEFAULT_TIMEOUT,
89
92
  ):
90
93
  """
@@ -93,19 +96,91 @@ class Client:
93
96
  Args:
94
97
  api_key: API key for authentication. If not provided, the client will look for the
95
98
  INDOX_ROUTER_API_KEY environment variable.
96
- base_url: Custom base URL for the API. If not provided, the default base URL will be used.
97
99
  timeout: Request timeout in seconds.
98
100
  """
101
+
102
+ use_cookies = USE_COOKIES
99
103
  self.api_key = api_key or os.environ.get("INDOX_ROUTER_API_KEY")
100
104
  if not self.api_key:
101
105
  raise ValueError(
102
106
  "API key must be provided either as an argument or as the INDOX_ROUTER_API_KEY environment variable."
103
107
  )
104
108
 
105
- self.base_url = base_url or DEFAULT_BASE_URL
109
+ self.base_url = DEFAULT_BASE_URL
106
110
  self.timeout = timeout
111
+ self.use_cookies = use_cookies
107
112
  self.session = requests.Session()
108
- self.session.headers.update({"Authorization": f"Bearer {self.api_key}"})
113
+
114
+ # Authenticate and get JWT tokens
115
+ self._authenticate()
116
+
117
+ def _authenticate(self):
118
+ """
119
+ Authenticate with the server and get JWT tokens.
120
+ This uses the /auth/token endpoint to get JWT tokens using the API key.
121
+ """
122
+ try:
123
+ # First try using the API key as a username with empty password (API key flow)
124
+ logger.debug("Authenticating with API key as username")
125
+ response = self.session.post(
126
+ f"{self.base_url}/api/v1/auth/token",
127
+ data={
128
+ "username": self.api_key,
129
+ "password": "",
130
+ },
131
+ timeout=self.timeout,
132
+ )
133
+
134
+ if response.status_code != 200:
135
+ # Try using email:api_key format if the first method fails
136
+ logger.debug(
137
+ "First auth method failed, trying with API key as password"
138
+ )
139
+ response = self.session.post(
140
+ f"{self.base_url}/api/v1/auth/login",
141
+ json={
142
+ "username": "pip_client",
143
+ "password": self.api_key,
144
+ },
145
+ timeout=self.timeout,
146
+ )
147
+
148
+ if response.status_code != 200:
149
+ error_data = {}
150
+ try:
151
+ error_data = response.json()
152
+ except:
153
+ error_data = {"detail": response.text}
154
+
155
+ raise AuthenticationError(
156
+ f"Authentication failed: {error_data.get('detail', 'Unknown error')}"
157
+ )
158
+
159
+ # At this point, the cookies should be set in the session
160
+ logger.debug("Authentication successful")
161
+
162
+ # Check if we have the cookies we need
163
+ if "access_token" not in self.session.cookies:
164
+ logger.warning(
165
+ "Authentication succeeded but no access_token cookie was set"
166
+ )
167
+
168
+ except requests.RequestException as e:
169
+ logger.error(f"Authentication request failed: {str(e)}")
170
+ raise NetworkError(f"Network error during authentication: {str(e)}")
171
+
172
+ def _get_domain(self):
173
+ """
174
+ Extract domain from the base URL for cookie setting.
175
+ """
176
+ try:
177
+ from urllib.parse import urlparse
178
+
179
+ parsed_url = urlparse(self.base_url)
180
+ return parsed_url.netloc
181
+ except Exception:
182
+ # If parsing fails, return a default value
183
+ return ""
109
184
 
110
185
  def enable_debug(self, level=logging.DEBUG):
111
186
  """
@@ -177,6 +252,24 @@ class Client:
177
252
  if stream:
178
253
  return response
179
254
 
255
+ # Check if we need to reauthenticate (401 Unauthorized)
256
+ if response.status_code == 401:
257
+ logger.debug("Received 401, attempting to reauthenticate")
258
+ self._authenticate()
259
+
260
+ # Retry the request after reauthentication
261
+ response = self.session.request(
262
+ method,
263
+ url,
264
+ headers=headers,
265
+ json=data,
266
+ timeout=self.timeout,
267
+ stream=stream,
268
+ )
269
+
270
+ if stream:
271
+ return response
272
+
180
273
  response.raise_for_status()
181
274
  return response.json()
182
275
  except requests.HTTPError as e:
indoxrouter/constants.py CHANGED
@@ -7,6 +7,7 @@ DEFAULT_API_VERSION = "v1"
7
7
  DEFAULT_BASE_URL = "https://api.indox.org" # Production server URL with HTTPS
8
8
  # DEFAULT_BASE_URL = "http://localhost:8000" # Local development server
9
9
  DEFAULT_TIMEOUT = 60
10
+ USE_COOKIES = True # Always use cookie-based authentication
10
11
 
11
12
  # Default models
12
13
  DEFAULT_MODEL = "openai/gpt-4o-mini"
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Test script for the IndoxRouter client.
4
+ This script tests authentication and basic functionality of the client.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import logging
10
+ from indoxrouter import Client, AuthenticationError, NetworkError
11
+
12
+ # Set up logging
13
+ logging.basicConfig(
14
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
15
+ )
16
+ logger = logging.getLogger("indoxrouter_test")
17
+
18
+
19
+ def test_client(api_key=None, debug=False):
20
+ """
21
+ Test the IndoxRouter client with the provided API key.
22
+
23
+ Args:
24
+ api_key: API key to use for authentication
25
+ debug: Whether to enable debug logging
26
+ """
27
+ if debug:
28
+ logging.getLogger("indoxrouter").setLevel(logging.DEBUG)
29
+
30
+ logger.info("Testing IndoxRouter client...")
31
+
32
+ # If no API key is provided, try to get it from environment variable
33
+ if not api_key:
34
+ api_key = os.environ.get("INDOX_ROUTER_API_KEY")
35
+ if not api_key:
36
+ logger.error(
37
+ "No API key provided. Please provide an API key as an argument or set the INDOX_ROUTER_API_KEY environment variable."
38
+ )
39
+ sys.exit(1)
40
+
41
+ try:
42
+ # Initialize client
43
+ logger.info("Initializing client...")
44
+ client = Client(api_key=api_key)
45
+
46
+ # Test connection
47
+ logger.info("Testing connection...")
48
+ connection_info = client.test_connection()
49
+ logger.info(f"Connection test: {connection_info['status']}")
50
+
51
+ # Try to get available models
52
+ logger.info("Fetching available models...")
53
+ models = client.models()
54
+
55
+ # Display some models
56
+ providers = [p.get("name") for p in models]
57
+ logger.info(f"Available providers: {', '.join(providers)}")
58
+
59
+ # Try a simple chat completion
60
+ logger.info("Testing chat completion...")
61
+ response = client.chat(
62
+ messages=[{"role": "user", "content": "Hello, who are you?"}],
63
+ model="openai/gpt-3.5-turbo",
64
+ max_tokens=30,
65
+ )
66
+
67
+ logger.info("Chat completion successful!")
68
+ logger.info(f"Response: {response['choices'][0]['message']['content']}")
69
+
70
+ logger.info("All tests passed! The client is working correctly.")
71
+
72
+ except AuthenticationError as e:
73
+ logger.error(f"Authentication error: {e}")
74
+ logger.error("Please check that your API key is correct.")
75
+ sys.exit(1)
76
+ except NetworkError as e:
77
+ logger.error(f"Network error: {e}")
78
+ logger.error(
79
+ "Please check your internet connection and that the IndoxRouter server is accessible."
80
+ )
81
+ sys.exit(1)
82
+ except Exception as e:
83
+ logger.error(f"Unexpected error: {e}")
84
+ sys.exit(1)
85
+
86
+
87
+ if __name__ == "__main__":
88
+ import argparse
89
+
90
+ parser = argparse.ArgumentParser(description="Test the IndoxRouter client")
91
+ parser.add_argument("--api-key", "-k", help="API key to use for authentication")
92
+ parser.add_argument(
93
+ "--debug", "-d", action="store_true", help="Enable debug logging"
94
+ )
95
+
96
+ args = parser.parse_args()
97
+
98
+ test_client(api_key=args.api_key, debug=args.debug)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: indoxrouter
3
- Version: 0.1.8
3
+ Version: 0.1.11
4
4
  Summary: A unified client for various AI providers
5
5
  Home-page: https://github.com/indoxrouter/indoxrouter
6
6
  Author: indoxRouter Team
@@ -45,7 +45,7 @@ A unified client for various AI providers, including OpenAI, Anthropic, Google,
45
45
  - **Unified API**: Access multiple AI providers through a single API
46
46
  - **Simple Interface**: Easy-to-use methods for chat, completion, embeddings, and image generation
47
47
  - **Error Handling**: Standardized error handling across providers
48
- - **Authentication**: Automatic token management
48
+ - **Authentication**: Secure cookie-based authentication
49
49
 
50
50
  ## Installation
51
51
 
@@ -60,7 +60,7 @@ pip install indoxrouter
60
60
  ```python
61
61
  from indoxrouter import Client
62
62
 
63
- # Initialize with API key (default connects to localhost:8000)
63
+ # Initialize with API key
64
64
  client = Client(api_key="your_api_key")
65
65
 
66
66
  # Using environment variables
@@ -68,6 +68,42 @@ client = Client(api_key="your_api_key")
68
68
  import os
69
69
  os.environ["INDOX_ROUTER_API_KEY"] = "your_api_key"
70
70
  client = Client()
71
+
72
+ # Connect to a custom server
73
+ client = Client(
74
+ api_key="your_api_key",
75
+ base_url="https://your-indoxrouter-server.com"
76
+ )
77
+ ```
78
+
79
+ ### Authentication
80
+
81
+ IndoxRouter uses cookie-based authentication with JWT tokens. The client handles this automatically by:
82
+
83
+ 1. Taking your API key and exchanging it for JWT tokens using the server's authentication endpoints
84
+ 2. Storing the JWT tokens in cookies
85
+ 3. Using the cookies for subsequent requests
86
+ 4. Automatically refreshing tokens when they expire
87
+
88
+ ```python
89
+ # Authentication is handled automatically when creating the client
90
+ client = Client(api_key="your_api_key")
91
+ ```
92
+
93
+ ### Testing Your API Key
94
+
95
+ The package includes a test script to verify your API key and connection:
96
+
97
+ ```bash
98
+ # Run the test script with your API key
99
+ python -m indoxrouter.test_api_key --api-key YOUR_API_KEY
100
+
101
+ # Or set the environment variable and run
102
+ export INDOX_ROUTER_API_KEY=YOUR_API_KEY
103
+ python -m indoxrouter.test_api_key
104
+
105
+ # To see detailed debugging information
106
+ python -m indoxrouter.test_api_key --debug
71
107
  ```
72
108
 
73
109
  ### Chat Completions
@@ -0,0 +1,9 @@
1
+ indoxrouter/__init__.py,sha256=28pdx482uGFF_S1msov0LTTGsFTvVBKRqMkDmoXWUBY,1416
2
+ indoxrouter/client.py,sha256=Bt8JuU7G_TSX2sVn3Voi6UBXeZnmG-vLCGniAGh_r5U,27387
3
+ indoxrouter/constants.py,sha256=D-l5qhEmeDIXOEfogvf6lJI1Sw_fXSKZy-Nj_l_MV7E,1184
4
+ indoxrouter/exceptions.py,sha256=0ULxtK9va4718PGTO5VoClXYEJeojpiM-7AganeiZZ4,1263
5
+ indoxrouter/test_api_key.py,sha256=u4fUTJwxC7-kTrLdCq8u5a1Mx66jeExfsBlHLhyzNmA,3229
6
+ indoxrouter-0.1.11.dist-info/METADATA,sha256=3SEOZwK_ZKPQCfZc7BRKYQ8q3u4meMtmSIbSY4VYZxg,6004
7
+ indoxrouter-0.1.11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
8
+ indoxrouter-0.1.11.dist-info/top_level.txt,sha256=v6FGWkw0QAnXhyYtnXLI1cxzna0iveNvZUotVzCWabM,12
9
+ indoxrouter-0.1.11.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- indoxrouter/__init__.py,sha256=28pdx482uGFF_S1msov0LTTGsFTvVBKRqMkDmoXWUBY,1416
2
- indoxrouter/client.py,sha256=1XhBiz6CBoN_jNgKmmHvyXecdHZftDckssY2lAir_tA,24044
3
- indoxrouter/constants.py,sha256=m5EW5DOxjpvjwj_u2AxMf_5RuPpjpx2Iih35b0E0LEY,1123
4
- indoxrouter/exceptions.py,sha256=0ULxtK9va4718PGTO5VoClXYEJeojpiM-7AganeiZZ4,1263
5
- indoxrouter-0.1.8.dist-info/METADATA,sha256=HZqWq-PhdEuCfSzROo7L5rQPCvnbSJVur4CKLjMqD98,4971
6
- indoxrouter-0.1.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
7
- indoxrouter-0.1.8.dist-info/top_level.txt,sha256=v6FGWkw0QAnXhyYtnXLI1cxzna0iveNvZUotVzCWabM,12
8
- indoxrouter-0.1.8.dist-info/RECORD,,