mirror of
https://github.com/coaidev/coai.git
synced 2025-05-21 05:50:14 +09:00
feat: seo optimization (#91)
This commit is contained in:
parent
e12fd20f9e
commit
be2bd3da35
@ -9,6 +9,7 @@ app/target
|
|||||||
app/tauri.conf.json
|
app/tauri.conf.json
|
||||||
app/tauri.js
|
app/tauri.js
|
||||||
|
|
||||||
|
screenshot
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
config.yaml
|
config.yaml
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@ app/node_modules
|
|||||||
.idea
|
.idea
|
||||||
config.yaml
|
config.yaml
|
||||||
config.dev.yaml
|
config.dev.yaml
|
||||||
|
storage
|
||||||
|
|
||||||
addition/generation/data/*
|
addition/generation/data/*
|
||||||
!addition/generation/data/.gitkeep
|
!addition/generation/data/.gitkeep
|
||||||
|
@ -140,7 +140,7 @@ _🚀 **Next Generation AI One-Stop Solution**_
|
|||||||
2. ⚡ Docker 安装 (轻量运行时, 常用于外置 _MYSQL/RDS_ 服务)
|
2. ⚡ Docker 安装 (轻量运行时, 常用于外置 _MYSQL/RDS_ 服务)
|
||||||
> 如需使用 stable 版本, 请使用 `programzmh/chatnio:stable` 替代 `programzmh/chatnio:latest`
|
> 如需使用 stable 版本, 请使用 `programzmh/chatnio:stable` 替代 `programzmh/chatnio:latest`
|
||||||
```shell
|
```shell
|
||||||
docker run -d --name chatnio:latest \
|
docker run -d --name chatnio \
|
||||||
--network host \
|
--network host \
|
||||||
-p 8000:8094 \
|
-p 8000:8094 \
|
||||||
-v ~/config:/config \
|
-v ~/config:/config \
|
||||||
@ -196,6 +196,7 @@ _🚀 **Next Generation AI One-Stop Solution**_
|
|||||||
- 如果使用了端口映射, 端口转发, CDN, API Gateway 等服务, 请确保你的服务支持并开启 websocket。
|
- 如果使用了端口映射, 端口转发, CDN, API Gateway 等服务, 请确保你的服务支持并开启 websocket。
|
||||||
2. **我配置的 Midjourney Proxy 格式的渠道一直转圈或报错 `please provide available notify url`**
|
2. **我配置的 Midjourney Proxy 格式的渠道一直转圈或报错 `please provide available notify url`**
|
||||||
- 若为转圈,请确保你的 Midjourney Proxy 服务已正常运行, 并且已配置正确的上游地址。
|
- 若为转圈,请确保你的 Midjourney Proxy 服务已正常运行, 并且已配置正确的上游地址。
|
||||||
|
- **Midjourney 要填渠道类型要用 Midjourney 而不是 OpenAI (不知道为什么很多人填成了 OpenAI 类型格式然后过来反馈为什么empty response, mj-chat 类除外)**
|
||||||
- 排查完这些问题后, 请查看你的系统设置中的**后端域名**是否已经配置并配置正确。如果不配置, 将导致 Midjourney Proxy 服务无法正常回调。
|
- 排查完这些问题后, 请查看你的系统设置中的**后端域名**是否已经配置并配置正确。如果不配置, 将导致 Midjourney Proxy 服务无法正常回调。
|
||||||
3. **此项目有什么外部依赖?**
|
3. **此项目有什么外部依赖?**
|
||||||
- MySQL: 存储用户信息, 对话记录, 管理员信息等持久化数据。
|
- MySQL: 存储用户信息, 对话记录, 管理员信息等持久化数据。
|
||||||
|
@ -19,7 +19,7 @@ func GenerateProject(path string, instance ProjectResult) bool {
|
|||||||
for name, data := range instance.Result {
|
for name, data := range instance.Result {
|
||||||
current := fmt.Sprintf("%s/%s", path, name)
|
current := fmt.Sprintf("%s/%s", path, name)
|
||||||
if content, ok := data.(string); ok {
|
if content, ok := data.(string); ok {
|
||||||
if !utils.WriteFile(current, content, true) {
|
if utils.WriteFile(current, content, true) != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -132,6 +132,8 @@ func (c *SystemConfig) UpdateConfig(data *SystemConfig) error {
|
|||||||
c.Search = data.Search
|
c.Search = data.Search
|
||||||
c.Common = data.Common
|
c.Common = data.Common
|
||||||
|
|
||||||
|
utils.ApplySeo(c.General.Title, c.General.Logo)
|
||||||
|
|
||||||
return c.SaveConfig()
|
return c.SaveConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"chat/globals"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-contrib/static"
|
"github.com/gin-contrib/static"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -46,6 +47,35 @@ func NewEngine() *gin.Engine {
|
|||||||
return 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) {
|
func RegisterStaticRoute(engine *gin.Engine) {
|
||||||
// static files are in ~/app/dist
|
// static files are in ~/app/dist
|
||||||
|
|
||||||
@ -61,9 +91,15 @@ func RegisterStaticRoute(engine *gin.Engine) {
|
|||||||
return
|
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.Use(static.Serve("/", static.LocalFile("./app/dist", true)))
|
||||||
engine.NoRoute(func(c *gin.Context) {
|
engine.NoRoute(func(c *gin.Context) {
|
||||||
c.File("./app/dist/index.html")
|
c.File("./app/dist/index.cache.html")
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, route := range redirectRoutes {
|
for _, route := range redirectRoutes {
|
||||||
|
29
utils/fs.go
29
utils/fs.go
@ -36,14 +36,14 @@ func CreateFolderOnFile(file string) string {
|
|||||||
return CreateFolderNotExists(file[:strings.LastIndex(file, "/")])
|
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 {
|
if folderSafe {
|
||||||
CreateFolderOnFile(path)
|
CreateFolderOnFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return err
|
||||||
}
|
}
|
||||||
defer func(file *os.File) {
|
defer func(file *os.File) {
|
||||||
err := file.Close()
|
err := file.Close()
|
||||||
@ -54,9 +54,30 @@ func WriteFile(path string, data string, folderSafe bool) bool {
|
|||||||
|
|
||||||
if _, err := file.WriteString(data); err != nil {
|
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)))
|
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 {
|
func Walk(path string) []string {
|
||||||
|
Loading…
Reference in New Issue
Block a user