Skip to content

Commit 15d9f76

Browse files
authored
add plugin: ai-prompt-decorator (#1021)
1 parent 5f15017 commit 15d9f76

File tree

5 files changed

+223
-0
lines changed

5 files changed

+223
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
config.yaml
2+
main.wasm
3+
tmp/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# 简介
2+
AI提示词修饰插件,通过在与大模型发起的请求前后插入指定信息来调整大模型的输出。
3+
4+
# 配置说明
5+
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
6+
|----------------|-----------------|------|-----|----------------------------------|
7+
| `decorators` | array of object | 必填 | - | 修饰设置 |
8+
9+
template object 配置说明:
10+
11+
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
12+
|----------------|-----------------|------|-----|----------------------------------|
13+
| `name` | string | 必填 | - | 修饰名称 |
14+
| `decorator.prepend` | array of message object | 必填 | - | 在初始输入之前插入的语句 |
15+
| `decorator.append` | array of message object | 必填 | - | 在初始输入之后插入的语句 |
16+
17+
message object 配置说明:
18+
19+
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
20+
|----------------|-----------------|------|-----|----------------------------------|
21+
| `role` | string | 必填 | - | 角色 |
22+
| `content` | string | 必填 | - | 消息 |
23+
24+
# 示例
25+
26+
配置示例如下:
27+
28+
```yaml
29+
decorators:
30+
- name: "hangzhou-guide"
31+
decorator:
32+
prepend:
33+
- role: system
34+
content: "You will always respond in the Chinese language."
35+
- role: user
36+
content: "Assume you are from Hangzhou."
37+
append:
38+
- role: user
39+
content: "Don't introduce Hangzhou's food."
40+
```
41+
42+
使用以上配置发起请求:
43+
44+
```bash
45+
{
46+
"model": "gpt-3.5-turbo",
47+
"messages": [
48+
{
49+
"role": "user",
50+
"content": "Please introduce your home."
51+
}
52+
]
53+
}
54+
```
55+
56+
响应如下:
57+
58+
```
59+
{
60+
"id": "chatcmpl-9UYwQlEg6GwAswEZBDYXl41RU4gab",
61+
"object": "chat.completion",
62+
"created": 1717071182,
63+
"model": "gpt-3.5-turbo-0125",
64+
"choices": [
65+
{
66+
"index": 0,
67+
"message": {
68+
"role": "assistant",
69+
"content": "杭州是一个美丽的城市,有着悠久的历史和富有特色的文化。这里风景优美,有西湖、雷峰塔等著名景点,吸引着许多游客前来观光。杭州人民热情好客,城市宁静安逸,是一个适合居住和旅游的地方。"
70+
},
71+
"logprobs": null,
72+
"finish_reason": "stop"
73+
}
74+
],
75+
"usage": {
76+
"prompt_tokens": 49,
77+
"completion_tokens": 117,
78+
"total_tokens": 166
79+
},
80+
"system_fingerprint": null
81+
}
82+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module ai-prompt-decorator
2+
3+
go 1.18
4+
5+
require (
6+
github.com/alibaba/higress/plugins/wasm-go v1.3.5
7+
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a
8+
github.com/tidwall/gjson v1.14.3
9+
)
10+
11+
require (
12+
github.com/google/uuid v1.3.0 // indirect
13+
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect
14+
github.com/magefile/mage v1.14.0 // indirect
15+
github.com/tidwall/match v1.1.1 // indirect
16+
github.com/tidwall/pretty v1.2.0 // indirect
17+
github.com/tidwall/resp v0.1.1 // indirect
18+
github.com/tidwall/sjson v1.2.5
19+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
github.com/alibaba/higress/plugins/wasm-go v1.3.5 h1:VOLL3m442IHCSu8mR5AZ4sc6LVT9X0w1hdqDI7oB9jY=
2+
github.com/alibaba/higress/plugins/wasm-go v1.3.5/go.mod h1:kr3V9Ntbspj1eSrX8rgjBsdMXkGupYEf+LM72caGPQc=
3+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4+
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
5+
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
6+
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
7+
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
8+
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1:luYRvxLTE1xYxrXYj7nmjd1U0HHh8pUPiKfdZ0MhCGE=
9+
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
10+
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
11+
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
12+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
13+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
14+
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
15+
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
16+
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
17+
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
18+
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
19+
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
20+
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
21+
github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE=
22+
github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0=
23+
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
24+
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
25+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
8+
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
9+
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
10+
"github.com/tidwall/gjson"
11+
"github.com/tidwall/sjson"
12+
)
13+
14+
func main() {
15+
wrapper.SetCtx(
16+
"ai-prompt-decorator",
17+
wrapper.ParseConfigBy(parseConfig),
18+
wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),
19+
wrapper.ProcessRequestBodyBy(onHttpRequestBody),
20+
)
21+
}
22+
23+
type AIPromptDecoratorConfig struct {
24+
decorators map[string]string
25+
}
26+
27+
func removeBrackets(raw string) (string, error) {
28+
startIndex := strings.Index(raw, "{")
29+
endIndex := strings.LastIndex(raw, "}")
30+
if startIndex == -1 || endIndex == -1 {
31+
return raw, errors.New("message format is wrong!")
32+
} else {
33+
return raw[startIndex : endIndex+1], nil
34+
}
35+
}
36+
37+
func parseConfig(json gjson.Result, config *AIPromptDecoratorConfig, log wrapper.Log) error {
38+
config.decorators = make(map[string]string)
39+
for _, v := range json.Get("decorators").Array() {
40+
config.decorators[v.Get("name").String()] = v.Get("decorator").Raw
41+
// log.Info(v.Get("decorator").Raw)
42+
}
43+
return nil
44+
}
45+
46+
func onHttpRequestHeaders(ctx wrapper.HttpContext, config AIPromptDecoratorConfig, log wrapper.Log) types.Action {
47+
decorator, _ := proxywasm.GetHttpRequestHeader("decorator")
48+
if decorator == "" {
49+
ctx.DontReadRequestBody()
50+
return types.ActionContinue
51+
}
52+
ctx.SetContext("decorator", decorator)
53+
proxywasm.RemoveHttpRequestHeader("decorator")
54+
proxywasm.RemoveHttpRequestHeader("content-length")
55+
return types.ActionContinue
56+
}
57+
58+
func onHttpRequestBody(ctx wrapper.HttpContext, config AIPromptDecoratorConfig, body []byte, log wrapper.Log) types.Action {
59+
decoratorName := ctx.GetContext("decorator").(string)
60+
decorator := config.decorators[decoratorName]
61+
62+
messageJson := `{"messages":[]}`
63+
64+
prependMessage := gjson.Get(decorator, "prepend")
65+
if prependMessage.Exists() {
66+
for _, entry := range prependMessage.Array() {
67+
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", entry.Raw)
68+
}
69+
}
70+
71+
rawMessage := gjson.GetBytes(body, "messages")
72+
if rawMessage.Exists() {
73+
for _, entry := range rawMessage.Array() {
74+
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", entry.Raw)
75+
}
76+
}
77+
78+
appendMessage := gjson.Get(decorator, "append")
79+
if appendMessage.Exists() {
80+
for _, entry := range appendMessage.Array() {
81+
messageJson, _ = sjson.SetRaw(messageJson, "messages.-1", entry.Raw)
82+
}
83+
}
84+
85+
newbody, err := sjson.SetRaw(string(body), "messages", gjson.Get(messageJson, "messages").Raw)
86+
if err != nil {
87+
log.Error("modify body failed")
88+
}
89+
if err = proxywasm.ReplaceHttpRequestBody([]byte(newbody)); err != nil {
90+
log.Error("rewrite body failed")
91+
}
92+
93+
return types.ActionContinue
94+
}

0 commit comments

Comments
 (0)