@@ -3,6 +3,7 @@ package openai
33import (
44 "context"
55 "log/slog"
6+ "strings"
67
78 "github.com/nduyhai/valjean/internal/app/entities"
89 goopenai "github.com/openai/openai-go/v3"
@@ -19,42 +20,82 @@ func NewClient(ai goopenai.Client, logger *slog.Logger) *Client {
1920
2021func (c * Client ) Evaluate (ctx context.Context , in entities.EvalInput ) (entities.EvalOutput , error ) {
2122
22- // Combine context snippets with the main message
23- var fullMessage string
24- if len (in .ContextSnips ) > 0 {
25- fullMessage = "Context:\n "
26- for _ , contextText := range in .ContextSnips {
27- if contextText != "" {
28- fullMessage += contextText + "\n "
23+ // 1) Select & compress context
24+ ctxSnips := uniqueNonEmpty (in .ContextSnips )
25+ if len (ctxSnips ) > 3 {
26+ ctxSnips = ctxSnips [len (ctxSnips )- 3 :] // keep last 3
27+ }
28+ for i := range ctxSnips {
29+ ctxSnips [i ] = truncateRunes (strings .TrimSpace (ctxSnips [i ]), 240 )
30+ }
31+
32+ // 2) Build compact prompt
33+ // ctx lines as "- ..."; then Q: <message>
34+ var b strings.Builder
35+ if len (ctxSnips ) > 0 {
36+ for _ , s := range ctxSnips {
37+ if s != "" {
38+ b .WriteString ("- " )
39+ b .WriteString (s )
40+ b .WriteByte ('\n' )
2941 }
3042 }
31- fullMessage += "\n User message:\n " + in .Text
32- } else {
33- fullMessage = in .Text
43+ b .WriteByte ('\n' )
3444 }
45+ b .WriteString ("Q: " )
46+ b .WriteString (strings .TrimSpace (in .Text ))
47+ userPrompt := b .String ()
3548
49+ // 3) Messages: short system + one user
3650 messages := []goopenai.ChatCompletionMessageParamUnion {
37- goopenai .UserMessage (fullMessage ),
51+ goopenai .SystemMessage ("You are concise. Answer ≤60 words. If uncertain, say so briefly." ),
52+ goopenai .UserMessage (userPrompt ),
3853 }
3954
55+ // 4) Call with a small model & caps
4056 chatCompletion , err := c .ai .Chat .Completions .New (ctx , goopenai.ChatCompletionNewParams {
41- Messages : messages ,
42- Model : goopenai .ChatModelGPT4o ,
57+ Messages : messages ,
58+ Model : goopenai .ChatModelGPT4oMini , // cheaper than 4o
59+ MaxTokens : goopenai .Int (120 ), // cap output tokens
60+ Temperature : goopenai .Float (0.2 ),
4361 })
4462
4563 msg := "Please try again"
4664 if err != nil {
47- return entities.EvalOutput {
48- Summary : msg ,
49- }, err
65+ return entities.EvalOutput {Summary : msg }, err
5066 }
51-
52- if length := len (chatCompletion .Choices ); length > 0 {
53- msg = chatCompletion .Choices [0 ].Message .Content
67+ if len (chatCompletion .Choices ) > 0 && chatCompletion .Choices [0 ].Message .Content != "" {
68+ msg = strings .TrimSpace (chatCompletion .Choices [0 ].Message .Content )
5469 }
5570 return entities.EvalOutput {
5671 Summary : msg ,
57- Citations : [] string { "Citation" } ,
72+ Citations : nil ,
5873 Confidence : 80 ,
5974 }, nil
6075}
76+
77+ func uniqueNonEmpty (ss []string ) []string {
78+ seen := make (map [string ]struct {}, len (ss ))
79+ out := make ([]string , 0 , len (ss ))
80+ for _ , s := range ss {
81+ s = strings .TrimSpace (s )
82+ if s == "" {
83+ continue
84+ }
85+ key := strings .ToLower (s ) // or hash/fingerprint
86+ if _ , ok := seen [key ]; ok {
87+ continue
88+ }
89+ seen [key ] = struct {}{}
90+ out = append (out , s )
91+ }
92+ return out
93+ }
94+
95+ func truncateRunes (s string , max int ) string {
96+ rs := []rune (s )
97+ if len (rs ) <= max {
98+ return s
99+ }
100+ return string (rs [:max ]) + "…"
101+ }
0 commit comments