caidaoli commited on
Commit
956580c
·
1 Parent(s): d7f796c

feat: 更新环境配置和文档,移除 Haiku 模型相关设置,支持新的 URL 格式

Browse files
Files changed (4) hide show
  1. .env.example +0 -22
  2. CLAUDE.md +16 -93
  3. README.md +1 -9
  4. main.go +43 -28
.env.example CHANGED
@@ -4,28 +4,6 @@
4
  # Server configuration
5
  PORT=8080
6
 
7
- # Haiku model shortcut configuration (optional)
8
- # If set, you can use paths containing "haiku" to access this model
9
- HAIKU_BASE_URL=https://api.anthropic.com/v1
10
- HAIKU_MODEL=claude-3-haiku-20240307
11
-
12
- # Example configurations for different APIs:
13
-
14
- # Google Gemini
15
- # HAIKU_BASE_URL=https://generativelanguage.googleapis.com/v1beta
16
- # HAIKU_MODEL=gemini-1.5-pro
17
-
18
- # Groq
19
- # HAIKU_BASE_URL=https://api.groq.com/openai/v1
20
- # HAIKU_MODEL=llama3-70b-8192
21
-
22
- # OpenAI
23
- # HAIKU_BASE_URL=https://api.openai.com/v1
24
- # HAIKU_MODEL=gpt-4
25
-
26
- # Ollama (local)
27
- # HAIKU_BASE_URL=http://localhost:11434/v1
28
- # HAIKU_MODEL=llama3
29
 
30
  # Debug mode (set to "true" to enable debug logging)
31
  DEBUG=false
 
4
  # Server configuration
5
  PORT=8080
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  # Debug mode (set to "true" to enable debug logging)
9
  DEBUG=false
CLAUDE.md CHANGED
@@ -11,81 +11,51 @@
11
 
12
  ## 🎯 核心功能
13
 
14
- ### 主要特性
15
  - **URL 路径解析**:自动从 URL 中提取目标 API 服务器和模型信息
16
  - **格式转换**:Claude API ↔ OpenAI API 双向转换
17
  - **流式响应**:支持流式和非流式响应
18
  - **错误处理**:完整的错误处理和调试日志
19
  - **CORS 支持**:支持跨域请求
20
 
21
- ### 技术栈
22
- - **语言**:Go
23
- - **框架**:Gin
24
- - **部署**:Docker 容器化
25
- - **平台**:Hugging Face Space
26
-
27
- ## 📁 文件结构
28
-
29
- ```
30
- 项目根目录/
31
- ├── main.go # 核心代理服务器代码
32
- ├── go.mod # Go 模块依赖
33
- ├── go.sum # 依赖校验文件
34
- ├── Dockerfile # Docker 构建配置
35
- ├── claude_proxy.sh # Claude CLI 配置脚本
36
- ├── test.sh # 功能测试脚本
37
- ├── .env.example # 环境变量模板
38
- ├── .env # 本地环境变量(git 忽略)
39
- ├── .gitignore # Git 忽略配置
40
- ├── README.md # 项目说明文档
41
- └── CLAUDE.md # 本文件
42
- ```
43
-
44
  ## ⚙️ 环境配置
45
 
46
- ### 重要环境变量
47
-
48
  ```bash
49
  # 服务器配置
50
  PORT=8080 # 服务器端口
51
  DEBUG=true # 开启调试模式
52
 
53
- # Haiku 快捷方式(可选)
54
- HAIKU_BASE_URL=https://api.anthropic.com/v1
55
- HAIKU_MODEL=claude-3-haiku-20240307
56
-
57
  # CORS 配置
58
  CORS_ALLOW_ORIGIN=*
59
  CORS_ALLOW_METHODS=POST,GET,OPTIONS,PUT,DELETE
60
  CORS_ALLOW_HEADERS=Accept,Content-Type,Authorization,x-api-key
61
  ```
62
 
63
- ### 配置加载顺序
64
- 1. `.env` 文件
65
- 2. 系统环境变量
66
- 3. 默认值
67
-
68
  ## 🌐 API 使用说明
