tarujain8 commited on
Commit
2cb0d12
ยท
1 Parent(s): a3400d1

feat: implement backend agent modules for relationship analysis, strategy, guardrails, perspective detection, and OCR services

Browse files
backend/agents/analyst.py CHANGED
@@ -1,5 +1,8 @@
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
 
 
 
3
 
4
  ANALYST_PROMPT = """
5
  You are Velra, an elite relationship profiler. You must distinguish between "Playful Tension" and "Hostile Dismissiveness" using behavioral evidence, NOT names.
@@ -48,6 +51,14 @@ Return ONLY valid JSON.
48
  """
49
 
50
  def analyze_conversation(chat, feelings=""):
51
- llm = get_llm()
52
- prompt = ANALYST_PROMPT.format(chat=chat, feelings=feelings)
53
- return safe_invoke(llm, prompt)
 
 
 
 
 
 
 
 
 
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
3
+ from backend.core.logger import get_logger
4
+
5
+ logger = get_logger(__name__)
6
 
7
  ANALYST_PROMPT = """
8
  You are Velra, an elite relationship profiler. You must distinguish between "Playful Tension" and "Hostile Dismissiveness" using behavioral evidence, NOT names.
 
51
  """
52
 
53
  def analyze_conversation(chat, feelings=""):
54
+ try:
55
+ logger.info("Starting conversation analysis")
56
+ llm = get_llm()
57
+ prompt = ANALYST_PROMPT.format(chat=chat, feelings=feelings)
58
+ response = safe_invoke(llm, prompt)
59
+ logger.info(f"LLM Response: {response}")
60
+ return response
61
+ except Exception as e:
62
+ logger.error(f"Error in analyze_conversation: {str(e)}")
63
+ return f"[ERROR] {str(e)}"
64
+
backend/agents/gaurdrail.py CHANGED
@@ -1,107 +1,116 @@
1
- RELATIONSHIP_KEYWORDS = [
2
-
3
- # relationships
4
- "boyfriend",
5
- "girlfriend",
6
- "dating",
7
- "relationship",
8
- "situationship",
9
- "partner",
10
- "ex",
11
-
12
- # emotional communication
13
- "love",
14
- "feelings",
15
- "emotion",
16
- "sad",
17
- "hurt",
18
- "confused",
19
- "mixed signals",
20
- "ghosting",
21
- "dry texting",
22
- "attachment",
23
-
24
- # texting/chat dynamics
25
- "text",
26
- "chat",
27
- "message",
28
- "reply",
29
- "left on read",
30
- "ignored",
31
-
32
- # conflict/emotional tension
33
- "argument",
34
- "fight",
35
- "conflict",
36
- "distance",
37
- "cold",
38
- "avoidant",
39
- "anxious",
40
-
41
- # common conversational indicators
42
- "hey",
43
- "okay",
44
- "sorry",
45
- "why are you",
46
- "are you",
47
- "miss you",
48
- "coming",
49
- "meeting",
50
- ]
51
-
52
- BLOCKED_KEYWORDS = [
53
-
54
- "python",
55
- "javascript",
56
- "coding",
57
- "programming",
58
- "math",
59
- "physics",
60
- "chemistry",
61
- "politics",
62
- "religion",
63
- "hacking",
64
- "sql",
65
- "docker",
66
- "kubernetes",
67
- "algorithm",
68
- ]
69
-
70
-
71
- def validate_domain(user_input: str):
72
-
73
- text = user_input.lower()
74
-
75
- # -----------------------------------
76
- # BLOCK CLEARLY TECHNICAL INPUTS
77
- # -----------------------------------
78
-
79
- for word in BLOCKED_KEYWORDS:
80
-
81
- if word in text:
82
- return "OUT_OF_SCOPE"
83
-
84
- # -----------------------------------
85
- # ALLOW RELATIONSHIP / CHAT INPUTS
86
- # -----------------------------------
87
-
88
- for word in RELATIONSHIP_KEYWORDS:
89
-
90
- if word in text:
91
- return "ALLOWED"
92
-
93
- # -----------------------------------
94
- # HEURISTIC:
95
- # RAW CHAT DETECTION
96
- # -----------------------------------
97
-
98
- colon_count = text.count(":")
99
-
100
- if colon_count >= 2:
101
- return "ALLOWED"
102
-
103
- # -----------------------------------
104
- # DEFAULT
105
- # -----------------------------------
106
-
107
- return "ALLOWED"
 
 
 
 
 
 
 
 
 
 
1
+ from backend.core.logger import get_logger
2
+
3
+ logger = get_logger(__name__)
4
+
5
+ RELATIONSHIP_KEYWORDS = [
6
+
7
+ # relationships
8
+ "boyfriend",
9
+ "girlfriend",
10
+ "dating",
11
+ "relationship",
12
+ "situationship",
13
+ "partner",
14
+ "ex",
15
+
16
+ # emotional communication
17
+ "love",
18
+ "feelings",
19
+ "emotion",
20
+ "sad",
21
+ "hurt",
22
+ "confused",
23
+ "mixed signals",
24
+ "ghosting",
25
+ "dry texting",
26
+ "attachment",
27
+
28
+ # texting/chat dynamics
29
+ "text",
30
+ "chat",
31
+ "message",
32
+ "reply",
33
+ "left on read",
34
+ "ignored",
35
+
36
+ # conflict/emotional tension
37
+ "argument",
38
+ "fight",
39
+ "conflict",
40
+ "distance",
41
+ "cold",
42
+ "avoidant",
43
+ "anxious",
44
+
45
+ # common conversational indicators
46
+ "hey",
47
+ "okay",
48
+ "sorry",
49
+ "why are you",
50
+ "are you",
51
+ "miss you",
52
+ "coming",
53
+ "meeting",
54
+ ]
55
+
56
+ BLOCKED_KEYWORDS = [
57
+
58
+ "python",
59
+ "javascript",
60
+ "coding",
61
+ "programming",
62
+ "math",
63
+ "physics",
64
+ "chemistry",
65
+ "politics",
66
+ "religion",
67
+ "hacking",
68
+ "sql",
69
+ "docker",
70
+ "kubernetes",
71
+ "algorithm",
72
+ ]
73
+
74
+
75
+ def validate_domain(user_input: str):
76
+ try:
77
+ logger.info(f"Validating domain for input of length {len(user_input)}")
78
+ text = user_input.lower()
79
+
80
+ # -----------------------------------
81
+ # BLOCK CLEARLY TECHNICAL INPUTS
82
+ # -----------------------------------
83
+
84
+ for word in BLOCKED_KEYWORDS:
85
+ if word in text:
86
+ logger.info(f"Blocked keyword detected: {word}")
87
+ return "OUT_OF_SCOPE"
88
+
89
+ # -----------------------------------
90
+ # ALLOW RELATIONSHIP / CHAT INPUTS
91
+ # -----------------------------------
92
+
93
+ for word in RELATIONSHIP_KEYWORDS:
94
+ if word in text:
95
+ logger.info(f"Relationship keyword detected: {word}")
96
+ return "ALLOWED"
97
+
98
+ # -----------------------------------
99
+ # HEURISTIC:
100
+ # RAW CHAT DETECTION
101
+ # -----------------------------------
102
+
103
+ colon_count = text.count(":")
104
+
105
+ if colon_count >= 2:
106
+ logger.info(f"Heuristic match: {colon_count} colons found")
107
+ return "ALLOWED"
108
+
109
+ # -----------------------------------
110
+ # DEFAULT
111
+ # -----------------------------------
112
+
113
+ return "ALLOWED"
114
+ except Exception as e:
115
+ logger.error(f"Error in validate_domain: {str(e)}")
116
+ return "ALLOWED" # Default to allowed on error to avoid blocking users
backend/agents/perspective.py CHANGED
@@ -1,5 +1,8 @@
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
 
 
 
