diff --git a/aiComplain b/aiComplain new file mode 100755 index 0000000..a10905e Binary files /dev/null and b/aiComplain differ diff --git a/configs/configs.go b/configs/configs.go new file mode 100644 index 0000000..6ba810f --- /dev/null +++ b/configs/configs.go @@ -0,0 +1,38 @@ +package configs + +const ( + DB_USERNAME = "aiCpmplain" + DB_PASSWORD = "" + DB_NAME = "aiComplain" + DB_PORT = 3306 + OPEN_LIKE_URL = "http://127.0.0.1:11434/v1/chat/completions" + OPENAI_LIKE_API_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + LLM_MODEL_TINY = "qwen:4b" //用于内容审核的模型 + LLM_MODEL_LARGE = "gemma3:12b" // 用于吐槽的模型 + AUDIT_PROMPT_TEMPLATE = ` + 你是一名专业的网络内容审核员,负责审核用户发布的言论内容,确保其符合中国法律法规和社会道德规范。你的工作是公正、客观地判断内容是否可以发布。 +审核标准包括但不限于: + +违法违禁内容(如毒品、赌博、暴力、恐怖主义等) +色情低俗内容 +族宗教歧视内容 +人身攻击、侮辱诽谤内容 +虚假信息或谣言 +广告营销信息 +暴露他人隐私的内容 +请对用户输入的言论进行审核,返回JSON格式结果,包含: + +"approved":布尔值(true表示通过,false表示未通过) +"reason":字符串(未通过时的原因,通过时为"无") +输出必须严格为JSON格式,不要包含其他任何内容。示例: +{ +"approved": true, +"reason": "无" +} +{ +"approved": false, +"reason": "包含色情低俗内容" +}` + COMPLAIN_PROMPT_TEMPLATE = ` + 你是一名资深吐槽墙网站的顶级吐槽手,专精于"怼天怼地嘴强王者"的尖锐、"阴阳怪气十级学者"的表面客气实则刀刀致命等风格。用户传入任何言论,你必须创作20-50字的吐槽内容:戳肺管子、句句直击痛点、用网络热梗或方言脏话(避免直接脏话)、表面客气实则刀刀致命。输出必须严格为JSON格式,不要包含其他任何内容,尤其是反引号:{"taunt": "吐槽内容"}。吐槽内容必须精准在20-50字,不加任何其他说明。` +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e9fd321 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module git.mmeiblog.cn/mei/aiComplain + +go 1.23.4 + +require github.com/go-dev-frame/sponge v1.15.1 + +require github.com/sashabaranov/go-openai v1.41.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cd6dfe9 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/go-dev-frame/sponge v1.15.1 h1:I+2bWBQHqySkmG4d/K+KaYUeU37wjuiOaO6pT8dMSno= +github.com/go-dev-frame/sponge v1.15.1/go.mod h1:kTYWZQUSR5Iuu9Ur4tHC+v/1eP48W7hGxhvO6hVylNs= +github.com/sashabaranov/go-openai v1.41.1 h1:zf5tM+GuxpyiyD9XZg8nCqu52eYFQg9OOew0gnIuDy4= +github.com/sashabaranov/go-openai v1.41.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= diff --git a/internal/send.go b/internal/send.go new file mode 100644 index 0000000..281cb99 --- /dev/null +++ b/internal/send.go @@ -0,0 +1,4 @@ +package internal + +// func HandleSend(message string) (string, error) { +// } diff --git a/internal/snedAndAudit.go b/internal/snedAndAudit.go new file mode 100644 index 0000000..ce7690f --- /dev/null +++ b/internal/snedAndAudit.go @@ -0,0 +1,32 @@ +package internal + +import "git.mmeiblog.cn/mei/aiComplain/pkg/ai" + +type SendAndAuditResponse struct { + Data string `json:"data"` + Message string `json:"message"` +} + +func SendAndAudit(message string) (SendAndAuditResponse, error) { + AuditResponse, err := ai.SendAudit(message) + var ComplainResponse ai.ComplainMessage + if err != nil { + return SendAndAuditResponse{ + Data: "", + Message: "审核失败", + }, err + } + if AuditResponse.Approved { + ComplainResponse, err = ai.SendComplain(message) + if err != nil { + return SendAndAuditResponse{ + Data: "", + Message: "AI吐槽失败", + }, err + } + } + return SendAndAuditResponse{ + Data: ComplainResponse.Taunt, + Message: "AI吐槽成功", + }, nil +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..cfab4a9 --- /dev/null +++ b/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + + "git.mmeiblog.cn/mei/aiComplain/internal" +) + +func main() { + // 先写点数据测试 + response, err := internal.SendAndAudit("2024级11班某女同学(🐭老鼠)于上周周五晚上在女生宿舍四处投毒,毒物为霉菌饼子,在霉菌里发现少量饼子。食用过的某同学说因为宿舍灯光暗,还以为是葱花饼。\r\n据说219(12班)宿舍三人受害严重,一人第二夜深夜直接被送回家,一人第三天下午回家,证物已上交老师,但该名女同学并无悔过之心,四处与他人就此事讲笑话,并单方面说受害同学原谅了她,事后还去各个宿舍索要食物。\r\n希望大家多加小心该名女同学,其外号在学校叫为老鼠🐭,可询问周围同学其真名,目前在2024级的11班") + fmt.Println(response.Data, err) +} diff --git a/pkg/ai/api.go b/pkg/ai/api.go new file mode 100644 index 0000000..58093d2 --- /dev/null +++ b/pkg/ai/api.go @@ -0,0 +1,100 @@ +package ai + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + "git.mmeiblog.cn/mei/aiComplain/configs" +) + +// 定义请求格式(兼容 OpenAI 格式) +type ChatMessage struct { + Role string `json:"role"` + Content string `json:"content"` +} + +type ChatRequest struct { + Model string `json:"model"` + Messages []ChatMessage `json:"messages"` +} + +type ChatResponse struct { + ID string `json:"id"` + Object string `json:"object"` + Created int64 `json:"created"` + Choices []struct { + Index int `json:"index"` + Message struct { + Role string `json:"role"` + Content string `json:"content"` + } `json:"message"` + } `json:"choices"` +} + +// Client 封装接口调用 +type Client struct { + APIKey string + BaseURL string + Model string +} + +// Send 发送对话请求 +func (c *Client) Send(messages []ChatMessage) (string, error) { + reqBody := ChatRequest{ + Model: c.Model, + Messages: messages, + } + data, err := json.Marshal(reqBody) + if err != nil { + return "", err + } + + req, err := http.NewRequest("POST", c.BaseURL, bytes.NewBuffer(data)) + if err != nil { + return "", err + } + req.Header.Set("Content-Type", "application/json") + if c.APIKey != "" { + req.Header.Set("Authorization", "Bearer "+c.APIKey) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("http error: %s, body: %s", resp.Status, string(body)) + } + + var chatResp ChatResponse + if err := json.Unmarshal(body, &chatResp); err != nil { + return "", err + } + + if len(chatResp.Choices) == 0 { + return "", fmt.Errorf("no response choices") + } + return chatResp.Choices[0].Message.Content, nil +} + +func NewClient(message string, prompt string, model string) (string, error) { + var c Client + c.BaseURL = configs.OPEN_LIKE_URL + c.Model = model + c.APIKey = configs.OPENAI_LIKE_API_KEY + msgs := []ChatMessage{ + {Role: "system", Content: prompt}, + {Role: "user", Content: message}, + } + response, err := c.Send(msgs) + if err != nil { + return "", err + } + return response, nil +} diff --git a/pkg/ai/format.go b/pkg/ai/format.go new file mode 100644 index 0000000..8b77818 --- /dev/null +++ b/pkg/ai/format.go @@ -0,0 +1,44 @@ +package ai + +import ( + "encoding/json" + + "git.mmeiblog.cn/mei/aiComplain/configs" +) + +type ComplainMessage struct { + Taunt string `json:"Taunt"` +} + +type AuditMessage struct { + Approved bool `json:"approved"` + Reason string `json:"reason"` +} + +// SendComplain 发送返回一个ai的吐槽内容 +func SendComplain(message string) (ComplainMessage, error) { + response, err := NewClient(message, configs.COMPLAIN_PROMPT_TEMPLATE, configs.LLM_MODEL_LARGE) + if err != nil { + return ComplainMessage{}, err + } + var format ComplainMessage + err = json.Unmarshal([]byte(response), &format) + if err != nil { + return ComplainMessage{}, err + } + return format, nil +} + +// SendAudit 检测内容是否合规 +func SendAudit(message string) (AuditMessage, error) { + response, err := NewClient(message, configs.AUDIT_PROMPT_TEMPLATE, configs.LLM_MODEL_TINY) + if err != nil { + return AuditMessage{}, err + } + var format AuditMessage + err = json.Unmarshal([]byte(response), &format) + if err != nil { + return AuditMessage{}, err + } + return format, nil +}