File size: 4,149 Bytes
cf52a55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Camada L5 — Geração de resposta em texto livre.
================================================
A partir da síntese L4 (e contexto L1–L3), gera resposta natural via LLM externo
(Groq) ou fallback para o template da L4. Opcional: LM customizado (EpistemicLanguageModel).
"""

from __future__ import annotations
import os
from typing import Optional

# Resultado da L4
try:
    from l4_synthesis import SynthesisResult
except Exception:
    SynthesisResult = None  # type: ignore


def build_context_for_generation(
    prompt: str,
    synthesis_result: "SynthesisResult",
    concepts_summary: str = "",
    top_judgments: str = "",
) -> str:
    """Monta o contexto (texto) a ser enviado ao LLM para gerar a resposta final."""
    lines = [
        "## Contexto epistemológico (L1–L4)",
        f"Pergunta do usuário: {prompt}",
        "",
        f"Resposta sintetizada (L4): {synthesis_result.response}",
        f"Valor de verdade: {synthesis_result.truth_value:.2f} | Estado: {synthesis_result.state} | Certeza: {synthesis_result.certainty:+.2f}",
        "",
    ]
    if synthesis_result.supporting_evidence:
        lines.append("Evidências de suporte:")
        for ev in synthesis_result.supporting_evidence[:5]:
            lines.append(f"  - {ev}")
        lines.append("")
    if concepts_summary:
        lines.append("Conceitos extraídos (L1):")
        lines.append(concepts_summary)
        lines.append("")
    if top_judgments:
        lines.append("Juízos relevantes (L2):")
        lines.append(top_judgments)
        lines.append("")
    lines.append("## Instrução")
    lines.append("Com base no contexto acima, elabore uma resposta final clara e precisa em português, sem repetir literalmente o texto da síntese. Seja conciso e cite a confiança quando relevante.")
    return "\n".join(lines)


def generate_with_groq(
    context: str,
    api_key: Optional[str] = None,
    model: str = "mixtral-8x7b-32768",
) -> str:
    """Gera resposta usando ChatGroq."""
    api_key = api_key or os.getenv("GROQ_API_KEY")
    if not api_key:
        return ""
    try:
        from langchain_groq import ChatGroq
        from langchain_core.messages import HumanMessage
        llm = ChatGroq(model=model, api_key=api_key, temperature=0.3)
        msg = llm.invoke([HumanMessage(content=context)])
        return msg.content if hasattr(msg, "content") else str(msg)
    except Exception:
        return ""


def generate_with_custom_lm(
    context: str,
    model_path: str,
    max_new_tokens: int = 150,
    temperature: float = 0.7,
) -> str:
    """Gera resposta usando EpistemicLanguageModel (custom_lm_model)."""
    try:
        from custom_lm_model import EpistemicLanguageModel, LMConfig, generate_text, load_lm
        from custom_tokenizer import CustomSPTokenizer, SPConfig
        import torch
        tokenizer = CustomSPTokenizer(SPConfig())
        tokenizer.load()
        vocab_size = tokenizer.vocab_size()
        model = load_lm(model_path, vocab_size)
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        out = generate_text(model, tokenizer, context, max_new_tokens=max_new_tokens, temperature=temperature, device=device)
        return out or ""
    except Exception:
        return ""


def generate_response(
    prompt: str,
    synthesis_result: "SynthesisResult",
    provider: str = "template",
    concepts_summary: str = "",
    top_judgments: str = "",
    groq_model: str = "mixtral-8x7b-32768",
    custom_lm_path: str = "",
) -> str:
    """
    Gera a resposta final em texto livre (ou template).
    provider: "groq" | "template" | "custom_lm"
    """
    context = build_context_for_generation(prompt, synthesis_result, concepts_summary, top_judgments)

    if provider == "groq":
        text = generate_with_groq(context, model=groq_model)
        if text:
            return text.strip()

    if provider == "custom_lm" and custom_lm_path:
        text = generate_with_custom_lm(context, custom_lm_path)
        if text:
            return text.strip()

    # Fallback: resposta da L4 (template)
    return synthesis_result.response