mirror of
https://github.com/coaidev/coai.git
synced 2025-05-19 21:10:18 +09:00
enhanced online search function and implementation of the word intelligent segmentation function
This commit is contained in:
parent
121ed8e9a2
commit
f7f467772c
@ -16,39 +16,50 @@ type AnonymousRequestBody struct {
|
|||||||
Message string `json:"message" required:"true"`
|
Message string `json:"message" required:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnonymousResponse(message string) (string, error) {
|
type AnonymousResponseCache struct {
|
||||||
|
Keyword string `json:"keyword"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetChatGPTResponse(message []types.ChatGPTMessage, token int) (string, error) {
|
||||||
res, err := utils.Post(viper.GetString("openai.anonymous_endpoint")+"/chat/completions", map[string]string{
|
res, err := utils.Post(viper.GetString("openai.anonymous_endpoint")+"/chat/completions", map[string]string{
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Authorization": "Bearer " + viper.GetString("openai.anonymous"),
|
"Authorization": "Bearer " + GetRandomKey(viper.GetString("openai.anonymous")),
|
||||||
}, types.ChatGPTRequest{
|
}, types.ChatGPTRequest{
|
||||||
Model: "gpt-3.5-turbo",
|
Model: "gpt-3.5-turbo",
|
||||||
Messages: ChatWithWeb([]types.ChatGPTMessage{
|
Messages: message,
|
||||||
{
|
MaxToken: token,
|
||||||
Role: "user",
|
|
||||||
Content: message,
|
|
||||||
},
|
|
||||||
}, message),
|
|
||||||
MaxToken: 1000,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil || res == nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
data := res.(map[string]interface{})["choices"].([]interface{})[0].(map[string]interface{})["message"].(map[string]interface{})["content"]
|
data := res.(map[string]interface{})["choices"].([]interface{})[0].(map[string]interface{})["message"].(map[string]interface{})["content"]
|
||||||
return data.(string), nil
|
return data.(string), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnonymousResponseWithCache(c *gin.Context, message string) (string, error) {
|
func GetAnonymousResponse(message string) (string, string, error) {
|
||||||
|
keyword, source := ChatWithWeb([]types.ChatGPTMessage{{Role: "user", Content: message}})
|
||||||
|
resp, err := GetChatGPTResponse(source, 1000)
|
||||||
|
return keyword, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAnonymousResponseWithCache(c *gin.Context, message string) (string, string, error) {
|
||||||
cache := c.MustGet("cache").(*redis.Client)
|
cache := c.MustGet("cache").(*redis.Client)
|
||||||
res, err := cache.Get(c, fmt.Sprintf(":chatgpt:%s", message)).Result()
|
res, err := cache.Get(c, fmt.Sprintf(":chatgpt:%s", message)).Result()
|
||||||
if err != nil || len(res) == 0 {
|
form := utils.UnmarshalJson[AnonymousResponseCache](res)
|
||||||
res, err := GetAnonymousResponse(message)
|
if err != nil || len(res) == 0 || res == "{}" || form.Message == "" {
|
||||||
|
key, res, err := GetAnonymousResponse(message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "There was something wrong...", err
|
return "", "There was something wrong...", err
|
||||||
}
|
}
|
||||||
cache.Set(c, fmt.Sprintf(":chatgpt:%s", message), res, time.Hour*6)
|
|
||||||
return res, nil
|
cache.Set(c, fmt.Sprintf(":chatgpt:%s", message), utils.ToJson(AnonymousResponseCache{
|
||||||
|
Keyword: key,
|
||||||
|
Message: res,
|
||||||
|
}), time.Hour*6)
|
||||||
|
return key, res, nil
|
||||||
}
|
}
|
||||||
return res, nil
|
return form.Keyword, form.Message, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AnonymousAPI(c *gin.Context) {
|
func AnonymousAPI(c *gin.Context) {
|
||||||
@ -57,6 +68,7 @@ func AnonymousAPI(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"status": false,
|
"status": false,
|
||||||
"message": "",
|
"message": "",
|
||||||
|
"keyword": "",
|
||||||
"reason": err.Error(),
|
"reason": err.Error(),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -66,15 +78,17 @@ func AnonymousAPI(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"status": false,
|
"status": false,
|
||||||
"message": "",
|
"message": "",
|
||||||
|
"keyword": "",
|
||||||
"reason": "message is empty",
|
"reason": "message is empty",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res, err := GetAnonymousResponseWithCache(c, message)
|
key, res, err := GetAnonymousResponseWithCache(c, message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"status": false,
|
"status": false,
|
||||||
"message": res,
|
"message": res,
|
||||||
|
"keyword": key,
|
||||||
"reason": err.Error(),
|
"reason": err.Error(),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -82,6 +96,7 @@ func AnonymousAPI(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"status": true,
|
"status": true,
|
||||||
"message": res,
|
"message": res,
|
||||||
|
"keyword": key,
|
||||||
"reason": "",
|
"reason": "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,11 @@ func ChatAPI(c *gin.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if msg, err := instance.AddMessageFromUserForm(message); err == nil {
|
if _, err := instance.AddMessageFromUserForm(message); err == nil {
|
||||||
StreamRequest("gpt-3.5-turbo", ChatWithWeb(instance.GetMessageSegment(5), msg), 1500, func(resp string) {
|
keyword, segment := ChatWithWeb(instance.GetMessageSegment(12))
|
||||||
|
StreamRequest("gpt-3.5-turbo-16k", segment, 1500, func(resp string) {
|
||||||
data, _ := json.Marshal(map[string]interface{}{
|
data, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"keyword": keyword,
|
||||||
"message": resp,
|
"message": resp,
|
||||||
"end": false,
|
"end": false,
|
||||||
})
|
})
|
||||||
|
@ -30,12 +30,17 @@ func processLine(buf []byte) []string {
|
|||||||
item = item + "}"
|
item = item + "}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if item == "{data: [DONE]}" {
|
if item == "{data: [DONE]}" || item == "{data: [DONE]}}" || item == "{[DONE]}" {
|
||||||
break
|
break
|
||||||
|
} else if item == "{data:}" || item == "{data:}}" {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var form types.ChatGPTStreamResponse
|
var form types.ChatGPTStreamResponse
|
||||||
if err := json.Unmarshal([]byte(item), &form); err != nil {
|
if err := json.Unmarshal([]byte(item), &form); err != nil {
|
||||||
log.Println(item, err)
|
if err := json.Unmarshal([]byte(item[:len(item)-1]), &form); err != nil {
|
||||||
|
log.Println(item, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
choices := form.Data.Choices
|
choices := form.Data.Choices
|
||||||
if len(choices) > 0 {
|
if len(choices) > 0 {
|
||||||
@ -60,7 +65,7 @@ func StreamRequest(model string, messages []types.ChatGPTMessage, token int, cal
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("Authorization", "Bearer "+viper.GetString("openai.user"))
|
req.Header.Set("Authorization", "Bearer "+GetRandomKey(viper.GetString("openai.user")))
|
||||||
|
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
51
api/utils.go
51
api/utils.go
@ -5,12 +5,55 @@ import (
|
|||||||
"chat/utils"
|
"chat/utils"
|
||||||
"chat/web"
|
"chat/web"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ChatWithWeb(message []types.ChatGPTMessage, current string) []types.ChatGPTMessage {
|
func ChatWithWeb(message []types.ChatGPTMessage) (string, []types.ChatGPTMessage) {
|
||||||
return utils.Insert(message, 0, types.ChatGPTMessage{
|
keyword := SearchWeb(message)
|
||||||
Role: "system",
|
return keyword, utils.Insert(message, 0, types.ChatGPTMessage{
|
||||||
Content: fmt.Sprintf("你将扮演AI问答助手,你的知识库不是截止于2021年9月,而是可以实时联网的,你可以提供实时联网的知识库。当前时间: %s, 你的知识库:%s", time.Now().Format("2006-01-02 15:04:05"), web.SearchBing(current)),
|
Role: "system",
|
||||||
|
Content: fmt.Sprintf("你将扮演AI问答助手,你的知识库不是截止于2021年9月,而是可以实时联网的,你可以提供实时联网的知识库。"+
|
||||||
|
"官网网站使用链接包裹,给予用户精确的答复。"+
|
||||||
|
"当前时间: %s, 你的知识库:%s",
|
||||||
|
time.Now().Format("2006-01-02 15:04:05"), web.SearchBing(keyword),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRandomKey(apikey string) string {
|
||||||
|
arr := strings.Split(apikey, "|")
|
||||||
|
idx := rand.Intn(len(arr))
|
||||||
|
return arr[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringCleaner(content string) string {
|
||||||
|
for _, replacer := range []string{",", "、", ",", "。", ":", ":", ";", ";", "!", "!", "?", "?", "(", ")", "(", ")"} {
|
||||||
|
content = strings.ReplaceAll(content, replacer, " ")
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchWeb(message []types.ChatGPTMessage) string {
|
||||||
|
source := make([]string, 0)
|
||||||
|
for _, item := range message {
|
||||||
|
if item.Role == "user" && item.Content != "" {
|
||||||
|
source = append(source, item.Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(source) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword, _ := GetChatGPTResponse([]types.ChatGPTMessage{{
|
||||||
|
Role: "system",
|
||||||
|
Content: "在接下来的对话中,不要回答问题,你需要总结接下来的对话中出现的内容," +
|
||||||
|
"然后用关键字和空格分词,输出精简,请不要输出冗余内容," +
|
||||||
|
"不能出现逗号顿号等特殊字符,仅回答出现的关键词。",
|
||||||
|
}, {
|
||||||
|
Role: "user",
|
||||||
|
Content: strings.Join(source, " "),
|
||||||
|
}}, 40)
|
||||||
|
return StringCleaner(keyword)
|
||||||
|
}
|
||||||
|
@ -10,10 +10,12 @@ type Message = {
|
|||||||
role: string;
|
role: string;
|
||||||
time: string;
|
time: string;
|
||||||
stamp: number;
|
stamp: number;
|
||||||
|
keyword?: string;
|
||||||
gpt4?: boolean;
|
gpt4?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamMessage = {
|
type StreamMessage = {
|
||||||
|
keyword?: string;
|
||||||
message: string;
|
message: string;
|
||||||
end: boolean;
|
end: boolean;
|
||||||
}
|
}
|
||||||
@ -102,16 +104,17 @@ export class Conversation {
|
|||||||
public async sendAuthenticated(content: string): Promise<void> {
|
public async sendAuthenticated(content: string): Promise<void> {
|
||||||
this.state.value = true;
|
this.state.value = true;
|
||||||
this.addMessageFromUser(content);
|
this.addMessageFromUser(content);
|
||||||
let message = ref(""), end = ref(false);
|
let message = ref(""), end = ref(false), keyword = ref("");
|
||||||
this.connection?.setCallback((res: StreamMessage) => {
|
this.connection?.setCallback((res: StreamMessage) => {
|
||||||
message.value += res.message;
|
message.value += res.message;
|
||||||
|
res.keyword && (keyword.value = res.keyword);
|
||||||
end.value = res.end;
|
end.value = res.end;
|
||||||
})
|
})
|
||||||
const status = this.connection?.send({
|
const status = this.connection?.send({
|
||||||
message: content,
|
message: content,
|
||||||
});
|
});
|
||||||
if (status) {
|
if (status) {
|
||||||
this.addDynamicMessageFromAI(message, end);
|
this.addDynamicMessageFromAI(message, keyword, end);
|
||||||
} else {
|
} else {
|
||||||
this.addMessageFromAI("网络错误,请稍后再试");
|
this.addMessageFromAI("网络错误,请稍后再试");
|
||||||
}
|
}
|
||||||
@ -152,9 +155,10 @@ export class Conversation {
|
|||||||
}).then(r => 0);
|
}).then(r => 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addMessageFromAI(content: string): void {
|
public addMessageFromAI(content: string, keyword?: string): void {
|
||||||
this.addMessage({
|
this.addMessage({
|
||||||
content: "",
|
content: "",
|
||||||
|
keyword: keyword ? keyword : "",
|
||||||
role: "bot",
|
role: "bot",
|
||||||
time: new Date().toLocaleTimeString(),
|
time: new Date().toLocaleTimeString(),
|
||||||
stamp: new Date().getTime(),
|
stamp: new Date().getTime(),
|
||||||
@ -163,15 +167,16 @@ export class Conversation {
|
|||||||
this.typingEffect(this.len.value - 1, content);
|
this.typingEffect(this.len.value - 1, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addDynamicMessageFromAI(content: Ref<string>, end: Ref<boolean>): void {
|
public addDynamicMessageFromAI(content: Ref<string>, keyword: Ref<string>, end: Ref<boolean>): void {
|
||||||
this.addMessage({
|
this.addMessage({
|
||||||
content: "",
|
content: "",
|
||||||
role: "bot",
|
role: "bot",
|
||||||
|
keyword: keyword.value || "",
|
||||||
time: new Date().toLocaleTimeString(),
|
time: new Date().toLocaleTimeString(),
|
||||||
stamp: new Date().getTime(),
|
stamp: new Date().getTime(),
|
||||||
gpt4: gpt4.value,
|
gpt4: gpt4.value,
|
||||||
})
|
})
|
||||||
this.dynamicTypingEffect(this.len.value - 1, content, end);
|
this.dynamicTypingEffect(this.len.value - 1, content, keyword, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
public typingEffect(index: number, content: string): void {
|
public typingEffect(index: number, content: string): void {
|
||||||
@ -187,9 +192,10 @@ export class Conversation {
|
|||||||
}, 20);
|
}, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
public dynamicTypingEffect(index: number, content: Ref<string>, end: Ref<boolean>): void {
|
public dynamicTypingEffect(index: number, content: Ref<string>, keyword: Ref<string>, end: Ref<boolean>): void {
|
||||||
let cursor = 0;
|
let cursor = 0;
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
|
keyword.value && (this.messages[index].keyword = keyword.value);
|
||||||
if (end.value && cursor >= content.value.length) {
|
if (end.value && cursor >= content.value.length) {
|
||||||
this.messages[index].content = content.value;
|
this.messages[index].content = content.value;
|
||||||
this.state.value = false;
|
this.state.value = false;
|
||||||
|
@ -39,3 +39,12 @@
|
|||||||
transform: rotate(359deg);
|
transform: rotate(359deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes FadeInAnimation {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
24
app/src/components/icons/bing.vue
Normal file
24
app/src/components/icons/bing.vue
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<svg width="256px" height="388px" viewBox="0 0 256 388" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||||
|
<title>bing</title>
|
||||||
|
<defs>
|
||||||
|
<radialGradient cx="93.7173476%" cy="77.8181394%" fx="93.7173476%" fy="77.8181394%" r="143.12136%" gradientTransform="translate(0.937173,0.778181),scale(1.000000,0.719543),rotate(-130.909000),translate(-0.937173,-0.778181)" id="bingRadialGradient-1">
|
||||||
|
<stop stop-color="#00CACC" offset="0%"></stop>
|
||||||
|
<stop stop-color="#048FCE" offset="100%"></stop>
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient cx="13.8926614%" cy="71.4480037%" fx="13.8926614%" fy="71.4480037%" r="150.086127%" gradientTransform="translate(0.138927,0.714480),scale(0.600049,1.000000),rotate(-23.195400),translate(-0.138927,-0.714480)" id="bingRadialGradient-2">
|
||||||
|
<stop stop-color="#00BBEC" offset="0%"></stop>
|
||||||
|
<stop stop-color="#2756A9" offset="100%"></stop>
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient x1="50.0002111%" y1="-3.51563173e-08%" x2="50.0002111%" y2="99.9999984%" id="bingLinearGradient-3">
|
||||||
|
<stop stop-color="#00BBEC" offset="0%"></stop>
|
||||||
|
<stop stop-color="#2756A9" offset="100%"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<g>
|
||||||
|
<path d="M129.424369,122.046918 C122.29107,122.875748 116.850956,128.668861 116.345268,135.974502 C116.127195,139.122391 116.195602,139.335928 123.330791,157.696785 C139.564206,199.470843 143.497083,209.524887 144.158483,210.939907 C145.760962,214.366717 148.01426,217.590572 150.829558,220.484105 C152.989881,222.704521 154.414727,223.898444 156.824493,225.508104 C161.059724,228.33663 163.161466,229.118595 179.641677,233.998219 C195.695191,238.75161 204.46574,241.910837 212.02347,245.661923 C221.814465,250.521516 228.645788,256.049313 232.966812,262.608139 C236.06708,267.314287 238.812837,275.75338 240.007515,284.248408 C240.474653,287.569017 240.477677,294.909429 240.013185,297.911432 C239.00521,304.426794 236.991907,309.886561 233.912048,314.455516 C232.274042,316.885312 232.843981,316.478646 235.225401,313.517461 C241.964883,305.138083 248.830221,290.816683 252.333376,277.8298 C256.572764,262.112277 257.149506,245.234469 253.992924,229.259946 C247.845679,198.151822 228.207374,171.305385 200.548737,156.199752 C198.810955,155.250359 192.191658,151.780841 183.217776,147.115133 C181.856046,146.406867 179.999212,145.437443 179.091392,144.960857 C178.183573,144.483892 176.326738,143.514468 174.965009,142.806581 C173.603279,142.098693 169.683253,140.056288 166.253797,138.268239 C162.82434,136.479812 158.987083,134.478981 157.726265,133.821738 C153.882961,131.817883 151.304255,130.471649 149.381658,129.465187 C140.489411,124.810061 136.725475,122.928282 135.652494,122.601739 C134.52698,122.259322 131.66784,121.819775 130.950504,121.878734 C130.799326,121.891206 130.112604,121.966794 129.424369,122.046918 Z" fill="url(#bingRadialGradient-1)"></path>
|
||||||
|
<path d="M148.810208,277.993827 C148.31737,278.285599 147.625734,278.70814 147.272735,278.93226 C146.919358,279.156758 146.135504,279.643927 145.530417,280.015445 C143.309245,281.378686 137.401993,285.018657 132.325839,288.152183 C128.989734,290.211596 128.494629,290.518486 124.256752,293.148592 C122.743468,294.087403 121.134186,295.076858 120.680276,295.347465 C120.226366,295.618073 118.28714,296.812373 116.37059,298.001382 C114.45404,299.190013 111.111889,301.253583 108.943251,302.586589 C106.774613,303.919216 102.895782,306.311974 100.323879,307.903493 C97.751598,309.494634 94.3678729,311.581258 92.8047,312.5401 C91.2411491,313.498564 89.7970283,314.424524 89.5952066,314.597622 C89.2954977,314.854624 75.3902128,323.468326 68.413004,327.719053 C63.1138629,330.947066 56.9836248,333.106255 50.7082565,333.95436 C47.7867558,334.348932 42.2582032,334.350444 39.3450173,333.956627 C31.445665,332.890072 24.1685583,329.944005 17.9362755,325.290768 C15.4916258,323.465303 10.8891851,318.866491 9.12970847,316.49074 C4.9833696,310.893024 2.30102759,304.888641 0.91181812,298.094734 C0.59216513,296.531183 0.289753151,295.211028 0.240053625,295.160383 C0.110210494,295.029237 0.344758621,297.391004 0.76784823,300.4788 C1.20781187,303.690183 2.14533768,308.335104 3.15510733,312.307665 C10.9691579,343.051452 33.2044235,368.056927 63.3054801,379.953822 C71.9732286,383.377987 80.7199673,385.536043 90.2369541,386.594284 C93.8130523,386.994903 103.935504,387.153639 107.667693,386.870182 C124.783605,385.573837 139.68666,380.535855 154.975217,370.873738 C156.336946,370.013161 158.895243,368.4001 160.660238,367.288569 C162.42561,366.177416 164.653585,364.764664 165.612049,364.149751 C166.570135,363.534459 167.725507,362.807675 168.179417,362.5348 C168.633327,362.261547 169.541146,361.69123 170.196878,361.2668 C170.852609,360.842748 173.658459,359.067927 176.432184,357.322963 L187.52406,350.317031 L191.332593,347.911423 L191.469787,347.824874 L191.889304,347.559936 L192.088858,347.433703 L194.892818,345.662661 L204.583281,339.541871 C216.930684,331.783076 220.612606,329.05924 226.349027,323.439981 C228.740652,321.097867 232.34623,317.099228 232.525375,316.591651 C232.561657,316.488472 233.202649,315.499773 233.949465,314.394667 C236.985104,309.902812 239.009368,304.400338 240.013185,297.911432 C240.477677,294.909429 240.474653,287.569017 240.007515,284.248408 C239.104609,277.828288 237.053134,270.546079 234.84141,265.909094 C231.21429,258.305634 223.48762,251.396833 212.387807,245.832753 C209.323066,244.296414 206.15817,242.890466 205.804793,242.908804 C205.637364,242.917678 195.308177,249.231218 182.851171,256.939747 C170.394164,264.648276 159.582722,271.339004 158.826458,271.808409 C158.069815,272.278192 156.770069,273.072251 155.937838,273.572648 L148.810208,277.993827 Z" fill="url(#bingRadialGradient-2)"></path>
|
||||||
|
<path d="M0.0533481895,241.013222 L0.106718678,294.701938 L0.801609893,297.819592 C2.97446184,307.567124 6.73918016,314.594977 13.2839464,321.122433 C16.3624068,324.192844 18.7164636,326.044009 22.0524167,328.018006 C29.1114124,332.195412 36.7087125,334.256336 45.0304163,334.252562 C53.7461636,334.248021 61.2857518,332.074092 69.0551294,327.325236 C70.3662143,326.523997 75.5035957,323.360991 80.4712807,320.296249 L89.5033664,314.724233 L89.5033664,251.024559 L89.5033664,187.324884 L89.5007208,129.051339 C89.4988311,91.8738258 89.4308013,69.7947641 89.313261,68.0626506 C88.5724924,57.1775095 84.020167,47.1707083 76.3653061,39.6016406 C74.0160114,37.2786885 72.0087553,35.7271562 66.0289385,31.6121866 C63.053392,29.5643772 57.6064751,25.8130645 53.9249307,23.2760076 C50.2433864,20.7387618 44.1777765,16.5590127 40.4455878,13.9874496 C36.7134746,11.4160755 31.3904475,7.74730564 28.6166092,5.83487543 C22.8380472,1.85062504 22.3858004,1.57350956 20.6389849,0.948501166 C18.366904,0.13569962 15.9591415,-0.162861118 13.6700153,0.0843541512 C6.99810902,0.80490922 1.65713716,5.62213122 0.268845335,12.1713194 C0.0528069748,13.1902541 0.013004155,26.7505903 0.0102532201,100.349957 L0.00714146286,187.324884 L0,187.324884 L0.0533481895,241.013222 Z" fill="url(#bingLinearGradient-3)"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</template>
|
@ -7,6 +7,7 @@ import {Conversation} from "../assets/script/conversation";
|
|||||||
import {nextTick, onMounted, ref} from "vue";
|
import {nextTick, onMounted, ref} from "vue";
|
||||||
import {auth, username} from "../assets/script/auth";
|
import {auth, username} from "../assets/script/auth";
|
||||||
import Loading from "../components/icons/loading.vue";
|
import Loading from "../components/icons/loading.vue";
|
||||||
|
import Bing from "../components/icons/bing.vue";
|
||||||
|
|
||||||
const conversation = new Conversation(1, refreshScrollbar);
|
const conversation = new Conversation(1, refreshScrollbar);
|
||||||
const state = conversation.getState(), length = conversation.getLength(), messages = conversation.getMessages();
|
const state = conversation.getState(), length = conversation.getLength(), messages = conversation.getMessages();
|
||||||
@ -57,6 +58,10 @@ onMounted(() => {
|
|||||||
<div class="grow" v-if="message.role === 'user'"></div>
|
<div class="grow" v-if="message.role === 'user'"></div>
|
||||||
<div class="avatar openai" :class="{'gpt4': message.gpt4}" v-else><openai /></div>
|
<div class="avatar openai" :class="{'gpt4': message.gpt4}" v-else><openai /></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
<div v-if="message.role === 'bot' && message.keyword !== ''" class="bing">
|
||||||
|
<bing />
|
||||||
|
{{ message.keyword }}
|
||||||
|
</div>
|
||||||
<div class="loader" v-if="!message.content" />
|
<div class="loader" v-if="!message.content" />
|
||||||
<span v-if="message.role === 'user'">{{ message.content }}</span>
|
<span v-if="message.role === 'user'">{{ message.content }}</span>
|
||||||
<md-preview v-model="message.content" theme="dark" v-else />
|
<md-preview v-model="message.content" theme="dark" v-else />
|
||||||
@ -179,6 +184,25 @@ onMounted(() => {
|
|||||||
transform: translateY(10px);
|
transform: translateY(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bing {
|
||||||
|
display: inline-block;
|
||||||
|
color: #2f7eee;
|
||||||
|
background: #e8f2ff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 4px 0;
|
||||||
|
user-select: none;
|
||||||
|
animation: FadeInAnimation .5s cubic-bezier(0.18, 0.89, 0.32, 1.28) both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bing svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 6px;
|
||||||
|
transform: translate(3px, 3px);
|
||||||
|
}
|
||||||
|
|
||||||
.input .button:hover {
|
.input .button:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
func Contains[T comparable](value T, slice []T) bool {
|
func Contains[T comparable](value T, slice []T) bool {
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
@ -29,3 +32,35 @@ func Insert[T any](arr []T, index int, value T) []T {
|
|||||||
arr[index] = value
|
arr[index] = value
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InsertSlice[T any](arr []T, index int, value []T) []T {
|
||||||
|
arr = append(arr, value...)
|
||||||
|
copy(arr[index+len(value):], arr[index:])
|
||||||
|
copy(arr[index:], value)
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
func Remove[T any](arr []T, index int) []T {
|
||||||
|
return append(arr[:index], arr[index+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveSlice[T any](arr []T, index int, length int) []T {
|
||||||
|
return append(arr[:index], arr[index+length:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToJson(value interface{}) string {
|
||||||
|
if res, err := json.Marshal(value); err == nil {
|
||||||
|
return string(res)
|
||||||
|
} else {
|
||||||
|
return "{}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalJson[T any](value string) T {
|
||||||
|
var res T
|
||||||
|
if err := json.Unmarshal([]byte(value), &res); err == nil {
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user