69
 
70
  ### URL 格式
 
71
  ```
72
- /<协议>/<域名>/<路径>/<模型名>/v1/messages
 
 
 
 
73
  ```
74
 
75
  ### 使用示例
76
 
77
  ```bash
78
- # DeepSeek API
79
- POST /https/voapi.16931.com/openai/v1/deepseek-v3-fast/v1/messages
80
 
81
- # Groq API
82
- POST /https/api.groq.com/openai/v1/llama3-70b-8192/v1/messages
83
 
84
- # Gemini API
85
- POST /https/generativelanguage.googleapis.com/v1beta/gemini-1.5-pro/v1/messages
86
 
87
- # Haiku 快捷方式(需要设置环境变量)
88
- POST /haiku/v1/messages
89
  ```
90
 
91
  ### 请求头部
@@ -97,7 +67,7 @@ POST /haiku/v1/messages
97
  ## 🔄 工作流程
98
 
99
  1. **接收请求**:Claude CLI 发送 Claude API 格式的请求
100
- 2. **解析 URL**:从路径中提取协议、域名、路径和模型信息
101
  3. **格式转换**:将 Claude 请求格式转换为 OpenAI 格式
102
  4. **转发请求**:向目标 API 发送转换后的请求
103
  5. **处理响应**:将 OpenAI 响应转换回 Claude 格式
@@ -110,11 +80,7 @@ POST /haiku/v1/messages
110
  # 1. 安装依赖
111
  go mod tidy
112
 
113
- # 2. 配置环境变量
114
- cp .env.example .env
115
- # 编辑 .env 文件
116
-
117
- # 3. 运行服务器
118
  go run main.go
119
  ```
120
 
@@ -130,34 +96,12 @@ curl http://localhost:8080/
130
  }
131
  ```
132
 
133
- ### 调试技巧
134
- - 设置 `DEBUG=true` 查看详细日志
135
- - 查看请求和响应的完整调试信息
136
- - 使用 `./test.sh` 进行基本功能测试
137
-
138
- ## 🚀 部署说明
139
-
140
- ### Hugging Face Space 部署
141
- - 专为 Hugging Face Space 优化
142
- - 使用 Docker 容器化部署
143
- - 支持通过 Space 设置页面配置环境变量
144
- - 自动处理容器生命周期
145
-
146
- ### Docker 特性
147
- - 多阶段构建优化镜像大小
148
- - 非 root 用户运行增强安全性
149
- - 健康检查和日志输出
150
- - 环境变量注入支持
151
-
152
  ## 🐛 故障排除
153
 
154
- ### 常见问题
155
-
156
  | 问题 | 解决方案 |
157
  |------|---------|
158
  | 400 错误(请求格式错误) | 检查 URL 格式是否正确 |
159
  | 401 错误(未授权) | 检查 API 密钥是否正确设置 |
160
- | 环境变量未生效 | 检查 `.env` 文件格式,确保没有多余空格 |
161
  | 端口冲突 | 修改 `PORT` 环境变量 |
162
  | CORS 错误 | 检查 `CORS_*` 环境变量配置 |
163
 
@@ -167,27 +111,6 @@ curl http://localhost:8080/
167
  3. 检查请求和响应的调试信息
168
  4. 验证目标 API 的 URL 格式和密钥
169
 
170
- ## ✅ 项目定位
171
-
172
- ### 这个项目是:
173
- - API 代理服务器
174
- - Claude API 到 OpenAI API 的格式转换器
175
- - 容器化的 Go 应用程序
176
- - 部署在 Hugging Face Space 的服务
177
-
178
- ### 这个项目不是:
179
- - Cloudflare Workers 项目
180
- - 传统的 Web 应用程序
181
- - 需要前端界面的应用
182
- - 直接的 AI 服务提供商
183
-
184
- ## 🎯 主要用途
185
-
186
- - 让 Claude CLI 与���种 OpenAI 兼容的 API 服务通信
187
- - 作为不同 AI 服务的统一接入点
188
- - 提供 API 格式转换的中间层服务
189
- - 支持多种 AI 模型的统一调用接口
190
-
191
  ---
