| 
									
										
										
										
											2024-02-13 07:06:57 +08:00
										 |  |  | package server | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-27 04:04:17 +08:00
										 |  |  | 	"github.com/ollama/ollama/api" | 
					
						
							| 
									
										
										
										
											2024-02-13 07:06:57 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPrompt(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name     string | 
					
						
							|  |  |  | 		template string | 
					
						
							|  |  |  | 		system   string | 
					
						
							|  |  |  | 		prompt   string | 
					
						
							|  |  |  | 		response string | 
					
						
							|  |  |  | 		generate bool | 
					
						
							|  |  |  | 		want     string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "simple prompt", | 
					
						
							|  |  |  | 			template: "[INST] {{ .System }} {{ .Prompt }} [/INST]", | 
					
						
							|  |  |  | 			system:   "You are a Wizard.", | 
					
						
							|  |  |  | 			prompt:   "What are the potion ingredients?", | 
					
						
							|  |  |  | 			want:     "[INST] You are a Wizard. What are the potion ingredients? [/INST]", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "implicit response", | 
					
						
							|  |  |  | 			template: "[INST] {{ .System }} {{ .Prompt }} [/INST]", | 
					
						
							|  |  |  | 			system:   "You are a Wizard.", | 
					
						
							|  |  |  | 			prompt:   "What are the potion ingredients?", | 
					
						
							|  |  |  | 			response: "I don't know.", | 
					
						
							|  |  |  | 			want:     "[INST] You are a Wizard. What are the potion ingredients? [/INST]I don't know.", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "response", | 
					
						
							|  |  |  | 			template: "[INST] {{ .System }} {{ .Prompt }} [/INST] {{ .Response }}", | 
					
						
							|  |  |  | 			system:   "You are a Wizard.", | 
					
						
							|  |  |  | 			prompt:   "What are the potion ingredients?", | 
					
						
							|  |  |  | 			response: "I don't know.", | 
					
						
							|  |  |  | 			want:     "[INST] You are a Wizard. What are the potion ingredients? [/INST] I don't know.", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "cut", | 
					
						
							|  |  |  | 			template: "<system>{{ .System }}</system><user>{{ .Prompt }}</user><assistant>{{ .Response }}</assistant>", | 
					
						
							|  |  |  | 			system:   "You are a Wizard.", | 
					
						
							|  |  |  | 			prompt:   "What are the potion ingredients?", | 
					
						
							|  |  |  | 			response: "I don't know.", | 
					
						
							|  |  |  | 			generate: true, | 
					
						
							|  |  |  | 			want:     "<system>You are a Wizard.</system><user>What are the potion ingredients?</user><assistant>I don't know.", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "nocut", | 
					
						
							|  |  |  | 			template: "<system>{{ .System }}</system><user>{{ .Prompt }}</user><assistant>{{ .Response }}</assistant>", | 
					
						
							|  |  |  | 			system:   "You are a Wizard.", | 
					
						
							|  |  |  | 			prompt:   "What are the potion ingredients?", | 
					
						
							|  |  |  | 			response: "I don't know.", | 
					
						
							|  |  |  | 			want:     "<system>You are a Wizard.</system><user>What are the potion ingredients?</user><assistant>I don't know.</assistant>", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range tests { | 
					
						
							|  |  |  | 		t.Run(tc.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			got, err := Prompt(tc.template, tc.system, tc.prompt, tc.response, tc.generate) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("error = %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if got != tc.want { | 
					
						
							|  |  |  | 				t.Errorf("got = %v, want %v", got, tc.want) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestChatPrompt(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name     string | 
					
						
							|  |  |  | 		template string | 
					
						
							|  |  |  | 		messages []api.Message | 
					
						
							|  |  |  | 		window   int | 
					
						
							|  |  |  | 		want     string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "simple prompt", | 
					
						
							|  |  |  | 			template: "[INST] {{ .Prompt }} [/INST]", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "user", Content: "Hello"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							|  |  |  | 			want:   "[INST] Hello [/INST]", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "with system message", | 
					
						
							|  |  |  | 			template: "[INST] {{ if .System }}<<SYS>>{{ .System }}<</SYS>> {{ end }}{{ .Prompt }} [/INST]", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "system", Content: "You are a Wizard."}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Hello"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							|  |  |  | 			want:   "[INST] <<SYS>>You are a Wizard.<</SYS>> Hello [/INST]", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "with response", | 
					
						
							|  |  |  | 			template: "[INST] {{ if .System }}<<SYS>>{{ .System }}<</SYS>> {{ end }}{{ .Prompt }} [/INST] {{ .Response }}", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "system", Content: "You are a Wizard."}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Hello"}, | 
					
						
							|  |  |  | 				{Role: "assistant", Content: "I am?"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							|  |  |  | 			want:   "[INST] <<SYS>>You are a Wizard.<</SYS>> Hello [/INST] I am?", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "with implicit response", | 
					
						
							|  |  |  | 			template: "[INST] {{ if .System }}<<SYS>>{{ .System }}<</SYS>> {{ end }}{{ .Prompt }} [/INST]", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "system", Content: "You are a Wizard."}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Hello"}, | 
					
						
							|  |  |  | 				{Role: "assistant", Content: "I am?"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							|  |  |  | 			want:   "[INST] <<SYS>>You are a Wizard.<</SYS>> Hello [/INST]I am?", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "with conversation", | 
					
						
							|  |  |  | 			template: "[INST] {{ if .System }}<<SYS>>{{ .System }}<</SYS>> {{ end }}{{ .Prompt }} [/INST] {{ .Response }} ", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "system", Content: "You are a Wizard."}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "What are the potion ingredients?"}, | 
					
						
							|  |  |  | 				{Role: "assistant", Content: "sugar"}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Anything else?"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							|  |  |  | 			want:   "[INST] <<SYS>>You are a Wizard.<</SYS>> What are the potion ingredients? [/INST] sugar [INST] Anything else? [/INST] ", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "with truncation", | 
					
						
							|  |  |  | 			template: "{{ .System }} {{ .Prompt }} {{ .Response }} ", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "system", Content: "You are a Wizard."}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Hello"}, | 
					
						
							|  |  |  | 				{Role: "assistant", Content: "I am?"}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Why is the sky blue?"}, | 
					
						
							|  |  |  | 				{Role: "assistant", Content: "The sky is blue from rayleigh scattering"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 10, | 
					
						
							|  |  |  | 			want:   "You are a Wizard. Why is the sky blue? The sky is blue from rayleigh scattering", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "images", | 
					
						
							|  |  |  | 			template: "{{ .System }} {{ .Prompt }}", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "system", Content: "You are a Wizard."}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Hello", Images: []api.ImageData{[]byte("base64")}}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							| 
									
										
										
										
											2024-03-01 03:30:14 +08:00
										 |  |  | 			want:   "You are a Wizard. [img-0] Hello", | 
					
						
							| 
									
										
										
										
											2024-02-13 07:06:57 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "images truncated", | 
					
						
							|  |  |  | 			template: "{{ .System }} {{ .Prompt }}", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "system", Content: "You are a Wizard."}, | 
					
						
							|  |  |  | 				{Role: "user", Content: "Hello", Images: []api.ImageData{[]byte("img1"), []byte("img2")}}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							| 
									
										
										
										
											2024-03-01 03:30:14 +08:00
										 |  |  | 			want:   "You are a Wizard. [img-0] [img-1] Hello", | 
					
						
							| 
									
										
										
										
											2024-02-13 07:06:57 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "empty list", | 
					
						
							|  |  |  | 			template: "{{ .System }} {{ .Prompt }}", | 
					
						
							|  |  |  | 			messages: []api.Message{}, | 
					
						
							|  |  |  | 			window:   1024, | 
					
						
							|  |  |  | 			want:     "", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "empty prompt", | 
					
						
							|  |  |  | 			template: "[INST] {{ if .System }}<<SYS>>{{ .System }}<</SYS>> {{ end }}{{ .Prompt }} [/INST] {{ .Response }} ", | 
					
						
							|  |  |  | 			messages: []api.Message{ | 
					
						
							|  |  |  | 				{Role: "user", Content: ""}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			window: 1024, | 
					
						
							|  |  |  | 			want:   "", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encode := func(s string) ([]int, error) { | 
					
						
							|  |  |  | 		words := strings.Fields(s) | 
					
						
							|  |  |  | 		return make([]int, len(words)), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range tests { | 
					
						
							|  |  |  | 		t.Run(tc.name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-02-17 03:42:43 +08:00
										 |  |  | 			got, err := ChatPrompt(tc.template, tc.messages, tc.window, encode) | 
					
						
							| 
									
										
										
										
											2024-02-13 07:06:57 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("error = %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if got != tc.want { | 
					
						
							| 
									
										
										
										
											2024-03-01 03:30:14 +08:00
										 |  |  | 				t.Errorf("got: %q, want: %q", got, tc.want) | 
					
						
							| 
									
										
										
										
											2024-02-13 07:06:57 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |