Spaces:
Paused
Paused
add deepseek via openrouter
Browse files- internal/handler/chat.go +12 -0
- internal/handler/openrouter.go +47 -0
- internal/model/mapping.go +5 -0
internal/handler/chat.go
CHANGED
|
@@ -6,6 +6,8 @@ import (
|
|
| 6 |
"fmt"
|
| 7 |
"io"
|
| 8 |
"net/http"
|
|
|
|
|
|
|
| 9 |
"strings"
|
| 10 |
"time"
|
| 11 |
|
|
@@ -44,6 +46,16 @@ func HandleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
|
| 44 |
}
|
| 45 |
token = anonymousToken
|
| 46 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
var req model.ChatRequest
|
| 48 |
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
| 49 |
http.Error(w, "Invalid request", http.StatusBadRequest)
|
|
|
|
| 6 |
"fmt"
|
| 7 |
"io"
|
| 8 |
"net/http"
|
| 9 |
+
"bytes"
|
| 10 |
+
"io"
|
| 11 |
"strings"
|
| 12 |
"time"
|
| 13 |
|
|
|
|
| 46 |
}
|
| 47 |
token = anonymousToken
|
| 48 |
}
|
| 49 |
+
body, _ := io.ReadAll(r.Body)
|
| 50 |
+
r.Body = io.NopCloser(bytes.NewReader(body))
|
| 51 |
+
var tempReq map[string]interface{}
|
| 52 |
+
json.Unmarshal(body, &tempReq)
|
| 53 |
+
if m, ok := tempReq["model"].(string); ok && IsOpenRouterModel(m) {
|
| 54 |
+
ok2, reason := CheckAndTrack(apiKey, 0)
|
| 55 |
+
if !ok2 { http.Error(w, reason, 429); return }
|
| 56 |
+
HandleOpenRouter(w, r, body)
|
| 57 |
+
return
|
| 58 |
+
}
|
| 59 |
var req model.ChatRequest
|
| 60 |
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
| 61 |
http.Error(w, "Invalid request", http.StatusBadRequest)
|
internal/handler/openrouter.go
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package handler
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"bytes"
|
| 5 |
+
"encoding/json"
|
| 6 |
+
"io"
|
| 7 |
+
"net/http"
|
| 8 |
+
"os"
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
var openRouterKey = os.Getenv("OP_Rowproxy_key")
|
| 12 |
+
|
| 13 |
+
var openRouterModels = map[string]string{
|
| 14 |
+
"deepseek-r1": "deepseek/deepseek-r1",
|
| 15 |
+
"deepseek-v3": "deepseek/deepseek-v3-0324",
|
| 16 |
+
"deepseek-r1-0528": "deepseek/deepseek-r1-0528",
|
| 17 |
+
"deepseek-v3-turbo": "deepseek/deepseek-v3",
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
func IsOpenRouterModel(model string) bool {
|
| 21 |
+
_, ok := openRouterModels[model]
|
| 22 |
+
return ok
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
func HandleOpenRouter(w http.ResponseWriter, r *http.Request, body []byte) {
|
| 26 |
+
var req map[string]interface{}
|
| 27 |
+
json.Unmarshal(body, &req)
|
| 28 |
+
if m, ok := req["model"].(string); ok {
|
| 29 |
+
if mapped, found := openRouterModels[m]; found {
|
| 30 |
+
req["model"] = mapped
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
newBody, _ := json.Marshal(req)
|
| 34 |
+
proxyReq, _ := http.NewRequest("POST", "https://openrouter.ai/api/v1/chat/completions", bytes.NewReader(newBody))
|
| 35 |
+
proxyReq.Header.Set("Authorization", "Bearer "+openRouterKey)
|
| 36 |
+
proxyReq.Header.Set("Content-Type", "application/json")
|
| 37 |
+
client := &http.Client{}
|
| 38 |
+
resp, err := client.Do(proxyReq)
|
| 39 |
+
if err != nil {
|
| 40 |
+
http.Error(w, "OpenRouter error", 500)
|
| 41 |
+
return
|
| 42 |
+
}
|
| 43 |
+
defer resp.Body.Close()
|
| 44 |
+
w.Header().Set("Content-Type", "application/json")
|
| 45 |
+
w.WriteHeader(resp.StatusCode)
|
| 46 |
+
io.Copy(w, resp.Body)
|
| 47 |
+
}
|
internal/model/mapping.go
CHANGED
|
@@ -48,6 +48,11 @@ func ResolveClaudeModel(model string, thinkingEnabled bool) (resolvedModel strin
|
|
| 48 |
|
| 49 |
// v1/models 返回的模型列表(全部小写)
|
| 50 |
var ModelList = []string{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
// CLAUDE
|
| 52 |
"claude-sonnet-4-6",
|
| 53 |
"claude-sonnet-4-5-20241022",
|
|
|
|
| 48 |
|
| 49 |
// v1/models 返回的模型列表(全部小写)
|
| 50 |
var ModelList = []string{
|
| 51 |
+
// DEEPSEEK via OpenRouter
|
| 52 |
+
"deepseek-r1",
|
| 53 |
+
"deepseek-v3",
|
| 54 |
+
"deepseek-r1-0528",
|
| 55 |
+
"deepseek-v3-turbo",
|
| 56 |
// CLAUDE
|
| 57 |
"claude-sonnet-4-6",
|
| 58 |
"claude-sonnet-4-5-20241022",
|