mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
fix: 修复日志清理和提供商显示问题 (#51)
问题修复: 1. 清除日志后列表仍有数据 - cleanup_flows 现在同时清理 file_store 和 memory_store 2. 提供商显示不正确 - 从模型名推断实际提供商(如 deepseek 模型显示 DeepSeek 而非 Kiro) 改动说明: - flow_monitor_cmd.rs: 在 All/ByTime/ByCount 清理类型中添加内存存储清理 - memory_store.rs: 添加 cleanup_before() 方法支持按时间清理内存数据 - FlowList.tsx: 添加 inferProviderFromModel/getDisplayProvider 函数从模型名推断提供商 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -507,6 +507,7 @@ pub async fn cleanup_flows(
|
||||
// 清理所有数据 - 使用当前时间 + 1天,确保删除所有数据
|
||||
let before = chrono::Utc::now() + chrono::Duration::days(1);
|
||||
|
||||
// 清理文件存储
|
||||
if let Some(file_store) = monitor.0.file_store() {
|
||||
match file_store.cleanup(before) {
|
||||
Ok(result) => {
|
||||
@@ -520,6 +521,14 @@ pub async fn cleanup_flows(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清理内存存储
|
||||
{
|
||||
let memory_store = monitor.0.memory_store();
|
||||
let mut store = memory_store.write().await;
|
||||
store.clear();
|
||||
tracing::info!("已清理内存存储");
|
||||
}
|
||||
}
|
||||
|
||||
CleanupType::ByTime => {
|
||||
@@ -546,6 +555,15 @@ pub async fn cleanup_flows(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清理内存存储
|
||||
{
|
||||
let memory_store = monitor.0.memory_store();
|
||||
let mut store = memory_store.write().await;
|
||||
let memory_cleaned = store.cleanup_before(before);
|
||||
cleaned_count += memory_cleaned;
|
||||
tracing::info!("已清理内存存储 {} 条记录", memory_cleaned);
|
||||
}
|
||||
}
|
||||
|
||||
CleanupType::ByCount => {
|
||||
@@ -563,6 +581,15 @@ pub async fn cleanup_flows(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清理内存存储 - 对于按数量清理,清空所有内存数据
|
||||
// 因为文件存储已按保留策略清理,内存应保持一致
|
||||
{
|
||||
let memory_store = monitor.0.memory_store();
|
||||
let mut store = memory_store.write().await;
|
||||
store.clear();
|
||||
tracing::info!("已清理内存存储");
|
||||
}
|
||||
}
|
||||
|
||||
CleanupType::ByStatus => {
|
||||
|
||||
@@ -506,6 +506,37 @@ impl FlowMemoryStore {
|
||||
self.ordered_ids.clear();
|
||||
}
|
||||
|
||||
/// 按时间清理 Flow
|
||||
///
|
||||
/// 删除指定时间之前创建的所有 Flow。
|
||||
///
|
||||
/// # 参数
|
||||
/// - `before`: 截止时间,早于此时间的 Flow 将被删除
|
||||
///
|
||||
/// # 返回
|
||||
/// 删除的 Flow 数量
|
||||
pub fn cleanup_before(&mut self, before: chrono::DateTime<chrono::Utc>) -> usize {
|
||||
let mut to_remove = Vec::new();
|
||||
|
||||
for id in &self.ordered_ids {
|
||||
if let Some(flow_lock) = self.flows.get(id) {
|
||||
if let Ok(flow) = flow_lock.read() {
|
||||
if flow.timestamps.created < before {
|
||||
to_remove.push(id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let count = to_remove.len();
|
||||
for id in to_remove {
|
||||
self.flows.remove(&id);
|
||||
self.ordered_ids.retain(|i| i != &id);
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
|
||||
/// 驱逐最旧的 Flow
|
||||
fn evict_oldest(&mut self) {
|
||||
if let Some(oldest_id) = self.ordered_ids.pop_front() {
|
||||
|
||||
@@ -327,6 +327,66 @@ export function FlowList({
|
||||
}
|
||||
};
|
||||
|
||||
// 从模型名推断实际的模型提供商
|
||||
const inferProviderFromModel = (model: string): string | null => {
|
||||
const modelLower = model.toLowerCase();
|
||||
|
||||
// DeepSeek 模型
|
||||
if (modelLower.includes("deepseek")) {
|
||||
return "DeepSeek";
|
||||
}
|
||||
// Claude 模型
|
||||
if (
|
||||
modelLower.includes("claude") ||
|
||||
modelLower.includes("anthropic") ||
|
||||
modelLower.includes("sonnet") ||
|
||||
modelLower.includes("opus") ||
|
||||
modelLower.includes("haiku")
|
||||
) {
|
||||
return "Claude";
|
||||
}
|
||||
// GPT/OpenAI 模型
|
||||
if (
|
||||
modelLower.includes("gpt") ||
|
||||
modelLower.includes("o1") ||
|
||||
modelLower.includes("o3") ||
|
||||
modelLower.includes("chatgpt")
|
||||
) {
|
||||
return "OpenAI";
|
||||
}
|
||||
// Gemini 模型
|
||||
if (modelLower.includes("gemini")) {
|
||||
return "Gemini";
|
||||
}
|
||||
// Qwen 模型
|
||||
if (modelLower.includes("qwen") || modelLower.includes("qwq")) {
|
||||
return "Qwen";
|
||||
}
|
||||
// Llama 模型
|
||||
if (modelLower.includes("llama")) {
|
||||
return "Llama";
|
||||
}
|
||||
// Mistral 模型
|
||||
if (modelLower.includes("mistral") || modelLower.includes("mixtral")) {
|
||||
return "Mistral";
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// 获取显示的提供商名称(优先使用模型推断的提供商)
|
||||
const getDisplayProvider = (
|
||||
metadataProvider: string,
|
||||
model: string,
|
||||
): string => {
|
||||
const inferredProvider = inferProviderFromModel(model);
|
||||
// 如果能从模型名推断出提供商,且与凭证池不同,则显示推断的提供商
|
||||
if (inferredProvider && inferredProvider !== metadataProvider) {
|
||||
return inferredProvider;
|
||||
}
|
||||
return metadataProvider;
|
||||
};
|
||||
|
||||
const getProviderColor = (provider: string) => {
|
||||
const colors: Record<string, string> = {
|
||||
Kiro: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300",
|
||||
@@ -339,6 +399,12 @@ export function FlowList({
|
||||
Qwen: "bg-cyan-100 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-300",
|
||||
Antigravity:
|
||||
"bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-300",
|
||||
DeepSeek:
|
||||
"bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300",
|
||||
Llama:
|
||||
"bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300",
|
||||
Mistral:
|
||||
"bg-teal-100 text-teal-700 dark:bg-teal-900/30 dark:text-teal-300",
|
||||
};
|
||||
return (
|
||||
colors[provider] ||
|
||||
@@ -553,6 +619,7 @@ export function FlowList({
|
||||
onCopyId={(e) => handleCopyId(e, flow.id)}
|
||||
getStateIcon={getStateIcon}
|
||||
getProviderColor={getProviderColor}
|
||||
getDisplayProvider={getDisplayProvider}
|
||||
formatTime={formatTime}
|
||||
/>
|
||||
))}
|
||||
@@ -605,6 +672,7 @@ interface FlowListItemProps {
|
||||
onCopyId: (e: React.MouseEvent) => void;
|
||||
getStateIcon: (state: FlowState) => React.ReactNode;
|
||||
getProviderColor: (provider: string) => string;
|
||||
getDisplayProvider: (metadataProvider: string, model: string) => string;
|
||||
formatTime: (timestamp: string) => string;
|
||||
}
|
||||
|
||||
@@ -619,6 +687,7 @@ function FlowListItem({
|
||||
onCopyId,
|
||||
getStateIcon,
|
||||
getProviderColor,
|
||||
getDisplayProvider,
|
||||
formatTime,
|
||||
}: FlowListItemProps) {
|
||||
const hasToolCalls =
|
||||
@@ -669,14 +738,27 @@ function FlowListItem({
|
||||
</span>
|
||||
|
||||
{/* 提供商 */}
|
||||
<span
|
||||
className={cn(
|
||||
"text-xs px-2 py-0.5 rounded-full shrink-0",
|
||||
getProviderColor(flow.metadata.provider),
|
||||
)}
|
||||
>
|
||||
{flow.metadata.provider}
|
||||
</span>
|
||||
{(() => {
|
||||
const displayProvider = getDisplayProvider(
|
||||
flow.metadata.provider,
|
||||
flow.request.model,
|
||||
);
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"text-xs px-2 py-0.5 rounded-full shrink-0",
|
||||
getProviderColor(displayProvider),
|
||||
)}
|
||||
title={
|
||||
displayProvider !== flow.metadata.provider
|
||||
? `凭证池: ${flow.metadata.provider}`
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{displayProvider}
|
||||
</span>
|
||||
);
|
||||
})()}
|
||||
|
||||
{/* 模型 */}
|
||||
<span className="text-sm font-medium truncate flex-1 min-w-0">
|
||||
|
||||
Reference in New Issue
Block a user