AstroResearch/tests/live_llm_test.rs
Asfmq 3f1935678b feat: LLM/Embedding 客户端模块化、侧边栏折叠交互、arXiv→ADS 下载回退与前端体验重构
**后端架构**
  - 抽取翻译服务中内嵌的 LLM HTTP 调用为独立的 LlmClient /
    EmbeddingClient(src/clients/llm.rs),翻译模块改为委托调用,消除
    对 reqwest/serde 的直接耦合
  - Config 新增 EMBEDDING_API_KEY/EMBEDDING_API_BASE/EMBEDDING_MODEL
    三项配置,默认 fallback 至 LLM 对应值,补齐向量嵌入基础设施

  **下载策略优化**
  - arXiv 直连下载失败后自动回退至 ADS 网关 PUB_PDF→EPRINT_PDF→CrossRef
    多级通道,替换此前单路径策略;批量同步同步应用此逻辑
  - PDF/HTML 任一方成功时,失败方的 path 字段不再存储 "error:" 报错字符串,
    改为置 NULL,防止日志污染数据

  **前端交互增强**
  - 侧边栏支持折叠/展开:收起为仅图标模式(w-16),展开恢复完整模式(w-64);
    收起后点击 Logo 展开,含流畅 cubic-bezier 过渡动画
  - 阅读面板新增 PDF 内嵌预览:已下载 PDF 时可通过 iframe 切换查看
    /api/files 下的本地文献
  - reader/citation 面板未选文献时展示带图标的空状态引导页,替代空白页
  - 文献详情面板改为固定高度弹性布局(h-[460px]),各区块按比例分配避免
    内容挤压;期刊名过长截断+悬停tooltip;关键词无数据显式占位
  - 全局移除 emoji Unicode,统一替换为 lucide-react 图标组件,
    消除跨平台字体渲染差异

  **反爬检测精细化**
  - 按响应长度分层:>150KB 跳过检测(完整文献),<5KB 才扫描通用 HTTP
    错误关键字,杜绝长文献误触 Cloudflare/503 模式匹配
  - 新增 Radware Bot Manager、ShieldSquare WAF 特征识别

  **健壮性**
  - Obscura 下载校验失败后自动清理硬盘残留坏文件
  - 健康检查工具:文献已有有效 HTML 但 PDF 字段为旧报错时自动判定可修复
  - 上传接口 body limit 提升至 100MB,新增 /api/files 静态文件服务路由
  - StandardPaper 新增 has_pdf/has_html 字段区分格式级下载状态
2026-06-13 11:11:33 +08:00

61 lines
2.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// tests/live_llm_test.rs
use astroresearch::Config;
use astroresearch::clients::llm::{LlmClient, EmbeddingClient};
#[tokio::test]
async fn test_live_llm_and_embedding() -> anyhow::Result<()> {
let config = Config::from_env();
println!("================= 开始大模型与向量模型真实网络集成测试 =================");
// 1. 测试 LlmClient
if config.llm_api_key.is_empty() {
println!("警告: 未在环境配置中检测到 LLM_API_KEY跳过 LlmClient 集成测试。");
} else {
println!("测试大模型: {} (API Base: {})", config.llm_model, config.llm_api_base);
let llm = LlmClient::new(
config.llm_api_key.clone(),
config.llm_api_base.clone(),
config.llm_model.clone(),
);
match llm.chat_completion("You are a helpful assistant.", "Say Hello!").await {
Ok(reply) => {
println!("LlmClient 响应成功: {}", reply.trim());
assert!(!reply.trim().is_empty(), "错误: 大模型返回了空响应");
}
Err(e) => {
panic!("LlmClient 接口调用失败: {}", e);
}
}
}
// 2. 测试 EmbeddingClient
if config.embedding_api_key.is_empty() {
println!("警告: 未在环境配置中检测到 EMBEDDING_API_KEY跳过 EmbeddingClient 集成测试。");
} else {
println!("测试向量模型: {} (API Base: {})", config.embedding_model, config.embedding_api_base);
let embedding_client = EmbeddingClient::new(
config.embedding_api_key.clone(),
config.embedding_api_base.clone(),
config.embedding_model.clone(),
);
let test_text = "active galactic nucleus";
match embedding_client.create_embedding(test_text).await {
Ok(vector) => {
println!("EmbeddingClient 响应成功!向量维度: {}", vector.len());
assert!(!vector.is_empty(), "错误: 向量数据为空");
let preview_len = std::cmp::min(5, vector.len());
println!("{} 个向量数值样例: {:?}", preview_len, &vector[..preview_len]);
}
Err(e) => {
panic!("EmbeddingClient 接口调用失败: {}", e);
}
}
}
println!("================= 大模型与向量模型真实网络集成测试完成 =================");
Ok(())
}