File size: 2,762 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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { createContext, useContext } from 'react';
import type { SearchRefType, ValidSource, ResultReference } from 'librechat-data-provider';
import type * as t from './types';
import { useSearchContext } from '~/Providers';

export interface CitationContextType {
  hoveredCitationId: string | null;
  setHoveredCitationId: (id: string | null) => void;
}

export const CitationContext = createContext<CitationContextType>({
  hoveredCitationId: null,
  setHoveredCitationId: () => {},
});

export function useHighlightState(citationId: string | undefined) {
  const { hoveredCitationId } = useContext(CitationContext);
  return citationId && hoveredCitationId === citationId;
}

export type CitationSource = (ValidSource | ResultReference) & {
  turn: number;
  refType: string | SearchRefType;
  index: number;
};

const refTypeMap: Record<string | SearchRefType, string> = {
  search: 'organic',
  ref: 'references',
  news: 'topStories',
  file: 'references',
};

export function useCitation({
  turn,
  index,
  refType: _refType,
}: {
  turn: number;
  index: number;
  refType?: SearchRefType | string;
}): (t.Citation & t.Reference) | undefined {
  const { searchResults } = useSearchContext();
  if (!_refType) {
    return undefined;
  }
  const refType = refTypeMap[_refType.toLowerCase()]
    ? refTypeMap[_refType.toLowerCase()]
    : _refType;

  if (!searchResults || !searchResults[turn] || !searchResults[turn][refType]) {
    return undefined;
  }

  const source: CitationSource = searchResults[turn][refType][index];

  if (!source) {
    return undefined;
  }

  return {
    ...source,
    turn,
    refType: _refType.toLowerCase(),
    index,
    link: source.link ?? '',
    title: source.title ?? '',
    snippet: source['snippet'] ?? '',
    attribution: source.attribution ?? '',
  };
}

export function useCompositeCitations(
  citations: Array<{ turn: number; refType: SearchRefType | string; index: number }>,
): Array<t.Citation & t.Reference> {
  const { searchResults } = useSearchContext();

  const result: Array<t.Citation & t.Reference> = [];

  for (const { turn, refType: _refType, index } of citations) {
    const refType = refTypeMap[_refType.toLowerCase()]
      ? refTypeMap[_refType.toLowerCase()]
      : _refType;

    if (!searchResults || !searchResults[turn] || !searchResults[turn][refType]) {
      continue;
    }
    const source: CitationSource = searchResults[turn][refType][index];
    if (!source) {
      continue;
    }

    result.push({
      ...source,
      turn,
      refType: _refType.toLowerCase(),
      index,
      link: source.link ?? '',
      title: source.title ?? '',
      snippet: source['snippet'] ?? '',
      attribution: source.attribution ?? '',
    });
  }

  return result;
}