|
|
from langchain.prompts import PromptTemplate
|
|
|
from backend.langchain_tools import llm, deepseek_tool
|
|
|
from langchain_core.runnables import RunnableSequence
|
|
|
import json
|
|
|
import logging
|
|
|
import re
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
|
|
|
tone_intent_prompt = PromptTemplate.from_template("""
|
|
|
You are an expert language analyst trained to detect the tone and intent of a given piece of text. Your task is to analyze the text and determine both its tone and intent from the following predefined categories:
|
|
|
|
|
|
Tone Categories:
|
|
|
1. Neutral
|
|
|
2. Sarcastic
|
|
|
3. Clickbait
|
|
|
4. Propaganda
|
|
|
5. Aggressive / Toxic
|
|
|
6. Persuasive
|
|
|
7. Humorous
|
|
|
|
|
|
Intent Categories:
|
|
|
1. To Inform
|
|
|
2. To Persuade
|
|
|
3. To Deceive
|
|
|
4. To Express Emotion
|
|
|
5. To Incite Hate
|
|
|
6. To Promote Agenda
|
|
|
|
|
|
Text: "{text}"
|
|
|
|
|
|
Respond in JSON format:
|
|
|
{{
|
|
|
"tone": "<one of: Neutral, Sarcastic, Clickbait, Propaganda, Aggressive / Toxic, Persuasive, Humorous>",
|
|
|
"intent": "<one of: To Inform, To Persuade, To Deceive, To Express Emotion, To Incite Hate, To Promote Agenda>",
|
|
|
"reasoning": "<brief justification for tone and intent>"
|
|
|
}}
|
|
|
""")
|
|
|
|
|
|
|
|
|
tone_intent_chain = tone_intent_prompt | llm
|
|
|
|
|
|
|
|
|
prompt_template_str = tone_intent_prompt.template
|
|
|
|
|
|
|
|
|
def detect_tone_and_intent(text: str) -> dict:
|
|
|
try:
|
|
|
result = tone_intent_chain.invoke({"text": text})
|
|
|
detection = json.loads(result.content.strip())
|
|
|
|
|
|
if 'tone' not in detection or 'intent' not in detection or 'reasoning' not in detection:
|
|
|
logging.error(f"Unexpected response format: {result.content.strip()}")
|
|
|
return {"error": "Response format is incorrect. Missing required fields."}
|
|
|
|
|
|
return detection
|
|
|
|
|
|
except Exception as e:
|
|
|
logging.error(f"Error with primary model (LLM): {str(e)}. Falling back to DeepSeek-V3.")
|
|
|
|
|
|
try:
|
|
|
|
|
|
deepseek_prompt = prompt_template_str.format(text=text)
|
|
|
|
|
|
deepseek_result = deepseek_tool.invoke({"input": deepseek_prompt})
|
|
|
logging.info(f"Raw DeepSeek Output: {deepseek_result}")
|
|
|
|
|
|
cleaned_output = re.sub(r"```(?:json)?\s*([\s\S]*?)\s*```", r"\1", deepseek_result.strip())
|
|
|
|
|
|
deepseek_detection = json.loads(cleaned_output)
|
|
|
|
|
|
if 'tone' not in deepseek_detection or 'intent' not in deepseek_detection or 'reasoning' not in deepseek_detection:
|
|
|
logging.error(f"Unexpected format from DeepSeek-V3: {cleaned_output}")
|
|
|
return {"error": "Response format from DeepSeek-V3 is incorrect. Missing required fields."}
|
|
|
|
|
|
return deepseek_detection
|
|
|
|
|
|
except Exception as fallback_e:
|
|
|
logging.error(f"Error with both LLM and DeepSeek-V3: {str(fallback_e)}")
|
|
|
return {"error": f"An error occurred with both LLM and DeepSeek-V3: {str(fallback_e)}"}
|
|
|
|
|
|
|