File size: 2,773 Bytes
f0743f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { useMemo } from 'react';
import type { TAttachment } from 'librechat-data-provider';
import { StackedFavicons } from '~/components/Web/Sources';
import { useSearchContext } from '~/Providers';
import ProgressText from './ProgressText';
import { useLocalize } from '~/hooks';

type ProgressKeys =
  | 'com_ui_web_searching'
  | 'com_ui_web_searching_again'
  | 'com_ui_web_search_processing'
  | 'com_ui_web_search_reading';

export default function WebSearch({
  initialProgress: progress = 0.1,
  isSubmitting,
  isLast,
  output,
}: {
  isLast?: boolean;
  isSubmitting: boolean;
  output?: string | null;
  initialProgress: number;
  attachments?: TAttachment[];
}) {
  const localize = useLocalize();
  const { searchResults } = useSearchContext();
  const error = typeof output === 'string' && output.toLowerCase().includes('error processing');
  const cancelled = (!isSubmitting && progress < 1) || error === true;

  const complete = !isLast && progress === 1;
  const finalizing = isSubmitting && isLast && progress === 1;
  const processedSources = useMemo(() => {
    if (complete && !finalizing) {
      return [];
    }
    if (!searchResults) return [];
    const values = Object.values(searchResults);
    const result = values[values.length - 1];
    if (!result) return [];
    if (finalizing) {
      return [...(result.organic || []), ...(result.topStories || [])];
    }
    return [...(result.organic || []), ...(result.topStories || [])].filter(
      (source) => source.processed === true,
    );
  }, [searchResults, complete, finalizing]);
  const turns = useMemo(() => {
    if (!searchResults) return 0;
    return Object.values(searchResults).length;
  }, [searchResults]);

  const clampedProgress = useMemo(() => {
    return Math.min(progress, 0.99);
  }, [progress]);

  const showSources = processedSources.length > 0;
  const progressText = useMemo(() => {
    let text: ProgressKeys = turns > 1 ? 'com_ui_web_searching_again' : 'com_ui_web_searching';
    if (showSources) {
      text = 'com_ui_web_search_processing';
    }
    if (finalizing) {
      text = 'com_ui_web_search_reading';
    }
    return localize(text);
  }, [turns, localize, showSources, finalizing]);

  if (complete || cancelled) {
    return null;
  }
  return (
    <>
      <div className="relative my-2.5 flex size-5 shrink-0 items-center gap-2.5">
        {showSources && (
          <div className="mr-2">
            <StackedFavicons sources={processedSources} start={-5} />
          </div>
        )}
        <ProgressText
          finishedText=""
          hasInput={false}
          error={cancelled}
          isExpanded={false}
          progress={clampedProgress}
          inProgressText={progressText}
        />
      </div>
    </>
  );
}