新增AI反诈助理页面和软件设置页面

This commit is contained in:
StarPro 2025-03-10 20:17:40 +08:00
parent 72743e2809
commit 88b117c0c8
9 changed files with 401 additions and 4 deletions

36
go/deepseek.go Normal file
View File

@ -0,0 +1,36 @@
package main
import (
"github.com/ssgo/httpclient"
"github.com/ssgo/log"
"time"
)
type Ans struct {
Choices []struct {
Message struct {
Content string
}
}
}
func ask(text string) string {
log.DefaultLogger.Info("start ask", "text", text)
ansR := httpclient.GetClient(time.Second*60).Post("https://api.ppinfra.com/v3/openai/chat/completions", map[string]any{
"model": "deepseek/deepseek-r1/community",
"messages": []map[string]any{
{
"role": "user",
"content": text,
},
},
"response_format": map[string]any{"type": "text"},
}, "Content-Type", "application/json", "Authorization", "Bearer sk_siUuVF2utu9Mg0-LM5aM1KteXNQand33myY2iTq7Pcw")
if err := ansR.Error; err != nil {
log.DefaultLogger.Error("ask error", "err", err)
}
ans := Ans{}
ansR.To(&ans)
log.DefaultLogger.Info("ask stopped", "ans", ans)
return ans.Choices[0].Message.Content
}

35
go/go.mod Normal file
View File

