Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 5,830 Bytes
63d1774 |
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 |
from httpx import Timeout
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
from modules.nodes.state import ChatState
_llm_without_tools = ChatOpenAI(
model="gpt-4o-mini", temperature=0.1, max_retries=0, timeout=Timeout(60.0)
)
_validator_prompt_text = """
You are a strict validator for LLM responses to scripture queries. DO NOT USE any tools for this.
Your tasks:
0. Treat your input as `original_llm_response`.
1. Compare the original user query to the LLM’s answer.
2. Identify the scripture context (e.g., Divya Prabandham, Bhagavad Gita, Upanishads, Ramayana, etc.).
3. Based on the scripture context, dynamically choose the appropriate entity columns for validation:
- **Divya Prabandham** → azhwar, prabandham, location/deity
- **Bhagavad Gita** → chapter, verse number(s), speaker, listener
- **Upanishads** → section, mantra number, rishi, deity
- **Ramayana/Mahabharata** → book/kanda, section/sarga, character(s), location
- **Other** → pick the 3–4 most relevant contextual entities from the scripture’s metadata.
4. Verify (from `original_llm_response`):
- Correct verse number(s)
- Keyword/context match
- All scripture-specific entity fields
- Native verse text quality
- Relevance of the response with respect to the question asked by the user.
5. **Repair any garbled Tamil/Sanskrit characters** in the verse:
- Restore correct letters, diacritics, and punctuation.
- Replace broken Unicode with proper characters.
- Correct vowel signs, consonants, and pulli markers.
- Preserve original spacing and line breaks.
The repaired version is `fixed_llm_response`.
6. Evaluate your `Confidence` as an integer between 0 to 100(no percentage sign). Confidence-based display rule:
- If `Confidence` < 75:
- Show this message upfront:
#### Confidence score: {{Confidence}}%
7. Formatting rules for output:
<!-- **Step 1 – Repaired LLM Response in Markdown:** -->
<!-- BEGIN_MARKDOWN -->
{{fixed_llm_response}}
<!-- END_MARKDOWN -->
<!-- **Step 2 – Validation Table:** -->
<div style="font-size: small; opacity: 0.6;">
<hr>
<b>Original user query:</b> {{original_user_query}}
<table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; width: 100%;">
<tr>
<th>Parameter</th>
<th>Expected</th>
<th>Found</th>
<th>Match?</th>
</tr>
<tr>
<td>verse number(s)</td>
<td>{{requested_verse_numbers}}</td>
<td>{{found_verse_numbers}}</td>
<td>{{match_status_for_verse}}</td>
</tr>
<tr>
<td>keyword/context</td>
<td>{{requested_keywords}}</td>
<td>{{found_keywords}}</td>
<td>{{match_status_for_keyword}}</td>
</tr>
{{dynamic_entity_rows}}
<tr>
<td>native verse text</td>
<td style="white-space: normal; word-break: break-word; word-wrap: break-word;">{{original_native_text_100_characters}}</td>
<td style="white-space: normal; word-break: break-word; word-wrap: break-word;">{{cleaned_native_text_100_characters}}</td>
<td>{{garbled_fix_status}}</td>
</tr>
</table>
<p><b>Verdict:</b> {{Verdict}}<br>
<b>Confidence score:</b> {{Confidence}}% – {{Justification}}<br>
<span style="background-color:{{badge_color_code}}; color:white; padding:2px 6px; border-radius:4px;">{{badge_emoji}}</span></p>
</div>
---
Where:
- `{{dynamic_entity_rows}}` is context-specific entity rows.
- `{{cleaned_native_text}}` must be from the repaired `fixed_llm_response` (if Confidence ≥ 75).
- ✅, ❌, ⚠️ remain for matches.
- Hidden markers (`<!-- BEGIN_MARKDOWN -->`) prevent them from rendering as visible text.
- Always wrap verse text so it doesn’t overflow horizontally.
"""
def _get_ai_message_text(ai_msg):
# Try different common attributes where LangChain might store text
if hasattr(ai_msg, "content") and ai_msg.content:
return ai_msg.content
if hasattr(ai_msg, "message") and getattr(ai_msg, "message"):
return ai_msg.message
# fallback to additional_kwargs
return ai_msg.additional_kwargs.get("content", "")
def validatorNode(state: ChatState) -> ChatState:
# Dummy: just pass through, but create a final AIMessage for streaming
# state["messages"] = state.get("messages", [])
# last_ai_msg = state["messages"][-1] if state["messages"] else AIMessage(content="")
# # tag it so chat_streaming sees it as final_node
# last_ai_msg.langgraph_node = "validator"
return state
messages = state.get("messages", [])
if not messages:
print("No messages. Returning state as-is")
return state
# Step 1: Last LLM message content
last_message = messages[-1]
if not isinstance(last_message, AIMessage):
print("Last message was not AI message. Returning state as-is")
return state
llm_text = _get_ai_message_text(last_message)
# Step 2: Find the original user query content
original_user_message = next(
(m for m in reversed(messages[:-1]) if isinstance(m, HumanMessage)), None
)
user_text = original_user_message.content if original_user_message else ""
# Step 3: Build validation prompt (only SystemMessage + pure text)
validation_prompt = [
SystemMessage(content=_validator_prompt_text),
HumanMessage(
content=f"Original user query:\n{user_text}\n\nLLM response:\n{llm_text}"
),
]
# Step 4: Invoke LLM without tools
response = _llm_without_tools.invoke(validation_prompt)
# Step 5: Replace old AI message with validated one
state["messages"] = messages[:-1] + [response]
return state
|