local-openai2anthropic 0.3.6__py3-none-any.whl → 0.3.7__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.
- local_openai2anthropic/__init__.py +1 -1
- local_openai2anthropic/config.py +153 -6
- local_openai2anthropic/main.py +2 -2
- {local_openai2anthropic-0.3.6.dist-info → local_openai2anthropic-0.3.7.dist-info}/METADATA +2 -2
- {local_openai2anthropic-0.3.6.dist-info → local_openai2anthropic-0.3.7.dist-info}/RECORD +8 -8
- {local_openai2anthropic-0.3.6.dist-info → local_openai2anthropic-0.3.7.dist-info}/WHEEL +0 -0
- {local_openai2anthropic-0.3.6.dist-info → local_openai2anthropic-0.3.7.dist-info}/entry_points.txt +0 -0
- {local_openai2anthropic-0.3.6.dist-info → local_openai2anthropic-0.3.7.dist-info}/licenses/LICENSE +0 -0
local_openai2anthropic/config.py
CHANGED
|
@@ -88,6 +88,135 @@ websearch_max_uses = 5
|
|
|
88
88
|
return True
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
def interactive_setup() -> dict:
|
|
92
|
+
"""Interactive configuration setup wizard.
|
|
93
|
+
|
|
94
|
+
Guides user through setting up essential configuration values.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Dictionary containing user-provided configuration
|
|
98
|
+
"""
|
|
99
|
+
print("=" * 60)
|
|
100
|
+
print(" Welcome to local-openai2anthropic Setup Wizard")
|
|
101
|
+
print("=" * 60)
|
|
102
|
+
print()
|
|
103
|
+
print("This wizard will help you create the initial configuration.")
|
|
104
|
+
print(f"Config file will be saved to: {get_config_file()}")
|
|
105
|
+
print()
|
|
106
|
+
|
|
107
|
+
config = {}
|
|
108
|
+
|
|
109
|
+
# OpenAI API Key (required)
|
|
110
|
+
print("[1/3] OpenAI API Configuration")
|
|
111
|
+
print("-" * 40)
|
|
112
|
+
while True:
|
|
113
|
+
api_key = input("Enter your OpenAI API Key (required): ").strip()
|
|
114
|
+
if api_key:
|
|
115
|
+
config["openai_api_key"] = api_key
|
|
116
|
+
break
|
|
117
|
+
print("API Key is required. Please enter a valid key.")
|
|
118
|
+
|
|
119
|
+
# Base URL (optional, with default)
|
|
120
|
+
default_url = "https://api.openai.com/v1"
|
|
121
|
+
base_url = input(f"Enter OpenAI Base URL [{default_url}]: ").strip()
|
|
122
|
+
config["openai_base_url"] = base_url if base_url else default_url
|
|
123
|
+
|
|
124
|
+
print()
|
|
125
|
+
print("[2/3] Server Configuration")
|
|
126
|
+
print("-" * 40)
|
|
127
|
+
|
|
128
|
+
# Host (with default)
|
|
129
|
+
default_host = "0.0.0.0"
|
|
130
|
+
host = input(f"Enter server host [{default_host}]: ").strip()
|
|
131
|
+
config["host"] = host if host else default_host
|
|
132
|
+
|
|
133
|
+
# Port (with default)
|
|
134
|
+
default_port = "8080"
|
|
135
|
+
port_input = input(f"Enter server port [{default_port}]: ").strip()
|
|
136
|
+
try:
|
|
137
|
+
config["port"] = int(port_input) if port_input else int(default_port)
|
|
138
|
+
except ValueError:
|
|
139
|
+
print(f"Invalid port number, using default: {default_port}")
|
|
140
|
+
config["port"] = int(default_port)
|
|
141
|
+
|
|
142
|
+
# API Key for server authentication (optional)
|
|
143
|
+
print()
|
|
144
|
+
print("[3/3] Server API Authentication (Optional)")
|
|
145
|
+
print("-" * 40)
|
|
146
|
+
print("Set an API key to authenticate requests to this server.")
|
|
147
|
+
print(
|
|
148
|
+
"Leave empty to allow unauthenticated access (not recommended for production)."
|
|
149
|
+
)
|
|
150
|
+
server_api_key = input("Enter server API key (optional): ").strip()
|
|
151
|
+
if server_api_key:
|
|
152
|
+
config["api_key"] = server_api_key
|
|
153
|
+
|
|
154
|
+
print()
|
|
155
|
+
print("=" * 60)
|
|
156
|
+
print(" Configuration Summary")
|
|
157
|
+
print("=" * 60)
|
|
158
|
+
print(f"OpenAI Base URL: {config.get('openai_base_url', default_url)}")
|
|
159
|
+
print(
|
|
160
|
+
f"Server: {config.get('host', default_host)}:{config.get('port', default_port)}"
|
|
161
|
+
)
|
|
162
|
+
print(f"OpenAI API Key: {config.get('openai_api_key', '')[:8]}... (configured)")
|
|
163
|
+
if config.get("api_key"):
|
|
164
|
+
print(f"Server Auth: {config['api_key'][:8]}... (configured)")
|
|
165
|
+
print()
|
|
166
|
+
|
|
167
|
+
return config
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def create_config_from_dict(config: dict) -> None:
|
|
171
|
+
"""Create config file from dictionary.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
config: Dictionary containing configuration values
|
|
175
|
+
"""
|
|
176
|
+
import tomli_w
|
|
177
|
+
|
|
178
|
+
config_file = get_config_file()
|
|
179
|
+
config_dir = get_config_dir()
|
|
180
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
181
|
+
|
|
182
|
+
# Set restrictive permissions for the config directory on Unix-like systems
|
|
183
|
+
if sys.platform != "win32":
|
|
184
|
+
config_dir.chmod(0o700)
|
|
185
|
+
|
|
186
|
+
# Build config dict with proper structure
|
|
187
|
+
toml_config: dict = {
|
|
188
|
+
"openai_api_key": config.get("openai_api_key", ""),
|
|
189
|
+
"openai_base_url": config.get("openai_base_url", "https://api.openai.com/v1"),
|
|
190
|
+
"host": config.get("host", "0.0.0.0"),
|
|
191
|
+
"port": config.get("port", 8080),
|
|
192
|
+
"request_timeout": config.get("request_timeout", 300.0),
|
|
193
|
+
"cors_origins": ["*"],
|
|
194
|
+
"cors_credentials": True,
|
|
195
|
+
"cors_methods": ["*"],
|
|
196
|
+
"cors_headers": ["*"],
|
|
197
|
+
"log_level": "INFO",
|
|
198
|
+
"log_dir": "",
|
|
199
|
+
"tavily_timeout": 30.0,
|
|
200
|
+
"tavily_max_results": 5,
|
|
201
|
+
"websearch_max_uses": 5,
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
# Add optional values only if present
|
|
205
|
+
if config.get("api_key"):
|
|
206
|
+
toml_config["api_key"] = config["api_key"]
|
|
207
|
+
|
|
208
|
+
if config.get("tavily_api_key"):
|
|
209
|
+
toml_config["tavily_api_key"] = config["tavily_api_key"]
|
|
210
|
+
|
|
211
|
+
# Write using proper TOML serialization (prevents injection attacks)
|
|
212
|
+
with open(config_file, "wb") as f:
|
|
213
|
+
tomli_w.dump(toml_config, f)
|
|
214
|
+
|
|
215
|
+
# Set restrictive permissions for the config file on Unix-like systems
|
|
216
|
+
if sys.platform != "win32":
|
|
217
|
+
config_file.chmod(0o600)
|
|
218
|
+
|
|
219
|
+
|
|
91
220
|
def load_config_from_file() -> dict:
|
|
92
221
|
"""Load configuration from TOML file.
|
|
93
222
|
|
|
@@ -164,18 +293,36 @@ class Settings(BaseModel):
|
|
|
164
293
|
return cls(**config_data)
|
|
165
294
|
|
|
166
295
|
|
|
296
|
+
def is_interactive() -> bool:
|
|
297
|
+
"""Check if running in an interactive terminal.
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
True if stdin is a TTY (interactive), False otherwise
|
|
301
|
+
"""
|
|
302
|
+
return sys.stdin.isatty()
|
|
303
|
+
|
|
304
|
+
|
|
167
305
|
@lru_cache
|
|
168
306
|
def get_settings() -> Settings:
|
|
169
307
|
"""Get cached settings instance.
|
|
170
308
|
|
|
171
|
-
Creates
|
|
309
|
+
Creates config file interactively if it doesn't exist and running in a TTY.
|
|
310
|
+
Falls back to creating a default config file in non-interactive environments.
|
|
172
311
|
|
|
173
312
|
Returns:
|
|
174
313
|
Settings instance loaded from config file
|
|
175
314
|
"""
|
|
176
|
-
|
|
177
|
-
if
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
315
|
+
config_file = get_config_file()
|
|
316
|
+
if not config_file.exists():
|
|
317
|
+
if is_interactive():
|
|
318
|
+
# Interactive setup wizard
|
|
319
|
+
config = interactive_setup()
|
|
320
|
+
create_config_from_dict(config)
|
|
321
|
+
print(f"\nConfiguration saved to: {config_file}")
|
|
322
|
+
print("You can edit this file later to change settings.\n")
|
|
323
|
+
else:
|
|
324
|
+
# Non-interactive environment: create default config
|
|
325
|
+
create_default_config()
|
|
326
|
+
print(f"Created default config file: {config_file}")
|
|
327
|
+
print("Please edit it to add your API keys and settings.")
|
|
181
328
|
return Settings.from_toml()
|
local_openai2anthropic/main.py
CHANGED
|
@@ -101,7 +101,7 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
|
|
101
101
|
app = FastAPI(
|
|
102
102
|
title="local-openai2anthropic",
|
|
103
103
|
description="A proxy server that converts Anthropic Messages API to OpenAI API",
|
|
104
|
-
version="0.3.
|
|
104
|
+
version="0.3.7",
|
|
105
105
|
docs_url="/docs",
|
|
106
106
|
redoc_url="/redoc",
|
|
107
107
|
)
|
|
@@ -253,7 +253,7 @@ Examples:
|
|
|
253
253
|
parser.add_argument(
|
|
254
254
|
"--version",
|
|
255
255
|
action="version",
|
|
256
|
-
version="%(prog)s 0.3.
|
|
256
|
+
version="%(prog)s 0.3.7",
|
|
257
257
|
)
|
|
258
258
|
|
|
259
259
|
# Create subparsers for commands
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: local-openai2anthropic
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: A lightweight proxy server that converts Anthropic Messages API to OpenAI API
|
|
5
5
|
Project-URL: Homepage, https://github.com/dongfangzan/local-openai2anthropic
|
|
6
6
|
Project-URL: Repository, https://github.com/dongfangzan/local-openai2anthropic
|
|
@@ -24,7 +24,7 @@ Requires-Dist: httpx>=0.25.0
|
|
|
24
24
|
Requires-Dist: openai>=1.30.0
|
|
25
25
|
Requires-Dist: pydantic-settings>=2.0.0
|
|
26
26
|
Requires-Dist: pydantic>=2.0.0
|
|
27
|
-
Requires-Dist: tomli>=
|
|
27
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
28
28
|
Requires-Dist: uvicorn[standard]>=0.23.0
|
|
29
29
|
Provides-Extra: dev
|
|
30
30
|
Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
local_openai2anthropic/__init__.py,sha256=
|
|
1
|
+
local_openai2anthropic/__init__.py,sha256=ykkqdWKgqvSffE2-GmDcZQFHJRAe0y4d4aeD3fUq_Os,1059
|
|
2
2
|
local_openai2anthropic/__main__.py,sha256=K21u5u7FN8-DbO67TT_XDF0neGqJeFrVNkteRauCRQk,179
|
|
3
|
-
local_openai2anthropic/config.py,sha256=
|
|
3
|
+
local_openai2anthropic/config.py,sha256=Cjg6J7H7ydKtVSd5m0RlTj-YF6yht3TpF4LcyodqQP4,9621
|
|
4
4
|
local_openai2anthropic/converter.py,sha256=og94I514M9km_Wbk9c1ddU6fyaQNEbpd2zfpfnBQaTQ,16029
|
|
5
5
|
local_openai2anthropic/daemon.py,sha256=pZnRojGFcuIpR8yLDNjV-b0LJRBVhgRAa-dKeRRse44,10017
|
|
6
6
|
local_openai2anthropic/daemon_runner.py,sha256=rguOH0PgpbjqNsKYei0uCQX8JQOQ1wmtQH1CtW95Dbw,3274
|
|
7
|
-
local_openai2anthropic/main.py,sha256=
|
|
7
|
+
local_openai2anthropic/main.py,sha256=FPCEATNPXvGpkszftdXJh0o0F5sUAOXo2zDagmsWGKI,12174
|
|
8
8
|
local_openai2anthropic/openai_types.py,sha256=jFdCvLwtXYoo5gGRqOhbHQcVaxcsxNnCP_yFPIv7rG4,3823
|
|
9
9
|
local_openai2anthropic/protocol.py,sha256=VW3B1YrbYg5UAo7PveQv0Ny5vfuNa6yG6IlHtkuyXiI,5178
|
|
10
10
|
local_openai2anthropic/router.py,sha256=gwSGCYQGd0tAj4B4cl30UDkIJDIfBP4D8T9KEMKnxyk,16196
|
|
@@ -18,8 +18,8 @@ local_openai2anthropic/tools/__init__.py,sha256=OM_6YAwy3G1kbrF7n5NvmBwWPGO0hwq4
|
|
|
18
18
|
local_openai2anthropic/tools/handler.py,sha256=SO8AmEUfNIg16s6jOKBaYdajYc0fiI8ciOoiKXIJe_c,14106
|
|
19
19
|
local_openai2anthropic/utils/__init__.py,sha256=0Apd3lQCmWpQHol4AfjtQe6A3Cpex9Zn-8dyK_FU8Z0,372
|
|
20
20
|
local_openai2anthropic/utils/tokens.py,sha256=TV3vGAjoGZeyo1xPvwb5jto43p1U1f4HteCApB86X0g,3187
|
|
21
|
-
local_openai2anthropic-0.3.
|
|
22
|
-
local_openai2anthropic-0.3.
|
|
23
|
-
local_openai2anthropic-0.3.
|
|
24
|
-
local_openai2anthropic-0.3.
|
|
25
|
-
local_openai2anthropic-0.3.
|
|
21
|
+
local_openai2anthropic-0.3.7.dist-info/METADATA,sha256=ZqgaeWvxJAKD1fDKC0XWiSwf3BI1DbH5UQpjvOzFewo,11270
|
|
22
|
+
local_openai2anthropic-0.3.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
23
|
+
local_openai2anthropic-0.3.7.dist-info/entry_points.txt,sha256=hdc9tSJUNxyNLXcTYye5SuD2K0bEQhxBhGnWTFup6ZM,116
|
|
24
|
+
local_openai2anthropic-0.3.7.dist-info/licenses/LICENSE,sha256=X3_kZy3lJvd_xp8IeyUcIAO2Y367MXZc6aaRx8BYR_s,11369
|
|
25
|
+
local_openai2anthropic-0.3.7.dist-info/RECORD,,
|
|
File without changes
|
{local_openai2anthropic-0.3.6.dist-info → local_openai2anthropic-0.3.7.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{local_openai2anthropic-0.3.6.dist-info → local_openai2anthropic-0.3.7.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|