3
 
4
  PERSPECTIVE_PROMPT = """
5
  You are Velra's Perspective Detection Engine.
@@ -36,9 +39,17 @@ Return ONLY the raw JSON without markdown fences.
36
  """
37
 
38
  def detect_perspective(chat, feelings):
39
- llm = get_llm()
40
- chat_block = chat if chat and str(chat).strip() else "No conversation provided."
41
- feelings_block = feelings if feelings and str(feelings).strip() else "No explicit feelings provided."
42
-
43
- prompt = PERSPECTIVE_PROMPT.format(chat=chat_block, feelings=feelings_block)
44
- return safe_invoke(llm, prompt)
 
 
 
 
 
 
 
 
 
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
3
+ from backend.core.logger import get_logger
4
+
5
+ logger = get_logger(__name__)
6
 
7
  PERSPECTIVE_PROMPT = """
8
  You are Velra's Perspective Detection Engine.
 
39
  """
40
 
41
  def detect_perspective(chat, feelings):
42
+ try:
43
+ logger.info("Starting perspective detection")
44
+ llm = get_llm()
45
+ chat_block = chat if chat and str(chat).strip() else "No conversation provided."
46
+ feelings_block = feelings if feelings and str(feelings).strip() else "No explicit feelings provided."
47
+
48
+ prompt = PERSPECTIVE_PROMPT.format(chat=chat_block, feelings=feelings_block)
49
+ response = safe_invoke(llm, prompt)
50
+ logger.info(f"LLM Response: {response}")
51
+ return response
52
+ except Exception as e:
53
+ logger.error(f"Error in detect_perspective: {str(e)}")
54
+ return f"[ERROR] {str(e)}"
55
+
backend/agents/psychology.py CHANGED
@@ -1,5 +1,8 @@
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
 
 
 