192
 
193
  **注意**:这个代理服务器主要用于开发和测试环境,生产环境使用时请确保妥善处理 API 密钥和安全配置。
 
11
 
12
  ## 🎯 核心功能
13
 
 
14
  - **URL 路径解析**:自动从 URL 中提取目标 API 服务器和模型信息
15
  - **格式转换**:Claude API ↔ OpenAI API 双向转换
16
  - **流式响应**:支持流式和非流式响应
17
  - **错误处理**:完整的错误处理和调试日志
18
  - **CORS 支持**:支持跨域请求
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  ## ⚙️ 环境配置
21
 
 
 
22
  ```bash
23
  # 服务器配置
24
  PORT=8080 # 服务器端口
25
  DEBUG=true # 开启调试模式
26
 
 
 
 
 
27
  # CORS 配置
28
  CORS_ALLOW_ORIGIN=*
29
  CORS_ALLOW_METHODS=POST,GET,OPTIONS,PUT,DELETE
30
  CORS_ALLOW_HEADERS=Accept,Content-Type,Authorization,x-api-key
31
  ```
32
 
 
 
 
 
 
33
  ## 🌐 API 使用说明
34
 
35
  ### URL 格式
36
+ 支持两种格式:
37
  ```
38
+ # 格式一(不带冒号)
39
+ /<协议>/<域名>/<路径>/<HAIKU_MODEL>/<模型名称>/v1/messages
40
+
41
+ # 格式二(带冒号)
42
+ /<协议>://<域名>/<路径>/<HAIKU_MODEL>/<模型名称>/v1/messages
43
  ```
44
 
45
  ### 使用示例
46
 
47
  ```bash
48
+ # DeepSeek API - 格式一(不带冒号)
49
+ POST /https/voapi.16931.com/v1/qwen-3-32b/deepseek-v3-fast/v1/messages
50
 
51
+ # DeepSeek API - 格式二(带冒号)
52
+ POST /https://voapi.16931.com/v1/qwen-3-32b/deepseek-v3-fast/v1/messages
53
 
54
+ # Groq API - 格式一
55
+ POST /https/api.groq.com/openai/v1/claude-3-haiku-20240307/llama3-70b-8192/v1/messages
56
 
57
+ # Groq API - 格式二
58
+ POST /https://api.groq.com/openai/v1/claude-3-haiku-20240307/llama3-70b-8192/v1/messages
59
  ```
60
 
61
  ### 请求头部
 
67
  ## 🔄 工作流程
68
 
69
  1. **接收请求**:Claude CLI 发送 Claude API 格式的请求
70
+ 2. **解析 URL**:从路径中提取协议、域名、路径、HAIKU_MODEL 和模型名称信息
71
  3. **格式转换**:将 Claude 请求格式转换为 OpenAI 格式
72
  4. **转发请求**:向目标 API 发送转换后的请求
73
  5. **处理响应**:将 OpenAI 响应转换回 Claude 格式
 
80
  # 1. 安装依赖
81
  go mod tidy
82
 
83
+ # 2. 运行服务器
 
 
 
 
84
  go run main.go
85
  ```
86
 
 
96
  }
97
  ```
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  ## 🐛 故障排除
100
 
 
 
101
  | 问题 | 解决方案 |
102
  |------|---------|
103
  | 400 错误(请求格式错误) | 检查 URL 格式是否正确 |
104
  | 401 错误(未授权) | 检查 API 密钥是否正确设置 |
 
105
  | 端口冲突 | 修改 `PORT` 环境变量 |
106
  | CORS 错误 | 检查 `CORS_*` 环境变量配置 |
107
 
 
111
  3. 检查请求和响应的调试信息
112
  4. 验证目标 API 的 URL 格式和密钥
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  ---
115
 
116
  **注意**:这个代理服务器主要用于开发和测试环境,生产环境使用时请确保妥善处理 API 密钥和安全配置。
README.md CHANGED
@@ -28,7 +28,7 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
28
 