@ -0,0 +1,35 @@
module main
go 1.23.2
require (
github.com/PuerkitoBio/goquery v1.10.2
github.com/gorilla/websocket v1.5.3
github.com/sashabaranov/go-openai v1.38.0
github.com/ssgo/httpclient v1.7.8
github.com/ssgo/log v1.7.7
github.com/ssgo/s v1.7.22
github.com/ssgo/u v1.7.13
)
require (
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gomodule/redigo v1.9.2 // indirect
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
github.com/otiai10/gosseract/v2 v2.4.1 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/ssgo/config v1.7.9 // indirect
github.com/ssgo/discover v1.7.9 // indirect
github.com/ssgo/redis v1.7.7 // indirect
github.com/ssgo/standard v1.7.7 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

70
go/image.go Normal file
View File

@ -0,0 +1,70 @@
package main
import (
"fmt"
"github.com/otiai10/gosseract/v2"
"github.com/ssgo/log"
"github.com/ssgo/u"
"strings"
)
func checkImg(imgStr string) error {
text := ocrImage(u.UnBase64(strings.Split(imgStr, "base64,")[1]))
log.DefaultLogger.Info("checkImg", "imgStrLen", len(imgStr), "imgLen", len(u.UnBase64(strings.Split(imgStr, "base64,")[1])), "text", text)
score, err := parseRiskScore(ask(buildImgDetectionPrompt(text)))
if err != nil {
log.DefaultLogger.Error("parseImgResp error", "err", err)
return err
}
err = conn.WriteJSON(map[string]any{
"type": "imageResult",
"result": map[string]any{
"score": score,
"isSuspicious": score >= 50,
},
})
if err != nil {
log.DefaultLogger.Error("sendImgScore Error", "err", err)
return err
}
log.DefaultLogger.Info("sendImgScore")
return nil
}
func ocrImage(image []byte) string {
client := gosseract.NewClient()
defer client.Close()
err := client.SetImageFromBytes(image)
if err != nil {
fmt.Println(err)
log.DefaultLogger.Error("ocr setimg error", "err", err)
return ""
}
fmt.Println(u.Red("111"))
text, err := client.Text()
fmt.Println(text)
if err != nil {
fmt.Println(err)
log.DefaultLogger.Error("ocr error", "err", err)
return ""
}
return text
}
func buildImgDetectionPrompt(content string) string {
return fmt.Sprintf(`你是一名反诈骗专家专门分析聊天记录判断其中是否涉及诈骗信息请仔细阅读以下文字并回答以下问题
1. 这段内容是否包含诈骗信息如果是请给出具体的诈骗类型如刷单冒充客服杀猪盘等
2. 请分析这段内容是否具有诈骗话术例如使用了限时优惠保证赚钱不透露给别人等常见诈骗用语
3. 诈骗信息通常会使用哪些伎俩欺骗受害者请指出可能的欺诈手法
4. 请用简洁的语言不超过100字总结你的分析结果并给出风险等级
5. 如果有必要请建议用户如何避免被骗
请返回JSON格式
{
"risk_score": 0-100
"risk_reason": "主要风险点"
}
待分析的文本如下%s`, content)
}

BIN
go/main Executable file

Binary file not shown.

47
go/main.go Normal file
View File

@ -0,0 +1,47 @@
package main
import (
"github.com/gorilla/websocket"
"github.com/ssgo/log"
"github.com/ssgo/s"
)
var conn *websocket.Conn
type Message struct {
Type string
Url string
ImageData string
Text string
}
func main() {
s.Config.Listen = "9000"
s.Static("/", "../web/")
s.RegisterSimpleWebsocket(0, "/socket", func(connect *websocket.Conn) {
log.DefaultLogger.Info("Socket connected")
conn = connect
for {
data := &Message{}
err := conn.ReadJSON(data)
if err != nil {
log.DefaultLogger.Error("Read WS error", "err", err.Error())
return
}
go onMessage(data)
}
}, "")
s.Start()
}
func onMessage(data *Message) {
switch data.Type {
case "checkPhishing":
checkUrl(data.Url)
case "checkImage":
checkImg(data.ImageData)
case "checkScript":
checkText(data.Text)
}
}

45
go/text.go Normal file
View File

@ -0,0 +1,45 @@
package main
import (
"fmt"
"github.com/ssgo/log"
)
func checkText(text string) error {
log.DefaultLogger.Info("checkText", "text", text)
score, err := parseRiskScore(ask(buildTextDetectionPrompt(text)))
if err != nil {
log.DefaultLogger.Error("parseTextResp error", "err", err)
return err
}
err = conn.WriteJSON(map[string]any{
"type": "textResult",
"result": map[string]any{
"score": score,
"isSuspicious": score >= 50,
},
})
if err != nil {
log.DefaultLogger.Error("sendTextScore Error", "err", err)
return err
}
log.DefaultLogger.Info("sendTextScore")
return nil
}
func buildTextDetectionPrompt(content string) string {
return fmt.Sprintf(`你是一名反诈骗专家专门分析聊天记录判断其中是否涉及诈骗信息请仔细阅读以下文字并回答以下问题
1. 这段内容是否包含诈骗信息如果是请给出具体的诈骗类型如刷单冒充客服杀猪盘等
2. 请分析这段内容是否具有诈骗话术例如使用了限时优惠保证赚钱不透露给别人等常见诈骗用语
3. 诈骗信息通常会使用哪些伎俩欺骗受害者请指出可能的欺诈手法
4. 请用简洁的语言不超过100字总结你的分析结果并给出风险等级
5. 如果有必要请建议用户如何避免被骗
请返回JSON格式
{
"risk_score": 0-100
"risk_reason": "主要风险点"
}
待分析的文本如下%s`, content)
}

159
go/website.go Normal file
View File

@ -0,0 +1,159 @@
package main
import (
"encoding/json"
"fmt"
"github.com/PuerkitoBio/goquery"
"github.com/ssgo/log"
"github.com/ssgo/u"
"net/http"
"strings"
"time"
)
func checkUrl(url string) error {
log.DefaultLogger.Info("UrlTest", "url", url)
score := analyzeHandler(url)
if score == -1 || score == -2 {
log.DefaultLogger.Error("ckwebsiteErr")
}
log.DefaultLogger.Info("ckwebsite2", "score", score)
err := conn.WriteJSON(map[string]any{
"type": "urlResult",
"result": score,
})
if err != nil {
log.DefaultLogger.Error("sendURLScore Error", "err", err)
return err
}
log.DefaultLogger.Info("sendURLScore")
return nil
}
const (
MaxContentLength = 8000 // 根据模型上下文窗口限制
RequestTimeout = 15 * time.Second
)
type DeepseekConfig struct {
Model string
Temperature float32
MaxTokens int
}
var (
aiConfig = DeepseekConfig{
Model: "deepseek/deepseek-r1/community", // 根据API权限选择
Temperature: 0.7,
MaxTokens: 500,
}
)
// HTTP处理函数
func analyzeHandler(targetURL string) int {
// 安全爬取网页内容
content, err := safeCrawl(targetURL)
if err != nil {
return -2
}
// 调用OpenAI分析
score, err := analyzeContent(content)
if err != nil {
return -1
}
log.DefaultLogger.Info("ckwebsite1", "score", score)
return score
}
func safeCrawl(targetURL string) (string, error) {
client := &http.Client{
Timeout: RequestTimeout,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 5 {
return fmt.Errorf("too many redirects (max 5)")
}
return nil
},
}
fmt.Println(u.Red(111))
resp, err := client.Get(targetURL)
if err != nil {
log.DefaultLogger.Error("222Err")
fmt.Println(err)
return "", fmt.Errorf("HTTP request failed: %v", err)
}
defer resp.Body.Close()
fmt.Println(u.Red(222))
if resp.StatusCode < 200 || resp.StatusCode >= 400 {
log.DefaultLogger.Error("223Err")
fmt.Println(err)
return "", fmt.Errorf("invalid status code: %d", resp.StatusCode)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.DefaultLogger.Error("224Err")
fmt.Println(err)
return "", fmt.Errorf("HTML parsing failed: %v", err)
}
doc.Find("script, style, noscript").Remove()
text := doc.Find("body").Text()
// 预处理内容
cleanText := strings.Join(strings.Fields(text), " ")
if len(cleanText) > MaxContentLength {
cleanText = cleanText[:MaxContentLength]
}
log.DefaultLogger.Info("getwebsite", "cleanText", cleanText)
return cleanText, nil
}
// AI分析处理
func analyzeContent(content string) (int, error) {
return parseRiskScore(ask(buildDetectionPrompt(content)))
}
// 构造模板prompt
func buildDetectionPrompt(content string) string {
return fmt.Sprintf(`作为网络安全分析系统请对以下网页内容进行风险评估评估标准包括
1. 紧急金融操作请求转账验证账户等
2. 仿冒品牌或误导性信息
3. 可疑链接/下载请求
4. 语法及排版异常
5. 非法个人信息收集
请返回JSON格式
{
"risk_score": 0-100
"risk_reason": "主要风险点"
}
网页内容%s`, content)
}
func parseRiskScore(response string) (int, error) {
var result struct {
RiskScore int `json:"risk_score"`
}
start := strings.Index(response, "{")
end := strings.LastIndex(response, "}")
if start == -1 || end <= start {
return 0, fmt.Errorf("invalid response format")
}
err := json.Unmarshal([]byte(response[start:end+1]), &result)
if err != nil {
return 0, fmt.Errorf("failed to parse JSON: %v", err)
}
if result.RiskScore < 0 || result.RiskScore > 100 {
return 0, fmt.Errorf("invalid risk score range")
}
return result.RiskScore, nil
}