3
 
4
  PSYCHOLOGY_PROMPT = """
5
  You are Velra, an elite psychological profiler. You calculate compatibility based on BEHAVIORAL ALIGNMENT.
@@ -45,6 +48,14 @@ Return ONLY valid JSON.
45
  """
46
 
47
  def analyze_psychology(chat, feelings):
48
- llm = get_llm()
49
- prompt = PSYCHOLOGY_PROMPT.format(chat=chat, feelings=feelings)
50
- return safe_invoke(llm, prompt)
 
 
 
 
 
 
 
 
 
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
3
+ from backend.core.logger import get_logger
4
+
5
+ logger = get_logger(__name__)
6
 
7
  PSYCHOLOGY_PROMPT = """
8
  You are Velra, an elite psychological profiler. You calculate compatibility based on BEHAVIORAL ALIGNMENT.
 
48
  """
49
 
50
  def analyze_psychology(chat, feelings):
51
+ try:
52
+ logger.info("Starting psychology analysis")
53
+ llm = get_llm()
54
+ prompt = PSYCHOLOGY_PROMPT.format(chat=chat, feelings=feelings)
55
+ response = safe_invoke(llm, prompt)
56
+ logger.info(f"LLM Response: {response}")
57
+ return response
58
+ except Exception as e:
59
+ logger.error(f"Error in analyze_psychology: {str(e)}")
60
+ return f"[ERROR] {str(e)}"
61
+
backend/agents/strategy.py CHANGED
@@ -1,5 +1,8 @@
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
 
 
 
3
 
4
  STRATEGY_PROMPT = """
5
  You are Velra, the ultimate relationship strategist.
@@ -39,6 +42,14 @@ Return ONLY valid JSON.
39
  """
40
 
41
  def generate_strategy(context):
42
- llm = get_llm()
43
- prompt = STRATEGY_PROMPT.format(context=context)
44
- return safe_invoke(llm, prompt)
 
 
 
 
 
 
 
 
 
1
  from backend.llm.factory import get_llm
2
  from backend.utils import safe_invoke
3
+ from backend.core.logger import get_logger
4
+
5
+ logger = get_logger(__name__)
6
 
7
  STRATEGY_PROMPT = """
8
  You are Velra, the ultimate relationship strategist.
 
42
  """
43
 
44
  def generate_strategy(context):
45
+ try:
46
+ logger.info("Starting strategy generation")
47
+ llm = get_llm()
48
+ prompt = STRATEGY_PROMPT.format(context=context)
49
+ response = safe_invoke(llm, prompt)
50
+ logger.info(f"LLM Response: {response}")
51
+ return response
52
+ except Exception as e:
53
+ logger.error(f"Error in generate_strategy: {str(e)}")
54
+ return f"[ERROR] {str(e)}"
55
+
backend/services/ocr_service.py CHANGED
@@ -1,19 +1,25 @@
1
- import pytesseract
2
- from PIL import Image
3
-
4
- # ๐Ÿ‘‡ ADD THIS LINE (VERY IMPORTANT FOR WINDOWS)
5
- # pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
6
-
7
-
8
- def extract_text_from_images(image_paths):
9
- texts = []
10
-
11
- for path in image_paths:
12
- try:
13
- img = Image.open(path)
14
- text = pytesseract.image_to_string(img)
15
- texts.append(text)
16
- except:
17
- texts.append("")
18
-
19
- return "\n".join(texts)
 
 
 
 
 
 
 
1
+ import pytesseract
2
+ from PIL import Image
3
+ from backend.core.logger import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+ # ๐Ÿ‘‡ ADD THIS LINE (VERY IMPORTANT FOR WINDOWS)
8
+ # pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
9
+
10
+
11
+ def extract_text_from_images(image_paths):
12
+ logger.info(f"Starting OCR extraction for {len(image_paths)} images")
13
+ texts = []
14
+
15
+ for path in image_paths:
16
+ try:
17
+ logger.info(f"Processing image: {path}")
18
+ img = Image.open(path)
19
+ text = pytesseract.image_to_string(img)
20
+ texts.append(text)
21
+ except Exception as e:
22
+ logger.error(f"Error processing image {path}: {str(e)}")
23
+ texts.append("")
24
+
25
+ return "\n".join(texts)