29
  ### 动态路由格式
30
  ```
31
- https://<代理地址>/<协议>/<目标API域名>/<路径>/<模型名称>/v1/messages
32
  ```
33
 
34
  ### 处理流程
@@ -90,8 +90,6 @@ docker build -t claude-proxy .
90
  2. 运行容器:
91
  ```bash
92
  docker run -p 8080:8080 \
93
- -e HAIKU_BASE_URL=https://api.anthropic.com/v1 \
94
- -e HAIKU_MODEL=claude-3-haiku-20240307 \
95
  -e DEBUG=false \
96
  claude-proxy
97
  ```
@@ -178,10 +176,6 @@ curl -X POST http://localhost:8080/https/api.openai.com/v1/gpt-4/v1/messages \
178
  PORT=8080
179
  DEBUG=true
180
 
181
- # Haiku模型快捷方式(可选)
182
- HAIKU_BASE_URL=https://api.anthropic.com/v1
183
- HAIKU_MODEL=claude-3-haiku-20240307
184
-
185
  # CORS配置(可选)
186
  CORS_ALLOW_ORIGIN=*
187
  CORS_ALLOW_METHODS=POST,GET,OPTIONS,PUT,DELETE
@@ -252,8 +246,6 @@ curl http://localhost:8080/
252
 
253
  - `PORT`: 服务器端口(默认8080)
254
  - `DEBUG`: 调试模式(true/false)
255
- - `HAIKU_BASE_URL`: Haiku快捷方式的基础URL
256
- - `HAIKU_MODEL`: Haiku快捷方式的模型名称
257
 
258
  ## 🤝 贡献
259
 
 
28
 
29
  ### 动态路由格式
30
  ```
31
+ https://<代理地址>/<协议>/<目标API域名>/<路径>/HAIKU_MODEL/<模型名称>
32
  ```
33
 
34
  ### 处理流程
 
90
  2. 运行容器:
91
  ```bash
92
  docker run -p 8080:8080 \
 
 
93
  -e DEBUG=false \
94
  claude-proxy
95
  ```
 
176
  PORT=8080
177
  DEBUG=true
178
 
 
 
 
 
179
  # CORS配置(可选)
180
  CORS_ALLOW_ORIGIN=*
181
  CORS_ALLOW_METHODS=POST,GET,OPTIONS,PUT,DELETE
 
246
 
247
  - `PORT`: 服务器端口(默认8080)
248
  - `DEBUG`: 调试模式(true/false)
 
 
249
 
250
  ## 🤝 贡献
251
 
