File size: 7,045 Bytes
1b447de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"""
Expansão de Queries (Multi-Query Retrieval)

Gera múltiplas variações de uma query para melhorar cobertura da busca.
"""
import re
from typing import List, Dict, Any, Optional
from src.generation import GenerationManager


class QueryExpander:
    """Expande queries em múltiplas variações para melhor retrieval"""

    def __init__(self, generation_manager: GenerationManager):
        """
        Args:
            generation_manager: Gerenciador de geração de texto
        """
        self.generation_manager = generation_manager

    def expand_query(
        self,
        query: str,
        num_variations: int = 3,
        method: str = "llm"
    ) -> List[str]:
        """
        Expande query em múltiplas variações

        Args:
            query: Query original
            num_variations: Número de variações a gerar
            method: Método de expansão ("llm", "template", "paraphrase")

        Returns:
            Lista com query original + variações
        """
        if method == "llm":
            return self._expand_with_llm(query, num_variations)
        elif method == "template":
            return self._expand_with_templates(query, num_variations)
        elif method == "paraphrase":
            return self._expand_with_paraphrase(query, num_variations)
        else:
            return [query]

    def _expand_with_llm(self, query: str, num_variations: int) -> List[str]:
        """
        Usa LLM para gerar variações da query

        Estratégia: Pede ao LLM para reformular a pergunta de formas diferentes
        """
        prompt = f"""Você é um assistente que ajuda a reformular perguntas para melhorar buscas.

Pergunta original: "{query}"

Gere {num_variations} reformulações diferentes desta pergunta. Cada reformulação deve:
- Manter o mesmo significado e intenção
- Usar palavras e estruturas diferentes
- Ser igualmente específica

Formato de saída (uma por linha):
1. [primeira reformulação]
2. [segunda reformulação]
3. [terceira reformulação]

Reformulações:"""

        try:
            response = self.generation_manager.generate(
                prompt=prompt,
                max_tokens=200,
                temperature=0.7
            )

            # Extrai variações do response
            variations = self._parse_llm_variations(response)

            # Garante que temos pelo menos a query original
            if not variations:
                variations = [query]
            elif query not in variations:
                variations.insert(0, query)

            return variations[:num_variations + 1]  # +1 para incluir original

        except Exception as e:
            print(f"Erro ao expandir query com LLM: {e}")
            return [query]

    def _parse_llm_variations(self, response: str) -> List[str]:
        """
        Extrai variações do response do LLM

        Procura por linhas numeradas ou bullets
        """
        variations = []

        # Tenta extrair linhas numeradas: "1. texto", "2. texto"
        pattern = r'^\d+\.\s*(.+)$'
        for line in response.split('\n'):
            line = line.strip()
            match = re.match(pattern, line)
            if match:
                variation = match.group(1).strip()
                if variation:
                    variations.append(variation)

        # Se não encontrou numeradas, tenta bullets: "- texto", "* texto"
        if not variations:
            pattern = r'^[-*]\s*(.+)$'
            for line in response.split('\n'):
                line = line.strip()
                match = re.match(pattern, line)
                if match:
                    variation = match.group(1).strip()
                    if variation:
                        variations.append(variation)

        return variations

    def _expand_with_templates(self, query: str, num_variations: int) -> List[str]:
        """
        Usa templates fixos para expandir query

        Útil quando LLM não está disponível ou para casos simples
        """
        templates = [
            query,  # Original
            f"Explique sobre {query}",
            f"O que é {query}?",
            f"Como funciona {query}?",
            f"Qual a definição de {query}?",
            f"Informações sobre {query}",
        ]

        return templates[:num_variations + 1]

    def _expand_with_paraphrase(self, query: str, num_variations: int) -> List[str]:
        """
        Usa paraphrasing simples baseado em sinônimos

        Nota: Implementação básica. Para produção, considere usar
        modelo de paraphrase como T5 ou BART
        """
        # Implementação simplificada com algumas variações comuns
        variations = [query]

        # Substituições comuns em português
        substitutions = [
            ("o que é", "qual é"),
            ("como funciona", "qual o funcionamento de"),
            ("explique", "descreva"),
            ("diferença entre", "distinção entre"),
            ("vantagens", "benefícios"),
        ]

        for old, new in substitutions:
            if old in query.lower():
                variation = query.lower().replace(old, new).capitalize()
                if variation not in variations:
                    variations.append(variation)
                    if len(variations) > num_variations:
                        break

        return variations[:num_variations + 1]

    def get_expansion_info(self, method: str) -> Dict[str, Any]:
        """
        Retorna informações sobre método de expansão

        Args:
            method: Nome do método

        Returns:
            Dicionário com informações
        """
        info = {
            "llm": {
                "name": "LLM-based",
                "description": "Usa modelo de linguagem para gerar variações contextuais",
                "pros": "Variações de alta qualidade, contextuais",
                "cons": "Mais lento, requer LLM disponível",
                "best_for": "Queries complexas e conceituais"
            },
            "template": {
                "name": "Template-based",
                "description": "Usa templates fixos para reformular queries",
                "pros": "Rápido, determinístico, sem dependências",
                "cons": "Variações genéricas, pode não preservar nuances",
                "best_for": "Queries simples, prototipação rápida"
            },
            "paraphrase": {
                "name": "Paraphrase-based",
                "description": "Usa substituições de sinônimos e paráfrases",
                "pros": "Balanceado, mantém estrutura original",
                "cons": "Limitado por dicionário de sinônimos",
                "best_for": "Queries médias, quando LLM não está disponível"
            }
        }

        return info.get(method, {
            "name": method,
            "description": "Método desconhecido",
            "pros": "N/A",
            "cons": "N/A",
            "best_for": "N/A"
        })