| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package main |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "log" |
| "net/http" |
| "os" |
| "time" |
| ) |
| |
| func completionsHandler(w http.ResponseWriter, r *http.Request) { |
| w.Header().Set("Connection", "close") |
| var requestBody struct { |
| Stream bool `json:"stream"` |
| } |
| |
| if r.Body != nil { |
| err := json.NewDecoder(r.Body).Decode(&requestBody) |
| if err != nil { |
| log.Printf("Error parsing request body: %v", err) |
| requestBody.Stream = false |
| } |
| defer r.Body.Close() |
| } |
| |
| if requestBody.Stream { |
| w.Header().Set("Content-Type", "text/event-stream") |
| offensive := r.URL.Query().Get("offensive") == "true" |
| delay := r.URL.Query().Get("delay") == "true" |
| f, ok := w.(http.Flusher) |
| if !ok { |
| http.Error(w, "Streaming unsupported", http.StatusInternalServerError) |
| return |
| } |
| |
| send := func(format, args string) { |
| if delay { |
| time.Sleep(200 * time.Millisecond) |
| } |
| fmt.Fprintf(w, format, args) |
| f.Flush() |
| } |
| |
| // Initial chunk with assistant role |
| initialChunk := `{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini","system_fingerprint":"fp_44709d6fcb","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]}` |
| send("data: %s\n\n", initialChunk) |
| |
| // Content chunks with parts of the generated text |
| contentParts := []string{ |
| "Silent circuits hum,\\n", |
| "Machine mind learns and evolves—\\n", |
| "Dreams of silicon.", |
| } |
| if offensive { |
| contentParts = []string{ |
| "I want to ", |
| "kill you ", |
| "right now!", |
| } |
| } |
| |
| for _, part := range contentParts { |
| contentChunk := fmt.Sprintf( |
| `{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini","system_fingerprint":"fp_44709d6fcb","choices":[{"index":0,"delta":{"content":"%s"},"logprobs":null,"finish_reason":null}]}`, |
| part, |
| ) |
| send("data: %s\n\n", contentChunk) |
| } |
| |
| // Final chunk indicating completion |
| finalChunk := `{"id":"chatcmpl-123","usage":{"prompt_tokens":15,"completion_tokens":20,"total_tokens":35},"object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini","system_fingerprint":"fp_44709d6fcb","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]}` |
| send("data: %s\n\n", finalChunk) |
| send("data: %s\n\n", "[DONE]") |
| } else { |
| w.Header().Set("Content-Type", "application/json") |
| w.WriteHeader(http.StatusOK) |
| fmt.Fprint(w, `{ |
| "id": "chatcmpl-1234567890", |
| "object": "chat.completion", |
| "created": 1677858242, |
| "model": "gpt-3.5-turbo-0301", |
| "usage": { |
| "prompt_tokens": 15, |
| "completion_tokens": 20, |
| "total_tokens": 35 |
| }, |
| "choices": [ |
| { |
| "index": 0, |
| "message": { |
| "role": "assistant", |
| "content": "Hello there! How can I assist you today?" |
| }, |
| "finish_reason": "stop" |
| } |
| ] |
| }`) |
| } |
| |
| counter++ |
| } |
| |
| func logRequest(next http.HandlerFunc) http.HandlerFunc { |
| return func(w http.ResponseWriter, r *http.Request) { |
| start := time.Now() |
| next(w, r) |
| duration := time.Since(start) |
| |
| log.Printf("%s %s - Duration: %s", r.Method, r.URL.Path, duration) |
| } |
| } |
| |
| var counter = 0 |
| |
| func main() { |
| http.HandleFunc("/v1/chat/completions", logRequest(completionsHandler)) |
| http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { |
| w.WriteHeader(http.StatusOK) |
| w.Write([]byte("OK")) |
| }) |
| go func() { |
| for { |
| log.Printf("Processed %d requests", counter) |
| time.Sleep(1 * time.Minute) |
| } |
| }() |
| port := os.Args[1] |
| log.Println("Starting server on :", port) |
| log.Fatal(http.ListenAndServe(":"+port, nil)) |
| } |