main.go CHANGED
@@ -247,44 +247,59 @@ func handleProxy(c *gin.Context) {
247
  func parseProxyConfig(path string) (*ProxyConfig, error) {
248
  log.Printf("Debug: Parsing path: %s", path)
249
 
250
- haikuBaseURL := os.Getenv("HAIKU_BASE_URL")
251
- haikuModel := os.Getenv("HAIKU_MODEL")
252
-
253
- if haikuBaseURL != "" && haikuModel != "" && strings.Contains(path, "haiku") {
254
- log.Printf("Debug: Using haiku shortcut")
255
- return &ProxyConfig{
256
- BaseURL: haikuBaseURL,
257
- Model: haikuModel,
258
- }, nil
259
- }
260
-
261
  // Remove query parameters from path before matching
262
  pathWithoutQuery := strings.Split(path, "?")[0]
263
  log.Printf("Debug: Path without query: %s", pathWithoutQuery)
264
 
265
- re := regexp.MustCompile(`^/([^/]+)/([^/]+)(/.*?)/([^/]+)/v1/messages$`)
266
- matches := re.FindStringSubmatch(pathWithoutQuery)
 
267
 
268
- log.Printf("Debug: Regex matches: %v", matches)
 
 
269
 
270
- if len(matches) != 5 {
271
- return nil, fmt.Errorf("invalid path format. Expected: /protocol/domain/path/model/v1/messages, got: %s", pathWithoutQuery)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  }
273
 
274
- protocol := matches[1]
275
- domain := matches[2]
276
- urlPath := matches[3]
277
- model := matches[4]
278
-
279
- baseURL := fmt.Sprintf("%s://%s%s", protocol, domain, urlPath)
280
 
281
- log.Printf("Debug: Parsed - protocol: %s, domain: %s, urlPath: %s, model: %s", protocol, domain, urlPath, model)
282
- log.Printf("Debug: Final baseURL: %s", baseURL)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
 
284
- return &ProxyConfig{
285
- BaseURL: baseURL,
286
- Model: model,
287
- }, nil
288
  }
289
 
290
  func convertClaudeToOpenAI(claudeReq ClaudeRequest, model string) OpenAIRequest {
 
247
  func parseProxyConfig(path string) (*ProxyConfig, error) {
248
  log.Printf("Debug: Parsing path: %s", path)
249
 
 
 
 
 
 
 
 
 
 
 
 
250
  // Remove query parameters from path before matching
251
  pathWithoutQuery := strings.Split(path, "?")[0]
252
  log.Printf("Debug: Path without query: %s", pathWithoutQuery)
253
 
254
+ // Support both formats:
255
+ // 1. /protocol/domain/path/haiku_model/model_name/v1/messages (without colon)
256
+ // 2. /protocol://domain/path/haiku_model/model_name/v1/messages (with colon)
257
 
258
+ // First try format with colon: /https://domain/path/haiku_model/model_name/v1/messages
259
+ reWithColon := regexp.MustCompile(`^/([^:]+)://([^/]+)(/.*?)/([^/]+)/([^/]+)/v1/messages$`)
260
+ matches := reWithColon.FindStringSubmatch(pathWithoutQuery)
261
 
262
+ if len(matches) == 6 {
263
+ protocol := matches[1]
264
+ domain := matches[2]
265
+ urlPath := matches[3]
266
+ haikuModel := matches[4]
267
+ modelName := matches[5]
268
+
269
+ baseURL := fmt.Sprintf("%s://%s%s", protocol, domain, urlPath)
270
+
271
+ log.Printf("Debug: Parsed (with colon) - protocol: %s, domain: %s, urlPath: %s, haikuModel: %s, modelName: %s", protocol, domain, urlPath, haikuModel, modelName)
272
+ log.Printf("Debug: Final baseURL: %s", baseURL)
273
+
274
+ return &ProxyConfig{
275
+ BaseURL: baseURL,
276
+ Model: modelName,
277
+ }, nil
278
  }
279
 
280
+ // Then try format without colon: /https/domain/path/haiku_model/model_name/v1/messages
281
+ reWithoutColon := regexp.MustCompile(`^/([^/]+)/([^/]+)(/.*?)/([^/]+)/([^/]+)/v1/messages$`)
282
+ matches = reWithoutColon.FindStringSubmatch(pathWithoutQuery)
 
 
 
283
 
284
+ if len(matches) == 6 {
285
+ protocol := matches[1]
286
+ domain := matches[2]
287
+ urlPath := matches[3]
288
+ haikuModel := matches[4]
289
+ modelName := matches[5]
290
+
291
+ baseURL := fmt.Sprintf("%s://%s%s", protocol, domain, urlPath)
292
+
293
+ log.Printf("Debug: Parsed (without colon) - protocol: %s, domain: %s, urlPath: %s, haikuModel: %s, modelName: %s", protocol, domain, urlPath, haikuModel, modelName)
294
+ log.Printf("Debug: Final baseURL: %s", baseURL)
295
+
296
+ return &ProxyConfig{
297
+ BaseURL: baseURL,
298
+ Model: modelName,
299
+ }, nil
300
+ }
301
 
302
+ return nil, fmt.Errorf("invalid path format. Expected: /protocol/domain/path/haiku_model/model_name/v1/messages or /protocol://domain/path/haiku_model/model_name/v1/messages, got: %s", pathWithoutQuery)
 
 
 
303
  }
304
 
305
  func convertClaudeToOpenAI(claudeReq ClaudeRequest, model string) OpenAIRequest {