feat: seo optimization (#91)

This commit is contained in:
Zhang Minghan 2024-03-08 16:15:30 +08:00
parent e12fd20f9e
commit be2bd3da35
7 changed files with 69 additions and 7 deletions

View File

@ -9,6 +9,7 @@ app/target
app/tauri.conf.json
app/tauri.js
screenshot
.vscode
.idea
config.yaml

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ app/node_modules
.idea
config.yaml
config.dev.yaml
storage
addition/generation/data/*
!addition/generation/data/.gitkeep

View File

@ -140,7 +140,7 @@ _🚀 **Next Generation AI One-Stop Solution**_
2. ⚡ Docker 安装 (轻量运行时, 常用于外置 _MYSQL/RDS_ 服务)
> 如需使用 stable 版本, 请使用 `programzmh/chatnio:stable` 替代 `programzmh/chatnio:latest`
```shell
docker run -d --name chatnio:latest \
docker run -d --name chatnio \
--network host \
-p 8000:8094 \
-v ~/config:/config \
@ -196,6 +196,7 @@ _🚀 **Next Generation AI One-Stop Solution**_
- 如果使用了端口映射, 端口转发, CDN, API Gateway 等服务, 请确保你的服务支持并开启 websocket。
2. **我配置的 Midjourney Proxy 格式的渠道一直转圈或报错 `please provide available notify url`**
- 若为转圈,请确保你的 Midjourney Proxy 服务已正常运行, 并且已配置正确的上游地址。
- **Midjourney 要填渠道类型要用 Midjourney 而不是 OpenAI (不知道为什么很多人填成了 OpenAI 类型格式然后过来反馈为什么empty response, mj-chat 类除外)**
- 排查完这些问题后, 请查看你的系统设置中的**后端域名**是否已经配置并配置正确。如果不配置, 将导致 Midjourney Proxy 服务无法正常回调。
3. **此项目有什么外部依赖?**
- MySQL: 存储用户信息, 对话记录, 管理员信息等持久化数据。

View File

@ -19,7 +19,7 @@ func GenerateProject(path string, instance ProjectResult) bool {
for name, data := range instance.Result {
current := fmt.Sprintf("%s/%s", path, name)
if content, ok := data.(string); ok {
if !utils.WriteFile(current, content, true) {
if utils.WriteFile(current, content, true) != nil {
return false
}
} else {

View File

@ -132,6 +132,8 @@ func (c *SystemConfig) UpdateConfig(data *SystemConfig) error {
c.Search = data.Search
c.Common = data.Common
utils.ApplySeo(c.General.Title, c.General.Logo)
return c.SaveConfig()
}

View File

@ -1,6 +1,7 @@
package utils
import (
"chat/globals"
"fmt"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
@ -46,6 +47,35 @@ func NewEngine() *gin.Engine {
return engine
}
func ApplySeo(title, icon string) {
// seo optimization
if !viper.GetBool("serve_static") {
return
}
content, err := ReadFile("./app/dist/index.html")
if err != nil {
globals.Warn(fmt.Sprintf("[service] failed to read index.html: %s", err.Error()))
return
}
if len(title) > 0 {
content = strings.ReplaceAll(content, "Chat Nio", title)
content = strings.ReplaceAll(content, "chatnio", strings.ToLower(title))
}
if len(icon) > 0 {
content = strings.ReplaceAll(content, "/favicon.ico", icon)
}
if err := WriteFile("./app/dist/index.cache.html", content, true); err != nil {
globals.Warn(fmt.Sprintf("[service] failed to write index.cache.html: %s", err.Error()))
}
globals.Info("[service] seo optimization applied to index.cache.html")
}
func RegisterStaticRoute(engine *gin.Engine) {
// static files are in ~/app/dist
@ -61,9 +91,15 @@ func RegisterStaticRoute(engine *gin.Engine) {
return
}
ApplySeo(viper.GetString("system.general.title"), viper.GetString("system.general.logo"))
// serve / -> index.cache.html
engine.GET("/", func(c *gin.Context) {
c.File("./app/dist/index.cache.html")
})
engine.Use(static.Serve("/", static.LocalFile("./app/dist", true)))
engine.NoRoute(func(c *gin.Context) {
c.File("./app/dist/index.html")
c.File("./app/dist/index.cache.html")
})
for _, route := range redirectRoutes {

View File

@ -36,14 +36,14 @@ func CreateFolderOnFile(file string) string {
return CreateFolderNotExists(file[:strings.LastIndex(file, "/")])
}
func WriteFile(path string, data string, folderSafe bool) bool {
func WriteFile(path string, data string, folderSafe bool) error {
if folderSafe {
CreateFolderOnFile(path)
}
file, err := os.Create(path)
if err != nil {
return false
return err
}
defer func(file *os.File) {
err := file.Close()
@ -54,9 +54,30 @@ func WriteFile(path string, data string, folderSafe bool) bool {
if _, err := file.WriteString(data); err != nil {
globals.Warn(fmt.Sprintf("[utils] write file error: %s (path: %s, bytes len: %d)", err.Error(), path, len(data)))
return false
return err
}
return true
return nil
}
func ReadFile(path string) (string, error) {
file, err := os.Open(path)
if err != nil {
return "", err
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
globals.Warn(fmt.Sprintf("[utils] close file error: %s (path: %s)", err.Error(), path))
}
}(file)
data, err := io.ReadAll(file)
if err != nil {
return "", err
}
return string(data), nil
}
func Walk(path string) []string {