Skip to content

Commit

Permalink
🐛 fix: fix 0 search results with specific search engine (#6487)
Browse files Browse the repository at this point in the history
* update

* improve plugin loading state

* improve loading style

* update favicon

* improve search display

* add search results

* fix lint
  • Loading branch information
arvinxx authored Feb 25, 2025
1 parent 237cc76 commit 74a09e2
Show file tree
Hide file tree
Showing 17 changed files with 231 additions and 147 deletions.
26 changes: 26 additions & 0 deletions src/components/WebFavicon/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Image from 'next/image';

interface WebFaviconProps {
alt?: string;
size?: number;
title?: string;
url: string;
}

const WebFavicon = ({ url, title, alt, size = 14 }: WebFaviconProps) => {
const urlObj = new URL(url);
const host = urlObj.hostname;

return (
<Image
alt={alt || title || url}
height={size}
src={`https://icons.duckduckgo.com/ip3/${host}.ico`}
style={{ borderRadius: 4 }}
unoptimized
width={size}
/>
);
};

export default WebFavicon;
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const CustomRender = memo<
const { t } = useTranslation('plugin');

const theme = useTheme();

useEffect(() => {
if (!plugin?.type || loading) return;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Suspense, memo } from 'react';

import { LOADING_FLAT } from '@/const/message';
import ErrorResponse from '@/features/Conversation/Messages/Assistant/Tool/Render/ErrorResponse';
import { useChatStore } from '@/store/chat';
import { chatSelectors } from '@/store/chat/selectors';
Expand Down Expand Up @@ -28,6 +29,11 @@ const Render = memo<RenderProps>(
return <ErrorResponse {...toolMessage.error} id={messageId} plugin={toolMessage.plugin} />;
}

// 如果是 LOADING_FLAT 则说明还在加载中
// 而 standalone 模式的插件 content 应该始终是 LOADING_FLAT
if (toolMessage.content === LOADING_FLAT && toolMessage.plugin?.type !== 'standalone')
return <Arguments arguments={requestArgs} shine />;

return (
<Suspense fallback={<Arguments arguments={requestArgs} shine />}>
<CustomRender
Expand Down
2 changes: 1 addition & 1 deletion src/store/chat/slices/aiChat/actions/generateAIChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ export const generateAIChat: StateCreator<
},

false,
'toggleToolCallingStreaming',
`toggleToolCallingStreaming/${!!streaming ? 'start' : 'end'}`,
);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { chatSelectors } from '@/store/chat/selectors';
import { ChatMessage } from '@/types/message';
import { DallEImageItem } from '@/types/tool/dalle';

import { useChatStore } from '../../store';
import { useChatStore } from '../../../store';

describe('chatToolSlice', () => {
describe('chatToolSlice - dalle', () => {
describe('generateImageFromPrompts', () => {
it('should generate images from prompts, update items, and upload images', async () => {
const { result } = renderHook(() => useChatStore());
Expand Down
126 changes: 126 additions & 0 deletions src/store/chat/slices/builtinTool/actions/dalle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { produce } from 'immer';
import pMap from 'p-map';
import { SWRResponse } from 'swr';
import { StateCreator } from 'zustand/vanilla';

import { useClientDataSWR } from '@/libs/swr';
import { fileService } from '@/services/file';
import { imageGenerationService } from '@/services/textToImage';
import { uploadService } from '@/services/upload';
import { chatSelectors } from '@/store/chat/selectors';
import { ChatStore } from '@/store/chat/store';
import { useFileStore } from '@/store/file';
import { DallEImageItem } from '@/types/tool/dalle';


import { setNamespace } from '@/utils/storeDebug';

const n = setNamespace('tool');

const SWR_FETCH_KEY = 'FetchImageItem';

export interface ChatDallEAction {
generateImageFromPrompts: (items: DallEImageItem[], id: string) => Promise<void>;
text2image: (id: string, data: DallEImageItem[]) => Promise<void>;
toggleDallEImageLoading: (key: string, value: boolean) => void;
updateImageItem: (id: string, updater: (data: DallEImageItem[]) => void) => Promise<void>;
useFetchDalleImageItem: (id: string) => SWRResponse;
}

export const dalleSlice: StateCreator<
ChatStore,
[['zustand/devtools', never]],
[],
ChatDallEAction
> = (set, get) => ({
generateImageFromPrompts: async (items, messageId) => {
const { toggleDallEImageLoading, updateImageItem } = get();
// eslint-disable-next-line unicorn/consistent-function-scoping
const getMessageById = (id: string) => chatSelectors.getMessageById(id)(get());

const message = getMessageById(messageId);
if (!message) return;

const parent = getMessageById(message!.parentId!);
const originPrompt = parent?.content;
let errorArray: any[] = [];

await pMap(items, async (params, index) => {
toggleDallEImageLoading(messageId + params.prompt, true);

let url = '';
try {
url = await imageGenerationService.generateImage(params);
} catch (e) {
toggleDallEImageLoading(messageId + params.prompt, false);
errorArray[index] = e;

await get().updatePluginState(messageId, { error: errorArray });
}

if (!url) return;

await updateImageItem(messageId, (draft) => {
draft[index].previewUrl = url;
});

toggleDallEImageLoading(messageId + params.prompt, false);
const imageFile = await uploadService.getImageFileByUrlWithCORS(
url,
`${originPrompt || params.prompt}_${index}.png`,
);

const data = await useFileStore.getState().uploadWithProgress({
file: imageFile,
});

if (!data) return;

await updateImageItem(messageId, (draft) => {
draft[index].imageId = data.id;
draft[index].previewUrl = undefined;
});
});
},
text2image: async (id, data) => {
// const isAutoGen = settingsSelectors.isDalleAutoGenerating(useGlobalStore.getState());
// if (!isAutoGen) return;

await get().generateImageFromPrompts(data, id);
},

toggleDallEImageLoading: (key, value) => {
set(
{ dalleImageLoading: { ...get().dalleImageLoading, [key]: value } },
false,
n('toggleDallEImageLoading'),
);
},

updateImageItem: async (id, updater) => {
const message = chatSelectors.getMessageById(id)(get());
if (!message) return;

const data: DallEImageItem[] = JSON.parse(message.content);

const nextContent = produce(data, updater);
await get().internal_updateMessageContent(id, JSON.stringify(nextContent));
},

useFetchDalleImageItem: (id) =>
useClientDataSWR([SWR_FETCH_KEY, id], async () => {
const item = await fileService.getFile(id);

set(
produce((draft) => {
if (draft.dalleImageMap[id]) return;

draft.dalleImageMap[id] = item;
}),
false,
n('useFetchFile'),
);

return item;
}),
});
18 changes: 18 additions & 0 deletions src/store/chat/slices/builtinTool/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { StateCreator } from 'zustand/vanilla';

import { ChatStore } from '@/store/chat/store';

import { ChatDallEAction, dalleSlice } from './dalle';
import { SearchAction, searchSlice } from './searXNG';

export interface ChatBuiltinToolAction extends ChatDallEAction, SearchAction {}

export const chatToolSlice: StateCreator<
ChatStore,
[['zustand/devtools', never]],
[],
ChatBuiltinToolAction
> = (...params) => ({
...dalleSlice(...params),
...searchSlice(...params),
});
Loading

0 comments on commit 74a09e2

Please sign in to comment.