🎨 优化扩展模块,完成ai接入和对话功能

This commit is contained in:
2026-02-12 23:12:28 +08:00
parent 4e611d3a5e
commit 572f3aa15b
779 changed files with 194400 additions and 3136 deletions

View File

@@ -3,7 +3,10 @@ package app
import (
"fmt"
"io"
"mime"
"net/http"
"os"
"path/filepath"
"strconv"
"git.echol.cn/loser/st/server/global"
@@ -563,3 +566,72 @@ func (a *ExtensionApi) InstallExtensionFromGit(c *gin.Context) {
sysResponse.OkWithData(response.ToExtensionResponse(extension), c)
}
// ProxyExtensionAsset 获取扩展资源文件(从本地文件系统读取)
// @Summary 获取扩展资源文件
// @Description 从本地存储读取扩展的 JS/CSS 等资源文件(与原版 SillyTavern 一致,扩展文件存储在本地)
// @Tags 扩展管理
// @Produce octet-stream
// @Param id path int true "扩展ID"
// @Param path path string true "资源文件路径"
// @Success 200 {file} binary
// @Router /app/extension/:id/asset/*path [get]
func (a *ExtensionApi) ProxyExtensionAsset(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extensionID := uint(id)
// 获取资源路径(去掉前导 /
assetPath := c.Param("path")
if len(assetPath) > 0 && assetPath[0] == '/' {
assetPath = assetPath[1:]
}
if assetPath == "" {
sysResponse.FailWithMessage("资源路径不能为空", c)
return
}
// 通过扩展 ID 查库获取信息(公开路由,不做 userID 过滤)
extInfo, err := extensionService.GetExtensionByID(extensionID)
if err != nil {
sysResponse.FailWithMessage("扩展不存在", c)
return
}
// 从本地文件系统读取资源
localPath, err := extensionService.GetExtensionAssetLocalPath(extInfo.Name, assetPath)
if err != nil {
global.GVA_LOG.Error("获取扩展资源失败",
zap.Error(err),
zap.String("name", extInfo.Name),
zap.String("asset", assetPath))
sysResponse.FailWithMessage("资源不存在: "+err.Error(), c)
return
}
// 读取文件内容
data, err := os.ReadFile(localPath)
if err != nil {
global.GVA_LOG.Error("读取扩展资源文件失败", zap.Error(err), zap.String("path", localPath))
sysResponse.FailWithMessage("资源读取失败", c)
return
}
// 根据文件扩展名设置正确的 Content-Type
fileExt := filepath.Ext(assetPath)
contentType := mime.TypeByExtension(fileExt)
if contentType == "" {
contentType = "application/octet-stream"
}
// 设置缓存和 CORS 头
c.Header("Content-Type", contentType)
c.Header("Cache-Control", "public, max-age=3600")
c.Header("Access-Control-Allow-Origin", "*")
c.Data(http.StatusOK, contentType, data)
}