11
This commit is contained in:
170
src-tauri/src/asr_db.rs
Normal file
170
src-tauri/src/asr_db.rs
Normal file
@@ -0,0 +1,170 @@
|
||||
//! 语音识别历史 SQLite
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use chrono::Utc;
|
||||
use rusqlite::{params, Connection};
|
||||
use serde::Serialize;
|
||||
use thiserror::Error;
|
||||
|
||||
const MAX_RECORDS: i64 = 50;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AsrDbError {
|
||||
#[error("{0}")]
|
||||
Db(#[from] rusqlite::Error),
|
||||
#[error("{0}")]
|
||||
Message(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AsrHistoryRecord {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub source_path: String,
|
||||
pub result_text: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsrDb {
|
||||
conn: Mutex<Connection>,
|
||||
}
|
||||
|
||||
impl AsrDb {
|
||||
pub fn open(path: PathBuf) -> Result<Self, AsrDbError> {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent).map_err(|e| {
|
||||
AsrDbError::Message(format!("创建数据库目录失败: {e}"))
|
||||
})?;
|
||||
}
|
||||
let conn = Connection::open(path)?;
|
||||
conn.execute_batch(
|
||||
r#"
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE IF NOT EXISTS asr_history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL DEFAULT '',
|
||||
source_path TEXT NOT NULL,
|
||||
result_text TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
"#,
|
||||
)?;
|
||||
Ok(Self {
|
||||
conn: Mutex::new(conn),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn list(&self) -> Result<Vec<AsrHistoryRecord>, AsrDbError> {
|
||||
let conn = self.conn.lock().map_err(|_| {
|
||||
AsrDbError::Message("ASR 数据库锁异常".into())
|
||||
})?;
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, name, source_path, result_text, created_at
|
||||
FROM asr_history ORDER BY id DESC LIMIT ?1",
|
||||
)?;
|
||||
let rows = stmt.query_map(params![MAX_RECORDS], |row| {
|
||||
Ok(AsrHistoryRecord {
|
||||
id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
source_path: row.get(2)?,
|
||||
result_text: row.get(3)?,
|
||||
created_at: row.get(4)?,
|
||||
})
|
||||
})?;
|
||||
let mut items = Vec::new();
|
||||
for row in rows {
|
||||
items.push(row?);
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
pub fn insert(
|
||||
&self,
|
||||
name: &str,
|
||||
source_path: &str,
|
||||
result_text: &str,
|
||||
) -> Result<AsrHistoryRecord, AsrDbError> {
|
||||
let source_path = source_path.trim();
|
||||
if source_path.is_empty() {
|
||||
return Err(AsrDbError::Message("源文件路径不能为空".into()));
|
||||
}
|
||||
let name = name.trim();
|
||||
let name = if name.is_empty() {
|
||||
source_path
|
||||
.replace('\\', "/")
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.unwrap_or("语音识别")
|
||||
.to_string()
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
let created_at = Utc::now().to_rfc3339();
|
||||
let conn = self.conn.lock().map_err(|_| {
|
||||
AsrDbError::Message("ASR 数据库锁异常".into())
|
||||
})?;
|
||||
conn.execute(
|
||||
"INSERT INTO asr_history (name, source_path, result_text, created_at)
|
||||
VALUES (?1, ?2, ?3, ?4)",
|
||||
params![name, source_path, result_text.trim(), created_at],
|
||||
)?;
|
||||
let id = conn.last_insert_rowid();
|
||||
self.prune_excess(&conn)?;
|
||||
Ok(AsrHistoryRecord {
|
||||
id,
|
||||
name,
|
||||
source_path: source_path.to_string(),
|
||||
result_text: result_text.trim().to_string(),
|
||||
created_at,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update_name(&self, id: i64, name: &str) -> Result<(), AsrDbError> {
|
||||
let name = name.trim();
|
||||
if name.is_empty() {
|
||||
return Err(AsrDbError::Message("名称不能为空".into()));
|
||||
}
|
||||
let conn = self.conn.lock().map_err(|_| {
|
||||
AsrDbError::Message("ASR 数据库锁异常".into())
|
||||
})?;
|
||||
let n = conn.execute(
|
||||
"UPDATE asr_history SET name = ?1 WHERE id = ?2",
|
||||
params![name, id],
|
||||
)?;
|
||||
if n == 0 {
|
||||
return Err(AsrDbError::Message("记录不存在".into()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prune_excess(&self, conn: &Connection) -> Result<(), AsrDbError> {
|
||||
let count: i64 = conn.query_row(
|
||||
"SELECT COUNT(1) FROM asr_history",
|
||||
[],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
if count <= MAX_RECORDS {
|
||||
return Ok(());
|
||||
}
|
||||
let excess = count - MAX_RECORDS;
|
||||
conn.execute(
|
||||
"DELETE FROM asr_history WHERE id IN (
|
||||
SELECT id FROM asr_history ORDER BY id ASC LIMIT ?1
|
||||
)",
|
||||
params![excess],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete(&self, id: i64) -> Result<bool, AsrDbError> {
|
||||
let conn = self.conn.lock().map_err(|_| {
|
||||
AsrDbError::Message("ASR 数据库锁异常".into())
|
||||
})?;
|
||||
let n = conn.execute("DELETE FROM asr_history WHERE id = ?1", params![id])?;
|
||||
Ok(n > 0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user