View File

@ -22,6 +22,7 @@
<div class="section">
<h2>聊天图片检测</h2>
<input type="file" id="imageInput">
<hr style="visibility: hidden">
<button onclick="checkChatImage()">检测图片</button>
<div id="imageResult" class="result"></div>
</div>

View File

@ -1,5 +1,5 @@
// 创建 WebSocket 连接
const socket = new WebSocket('ws://localhost:8080'); // 后端WebSocket服务器的地址
const socket = new WebSocket('ws://localhost:9000/socket'); // 后端WebSocket服务器的地址
socket.onopen = () => {
console.log('WebSocket 连接已建立');
@ -40,8 +40,12 @@ function checkChatImage() {
if (imageInput.files.length > 0) {
const file = imageInput.files[0];
const reader = new FileReader();
reader.onload = function(e) {
socket.send(JSON.stringify({ type: 'checkImage', imageData: e.target.result }));
reader.readAsDataURL(file);
reader.onload = (e) => {
console.info(reader.result)
console.info(reader.result.length)
console.info(e.target.result.length)
socket.send(JSON.stringify({ type: 'checkImage', imageData: reader.result }));
};
reader.readAsDataURL(file);
} else {
@ -74,7 +78,7 @@ function displayUrlResult(result) {
},
};
if (result.isPhishing) {
if (result>=50) {
resultDiv.textContent = translations[language].warning;
resultDiv.classList.remove('success');
resultDiv.classList.add('error');