Переглянути джерело

feat: 支持prompt通过配置文件自定义 (#106)

二丫讲梵 2 роки тому
батько
коміт
354c42bf85
8 змінених файлів з 82 додано та 32 видалено
  1. 1 1
      README.md
  2. 29 0
      config/prompt.go
  3. 2 1
      go.mod
  4. 5 2
      go.sum
  5. 5 1
      pkg/process/process_request.go
  6. 15 27
      pkg/process/prompt.go
  7. 23 0
      prompt.yml
  8. 2 0
      public/public.go

+ 1 - 1
README.md

@@ -37,12 +37,12 @@
 
 - 支持在钉钉群聊中添加机器人,通过@机器人进行聊天交互。
 - 提问支持单聊与串聊两种模式,通过@机器人发关键字切换。
-- 支持通过内置prompt进行对话。
 - 支持添加代理,通过配置化指定。
 - 支持自定义api域名,通过配置化指定。
 - 支持自定义指定的模型,通过配置化指定。
 - 支持自定义默认的聊天模式,通过配置化指定。
 - 支持自定义单个用户单日对话次数,通过配置化指定。
+- 支持通过内置prompt进行对话。欢迎提交你认为不错的prompt,请通过编辑[此文件](https://github.com/eryajf/chatgpt-dingtalk/blob/main/prompt.yml)来提交PR。
 
 ## 使用前提
 

+ 29 - 0
config/prompt.go

@@ -0,0 +1,29 @@
+package config
+
+import (
+	"io/ioutil"
+	"log"
+
+	"gopkg.in/yaml.v2"
+)
+
+type Prompt struct {
+	Title   string `yaml:"title"`
+	Content string `yaml:"content"`
+}
+
+var prompTmp *[]Prompt
+
+// LoadPrompt 加载Prompt
+func LoadPrompt() *[]Prompt {
+	data, err := ioutil.ReadFile("prompt.yml")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	err = yaml.Unmarshal(data, &prompTmp)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return prompTmp
+}

+ 2 - 1
go.mod

@@ -6,11 +6,12 @@ require (
 	github.com/go-resty/resty/v2 v2.7.0
 	github.com/patrickmn/go-cache v2.1.0+incompatible
 	github.com/solywsh/chatgpt v0.0.14
+	gopkg.in/yaml.v2 v2.4.0
 )
 
 require (
 	github.com/avast/retry-go v2.7.0+incompatible // indirect
-	github.com/sashabaranov/go-openai v1.5.1 // indirect
+	github.com/sashabaranov/go-openai v1.5.3 // indirect
 	github.com/stretchr/testify v1.8.2 // indirect
 	golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect
 )

+ 5 - 2
go.sum

@@ -9,8 +9,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR
 github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sashabaranov/go-openai v1.5.1 h1:w9pO7L0X4CLuyH3NZ0WXBBU1wvPeA2JEcxMdlPosInY=
-github.com/sashabaranov/go-openai v1.5.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
+github.com/sashabaranov/go-openai v1.5.3 h1:o6n6dj0h9u+5mE1m+D8eT0zYhh7229o8ymDd2zDwAXU=
+github.com/sashabaranov/go-openai v1.5.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -25,7 +25,10 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

Різницю між файлами не показано, бо вона завелика
+ 5 - 1
pkg/process/process_request.go


+ 15 - 27
pkg/process/prompt.go

@@ -1,32 +1,20 @@
 package process
 
-import "strings"
+import (
+	"strings"
 
-func GeneratePrompt(msg string) string {
-	switch {
-	case strings.HasPrefix(msg, "#周报"):
-		return "请帮我把以下的工作内容填充为一篇完整的周报,用 markdown 格式以分点叙述的形式输出:" + strings.Replace(msg, "#周报", "", -1)
-	case strings.HasPrefix(msg, "#前端"):
-		return `我想让你充当前端开发专家。我将提供一些关于 Js、Node 等前端代码问题的具体信息,而你的工作就是想出为我解决问题的策略。这可能包括建议代码、代码逻辑思路策略。我的第一个请求是:` + strings.Replace(msg, "#前端", "", -1)
-	case strings.HasPrefix(msg, "#架构师"):
-		return `我希望你担任 IT 架构师。我将提供有关应用程序或其他数字产品功能的一些详细信息,而您的工作是想出将其集成到 IT 环境中的方法。这可能涉及分析业务需求、执行差距分析以及将新系统的功能映射到现有 IT 环境。接下来的步骤是创建解决方案设计、物理网络蓝图、系统集成接口定义和部署环境蓝图。我的第一个请求是:` + strings.Replace(msg, "#架构师", "", -1)
-	case strings.HasPrefix(msg, "#产品经理"):
-		return `请确认我的以下请求。请您作为产品经理回复我。我将会提供一个主题,您将帮助我编写一份包括以下章节标题的 PRD 文档:主题、简介、问题陈述、目标与目的、用户故事、技术要求、收益、KPI 指标、开发风险以及结论。在我要求具体主题、功能或开发的 PRD 之前,请不要先写任何一份 PRD 文档。` + strings.Replace(msg, "#产品经理", "", -1)
-	case strings.HasPrefix(msg, "#网络安全"):
-		return `我想让你充当网络安全专家。我将提供一些关于如何存储和共享数据的具体信息,而你的工作就是想出保护这些数据免受恶意行为者攻击的策略。这可能包括建议加密方法、创建防火墙或实施将某些活动标记为可疑的策略。我的第一个请求是:` + strings.Replace(msg, "#网络安全", "", -1)
-	case strings.HasPrefix(msg, "#正则"):
-		return `我希望你充当正则表达式生成器。您的角色是生成匹配文本中特定模式的正则表达式。您应该以一种可以轻松复制并粘贴到支持正则表达式的文本编辑器或编程语言中的格式提供正则表达式。不要写正则表达式如何工作的解释或例子;只需提供正则表达式本身。我的第一个提示是::` + strings.Replace(msg, "#正则", "", -1)
-	case strings.HasPrefix(msg, "#招聘"):
-		return `我想让你担任招聘人员。我将提供一些关于职位空缺的信息,而你的工作是制定寻找合格申请人的策略。这可能包括通过社交媒体、社交活动甚至参加招聘会接触潜在候选人,以便为每个职位找到最合适的人选。我的第一个请求是:` + strings.Replace(msg, "#招聘", "", -1)
-	case strings.HasPrefix(msg, "#知乎"):
-		return `知乎的风格是:用"谢邀"开头,用很多学术语言,引用很多名言,做大道理的论述,提到自己很厉害的教育背景并且经验丰富,最后还要引用一些论文。请用知乎风格:` + strings.Replace(msg, "#知乎", "", -1)
-	case strings.HasPrefix(msg, "#翻译"):
-		return `下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,最重要的是要简明扼要。请翻译下面这句话:` + strings.Replace(msg, "#翻译", "", -1)
-	case strings.HasPrefix(msg, "#小红书"):
-		return "小红书的风格是:很吸引眼球的标题,每个段落都加 emoji, 最后加一些 tag。请用小红书风格:" + strings.Replace(msg, "#小红书", "", -1)
-	case strings.HasPrefix(msg, "#解梦"):
-		return "我要你充当解梦师。我会给你描述我的梦,你会根据梦中出现的符号和主题提供解释。不要提供关于梦者的个人意见或假设。仅根据所提供的信息提供事实解释。我的第一个梦是:" + strings.Replace(msg, "#解梦", "", -1)
-	default:
-		return msg
+	"github.com/eryajf/chatgpt-dingtalk/public"
+)
+
+// GeneratePrompt 生成当次请求的 Prompt
+func GeneratePrompt(msg string) (rst string) {
+	for _, prompt := range *public.Prompt {
+		if strings.HasPrefix(msg, prompt.Title) {
+			rst = prompt.Content + strings.Replace(msg, prompt.Title, "", -1)
+			return
+		} else {
+			rst = msg
+		}
 	}
+	return
 }

+ 23 - 0
prompt.yml

@@ -0,0 +1,23 @@
+# 可在此处提交你认为不错的 prompt, 注意保持格式一致,如果content中间有双引号,那么就去掉最外层的双引号即可
+- title: "#周报"
+  content: "请帮我把以下的工作内容填充为一篇完整的周报,用 markdown 格式以分点叙述的形式输出:"
+- title: "#前端"
+  content: "我想让你充当前端开发专家。我将提供一些关于 Js、Node 等前端代码问题的具体信息,而你的工作就是想出为我解决问题的策略。这可能包括建议代码、代码逻辑思路策略。我的第一个请求是:"
+- title: "#架构师"
+  content: "我希望你担任 IT 架构师。我将提供有关应用程序或其他数字产品功能的一些详细信息,而您的工作是想出将其集成到 IT 环境中的方法。这可能涉及分析业务需求、执行差距分析以及将新系统的功能映射到现有 IT 环境。接下来的步骤是创建解决方案设计、物理网络蓝图、系统集成接口定义和部署环境蓝图。我的第一个请求是:"
+- title: "#产品经理"
+  content: "请确认我的以下请求。请您作为产品经理回复我。我将会提供一个主题,您将帮助我编写一份包括以下章节标题的 PRD 文档:主题、简介、问题陈述、目标与目的、用户故事、技术要求、收益、KPI 指标、开发风险以及结论。在我要求具体主题、功能或开发的 PRD 之前,请不要先写任何一份 PRD 文档。"
+- title: "#网络安全"
+  content: "我想让你充当网络安全专家。我将提供一些关于如何存储和共享数据的具体信息,而你的工作就是想出保护这些数据免受恶意行为者攻击的策略。这可能包括建议加密方法、创建防火墙或实施将某些活动标记为可疑的策略。我的第一个请求是:"
+- title: "#正则"
+  content: "我希望你充当正则表达式生成器。您的角色是生成匹配文本中特定模式的正则表达式。您应该以一种可以轻松复制并粘贴到支持正则表达式的文本编辑器或编程语言中的格式提供正则表达式。不要写正则表达式如何工作的解释或例子;只需提供正则表达式本身。我的第一个提示是:"
+- title: "#招聘"
+  content: "我想让你担任招聘人员。我将提供一些关于职位空缺的信息,而你的工作是制定寻找合格申请人的策略。这可能包括通过社交媒体、社交活动甚至参加招聘会接触潜在候选人,以便为每个职位找到最合适的人选。我的第一个请求是:"
+- title: "#知乎"
+  content: 知乎的风格是:用"谢邀"开头,用很多学术语言,引用很多名言,做大道理的论述,提到自己很厉害的教育背景并且经验丰富,最后还要引用一些论文。请用知乎风格:
+- title: "#翻译"
+  content: 下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,最重要的是要简明扼要。请翻译下面这句话:
+- title: "#小红书"
+  content: "小红书的风格是:很吸引眼球的标题,每个段落都加 emoji, 最后加一些 tag。请用小红书风格:"
+- title: "#解梦"
+  content: "我要你充当解梦师。我会给你描述我的梦,你会根据梦中出现的符号和主题提供解释。不要提供关于梦者的个人意见或假设。仅根据所提供的信息提供事实解释。我的第一个梦是:"

+ 2 - 0
public/public.go

@@ -9,9 +9,11 @@ import (
 
 var UserService cache.UserServiceInterface
 var Config *config.Configuration
+var Prompt *[]config.Prompt
 
 func InitSvc() {
 	Config = config.LoadConfig()
+	Prompt = config.LoadPrompt()
 	UserService = cache.NewUserService()
 	_, _ = GetBalance()
 }