File size: 5,892 Bytes
c2adf08
3299552
 
 
 
c2adf08
 
 
3299552
 
c2adf08
 
3299552
c2adf08
 
 
 
 
 
3299552
 
c2adf08
 
 
3299552
 
 
a87bd5a
c2adf08
 
 
3299552
c2adf08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3299552
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c2adf08
 
 
 
 
 
 
 
 
a87bd5a
c2adf08
 
 
 
 
a87bd5a
c2adf08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3299552
 
 
 
 
 
c2adf08
 
 
 
 
 
 
 
 
3299552
c2adf08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3299552
 
 
 
 
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import React, { useState, useEffect } from 'react';
import { 
  Box, 
  Paper, 
  Typography, 
  IconButton,
  Alert,
  Grid
} from '@mui/material';
import styled from '@emotion/styled';
import { saveFeedback } from '../../services/search';
import { useAuth } from '../../hooks/useAuth';

const ResultCard = styled(Paper)(({ theme }) => ({
  padding: theme.spacing(3),
  height: '100%',
  display: 'flex',
  flexDirection: 'column',
  position: 'relative',
}));

const EmojiButton = styled(IconButton)(({ theme }) => ({
  fontSize: '1.5rem',
  padding: theme.spacing(1),
}));

const SearchResults = ({ results, query, isLoading, error }) => {
  const { user, authTokens, userType } = useAuth();
  const [shuffledResults, setShuffledResults] = useState([]);
  const [feedbackStatus, setFeedbackStatus] = useState({});
  const [savingFeedback, setSavingFeedback] = useState(false);

  // Shuffle and limit to 2 results when results change
  useEffect(() => {
    if (results && results.length) {
      // Get one result from each model type if possible
      const bgeResult = results.find(r => r.model_type?.includes('BGE'));
      const uaeResult = results.find(r => r.model_type?.includes('UAE'));
      
      let selectedResults = [];
      if (bgeResult && uaeResult) {
        selectedResults = [bgeResult, uaeResult];
      } else {
        // If we don't have both models, take top 2 (or all if less than 2)
        selectedResults = results.slice(0, 2);
      }
      
      // Randomly shuffle the order
      const shuffled = [...selectedResults].sort(() => Math.random() - 0.5);
      
      // Assign labels (A and B)
      setShuffledResults(shuffled.map((result, index) => ({
        ...result,
        resultLabel: index === 0 ? 'A' : 'B'
      })));

      // Reset feedback status
      setFeedbackStatus({});
    } else {
      setShuffledResults([]);
    }
  }, [results]);

  if (error) {
    return (
      <Alert severity="error" sx={{ my: 2 }}>
        {error}
      </Alert>
    );
  }

  if (!results || results.length === 0) {
    return (
      <Typography variant="body1" color="textSecondary" align="center" sx={{ my: 4 }}>
        No results found. Try a different query.
      </Typography>
    );
  }

  const handleReaction = async (result, reaction) => {
    // Prevent multiple submissions
    if (feedbackStatus[result.resultLabel] || savingFeedback) return;
    
    setSavingFeedback(true);
    
    try {
      // Prepare feedback data
      const feedbackData = {
        user_type: userType, // Use userType from auth context instead of hardcoded 'user'
        username: user || 'anonymous',
        query: query || '',
        retrieved_text: result.content || result.text || JSON.stringify(result),
        model_type: result.model_type || 'unknown',
        result_label: result.resultLabel || '',
        reaction: reaction, // Save the emoji directly instead of converting to text
        confidence_score: result.similarity || 0, // Send the model confidence score
      };

      // Save the feedback
      await saveFeedback(feedbackData, authTokens.access);
      
      // Update UI to show feedback was saved
      setFeedbackStatus(prev => ({
        ...prev,
        [result.resultLabel]: { status: 'success', reaction }
      }));
      
    } catch (err) {
      console.error("Feedback submission error:", err);
      setFeedbackStatus(prev => ({
        ...prev,
        [result.resultLabel]: { status: 'error', message: 'Failed to save feedback' }
      }));
    } finally {
      setSavingFeedback(false);
    }
  };

  return (
    <Box>
      <Typography variant="h6" gutterBottom>
        Search Results
      </Typography>
      
      <Grid container spacing={3} sx={{ mb: 4 }}>
        {shuffledResults.map((result) => (
          <Grid item xs={12} md={6} key={result.resultLabel}>
            <ResultCard elevation={3}>
              <Typography variant="h6" gutterBottom>
                Result {result.resultLabel}
              </Typography>
              <Typography variant="body1" paragraph sx={{ flexGrow: 1 }}>
                {result.text}
              </Typography>
              
              <Box mt={2}>
                {feedbackStatus[result.resultLabel]?.status === 'success' ? (
                  <Typography variant="body2" color="success.main" align="center">
                    Thank you for your feedback! You selected {feedbackStatus[result.resultLabel].reaction}
                  </Typography>
                ) : feedbackStatus[result.resultLabel]?.status === 'error' ? (
                  <Typography variant="body2" color="error" align="center">
                    {feedbackStatus[result.resultLabel].message}
                  </Typography>
                ) : (
                  <Box display="flex" justifyContent="center" gap={2}>
                    <EmojiButton 
                      onClick={() => handleReaction(result, 'πŸ‘')} 
                      disabled={savingFeedback}
                      aria-label="Good result"
                    >
                      πŸ‘
                    </EmojiButton>
                    <EmojiButton 
                      onClick={() => handleReaction(result, 'πŸ€·β€β™‚οΈ')} 
                      disabled={savingFeedback}
                      aria-label="Somewhat relevant"
                    >
                      πŸ€·β€β™‚οΈ
                    </EmojiButton>
                    <EmojiButton 
                      onClick={() => handleReaction(result, 'πŸ‘Ž')} 
                      disabled={savingFeedback}
                      aria-label="Not relevant"
                    >
                      πŸ‘Ž
                    </EmojiButton>
                  </Box>
                )}
              </Box>
            </ResultCard>
          </Grid>
        ))}
      </Grid>
    </Box>
  );
};

export default SearchResults;