mirror of
https://github.com/mudler/LocalAI.git
synced 2025-05-20 10:35:01 +00:00
feat: add machine tag and inference timings (#4577)
* Add machine tag option, add extraUsage option, grpc-server -> proto -> endpoint extraUsage data is broken for now Signed-off-by: mintyleaf <mintyleafdev@gmail.com> * remove redurant timing fields, fix not working timings output Signed-off-by: mintyleaf <mintyleafdev@gmail.com> * use middleware for Machine-Tag only if tag is specified Signed-off-by: mintyleaf <mintyleafdev@gmail.com> --------- Signed-off-by: mintyleaf <mintyleafdev@gmail.com>
This commit is contained in:
parent
8027fdf1c7
commit
96f8ec0402
15 changed files with 137 additions and 48 deletions
|
@ -159,6 +159,8 @@ message Reply {
|
||||||
bytes message = 1;
|
bytes message = 1;
|
||||||
int32 tokens = 2;
|
int32 tokens = 2;
|
||||||
int32 prompt_tokens = 3;
|
int32 prompt_tokens = 3;
|
||||||
|
double timing_prompt_processing = 4;
|
||||||
|
double timing_token_generation = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ModelOptions {
|
message ModelOptions {
|
||||||
|
@ -348,4 +350,4 @@ message StatusResponse {
|
||||||
message Message {
|
message Message {
|
||||||
string role = 1;
|
string role = 1;
|
||||||
string content = 2;
|
string content = 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2408,6 +2408,13 @@ public:
|
||||||
int32_t tokens_evaluated = result.result_json.value("tokens_evaluated", 0);
|
int32_t tokens_evaluated = result.result_json.value("tokens_evaluated", 0);
|
||||||
reply.set_prompt_tokens(tokens_evaluated);
|
reply.set_prompt_tokens(tokens_evaluated);
|
||||||
|
|
||||||
|
if (result.result_json.contains("timings")) {
|
||||||
|
double timing_prompt_processing = result.result_json.at("timings").value("prompt_ms", 0.0);
|
||||||
|
reply.set_timing_prompt_processing(timing_prompt_processing);
|
||||||
|
double timing_token_generation = result.result_json.at("timings").value("predicted_ms", 0.0);
|
||||||
|
reply.set_timing_token_generation(timing_token_generation);
|
||||||
|
}
|
||||||
|
|
||||||
// Log Request Correlation Id
|
// Log Request Correlation Id
|
||||||
LOG_VERBOSE("correlation:", {
|
LOG_VERBOSE("correlation:", {
|
||||||
{ "id", data["correlation_id"] }
|
{ "id", data["correlation_id"] }
|
||||||
|
@ -2448,6 +2455,13 @@ public:
|
||||||
reply->set_prompt_tokens(tokens_evaluated);
|
reply->set_prompt_tokens(tokens_evaluated);
|
||||||
reply->set_tokens(tokens_predicted);
|
reply->set_tokens(tokens_predicted);
|
||||||
reply->set_message(completion_text);
|
reply->set_message(completion_text);
|
||||||
|
|
||||||
|
if (result.result_json.contains("timings")) {
|
||||||
|
double timing_prompt_processing = result.result_json.at("timings").value("prompt_ms", 0.0);
|
||||||
|
reply->set_timing_prompt_processing(timing_prompt_processing);
|
||||||
|
double timing_token_generation = result.result_json.at("timings").value("predicted_ms", 0.0);
|
||||||
|
reply->set_timing_token_generation(timing_token_generation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,8 +27,10 @@ type LLMResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenUsage struct {
|
type TokenUsage struct {
|
||||||
Prompt int
|
Prompt int
|
||||||
Completion int
|
Completion int
|
||||||
|
TimingPromptProcessing float64
|
||||||
|
TimingTokenGeneration float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func ModelInference(ctx context.Context, s string, messages []schema.Message, images, videos, audios []string, loader *model.ModelLoader, c config.BackendConfig, o *config.ApplicationConfig, tokenCallback func(string, TokenUsage) bool) (func() (LLMResponse, error), error) {
|
func ModelInference(ctx context.Context, s string, messages []schema.Message, images, videos, audios []string, loader *model.ModelLoader, c config.BackendConfig, o *config.ApplicationConfig, tokenCallback func(string, TokenUsage) bool) (func() (LLMResponse, error), error) {
|
||||||
|
@ -123,6 +125,8 @@ func ModelInference(ctx context.Context, s string, messages []schema.Message, im
|
||||||
|
|
||||||
tokenUsage.Prompt = int(reply.PromptTokens)
|
tokenUsage.Prompt = int(reply.PromptTokens)
|
||||||
tokenUsage.Completion = int(reply.Tokens)
|
tokenUsage.Completion = int(reply.Tokens)
|
||||||
|
tokenUsage.TimingTokenGeneration = reply.TimingTokenGeneration
|
||||||
|
tokenUsage.TimingPromptProcessing = reply.TimingPromptProcessing
|
||||||
|
|
||||||
for len(partialRune) > 0 {
|
for len(partialRune) > 0 {
|
||||||
r, size := utf8.DecodeRune(partialRune)
|
r, size := utf8.DecodeRune(partialRune)
|
||||||
|
@ -157,6 +161,10 @@ func ModelInference(ctx context.Context, s string, messages []schema.Message, im
|
||||||
if tokenUsage.Completion == 0 {
|
if tokenUsage.Completion == 0 {
|
||||||
tokenUsage.Completion = int(reply.Tokens)
|
tokenUsage.Completion = int(reply.Tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokenUsage.TimingTokenGeneration = reply.TimingTokenGeneration
|
||||||
|
tokenUsage.TimingPromptProcessing = reply.TimingPromptProcessing
|
||||||
|
|
||||||
return LLMResponse{
|
return LLMResponse{
|
||||||
Response: string(reply.Message),
|
Response: string(reply.Message),
|
||||||
Usage: tokenUsage,
|
Usage: tokenUsage,
|
||||||
|
|
|
@ -70,6 +70,7 @@ type RunCMD struct {
|
||||||
WatchdogBusyTimeout string `env:"LOCALAI_WATCHDOG_BUSY_TIMEOUT,WATCHDOG_BUSY_TIMEOUT" default:"5m" help:"Threshold beyond which a busy backend should be stopped" group:"backends"`
|
WatchdogBusyTimeout string `env:"LOCALAI_WATCHDOG_BUSY_TIMEOUT,WATCHDOG_BUSY_TIMEOUT" default:"5m" help:"Threshold beyond which a busy backend should be stopped" group:"backends"`
|
||||||
Federated bool `env:"LOCALAI_FEDERATED,FEDERATED" help:"Enable federated instance" group:"federated"`
|
Federated bool `env:"LOCALAI_FEDERATED,FEDERATED" help:"Enable federated instance" group:"federated"`
|
||||||
DisableGalleryEndpoint bool `env:"LOCALAI_DISABLE_GALLERY_ENDPOINT,DISABLE_GALLERY_ENDPOINT" help:"Disable the gallery endpoints" group:"api"`
|
DisableGalleryEndpoint bool `env:"LOCALAI_DISABLE_GALLERY_ENDPOINT,DISABLE_GALLERY_ENDPOINT" help:"Disable the gallery endpoints" group:"api"`
|
||||||
|
MachineTag string `env:"LOCALAI_MACHINE_TAG" help:"Add Machine-Tag header to each response which is useful to track the machine in the P2P network" group:"api"`
|
||||||
LoadToMemory []string `env:"LOCALAI_LOAD_TO_MEMORY,LOAD_TO_MEMORY" help:"A list of models to load into memory at startup" group:"models"`
|
LoadToMemory []string `env:"LOCALAI_LOAD_TO_MEMORY,LOAD_TO_MEMORY" help:"A list of models to load into memory at startup" group:"models"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +108,7 @@ func (r *RunCMD) Run(ctx *cliContext.Context) error {
|
||||||
config.WithHttpGetExemptedEndpoints(r.HttpGetExemptedEndpoints),
|
config.WithHttpGetExemptedEndpoints(r.HttpGetExemptedEndpoints),
|
||||||
config.WithP2PNetworkID(r.Peer2PeerNetworkID),
|
config.WithP2PNetworkID(r.Peer2PeerNetworkID),
|
||||||
config.WithLoadToMemory(r.LoadToMemory),
|
config.WithLoadToMemory(r.LoadToMemory),
|
||||||
|
config.WithMachineTag(r.MachineTag),
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.DisableMetricsEndpoint {
|
if r.DisableMetricsEndpoint {
|
||||||
|
|
|
@ -65,6 +65,8 @@ type ApplicationConfig struct {
|
||||||
ModelsURL []string
|
ModelsURL []string
|
||||||
|
|
||||||
WatchDogBusyTimeout, WatchDogIdleTimeout time.Duration
|
WatchDogBusyTimeout, WatchDogIdleTimeout time.Duration
|
||||||
|
|
||||||
|
MachineTag string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppOption func(*ApplicationConfig)
|
type AppOption func(*ApplicationConfig)
|
||||||
|
@ -94,6 +96,12 @@ func WithModelPath(path string) AppOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithMachineTag(tag string) AppOption {
|
||||||
|
return func(o *ApplicationConfig) {
|
||||||
|
o.MachineTag = tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WithCors(b bool) AppOption {
|
func WithCors(b bool) AppOption {
|
||||||
return func(o *ApplicationConfig) {
|
return func(o *ApplicationConfig) {
|
||||||
o.CORS = b
|
o.CORS = b
|
||||||
|
|
|
@ -89,6 +89,14 @@ func API(application *application.Application) (*fiber.App, error) {
|
||||||
|
|
||||||
router.Use(middleware.StripPathPrefix())
|
router.Use(middleware.StripPathPrefix())
|
||||||
|
|
||||||
|
if application.ApplicationConfig().MachineTag != "" {
|
||||||
|
router.Use(func(c *fiber.Ctx) error {
|
||||||
|
c.Response().Header.Set("Machine-Tag", application.ApplicationConfig().MachineTag)
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
router.Hooks().OnListen(func(listenData fiber.ListenData) error {
|
router.Hooks().OnListen(func(listenData fiber.ListenData) error {
|
||||||
scheme := "http"
|
scheme := "http"
|
||||||
if listenData.TLS {
|
if listenData.TLS {
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
// @Router /tts [post]
|
// @Router /tts [post]
|
||||||
func TTSEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
func TTSEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
input := new(schema.TTSRequest)
|
input := new(schema.TTSRequest)
|
||||||
|
|
||||||
// Get input data from the request body
|
// Get input data from the request body
|
||||||
|
|
|
@ -19,7 +19,6 @@ import (
|
||||||
// @Router /vad [post]
|
// @Router /vad [post]
|
||||||
func VADEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
func VADEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
input := new(schema.VADRequest)
|
input := new(schema.VADRequest)
|
||||||
|
|
||||||
// Get input data from the request body
|
// Get input data from the request body
|
||||||
|
|
|
@ -30,7 +30,7 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
var id, textContentToReturn string
|
var id, textContentToReturn string
|
||||||
var created int
|
var created int
|
||||||
|
|
||||||
process := func(s string, req *schema.OpenAIRequest, config *config.BackendConfig, loader *model.ModelLoader, responses chan schema.OpenAIResponse) {
|
process := func(s string, req *schema.OpenAIRequest, config *config.BackendConfig, loader *model.ModelLoader, responses chan schema.OpenAIResponse, extraUsage bool) {
|
||||||
initialMessage := schema.OpenAIResponse{
|
initialMessage := schema.OpenAIResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
Created: created,
|
Created: created,
|
||||||
|
@ -40,18 +40,24 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
}
|
}
|
||||||
responses <- initialMessage
|
responses <- initialMessage
|
||||||
|
|
||||||
ComputeChoices(req, s, config, startupOptions, loader, func(s string, c *[]schema.Choice) {}, func(s string, usage backend.TokenUsage) bool {
|
ComputeChoices(req, s, config, startupOptions, loader, func(s string, c *[]schema.Choice) {}, func(s string, tokenUsage backend.TokenUsage) bool {
|
||||||
|
usage := schema.OpenAIUsage{
|
||||||
|
PromptTokens: tokenUsage.Prompt,
|
||||||
|
CompletionTokens: tokenUsage.Completion,
|
||||||
|
TotalTokens: tokenUsage.Prompt + tokenUsage.Completion,
|
||||||
|
}
|
||||||
|
if extraUsage {
|
||||||
|
usage.TimingTokenGeneration = tokenUsage.TimingTokenGeneration
|
||||||
|
usage.TimingPromptProcessing = tokenUsage.TimingPromptProcessing
|
||||||
|
}
|
||||||
|
|
||||||
resp := schema.OpenAIResponse{
|
resp := schema.OpenAIResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
Created: created,
|
Created: created,
|
||||||
Model: req.Model, // we have to return what the user sent here, due to OpenAI spec.
|
Model: req.Model, // we have to return what the user sent here, due to OpenAI spec.
|
||||||
Choices: []schema.Choice{{Delta: &schema.Message{Content: &s}, Index: 0}},
|
Choices: []schema.Choice{{Delta: &schema.Message{Content: &s}, Index: 0}},
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
Usage: schema.OpenAIUsage{
|
Usage: usage,
|
||||||
PromptTokens: usage.Prompt,
|
|
||||||
CompletionTokens: usage.Completion,
|
|
||||||
TotalTokens: usage.Prompt + usage.Completion,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
responses <- resp
|
responses <- resp
|
||||||
|
@ -59,7 +65,7 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
})
|
})
|
||||||
close(responses)
|
close(responses)
|
||||||
}
|
}
|
||||||
processTools := func(noAction string, prompt string, req *schema.OpenAIRequest, config *config.BackendConfig, loader *model.ModelLoader, responses chan schema.OpenAIResponse) {
|
processTools := func(noAction string, prompt string, req *schema.OpenAIRequest, config *config.BackendConfig, loader *model.ModelLoader, responses chan schema.OpenAIResponse, extraUsage bool) {
|
||||||
result := ""
|
result := ""
|
||||||
_, tokenUsage, _ := ComputeChoices(req, prompt, config, startupOptions, loader, func(s string, c *[]schema.Choice) {}, func(s string, usage backend.TokenUsage) bool {
|
_, tokenUsage, _ := ComputeChoices(req, prompt, config, startupOptions, loader, func(s string, c *[]schema.Choice) {}, func(s string, usage backend.TokenUsage) bool {
|
||||||
result += s
|
result += s
|
||||||
|
@ -90,6 +96,15 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
log.Error().Err(err).Msg("error handling question")
|
log.Error().Err(err).Msg("error handling question")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
usage := schema.OpenAIUsage{
|
||||||
|
PromptTokens: tokenUsage.Prompt,
|
||||||
|
CompletionTokens: tokenUsage.Completion,
|
||||||
|
TotalTokens: tokenUsage.Prompt + tokenUsage.Completion,
|
||||||
|
}
|
||||||
|
if extraUsage {
|
||||||
|
usage.TimingTokenGeneration = tokenUsage.TimingTokenGeneration
|
||||||
|
usage.TimingPromptProcessing = tokenUsage.TimingPromptProcessing
|
||||||
|
}
|
||||||
|
|
||||||
resp := schema.OpenAIResponse{
|
resp := schema.OpenAIResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -97,11 +112,7 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
Model: req.Model, // we have to return what the user sent here, due to OpenAI spec.
|
Model: req.Model, // we have to return what the user sent here, due to OpenAI spec.
|
||||||
Choices: []schema.Choice{{Delta: &schema.Message{Content: &result}, Index: 0}},
|
Choices: []schema.Choice{{Delta: &schema.Message{Content: &result}, Index: 0}},
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
Usage: schema.OpenAIUsage{
|
Usage: usage,
|
||||||
PromptTokens: tokenUsage.Prompt,
|
|
||||||
CompletionTokens: tokenUsage.Completion,
|
|
||||||
TotalTokens: tokenUsage.Prompt + tokenUsage.Completion,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
responses <- resp
|
responses <- resp
|
||||||
|
@ -170,6 +181,9 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
}
|
}
|
||||||
c.Set("X-Correlation-ID", correlationID)
|
c.Set("X-Correlation-ID", correlationID)
|
||||||
|
|
||||||
|
// Opt-in extra usage flag
|
||||||
|
extraUsage := c.Get("LocalAI-Extra-Usage", "") != ""
|
||||||
|
|
||||||
modelFile, input, err := readRequest(c, cl, ml, startupOptions, true)
|
modelFile, input, err := readRequest(c, cl, ml, startupOptions, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed reading parameters from request:%w", err)
|
return fmt.Errorf("failed reading parameters from request:%w", err)
|
||||||
|
@ -319,9 +333,9 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
responses := make(chan schema.OpenAIResponse)
|
responses := make(chan schema.OpenAIResponse)
|
||||||
|
|
||||||
if !shouldUseFn {
|
if !shouldUseFn {
|
||||||
go process(predInput, input, config, ml, responses)
|
go process(predInput, input, config, ml, responses, extraUsage)
|
||||||
} else {
|
} else {
|
||||||
go processTools(noActionName, predInput, input, config, ml, responses)
|
go processTools(noActionName, predInput, input, config, ml, responses, extraUsage)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
|
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
|
||||||
|
@ -449,6 +463,15 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
usage := schema.OpenAIUsage{
|
||||||
|
PromptTokens: tokenUsage.Prompt,
|
||||||
|
CompletionTokens: tokenUsage.Completion,
|
||||||
|
TotalTokens: tokenUsage.Prompt + tokenUsage.Completion,
|
||||||
|
}
|
||||||
|
if extraUsage {
|
||||||
|
usage.TimingTokenGeneration = tokenUsage.TimingTokenGeneration
|
||||||
|
usage.TimingPromptProcessing = tokenUsage.TimingPromptProcessing
|
||||||
|
}
|
||||||
|
|
||||||
resp := &schema.OpenAIResponse{
|
resp := &schema.OpenAIResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -456,11 +479,7 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
Model: input.Model, // we have to return what the user sent here, due to OpenAI spec.
|
Model: input.Model, // we have to return what the user sent here, due to OpenAI spec.
|
||||||
Choices: result,
|
Choices: result,
|
||||||
Object: "chat.completion",
|
Object: "chat.completion",
|
||||||
Usage: schema.OpenAIUsage{
|
Usage: usage,
|
||||||
PromptTokens: tokenUsage.Prompt,
|
|
||||||
CompletionTokens: tokenUsage.Completion,
|
|
||||||
TotalTokens: tokenUsage.Prompt + tokenUsage.Completion,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
respData, _ := json.Marshal(resp)
|
respData, _ := json.Marshal(resp)
|
||||||
log.Debug().Msgf("Response: %s", respData)
|
log.Debug().Msgf("Response: %s", respData)
|
||||||
|
|
|
@ -30,8 +30,17 @@ func CompletionEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, e
|
||||||
id := uuid.New().String()
|
id := uuid.New().String()
|
||||||
created := int(time.Now().Unix())
|
created := int(time.Now().Unix())
|
||||||
|
|
||||||
process := func(s string, req *schema.OpenAIRequest, config *config.BackendConfig, loader *model.ModelLoader, responses chan schema.OpenAIResponse) {
|
process := func(s string, req *schema.OpenAIRequest, config *config.BackendConfig, loader *model.ModelLoader, responses chan schema.OpenAIResponse, extraUsage bool) {
|
||||||
ComputeChoices(req, s, config, appConfig, loader, func(s string, c *[]schema.Choice) {}, func(s string, usage backend.TokenUsage) bool {
|
ComputeChoices(req, s, config, appConfig, loader, func(s string, c *[]schema.Choice) {}, func(s string, tokenUsage backend.TokenUsage) bool {
|
||||||
|
usage := schema.OpenAIUsage{
|
||||||
|
PromptTokens: tokenUsage.Prompt,
|
||||||
|
CompletionTokens: tokenUsage.Completion,
|
||||||
|
TotalTokens: tokenUsage.Prompt + tokenUsage.Completion,
|
||||||
|
}
|
||||||
|
if extraUsage {
|
||||||
|
usage.TimingTokenGeneration = tokenUsage.TimingTokenGeneration
|
||||||
|
usage.TimingPromptProcessing = tokenUsage.TimingPromptProcessing
|
||||||
|
}
|
||||||
resp := schema.OpenAIResponse{
|
resp := schema.OpenAIResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
Created: created,
|
Created: created,
|
||||||
|
@ -43,11 +52,7 @@ func CompletionEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, e
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Object: "text_completion",
|
Object: "text_completion",
|
||||||
Usage: schema.OpenAIUsage{
|
Usage: usage,
|
||||||
PromptTokens: usage.Prompt,
|
|
||||||
CompletionTokens: usage.Completion,
|
|
||||||
TotalTokens: usage.Prompt + usage.Completion,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("Sending goroutine: %s", s)
|
log.Debug().Msgf("Sending goroutine: %s", s)
|
||||||
|
|
||||||
|
@ -60,6 +65,10 @@ func CompletionEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, e
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
// Add Correlation
|
// Add Correlation
|
||||||
c.Set("X-Correlation-ID", id)
|
c.Set("X-Correlation-ID", id)
|
||||||
|
|
||||||
|
// Opt-in extra usage flag
|
||||||
|
extraUsage := c.Get("LocalAI-Extra-Usage", "") != ""
|
||||||
|
|
||||||
modelFile, input, err := readRequest(c, cl, ml, appConfig, true)
|
modelFile, input, err := readRequest(c, cl, ml, appConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed reading parameters from request:%w", err)
|
return fmt.Errorf("failed reading parameters from request:%w", err)
|
||||||
|
@ -113,7 +122,7 @@ func CompletionEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, e
|
||||||
|
|
||||||
responses := make(chan schema.OpenAIResponse)
|
responses := make(chan schema.OpenAIResponse)
|
||||||
|
|
||||||
go process(predInput, input, config, ml, responses)
|
go process(predInput, input, config, ml, responses, extraUsage)
|
||||||
|
|
||||||
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
|
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
|
||||||
|
|
||||||
|
@ -170,11 +179,20 @@ func CompletionEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
totalTokenUsage.Prompt += tokenUsage.Prompt
|
totalTokenUsage.TimingTokenGeneration += tokenUsage.TimingTokenGeneration
|
||||||
totalTokenUsage.Completion += tokenUsage.Completion
|
totalTokenUsage.TimingPromptProcessing += tokenUsage.TimingPromptProcessing
|
||||||
|
|
||||||
result = append(result, r...)
|
result = append(result, r...)
|
||||||
}
|
}
|
||||||
|
usage := schema.OpenAIUsage{
|
||||||
|
PromptTokens: totalTokenUsage.Prompt,
|
||||||
|
CompletionTokens: totalTokenUsage.Completion,
|
||||||
|
TotalTokens: totalTokenUsage.Prompt + totalTokenUsage.Completion,
|
||||||
|
}
|
||||||
|
if extraUsage {
|
||||||
|
usage.TimingTokenGeneration = totalTokenUsage.TimingTokenGeneration
|
||||||
|
usage.TimingPromptProcessing = totalTokenUsage.TimingPromptProcessing
|
||||||
|
}
|
||||||
|
|
||||||
resp := &schema.OpenAIResponse{
|
resp := &schema.OpenAIResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -182,11 +200,7 @@ func CompletionEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, e
|
||||||
Model: input.Model, // we have to return what the user sent here, due to OpenAI spec.
|
Model: input.Model, // we have to return what the user sent here, due to OpenAI spec.
|
||||||
Choices: result,
|
Choices: result,
|
||||||
Object: "text_completion",
|
Object: "text_completion",
|
||||||
Usage: schema.OpenAIUsage{
|
Usage: usage,
|
||||||
PromptTokens: totalTokenUsage.Prompt,
|
|
||||||
CompletionTokens: totalTokenUsage.Completion,
|
|
||||||
TotalTokens: totalTokenUsage.Prompt + totalTokenUsage.Completion,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonResult, _ := json.Marshal(resp)
|
jsonResult, _ := json.Marshal(resp)
|
||||||
|
|
|
@ -25,6 +25,9 @@ import (
|
||||||
func EditEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluator *templates.Evaluator, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
func EditEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluator *templates.Evaluator, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
|
// Opt-in extra usage flag
|
||||||
|
extraUsage := c.Get("LocalAI-Extra-Usage", "") != ""
|
||||||
|
|
||||||
modelFile, input, err := readRequest(c, cl, ml, appConfig, true)
|
modelFile, input, err := readRequest(c, cl, ml, appConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed reading parameters from request:%w", err)
|
return fmt.Errorf("failed reading parameters from request:%w", err)
|
||||||
|
@ -61,8 +64,20 @@ func EditEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
totalTokenUsage.Prompt += tokenUsage.Prompt
|
totalTokenUsage.Prompt += tokenUsage.Prompt
|
||||||
totalTokenUsage.Completion += tokenUsage.Completion
|
totalTokenUsage.Completion += tokenUsage.Completion
|
||||||
|
|
||||||
|
totalTokenUsage.TimingTokenGeneration += tokenUsage.TimingTokenGeneration
|
||||||
|
totalTokenUsage.TimingPromptProcessing += tokenUsage.TimingPromptProcessing
|
||||||
|
|
||||||
result = append(result, r...)
|
result = append(result, r...)
|
||||||
}
|
}
|
||||||
|
usage := schema.OpenAIUsage{
|
||||||
|
PromptTokens: totalTokenUsage.Prompt,
|
||||||
|
CompletionTokens: totalTokenUsage.Completion,
|
||||||
|
TotalTokens: totalTokenUsage.Prompt + totalTokenUsage.Completion,
|
||||||
|
}
|
||||||
|
if extraUsage {
|
||||||
|
usage.TimingTokenGeneration = totalTokenUsage.TimingTokenGeneration
|
||||||
|
usage.TimingPromptProcessing = totalTokenUsage.TimingPromptProcessing
|
||||||
|
}
|
||||||
|
|
||||||
id := uuid.New().String()
|
id := uuid.New().String()
|
||||||
created := int(time.Now().Unix())
|
created := int(time.Now().Unix())
|
||||||
|
@ -72,11 +87,7 @@ func EditEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, evaluat
|
||||||
Model: input.Model, // we have to return what the user sent here, due to OpenAI spec.
|
Model: input.Model, // we have to return what the user sent here, due to OpenAI spec.
|
||||||
Choices: result,
|
Choices: result,
|
||||||
Object: "edit",
|
Object: "edit",
|
||||||
Usage: schema.OpenAIUsage{
|
Usage: usage,
|
||||||
PromptTokens: totalTokenUsage.Prompt,
|
|
||||||
CompletionTokens: totalTokenUsage.Completion,
|
|
||||||
TotalTokens: totalTokenUsage.Prompt + totalTokenUsage.Completion,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonResult, _ := json.Marshal(resp)
|
jsonResult, _ := json.Marshal(resp)
|
||||||
|
|
|
@ -52,6 +52,8 @@ func ComputeChoices(
|
||||||
|
|
||||||
tokenUsage.Prompt += prediction.Usage.Prompt
|
tokenUsage.Prompt += prediction.Usage.Prompt
|
||||||
tokenUsage.Completion += prediction.Usage.Completion
|
tokenUsage.Completion += prediction.Usage.Completion
|
||||||
|
tokenUsage.TimingPromptProcessing += prediction.Usage.TimingPromptProcessing
|
||||||
|
tokenUsage.TimingTokenGeneration += prediction.Usage.TimingTokenGeneration
|
||||||
|
|
||||||
finetunedResponse := backend.Finetune(*config, predInput, prediction.Response)
|
finetunedResponse := backend.Finetune(*config, predInput, prediction.Response)
|
||||||
cb(finetunedResponse, &result)
|
cb(finetunedResponse, &result)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
// @Summary List and describe the various models available in the API.
|
// @Summary List and describe the various models available in the API.
|
||||||
// @Success 200 {object} schema.ModelsDataResponse "Response"
|
// @Success 200 {object} schema.ModelsDataResponse "Response"
|
||||||
// @Router /v1/models [get]
|
// @Router /v1/models [get]
|
||||||
func ListModelsEndpoint(bcl *config.BackendConfigLoader, ml *model.ModelLoader) func(ctx *fiber.Ctx) error {
|
func ListModelsEndpoint(bcl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) func(ctx *fiber.Ctx) error {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
// If blank, no filter is applied.
|
// If blank, no filter is applied.
|
||||||
filter := c.Query("filter")
|
filter := c.Query("filter")
|
||||||
|
|
|
@ -130,6 +130,6 @@ func RegisterOpenAIRoutes(app *fiber.App,
|
||||||
}
|
}
|
||||||
|
|
||||||
// List models
|
// List models
|
||||||
app.Get("/v1/models", openai.ListModelsEndpoint(application.BackendLoader(), application.ModelLoader()))
|
app.Get("/v1/models", openai.ListModelsEndpoint(application.BackendLoader(), application.ModelLoader(), application.ApplicationConfig()))
|
||||||
app.Get("/models", openai.ListModelsEndpoint(application.BackendLoader(), application.ModelLoader()))
|
app.Get("/models", openai.ListModelsEndpoint(application.BackendLoader(), application.ModelLoader(), application.ApplicationConfig()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ type OpenAIUsage struct {
|
||||||
PromptTokens int `json:"prompt_tokens"`
|
PromptTokens int `json:"prompt_tokens"`
|
||||||
CompletionTokens int `json:"completion_tokens"`
|
CompletionTokens int `json:"completion_tokens"`
|
||||||
TotalTokens int `json:"total_tokens"`
|
TotalTokens int `json:"total_tokens"`
|
||||||
|
// Extra timing data, disabled by default as is't not a part of OpenAI specification
|
||||||
|
TimingPromptProcessing float64 `json:"timing_prompt_processing,omitempty"`
|
||||||
|
TimingTokenGeneration float64 `json:"timing_token_generation,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Item struct {
|
type Item struct {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue