mirror of
https://github.com/Warky-Devs/vecna.git
synced 2026-08-07 10:47:38 +00:00
feat(server): add passthrough proxy for OpenAI-compatible endpoints
* implement proxy handler for various OpenAI API routes * add error handling for request body and response streaming * introduce new error response format for API compatibility * add tests for recover middleware to handle panics gracefully
This commit is contained in:
+34
-7
@@ -42,32 +42,59 @@ func (h *handler) openAIEmbeddings(w http.ResponseWriter, req bunrouter.Request)
|
||||
func (h *handler) openAIEmbeddingsMapped(w http.ResponseWriter, req bunrouter.Request) error {
|
||||
em, err := h.resolveExtraMap(req.Param("mapping"))
|
||||
if err != nil {
|
||||
return writeJSON(w, http.StatusNotFound, map[string]string{"error": err.Error()})
|
||||
return writeError(w, http.StatusNotFound, err.Error())
|
||||
}
|
||||
return h.openAIEmbeddingsWithAdapter(w, req, em.Adapter, em.ForwardTarget)
|
||||
}
|
||||
|
||||
// openAIEmbeddingsGet is a GET convenience variant (e.g. for browser/curl testing):
|
||||
// ?input=foo&input=bar&model=name in place of a JSON body.
|
||||
func (h *handler) openAIEmbeddingsGet(w http.ResponseWriter, req bunrouter.Request) error {
|
||||
return h.openAIEmbeddingsGetWithAdapter(w, req, h.adapter, "")
|
||||
}
|
||||
|
||||
func (h *handler) openAIEmbeddingsGetMapped(w http.ResponseWriter, req bunrouter.Request) error {
|
||||
em, err := h.resolveExtraMap(req.Param("mapping"))
|
||||
if err != nil {
|
||||
return writeError(w, http.StatusNotFound, err.Error())
|
||||
}
|
||||
return h.openAIEmbeddingsGetWithAdapter(w, req, em.Adapter, em.ForwardTarget)
|
||||
}
|
||||
|
||||
func (h *handler) openAIEmbeddingsGetWithAdapter(w http.ResponseWriter, req bunrouter.Request, adp adapter.Adapter, targetOverride string) error {
|
||||
q := req.URL.Query()
|
||||
texts := q["input"]
|
||||
if len(texts) == 0 {
|
||||
return writeError(w, http.StatusBadRequest, "query parameter \"input\" is required")
|
||||
}
|
||||
return h.processEmbeddings(w, req, adp, targetOverride, texts, q.Get("model"))
|
||||
}
|
||||
|
||||
func (h *handler) openAIEmbeddingsWithAdapter(w http.ResponseWriter, req bunrouter.Request, adp adapter.Adapter, targetOverride string) error {
|
||||
var body openAIEmbedRequest
|
||||
if err := json.NewDecoder(req.Body).Decode(&body); err != nil {
|
||||
return writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request body"})
|
||||
return writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
}
|
||||
|
||||
texts, err := toStringSlice(body.Input)
|
||||
if err != nil {
|
||||
return writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
||||
return writeError(w, http.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
client, targetName, targetURL := h.resolveClientOverride(targetOverride, body.Model)
|
||||
return h.processEmbeddings(w, req, adp, targetOverride, texts, body.Model)
|
||||
}
|
||||
|
||||
func (h *handler) processEmbeddings(w http.ResponseWriter, req bunrouter.Request, adp adapter.Adapter, targetOverride string, texts []string, model string) error {
|
||||
client, targetName, targetURL := h.resolveClientOverride(targetOverride, model)
|
||||
trace := TraceFromContext(req.Context())
|
||||
trace.ForwardTarget = targetName
|
||||
trace.ForwardURL = targetURL
|
||||
|
||||
t0 := time.Now()
|
||||
embedResp, err := client.Embed(req.Context(), embedclient.Request{Texts: texts, Model: body.Model})
|
||||
embedResp, err := client.Embed(req.Context(), embedclient.Request{Texts: texts, Model: model})
|
||||
trace.ForwardDuration = time.Since(t0)
|
||||
if err != nil {
|
||||
return writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
||||
return writeError(w, http.StatusBadGateway, err.Error())
|
||||
}
|
||||
trace.ForwardModel = embedResp.Model
|
||||
trace.PromptTokens = embedResp.Usage.PromptTokens
|
||||
@@ -78,7 +105,7 @@ func (h *handler) openAIEmbeddingsWithAdapter(w http.ResponseWriter, req bunrout
|
||||
for i, vec := range embedResp.Embeddings {
|
||||
adapted, adaptErr := adp.Adapt(vec)
|
||||
if adaptErr != nil {
|
||||
return writeJSON(w, http.StatusInternalServerError, map[string]string{"error": adaptErr.Error()})
|
||||
return writeError(w, http.StatusInternalServerError, adaptErr.Error())
|
||||
}
|
||||
data[i] = openAIEmbedDatum{Object: "embedding", Embedding: adapted, Index: i}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user