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

feat: 更新端口配置,将所有相关文件中的端口从 8080 修改为 7860

Browse files
Files changed (7) hide show
  1. .env.example +1 -1
  2. CLAUDE.md +2 -2
  3. Dockerfile +1 -1
  4. README.md +9 -9
  5. claude_proxy.sh +1 -1
  6. main.go +34 -34
  7. test.sh +3 -3
.env.example CHANGED
@@ -2,7 +2,7 @@
2
  # Copy this file to .env and set your own values
3
 
4
  # Server configuration
5
- PORT=8080
6
 
7
 
8
  # Debug mode (set to "true" to enable debug logging)
 
2
  # Copy this file to .env and set your own values
3
 
4
  # Server configuration
5
+ PORT=7860
6
 
7
 
8
  # Debug mode (set to "true" to enable debug logging)
CLAUDE.md CHANGED
@@ -21,7 +21,7 @@
21
 
22
  ```bash
23
  # 服务器配置
24
- PORT=8080 # 服务器端口
25
  DEBUG=true # 开启调试模式
26
 
27
  # CORS 配置
@@ -86,7 +86,7 @@ go run main.go
86
 
87
  ### 健康检查
88
  ```bash
89
- curl http://localhost:8080/
90
 
91
  # 预期响应
92
  {
 
21
 
22
  ```bash
23
  # 服务器配置
24
+ PORT=7860 # 服务器端口
25
  DEBUG=true # 开启调试模式
26
 
27
  # CORS 配置
 
86
 
87
  ### 健康检查
88
  ```bash
89
+ curl http://localhost:7860/
90
 
91
  # 预期响应
92
  {
Dockerfile CHANGED
@@ -17,6 +17,6 @@ WORKDIR /root/
17
 
18
  COPY --from=builder /app/main .
19
 
20
- EXPOSE 8080
21
 
22
  CMD ["./main"]
 
17
 
18
  COPY --from=builder /app/main .
19
 
20
+ EXPOSE 7860
21
 
22
  CMD ["./main"]
README.md CHANGED
@@ -64,7 +64,7 @@ go mod tidy
64
  go run main.go
65
  ```
66
 
67
- 服务器将在`http://localhost:8080`启动。
68
 
69
  ### 使用配置脚本
70
 
@@ -89,7 +89,7 @@ docker build -t claude-proxy .
89
 
90
  2. 运行容器:
91
  ```bash
92
- docker run -p 8080:8080 \
93
  -e DEBUG=false \
94
  claude-proxy
95
  ```
@@ -98,7 +98,7 @@ docker run -p 8080:8080 \
98
 
99
  ### Google Gemini
100
  ```bash
101
- curl -X POST http://localhost:8080/https/generativelanguage.googleapis.com/v1beta/gemini-1.5-pro/v1/messages \
102
  -H 'Content-Type: application/json' \
103
  -H 'x-api-key: YOUR_GEMINI_API_KEY' \
104
  -d '{
@@ -110,7 +110,7 @@ curl -X POST http://localhost:8080/https/generativelanguage.googleapis.com/v1bet
110
 
111
  ### Groq
112
  ```bash
113
- curl -X POST http://localhost:8080/https/api.groq.com/openai/v1/llama3-70b-8192/v1/messages \
114
  -H 'Content-Type: application/json' \
115
  -H 'x-api-key: YOUR_GROQ_API_KEY' \
116
  -d '{
@@ -122,7 +122,7 @@ curl -X POST http://localhost:8080/https/api.groq.com/openai/v1/llama3-70b-8192/
122
 
123
  ### OpenAI
124
  ```bash
125
- curl -X POST http://localhost:8080/https/api.openai.com/v1/gpt-4/v1/messages \
126
  -H 'Content-Type: application/json' \
127
  -H 'x-api-key: YOUR_OPENAI_API_KEY' \
128
  -d '{
@@ -173,7 +173,7 @@ curl -X POST http://localhost:8080/https/api.openai.com/v1/gpt-4/v1/messages \
173
 
174
  ```bash
175
  # 服务器配置
176
- PORT=8080
177
  DEBUG=true
178
 
179
  # CORS配置(可选)
@@ -187,7 +187,7 @@ CORS_ALLOW_HEADERS=Accept,Content-Type,Content-Length,Accept-Encoding,X-CSRF-Tok
187
  设置环境变量后,可以使用简化的URL:
188
  ```bash
189
  # 然后可以使用包含"haiku"的任何路径
190
- curl -X POST http://localhost:8080/haiku/v1/messages \
191
  -H 'Content-Type: application/json' \
192
  -H 'x-api-key: YOUR_ANTHROPIC_API_KEY' \
193
  -d '{...}'
@@ -213,7 +213,7 @@ curl -X POST http://localhost:8080/haiku/v1/messages \
213
 
214
  启动服务器后,访问根路径检查状态:
215
  ```bash
216
- curl http://localhost:8080/
217
  ```
218
 
219
  应该返回:
@@ -244,7 +244,7 @@ curl http://localhost:8080/
244
 
245
  在Hugging Face Space设置中配置以下环境变量:
246
 
247
- - `PORT`: 服务器端口(默认8080
248
  - `DEBUG`: 调试模式(true/false)
249
 
250
  ## 🤝 贡献
 
64
  go run main.go
65
  ```
66
 
67
+ 服务器将在`http://localhost:7860`启动。
68
 
69
  ### 使用配置脚本
70
 
 
89
 
90
  2. 运行容器:
91
  ```bash
92
+ docker run -p 7860:7860 \
93
  -e DEBUG=false \
94
  claude-proxy
95
  ```
 
98
 
99
  ### Google Gemini
100
  ```bash
101
+ curl -X POST http://localhost:7860/https/generativelanguage.googleapis.com/v1beta/gemini-1.5-pro/v1/messages \
102
  -H 'Content-Type: application/json' \
103
  -H 'x-api-key: YOUR_GEMINI_API_KEY' \
104
  -d '{
 
110
 
111
  ### Groq
112
  ```bash
113
+ curl -X POST http://localhost:7860/https/api.groq.com/openai/v1/llama3-70b-8192/v1/messages \
114
  -H 'Content-Type: application/json' \
115
  -H 'x-api-key: YOUR_GROQ_API_KEY' \
116
  -d '{
 
122
 
123
  ### OpenAI
124
  ```bash
125
+ curl -X POST http://localhost:7860/https/api.openai.com/v1/gpt-4/v1/messages \
126
  -H 'Content-Type: application/json' \
127
  -H 'x-api-key: YOUR_OPENAI_API_KEY' \
128
  -d '{
 
173
 
174
  ```bash
175
  # 服务器配置
176
+ PORT=7860
177
  DEBUG=true
178
 
179
  # CORS配置(可选)
 
187
  设置环境变量后,可以使用简化的URL:
188
  ```bash
189
  # 然后可以使用包含"haiku"的任何路径
190
+ curl -X POST http://localhost:7860/haiku/v1/messages \
191
  -H 'Content-Type: application/json' \
192
  -H 'x-api-key: YOUR_ANTHROPIC_API_KEY' \
193
  -d '{...}'
 
213
 
214
  启动服务器后,访问根路径检查状态:
215
  ```bash
216
+ curl http://localhost:7860/
217
  ```
218
 
219
  应该返回:
 
244
 
245
  在Hugging Face Space设置中配置以下环境变量:
246
 
247
+ - `PORT`: 服务器端口(默认7860
248
  - `DEBUG`: 调试模式(true/false)
249
 
250
  ## 🤝 贡献
claude_proxy.sh CHANGED
@@ -144,7 +144,7 @@ get_api_key() {
144
  # Function to get proxy URL
145
  get_proxy_url() {
146
  echo ""
147
- get_input "Enter your proxy server URL" "http://localhost:8080" "PROXY_URL"
148
  }
149
 
150
  # Function to get model name
 
144
  # Function to get proxy URL
145
  get_proxy_url() {
146
  echo ""
147
+ get_input "Enter your proxy server URL" "http://localhost:7860" "PROXY_URL"
148
  }
149
 
150
  # Function to get model name
main.go CHANGED
@@ -58,8 +58,8 @@ type OpenAIRequest struct {
58
  }
59
 
60
  type OpenAITool struct {
61
- Type string `json:"type"`
62
- Function OpenAIToolFunction `json:"function"`
63
  }
64
 
65
  type OpenAIToolFunction struct {
@@ -118,7 +118,7 @@ func main() {
118
 
119
  port := os.Getenv("PORT")
120
  if port == "" {
121
- port = "8080"
122
  }
123
 
124
  // Set debug mode based on environment variable
@@ -129,41 +129,41 @@ func main() {
129
  }
130
 
131
  router := gin.Default()
132
-
133
  // CORS configuration from environment or defaults
134
  corsOrigin := os.Getenv("CORS_ALLOW_ORIGIN")
135
  if corsOrigin == "" {
136
  corsOrigin = "*"
137
  }
138
-
139
  corsMethods := os.Getenv("CORS_ALLOW_METHODS")
140
  if corsMethods == "" {
141
  corsMethods = "POST, GET, OPTIONS, PUT, DELETE"
142
  }
143
-
144
  corsHeaders := os.Getenv("CORS_ALLOW_HEADERS")
145
  if corsHeaders == "" {
146
  corsHeaders = "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, x-api-key, anthropic-version"
147
  }
148
-
149
  router.Use(func(c *gin.Context) {
150
  c.Header("Access-Control-Allow-Origin", corsOrigin)
151
  c.Header("Access-Control-Allow-Methods", corsMethods)
152
  c.Header("Access-Control-Allow-Headers", corsHeaders)
153
-
154
  if c.Request.Method == "OPTIONS" {
155
  c.AbortWithStatus(204)
156
  return
157
  }
158
-
159
  c.Next()
160
  })
161
 
162
  router.POST("/*path", handleProxy)
163
  router.GET("/", func(c *gin.Context) {
164
  c.JSON(200, gin.H{
165
- "message": "Claude to OpenAI API Proxy",
166
- "version": "1.0.0",
167
  "environment": gin.Mode(),
168
  })
169
  })
@@ -174,7 +174,7 @@ func main() {
174
 
175
  func handleProxy(c *gin.Context) {
176
  path := c.Param("path")
177
-
178
  if !strings.HasSuffix(path, "/v1/messages") {
179
  c.JSON(404, gin.H{"error": "Not found"})
180
  return
@@ -203,7 +203,7 @@ func handleProxy(c *gin.Context) {
203
  log.Printf("=== End Claude Request Debug ===")
204
 
205
  openaiReq := convertClaudeToOpenAI(claudeReq, config.Model)
206
-
207
  // Debug: Print all incoming headers
208
  log.Printf("=== Incoming Headers Debug ===")
209
  for key, values := range c.Request.Header {
@@ -212,7 +212,7 @@ func handleProxy(c *gin.Context) {
212
  }
213
  }
214
  log.Printf("=== End Headers Debug ===")
215
-
216
  apiKey := c.GetHeader("x-api-key")
217
  if apiKey == "" {
218
  // Try alternative header names that Claude CLI might use
@@ -227,11 +227,11 @@ func handleProxy(c *gin.Context) {
227
  if apiKey == "" {
228
  apiKey = c.GetHeader("anthropic-version")
229
  }
230
-
231
  log.Printf("=== API Key Debug ===")
232
  log.Printf("Final API Key: %s", apiKey)
233
  log.Printf("=== End API Key Debug ===")
234
-
235
  if apiKey == "" {
236
  c.JSON(401, gin.H{"error": "API key required"})
237
  return
@@ -246,7 +246,7 @@ func handleProxy(c *gin.Context) {
246
 
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)
@@ -254,51 +254,51 @@ func parseProxyConfig(path string) (*ProxyConfig, error) {
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
 
@@ -523,7 +523,7 @@ func handleStreamingRequest(c *gin.Context, openaiReq OpenAIRequest, config *Pro
523
 
524
  reader := resp.Body
525
  buffer := make([]byte, 1024)
526
-
527
  for {
528
  n, err := reader.Read(buffer)
529
  if err != nil {
@@ -536,7 +536,7 @@ func handleStreamingRequest(c *gin.Context, openaiReq OpenAIRequest, config *Pro
536
 
537
  data := string(buffer[:n])
538
  lines := strings.Split(data, "\n")
539
-
540
  for _, line := range lines {
541
  if strings.HasPrefix(line, "data: ") {
542
  eventData := strings.TrimPrefix(line, "data: ")
@@ -545,7 +545,7 @@ func handleStreamingRequest(c *gin.Context, openaiReq OpenAIRequest, config *Pro
545
  flusher.Flush()
546
  return
547
  }
548
-
549
  convertedData := convertStreamingData(eventData)
550
  if convertedData != "" {
551
  c.Writer.WriteString("data: " + convertedData + "\n\n")
@@ -567,7 +567,7 @@ func convertStreamingData(data string) string {
567
  }
568
 
569
  claudeChunk := map[string]interface{}{
570
- "type": "content_block_delta",
571
  "index": 0,
572
  "delta": map[string]interface{}{
573
  "type": "text_delta",
@@ -607,7 +607,7 @@ func convertOpenAIToClaude(openaiResp OpenAIResponse) ClaudeResponse {
607
  Text: choice.Message.Content,
608
  },
609
  }
610
-
611
  switch choice.FinishReason {
612
  case "stop":
613
  claudeResp.StopReason = "end_turn"
@@ -622,4 +622,4 @@ func convertOpenAIToClaude(openaiResp OpenAIResponse) ClaudeResponse {
622
  claudeResp.Usage.OutputTokens = openaiResp.Usage.CompletionTokens
623
 
624
  return claudeResp
625
- }
 
58
  }
59
 
60
  type OpenAITool struct {
61
+ Type string `json:"type"`
62
+ Function OpenAIToolFunction `json:"function"`
63
  }
64
 
65
  type OpenAIToolFunction struct {
 
118
 
119
  port := os.Getenv("PORT")
120
  if port == "" {
121
+ port = "7860"
122
  }
123
 
124
  // Set debug mode based on environment variable
 
129
  }
130
 
131
  router := gin.Default()
132
+
133
  // CORS configuration from environment or defaults
134
  corsOrigin := os.Getenv("CORS_ALLOW_ORIGIN")
135
  if corsOrigin == "" {
136
  corsOrigin = "*"
137
  }
138
+
139
  corsMethods := os.Getenv("CORS_ALLOW_METHODS")
140
  if corsMethods == "" {
141
  corsMethods = "POST, GET, OPTIONS, PUT, DELETE"
142
  }
143
+
144
  corsHeaders := os.Getenv("CORS_ALLOW_HEADERS")
145
  if corsHeaders == "" {
146
  corsHeaders = "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, x-api-key, anthropic-version"
147
  }
148
+
149
  router.Use(func(c *gin.Context) {
150
  c.Header("Access-Control-Allow-Origin", corsOrigin)
151
  c.Header("Access-Control-Allow-Methods", corsMethods)
152
  c.Header("Access-Control-Allow-Headers", corsHeaders)
153
+
154
  if c.Request.Method == "OPTIONS" {
155
  c.AbortWithStatus(204)
156
  return
157
  }
158
+
159
  c.Next()
160
  })
161
 
162
  router.POST("/*path", handleProxy)
163
  router.GET("/", func(c *gin.Context) {
164
  c.JSON(200, gin.H{
165
+ "message": "Claude to OpenAI API Proxy",
166
+ "version": "1.0.0",
167
  "environment": gin.Mode(),
168
  })
169
  })
 
174
 
175
  func handleProxy(c *gin.Context) {
176
  path := c.Param("path")
177
+
178
  if !strings.HasSuffix(path, "/v1/messages") {
179
  c.JSON(404, gin.H{"error": "Not found"})
180
  return
 
203
  log.Printf("=== End Claude Request Debug ===")
204
 
205
  openaiReq := convertClaudeToOpenAI(claudeReq, config.Model)
206
+
207
  // Debug: Print all incoming headers
208
  log.Printf("=== Incoming Headers Debug ===")
209
  for key, values := range c.Request.Header {
 
212
  }
213
  }
214
  log.Printf("=== End Headers Debug ===")
215
+
216
  apiKey := c.GetHeader("x-api-key")
217
  if apiKey == "" {
218
  // Try alternative header names that Claude CLI might use
 
227
  if apiKey == "" {
228
  apiKey = c.GetHeader("anthropic-version")
229
  }
230
+
231
  log.Printf("=== API Key Debug ===")
232
  log.Printf("Final API Key: %s", apiKey)
233
  log.Printf("=== End API Key Debug ===")
234
+
235
  if apiKey == "" {
236
  c.JSON(401, gin.H{"error": "API key required"})
237
  return
 
246
 
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)
 
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
 
 
523
 
524
  reader := resp.Body
525
  buffer := make([]byte, 1024)
526
+
527
  for {
528
  n, err := reader.Read(buffer)
529
  if err != nil {
 
536
 
537
  data := string(buffer[:n])
538
  lines := strings.Split(data, "\n")
539
+
540
  for _, line := range lines {
541
  if strings.HasPrefix(line, "data: ") {
542
  eventData := strings.TrimPrefix(line, "data: ")
 
545
  flusher.Flush()
546
  return
547
  }
548
+
549
  convertedData := convertStreamingData(eventData)
550
  if convertedData != "" {
551
  c.Writer.WriteString("data: " + convertedData + "\n\n")
 
567
  }
568
 
569
  claudeChunk := map[string]interface{}{
570
+ "type": "content_block_delta",
571
  "index": 0,
572
  "delta": map[string]interface{}{
573
  "type": "text_delta",
 
607
  Text: choice.Message.Content,
608
  },
609
  }
610
+
611
  switch choice.FinishReason {
612
  case "stop":
613
  claudeResp.StopReason = "end_turn"
 
622
  claudeResp.Usage.OutputTokens = openaiResp.Usage.CompletionTokens
623
 
624
  return claudeResp
625
+ }
test.sh CHANGED
@@ -8,7 +8,7 @@ echo "====================================="
8
  # Test 1: Health check
9
  echo ""
10
  echo "📊 Test 1: Health check"
11
- response=$(curl -s http://localhost:8080/)
12
  echo "Response: $response"
13
 
14
  if echo "$response" | grep -q "Claude to OpenAI API Proxy"; then
@@ -21,7 +21,7 @@ fi
21
  # Test 2: Invalid path
22
  echo ""
23
  echo "📊 Test 2: Invalid path"
24
- response=$(curl -s -w "%{http_code}" -o /dev/null http://localhost:8080/invalid/path)
25
  echo "HTTP Status: $response"
26
 
27
  if [ "$response" = "404" ]; then
@@ -33,7 +33,7 @@ fi
33
  # Test 3: Valid path format validation
34
  echo ""
35
  echo "📊 Test 3: Valid path format validation"
36
- response=$(curl -s -w "%{http_code}" -o /dev/null -X POST http://localhost:8080/https/api.openai.com/v1/gpt-4/v1/messages \
37
  -H 'Content-Type: application/json' \
38
  -H 'x-api-key: test-key' \
39
  -d '{"model": "gpt-4", "max_tokens": 10, "messages": [{"role": "user", "content": "test"}]}')
 
8
  # Test 1: Health check
9
  echo ""
10
  echo "📊 Test 1: Health check"
11
+ response=$(curl -s http://localhost:7860/)
12
  echo "Response: $response"
13
 
14
  if echo "$response" | grep -q "Claude to OpenAI API Proxy"; then
 
21
  # Test 2: Invalid path
22
  echo ""
23
  echo "📊 Test 2: Invalid path"
24
+ response=$(curl -s -w "%{http_code}" -o /dev/null http://localhost:7860/invalid/path)
25
  echo "HTTP Status: $response"
26
 
27
  if [ "$response" = "404" ]; then
 
33
  # Test 3: Valid path format validation
34
  echo ""
35
  echo "📊 Test 3: Valid path format validation"
36
+ response=$(curl -s -w "%{http_code}" -o /dev/null -X POST http://localhost:7860/https/api.openai.com/v1/gpt-4/v1/messages \
37
  -H 'Content-Type: application/json' \
38
  -H 'x-api-key: test-key' \
39
  -d '{"model": "gpt-4", "max_tokens": 10, "messages": [{"role": "user", "content": "test"}]}')