feat: 新增语音转文字(ASR)功能

- 后端:新增 /api/audio/transcribe 接口,调用 Ollama whisper 进行语音识别
- 前端:新增 AudioTranscribePage.vue 页面,支持 MP3/WAV/M4A/OGG/FLAC 等格式
- 注册路由、工具卡片、智能助手欢迎语更新

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
eaiadmin
2026-09-14 00:53:36 +08:00
co-authored by Claude Code
parent 752c7837ef
commit 0455f064ac
299 changed files with 1588 additions and 432 deletions
@@ -0,0 +1,58 @@
package auth
import (
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
"golang.org/x/crypto/bcrypt"
)
// HashPassword bcrypt 哈希
func HashPassword(password string) (string, error) {
b, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(b), nil
}
// VerifyPassword 校验密码
func VerifyPassword(password, hashed string) bool {
return bcrypt.CompareHashAndPassword([]byte(hashed), []byte(password)) == nil
}
// CreateToken 签发 JWT(HS256),payload 对齐 Python:sub/role/iat/exp
func CreateToken(username, role, secret string, expireMin int) (string, error) {
now := time.Now()
claims := jwt.MapClaims{
"sub": username,
"role": role,
"iat": now.Unix(),
"exp": now.Add(time.Duration(expireMin) * time.Minute).Unix(),
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
}
// SignClaims 通用 JWT 签发(考试会话等复用)
func SignClaims(claims jwt.MapClaims, secret string) (string, error) {
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
}
// ParseToken 校验 JWT,返回 claims。失败返回 error。
func ParseToken(tokenStr, secret string) (jwt.MapClaims, error) {
token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (any, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, jwt.ErrSignatureInvalid
}
return []byte(secret), nil
})
if err != nil {
return nil, err
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
return nil, errors.New("invalid token claims")
}
return claims, nil
}