Skip to content

Commit c40e27c

Browse files
authored
feat: ability to mimic /v1/models/ api (#68)
* add: ability to mimic `/v1/models/` api * fix: missing json dependency * fix: accidentally remove dependency * fix: linter error caught by gh workflow
1 parent 80330ec commit c40e27c

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

azure/proxy.go

+80
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package azure
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"fmt"
67
"github.com/stulzq/azure-openai-proxy/util"
78
"io"
@@ -21,6 +22,85 @@ func ProxyWithConverter(requestConverter RequestConverter) gin.HandlerFunc {
2122
}
2223
}
2324

25+
type DeploymentInfo struct {
26+
Data []map[string]interface{} `json:"data"`
27+
Object string `json:"object"`
28+
}
29+
30+
func ModelProxy(c *gin.Context) {
31+
// Create a channel to receive the results of each request
32+
results := make(chan []map[string]interface{}, len(ModelDeploymentConfig))
33+
34+
// Send a request for each deployment in the map
35+
for _, deployment := range ModelDeploymentConfig {
36+
go func(deployment DeploymentConfig) {
37+
// Create the request
38+
req, err := http.NewRequest(http.MethodGet, deployment.Endpoint+"/openai/deployments?api-version=2022-12-01", nil)
39+
if err != nil {
40+
log.Printf("error parsing response body for deployment %s: %v", deployment.DeploymentName, err)
41+
results <- nil
42+
return
43+
}
44+
45+
// Set the auth header
46+
req.Header.Set(AuthHeaderKey, deployment.ApiKey)
47+
48+
// Send the request
49+
client := &http.Client{}
50+
resp, err := client.Do(req)
51+
if err != nil {
52+
log.Printf("error sending request for deployment %s: %v", deployment.DeploymentName, err)
53+
results <- nil
54+
return
55+
}
56+
defer resp.Body.Close()
57+
if resp.StatusCode != http.StatusOK {
58+
log.Printf("unexpected status code %d for deployment %s", resp.StatusCode, deployment.DeploymentName)
59+
results <- nil
60+
return
61+
}
62+
63+
// Read the response body
64+
body, err := io.ReadAll(resp.Body)
65+
if err != nil {
66+
log.Printf("error reading response body for deployment %s: %v", deployment.DeploymentName, err)
67+
results <- nil
68+
return
69+
}
70+
71+
// Parse the response body as JSON
72+
var deplotmentInfo DeploymentInfo
73+
err = json.Unmarshal(body, &deplotmentInfo)
74+
if err != nil {
75+
log.Printf("error parsing response body for deployment %s: %v", deployment.DeploymentName, err)
76+
results <- nil
77+
return
78+
}
79+
results <- deplotmentInfo.Data
80+
}(deployment)
81+
}
82+
83+
// Wait for all requests to finish and collect the results
84+
var allResults []map[string]interface{}
85+
for i := 0; i < len(ModelDeploymentConfig); i++ {
86+
result := <-results
87+
if result != nil {
88+
allResults = append(allResults, result...)
89+
}
90+
}
91+
var info = DeploymentInfo{Data: allResults, Object: "list"}
92+
combinedResults, err := json.Marshal(info)
93+
if err != nil {
94+
log.Printf("error marshalling results: %v", err)
95+
util.SendError(c, err)
96+
return
97+
}
98+
99+
// Set the response headers and body
100+
c.Header("Content-Type", "application/json")
101+
c.String(http.StatusOK, string(combinedResults))
102+
}
103+
24104
// Proxy Azure OpenAI
25105
func Proxy(c *gin.Context, requestConverter RequestConverter) {
26106
if c.Request.Method == http.MethodOptions {

cmd/router.go

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func registerRoute(r *gin.Engine) {
1717
})
1818
apiBase := viper.GetString("api_base")
1919
stripPrefixConverter := azure.NewStripPrefixConverter(apiBase)
20+
r.GET(stripPrefixConverter.Prefix+"/models", azure.ModelProxy)
2021
templateConverter := azure.NewTemplateConverter("/openai/deployments/{{.DeploymentName}}/embeddings")
2122
apiBasedRouter := r.Group(apiBase)
2223
{

0 commit comments

Comments
 (0)