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:
@@ -0,0 +1,84 @@
|
||||
package ai
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"eai_agentplatform/backend/internal/model"
|
||||
"eai_agentplatform/backend/internal/store"
|
||||
)
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// 按用户算力点计费(对齐 pj034 router.py 的 compute_credits / log_ai_call)
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
// AI 能力常量(pj034 AiCapability 的精简子集)
|
||||
const (
|
||||
CapabilityAIChat = "ai_chat" // PathCoach 对话(每轮扣 1 点)
|
||||
CapabilityTextGen = "text_gen" // 快捷动作(情景演练/查佣金/产品对比,扣 1 点)
|
||||
CapabilityImageGen = "image_gen" // 文生图(按次扣点)
|
||||
CapabilityEmbed = "embed" // 知识检索内部 embedding(不扣点,仅审计)
|
||||
CapabilityEssayGrade = "essay_grade" // 简答题 LLM 评分(系统自动,不扣点,仅审计)
|
||||
)
|
||||
|
||||
// CapabilityCredits 各能力扣点成本
|
||||
var CapabilityCredits = map[string]int{
|
||||
CapabilityAIChat: 1,
|
||||
CapabilityTextGen: 1,
|
||||
CapabilityImageGen: 1,
|
||||
CapabilityEmbed: 0,
|
||||
CapabilityEssayGrade: 0,
|
||||
}
|
||||
|
||||
// ComputeCredits 扣点决策:仅「成功」才扣点;失败不扣。
|
||||
func ComputeCredits(capability string, success bool) int {
|
||||
if !success {
|
||||
return 0
|
||||
}
|
||||
return CapabilityCredits[capability]
|
||||
}
|
||||
|
||||
// LogEntry 一次 AI 调用的审计入参
|
||||
type LogEntry struct {
|
||||
UserID uint
|
||||
Capability string
|
||||
Provider string
|
||||
RouteID string
|
||||
Model string
|
||||
TokensInput int
|
||||
TokensOutput int
|
||||
Success bool
|
||||
ErrorMessage string
|
||||
LatencyMs int
|
||||
}
|
||||
|
||||
// LogCall 写 ai_call_log;成功且需扣点时从用户余额扣点。审计写入失败不阻断主流程。
|
||||
func LogCall(e LogEntry) {
|
||||
credits := ComputeCredits(e.Capability, e.Success)
|
||||
status := "success"
|
||||
if !e.Success {
|
||||
status = "failed"
|
||||
}
|
||||
rec := model.AiCallLog{
|
||||
UserID: e.UserID,
|
||||
Capability: e.Capability,
|
||||
Provider: e.Provider,
|
||||
RouteID: e.RouteID,
|
||||
Model: e.Model,
|
||||
TokensInput: e.TokensInput,
|
||||
TokensOutput: e.TokensOutput,
|
||||
CreditsCharged: credits,
|
||||
Status: status,
|
||||
ErrorMessage: e.ErrorMessage,
|
||||
LatencyMs: e.LatencyMs,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
if err := store.DB.Create(&rec).Error; err != nil {
|
||||
return
|
||||
}
|
||||
if credits > 0 {
|
||||
store.DB.Model(&model.User{}).Where("id = ?", e.UserID).
|
||||
UpdateColumn("ai_points", gorm.Expr("ai_points - ?", credits))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user