fix(PictureService, SearchDialog): enhance vector search with error handling and tab management #9

This commit is contained in:
shiyu
2025-05-25 11:58:04 +08:00
parent 27a59e8938
commit 6866580dce
2 changed files with 101 additions and 60 deletions
+39 -3
View File
@@ -49,20 +49,33 @@ public class PictureService(
// 决定是使用向量搜索还是普通搜索 // 决定是使用向量搜索还是普通搜索
if (useVectorSearch && !string.IsNullOrWhiteSpace(searchQuery)) if (useVectorSearch && !string.IsNullOrWhiteSpace(searchQuery))
{
try
{ {
return await PerformVectorSearchAsync( return await PerformVectorSearchAsync(
dbContext, page, pageSize, searchQuery, tags, dbContext, page, pageSize, searchQuery, tags,
startDate, endDate, userId, onlyWithGps, similarityThreshold, startDate, endDate, userId, onlyWithGps, similarityThreshold,
excludeAlbumId, albumId, onlyFavorites, ownerId, includeAllPublic); excludeAlbumId, albumId, onlyFavorites, ownerId, includeAllPublic);
} }
else catch (Exception ex)
{ {
// 如果向量搜索失败,记录错误并回退到标准搜索
Console.WriteLine($"向量搜索失败,回退到标准搜索: {ex.Message}");
// 如果是明确的配置错误,则向上抛出异常
if (ex.Message.Contains("请检查嵌入模型配置"))
{
throw;
}
}
}
// 执行标准搜索(作为默认方法或向量搜索的回退选项)
return await PerformStandardSearchAsync( return await PerformStandardSearchAsync(
dbContext, page, pageSize, searchQuery, tags, dbContext, page, pageSize, searchQuery, tags,
startDate, endDate, userId, sortBy, onlyWithGps, startDate, endDate, userId, sortBy, onlyWithGps,
excludeAlbumId, albumId, onlyFavorites, ownerId, includeAllPublic); excludeAlbumId, albumId, onlyFavorites, ownerId, includeAllPublic);
} }
}
// 执行向量搜索 // 执行向量搜索
private async Task<PaginatedResult<PictureResponse>> PerformVectorSearchAsync( private async Task<PaginatedResult<PictureResponse>> PerformVectorSearchAsync(
@@ -82,7 +95,24 @@ public class PictureService(
int? ownerId, int? ownerId,
bool includeAllPublic) bool includeAllPublic)
{ {
var queryEmbedding = await embeddingService.GetEmbeddingAsync(searchQuery); try
{
float[]? queryEmbedding = null;
try
{
queryEmbedding = await embeddingService.GetEmbeddingAsync(searchQuery);
// 检查嵌入向量是否有效
if (queryEmbedding == null || queryEmbedding.Length == 0)
{
throw new InvalidOperationException("嵌入模型返回了空向量");
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"向量搜索失败,请检查嵌入模型配置: {ex.Message}", ex);
}
var queryVector = new Vector(queryEmbedding); var queryVector = new Vector(queryEmbedding);
// 构建基础查询 // 构建基础查询
@@ -132,6 +162,12 @@ public class PictureService(
TotalCount = totalCount TotalCount = totalCount
}; };
} }
catch (Exception ex)
{
Console.WriteLine($"向量搜索失败: {ex.Message}");
throw new InvalidOperationException($"向量搜索失败: {ex.Message}", ex);
}
}
// 执行标准搜索 // 执行标准搜索
private async Task<PaginatedResult<PictureResponse>> PerformStandardSearchAsync( private async Task<PaginatedResult<PictureResponse>> PerformStandardSearchAsync(
+12 -7
View File
@@ -126,6 +126,17 @@ const SearchDialog: React.FC<SearchDialogProps> = ({
} }
}; };
// 处理标签页切换,同时更新 useVectorSearch 状态
const handleTabChange = (key: string) => {
setActiveTabKey(key);
// 根据标签页自动设置向量搜索状态
if (key === 'vector') {
setUseVectorSearch(true);
} else {
setUseVectorSearch(false);
}
};
return ( return (
<Modal <Modal
title={ title={
@@ -143,7 +154,7 @@ const SearchDialog: React.FC<SearchDialogProps> = ({
> >
<Tabs <Tabs
activeKey={activeTabKey} activeKey={activeTabKey}
onChange={setActiveTabKey} onChange={handleTabChange}
className="search-tabs" className="search-tabs"
items={[ items={[
{ {
@@ -163,9 +174,6 @@ const SearchDialog: React.FC<SearchDialogProps> = ({
autoFocus={activeTabKey === 'text'} autoFocus={activeTabKey === 'text'}
/> />
</div> </div>
<Divider orientation="left" plain></Divider>
<div className="search-option-group"> <div className="search-option-group">
<Text strong className="option-label">:</Text> <Text strong className="option-label">:</Text>
<Select <Select
@@ -212,9 +220,6 @@ const SearchDialog: React.FC<SearchDialogProps> = ({
autoFocus={activeTabKey === 'vector'} autoFocus={activeTabKey === 'vector'}
/> />
</div> </div>
<Divider orientation="left" plain></Divider>
<div className="search-option-group vector-options"> <div className="search-option-group vector-options">
<div className="vector-switch-container"> <div className="vector-switch-container">
<Switch <Switch