fix: token统计+聊天记录入库静默失败, 列名/类型/去重不匹配

根因:insert_llm_usage / insert_chat_record 因旧 iPet 遗留列 (kind/entry NOT NULL,
context_token_present boolean→context_token text) 导致 INSERT 静默失败,
四个调用点 let _ = 吞掉错误。ias usage 显示 token 总量为 0。

修复:
- llm_usage: 迁移 0010 ADD COLUMN IF NOT EXISTS + 条件 DROP NOT NULL,
  insert_llm_usage 写入 kind/entry 默认值
- chat_records: 迁移 0011 列名 context_token_present→context_token 类型转换+重命名,
  迁移 0012 清理存量重复→partial UNIQUE index→恢复 ON CONFLICT
- main.rs: 所有 let _ = insert_* 改为 if let Err(e) 日志输出,
  message_id 缺失时归为 '' 而非 '0'
This commit is contained in:
2026-06-02 16:31:48 +08:00
parent 1aef0c2f69
commit dcfaf47809
5 changed files with 94 additions and 18 deletions
+9 -6
View File
@@ -66,11 +66,11 @@ pub async fn insert_chat_record(
) -> Result<i64, String> {
let ctx = context_token.unwrap_or("");
let row: (i64,) = sqlx::query_as(
let row: Option<(i64,)> = sqlx::query_as(
r#"
INSERT INTO chat_records (direction, user_id, account_id, text, source, context_token, message_id)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (message_id) DO NOTHING
ON CONFLICT (message_id) WHERE message_id NOT IN ('', '0') DO NOTHING
RETURNING id
"#,
)
@@ -81,11 +81,11 @@ pub async fn insert_chat_record(
.bind(source)
.bind(ctx)
.bind(message_id)
.fetch_one(pool)
.fetch_optional(pool)
.await
.map_err(|e| format!("插入聊天记录失败: {}", e))?;
Ok(row.0)
Ok(row.map(|r| r.0).unwrap_or(0))
}
/// 查询最近的聊天记录(用户维度)
@@ -115,6 +115,7 @@ pub async fn list_recent_chat_records(
// ─── LLM 用量 ───
/// 插入一条 LLM 用量记录
/// kind/entry 为 iPet 遗留兼容字段,写入默认值 ("llm_call" / null)
pub async fn insert_llm_usage(
pool: &PgPool,
user_id: &str,
@@ -128,8 +129,8 @@ pub async fn insert_llm_usage(
let total = prompt_tokens + completion_tokens;
sqlx::query(
r#"
INSERT INTO llm_usage (user_id, model, provider, prompt_tokens, completion_tokens, total_tokens, cache_hit_tokens, cache_miss_tokens)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
INSERT INTO llm_usage (user_id, model, provider, prompt_tokens, completion_tokens, total_tokens, cache_hit_tokens, cache_miss_tokens, kind, entry)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
"#,
)
.bind(user_id)
@@ -140,6 +141,8 @@ pub async fn insert_llm_usage(
.bind(total as i32)
.bind(cache_hit_tokens as i32)
.bind(cache_miss_tokens as i32)
.bind("llm_call")
.bind(serde_json::Value::Null)
.execute(pool)
.await
.map_err(|e| format!("插入 LLM 用量失败: {}", e))?;
+29 -12
View File
@@ -162,7 +162,9 @@ async fn cmd_listen(
account_id: fa.account_id,
base_url: fa.base_url,
};
let _ = db::models::save_auth(db.pool(), &a).await;
if let Err(e) = db::models::save_auth(db.pool(), &a).await {
error!("保存认证信息失败: {}", e);
}
break 'load Some(a);
}
} else if let Some(a) = file_state.load_auth() {
@@ -481,13 +483,13 @@ async fn listen_loop(
let from = msg.from_user_id.as_deref().unwrap_or("unknown");
let text = msg.text_content().unwrap_or("(非文本消息)");
let ctx_token = msg.context_token.as_deref();
let msg_id = msg.message_id.unwrap_or(0).to_string();
let msg_id = msg.message_id.map(|id| id.to_string()).unwrap_or_default();
info!("收到消息 from={}: {}", from, text);
// === 入库:收到的消息 ===
if let Some(db) = database {
let _ = db::models::insert_chat_record(
if let Err(e) = db::models::insert_chat_record(
db.pool(),
"inbound",
from,
@@ -497,7 +499,10 @@ async fn listen_loop(
ctx_token,
&msg_id,
)
.await;
.await
{
error!("保存聊天记录失败: {}", e);
}
}
// Echo 模式
@@ -507,7 +512,7 @@ async fn listen_loop(
info!("回显成功 msg_id={}", sent_id);
// === 入库:发送的回显 ===
if let Some(db) = database {
let _ = db::models::insert_chat_record(
if let Err(e) = db::models::insert_chat_record(
db.pool(),
"outbound",
from,
@@ -517,7 +522,10 @@ async fn listen_loop(
ctx_token,
&sent_id,
)
.await;
.await
{
error!("保存聊天记录失败: {}", e);
}
}
}
Err(e) => error!("回显失败: {}", e),
@@ -579,7 +587,7 @@ async fn listen_loop(
Ok(sent_id) => {
info!("LLM 回复成功 msg_id={}", sent_id);
if let Some(db) = database {
let _ = db::models::insert_chat_record(
if let Err(e) = db::models::insert_chat_record(
db.pool(),
"outbound",
&from_owned,
@@ -589,7 +597,10 @@ async fn listen_loop(
ctx_owned.as_deref(),
&sent_id,
)
.await;
.await
{
error!("保存聊天记录失败: {}", e);
}
}
}
Err(e) => error!("发送 LLM 回复失败: {}", e),
@@ -659,7 +670,7 @@ async fn store_usage(
u: &Usage,
) {
if let Some(db) = db {
let _ = db::models::insert_llm_usage(
if let Err(e) = db::models::insert_llm_usage(
db.pool(),
user_id,
model,
@@ -669,7 +680,10 @@ async fn store_usage(
u.prompt_cache_hit_tokens,
u.prompt_cache_miss_tokens,
)
.await;
.await
{
tracing::error!("存储 LLM 用量失败: {}", e);
}
}
}
@@ -797,7 +811,7 @@ async fn cmd_send(
// 入库:发送的消息
if let Some(db) = database {
let _ = db::models::insert_chat_record(
if let Err(e) = db::models::insert_chat_record(
db.pool(),
"outbound",
to,
@@ -807,7 +821,10 @@ async fn cmd_send(
context_token,
&msg_id,
)
.await;
.await
{
error!("保存聊天记录失败: {}", e);
}
}
}
Err(e) => error!("发送失败: {}", e),