added agent gender
Browse files- plan.md +0 -91
- python-services/conversation_manager.py +5 -0
- python-services/llm_server.py +5 -1
- python-services/prompt_builder.py +35 -1
plan.md
DELETED
|
@@ -1,91 +0,0 @@
|
|
| 1 |
-
# Project Scan & Improvement Plan
|
| 2 |
-
|
| 3 |
-
## 1. Overview
|
| 4 |
-
A static analysis of the **`c:/voice/the-brain/python-services`** package was performed. The goal is to surface:
|
| 5 |
-
- Critical bugs and runtime errors.
|
| 6 |
-
- Security concerns (PII leakage, missing environment validation).
|
| 7 |
-
- Performance bottlenecks.
|
| 8 |
-
- Code‑quality and maintainability issues.
|
| 9 |
-
- Recommendations for testing, documentation, and CI.
|
| 10 |
-
|
| 11 |
-
All file references are clickable for easy navigation.
|
| 12 |
-
|
| 13 |
-
---
|
| 14 |
-
|
| 15 |
-
## 2. Critical Bugs & Security Issues
|
| 16 |
-
| Severity | File | Line(s) | Issue | Recommendation |
|
| 17 |
-
|---|---|---|---|---|
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
| **High** | [caller_info_extractor.py](file:///c:/voice/the-brain/python-services/caller_info_extractor.py) | 46‑47 | Phone numbers are logged at `INFO` level, exposing PII. | Remove raw numbers from logs or mask them (e.g., `****1234`) and downgrade to `DEBUG`. |
|
| 21 |
-
| **High** | [utils.py](file:///c:/voice/the-brain/python-services/utils.py) | 135‑141 | `strip_formatting` removes all parenthetical text, potentially discarding spoken content. | Refine regex to only strip markdown parentheses (`[text](url)`) while preserving plain language parentheses. |
|
| 22 |
-
| **Medium** | [conversation_manager.py](file:///c:/voice/the-brain/python-services/conversation_manager.py) | 84‑86 | Hindi (`hi`) is forced to Urdu (`ur`), which may mis‑route genuine Hindi callers. | Document the rationale; make the mapping configurable. |
|
| 23 |
-
| **Medium** | [llm_server.py](file:///c:/voice/the-brain/python-services/llm_server.py) | 174‑176 | Token‑governor uses `req.sessionStart` which can be `None`, leading to misleading duration calculations. | Guard against `None` and log a warning when the timestamp is missing. |
|
| 24 |
-
|
| 25 |
-
---
|
| 26 |
-
|
| 27 |
-
## 3. High‑Priority Improvement Roadmap
|
| 28 |
-
|
| 29 |
-
1. **PII‑Safe Logging**
|
| 30 |
-
- Add a helper `mask_phone(phone: str) -> str` returning a masked version (e.g., `****1234`).
|
| 31 |
-
- Use it wherever phone numbers are logged and lower the log level to `DEBUG`.
|
| 32 |
-
2. **Typed Code & Static Checks**
|
| 33 |
-
- Add missing type hints across the code base.
|
| 34 |
-
- Integrate `mypy --strict` and `ruff`/`flake8` into CI.
|
| 35 |
-
3. **Test Suite**
|
| 36 |
-
- Add `tests/` with pytest covering:
|
| 37 |
-
- Regex extraction (`extract_phone_from_text`, `extract_name_from_text`).
|
| 38 |
-
- Language detection edge cases.
|
| 39 |
-
- Conversation session lifecycle (creation, expiration, cleanup).
|
| 40 |
-
- API endpoint sanity using FastAPI’s `TestClient`.
|
| 41 |
-
4. **Dependency Pinning**
|
| 42 |
-
- Update `requirements.txt` with explicit version numbers.
|
| 43 |
-
5. **Documentation Upgrade**
|
| 44 |
-
- Expand `README.md` with setup, run instructions, API reference, and contribution guide.
|
| 45 |
-
6. **Docker / Deploy Hygiene**
|
| 46 |
-
- Add a health‑check in the `Dockerfile` that hits `/health`.
|
| 47 |
-
- Externalise hard‑coded thresholds and model names to env vars or a config file.
|
| 48 |
-
|
| 49 |
-
---
|
| 50 |
-
|
| 51 |
-
## 4. Medium‑Priority Enhancements
|
| 52 |
-
- Lazy‑load Groq/Fireworks clients after configuration validation.
|
| 53 |
-
- Use a module‑level `ThreadPoolExecutor` for all `run_in_executor` calls to avoid per‑request thread creation.
|
| 54 |
-
- Replace duplicate `arabic_regex` definition in `utils.py` with a single compiled regex.
|
| 55 |
-
- Introduce structured JSON logging for easier aggregation.
|
| 56 |
-
- Implement exponential back‑off before falling back to Fireworks on 429 errors.
|
| 57 |
-
|
| 58 |
-
---
|
| 59 |
-
|
| 60 |
-
## 5. Low‑Priority / Nice‑to‑Have
|
| 61 |
-
- Add GitHub Actions workflow running lint, type‑check, and tests on each PR.
|
| 62 |
-
- Provide pre‑commit hooks (`black`, `ruff`).
|
| 63 |
-
- Expose OpenAPI schema (FastAPI does this automatically; just add the URL to docs).
|
| 64 |
-
- Add Prometheus metrics exporter for request latency, token usage, and error rates.
|
| 65 |
-
- Store language‑specific prompt templates in separate files for easier updates.
|
| 66 |
-
|
| 67 |
-
---
|
| 68 |
-
|
| 69 |
-
## 6. Verification Plan
|
| 70 |
-
- **Manual Review** – Walk through each changed file; confirm no raw PII appears in logs.
|
| 71 |
-
- **Automated Tests** – Run `pytest`; ensure ≥80 % coverage for core utilities.
|
| 72 |
-
- **Static Analysis** – Run `ruff` and `mypy --strict`; fix all reported issues.
|
| 73 |
-
- **Runtime Smoke Test** – Start the server (`uvicorn llm_server:app --port 7860`) and hit `/health` and `/session/start` endpoints.
|
| 74 |
-
- **Security Scan** – Simulate a request that extracts a phone number and verify logs contain only masked values.
|
| 75 |
-
|
| 76 |
-
---
|
| 77 |
-
|
| 78 |
-
## 7. Immediate Action Items (Task List)
|
| 79 |
-
- `[ ]` Create `config.py` with env‑var validation.
|
| 80 |
-
- `[ ]` Refactor `client.py` to lazily instantiate providers after config validation.
|
| 81 |
-
- `[ ]` Implement `mask_phone` and replace raw phone logs.
|
| 82 |
-
- `[ ]` Add missing type hints and run `mypy`.
|
| 83 |
-
- `[ ]` Write unit tests for regex utilities.
|
| 84 |
-
- `[ ]` Pin dependency versions in `requirements.txt`.
|
| 85 |
-
- `[ ]` Expand `README.md`.
|
| 86 |
-
- `[ ]` Add Docker health‑check.
|
| 87 |
-
- `[ ]` Externalise thresholds and model names.
|
| 88 |
-
|
| 89 |
-
---
|
| 90 |
-
|
| 91 |
-
*Prepared by Antigravity – your AI coding assistant.*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
python-services/conversation_manager.py
CHANGED
|
@@ -34,12 +34,14 @@ class ConversationSession:
|
|
| 34 |
session_id: str,
|
| 35 |
company_name: str,
|
| 36 |
agent_name: str,
|
|
|
|
| 37 |
custom_rules: List[str] = None,
|
| 38 |
document_context: str = "", # RAG payload vector string placeholder
|
| 39 |
):
|
| 40 |
self.session_id = session_id
|
| 41 |
self.company_name = company_name
|
| 42 |
self.agent_name = agent_name
|
|
|
|
| 43 |
self.custom_rules = custom_rules or []
|
| 44 |
self.document_context = document_context
|
| 45 |
|
|
@@ -151,6 +153,7 @@ class ConversationSession:
|
|
| 151 |
"session_id": self.session_id,
|
| 152 |
"company": self.company_name,
|
| 153 |
"agent": self.agent_name,
|
|
|
|
| 154 |
"language": self.get_current_language(),
|
| 155 |
"turns": self.turn_count,
|
| 156 |
"caller_info": self.caller_info.to_dict(),
|
|
@@ -172,6 +175,7 @@ class ConversationManager:
|
|
| 172 |
self,
|
| 173 |
company_name: str,
|
| 174 |
agent_name: str,
|
|
|
|
| 175 |
custom_rules: List[str] = None,
|
| 176 |
document_context: str = "",
|
| 177 |
session_id: Optional[str] = None,
|
|
@@ -183,6 +187,7 @@ class ConversationManager:
|
|
| 183 |
session_id=sid,
|
| 184 |
company_name=company_name,
|
| 185 |
agent_name=agent_name,
|
|
|
|
| 186 |
custom_rules=custom_rules,
|
| 187 |
document_context=document_context,
|
| 188 |
)
|
|
|
|
| 34 |
session_id: str,
|
| 35 |
company_name: str,
|
| 36 |
agent_name: str,
|
| 37 |
+
agent_gender: str = "female", # Added parameter
|
| 38 |
custom_rules: List[str] = None,
|
| 39 |
document_context: str = "", # RAG payload vector string placeholder
|
| 40 |
):
|
| 41 |
self.session_id = session_id
|
| 42 |
self.company_name = company_name
|
| 43 |
self.agent_name = agent_name
|
| 44 |
+
self.agent_gender = agent_gender # Store parameter
|
| 45 |
self.custom_rules = custom_rules or []
|
| 46 |
self.document_context = document_context
|
| 47 |
|
|
|
|
| 153 |
"session_id": self.session_id,
|
| 154 |
"company": self.company_name,
|
| 155 |
"agent": self.agent_name,
|
| 156 |
+
"agent_gender": self.agent_gender, # Added to summary dict
|
| 157 |
"language": self.get_current_language(),
|
| 158 |
"turns": self.turn_count,
|
| 159 |
"caller_info": self.caller_info.to_dict(),
|
|
|
|
| 175 |
self,
|
| 176 |
company_name: str,
|
| 177 |
agent_name: str,
|
| 178 |
+
agent_gender: str = "female", # Added parameter
|
| 179 |
custom_rules: List[str] = None,
|
| 180 |
document_context: str = "",
|
| 181 |
session_id: Optional[str] = None,
|
|
|
|
| 187 |
session_id=sid,
|
| 188 |
company_name=company_name,
|
| 189 |
agent_name=agent_name,
|
| 190 |
+
agent_gender=agent_gender, # Pass parameter
|
| 191 |
custom_rules=custom_rules,
|
| 192 |
document_context=document_context,
|
| 193 |
)
|
python-services/llm_server.py
CHANGED
|
@@ -66,6 +66,7 @@ manager = ConversationManager()
|
|
| 66 |
class StartSessionRequest(BaseModel):
|
| 67 |
company_name: str = "Our Company"
|
| 68 |
agent_name: str = "Sara"
|
|
|
|
| 69 |
custom_rules: List[str] = []
|
| 70 |
document_context: str = "" # RAG text block container
|
| 71 |
session_id: Optional[str] = None # Generated if missing
|
|
@@ -93,6 +94,7 @@ async def start_session(req: StartSessionRequest):
|
|
| 93 |
session = manager.create_session(
|
| 94 |
company_name=req.company_name,
|
| 95 |
agent_name=req.agent_name,
|
|
|
|
| 96 |
custom_rules=req.custom_rules,
|
| 97 |
document_context=req.document_context,
|
| 98 |
session_id=req.session_id,
|
|
@@ -125,6 +127,7 @@ async def chat(req: ChatRequest):
|
|
| 125 |
session = manager.create_session(
|
| 126 |
company_name=req.company_name or "Our Company",
|
| 127 |
agent_name=req.agent_name or "Sara",
|
|
|
|
| 128 |
session_id=req.session_id
|
| 129 |
)
|
| 130 |
logger.warning(f"Target memory space missing. Initialized emergency backup stack instance: {session.session_id}")
|
|
@@ -152,11 +155,12 @@ async def chat(req: ChatRequest):
|
|
| 152 |
system_prompt = build_system_prompt(
|
| 153 |
company_name=session.company_name,
|
| 154 |
agent_name=session.agent_name,
|
|
|
|
| 155 |
language=detected_language,
|
| 156 |
document_context=session.document_context,
|
| 157 |
custom_rules=session.custom_rules,
|
| 158 |
collected_caller_info=session.caller_info.to_dict(),
|
| 159 |
-
input_text=req.message
|
| 160 |
)
|
| 161 |
|
| 162 |
# Append structural input tokens into history logs
|
|
|
|
| 66 |
class StartSessionRequest(BaseModel):
|
| 67 |
company_name: str = "Our Company"
|
| 68 |
agent_name: str = "Sara"
|
| 69 |
+
agent_gender: str = "female" # Added field
|
| 70 |
custom_rules: List[str] = []
|
| 71 |
document_context: str = "" # RAG text block container
|
| 72 |
session_id: Optional[str] = None # Generated if missing
|
|
|
|
| 94 |
session = manager.create_session(
|
| 95 |
company_name=req.company_name,
|
| 96 |
agent_name=req.agent_name,
|
| 97 |
+
agent_gender=req.agent_gender, # Pass parameter
|
| 98 |
custom_rules=req.custom_rules,
|
| 99 |
document_context=req.document_context,
|
| 100 |
session_id=req.session_id,
|
|
|
|
| 127 |
session = manager.create_session(
|
| 128 |
company_name=req.company_name or "Our Company",
|
| 129 |
agent_name=req.agent_name or "Sara",
|
| 130 |
+
agent_gender="female", # Default backup gender
|
| 131 |
session_id=req.session_id
|
| 132 |
)
|
| 133 |
logger.warning(f"Target memory space missing. Initialized emergency backup stack instance: {session.session_id}")
|
|
|
|
| 155 |
system_prompt = build_system_prompt(
|
| 156 |
company_name=session.company_name,
|
| 157 |
agent_name=session.agent_name,
|
| 158 |
+
agent_gender=session.agent_gender, # Pass parameter from session
|
| 159 |
language=detected_language,
|
| 160 |
document_context=session.document_context,
|
| 161 |
custom_rules=session.custom_rules,
|
| 162 |
collected_caller_info=session.caller_info.to_dict(),
|
| 163 |
+
input_text=req.message
|
| 164 |
)
|
| 165 |
|
| 166 |
# Append structural input tokens into history logs
|
python-services/prompt_builder.py
CHANGED
|
@@ -34,6 +34,7 @@ LANGUAGE_SCRIPT_MAP = {
|
|
| 34 |
def build_system_prompt(
|
| 35 |
company_name: str,
|
| 36 |
agent_name: str,
|
|
|
|
| 37 |
language: str,
|
| 38 |
document_context: str = "", # RAG placeholder channel
|
| 39 |
custom_rules: List[str] = None, # Company-specific behavioral rules
|
|
@@ -54,6 +55,7 @@ def build_system_prompt(
|
|
| 54 |
caller_context = _get_caller_context(collected_caller_info or {})
|
| 55 |
document_section = _get_document_section(document_context)
|
| 56 |
rules_section = _get_rules_section(custom_rules or [])
|
|
|
|
| 57 |
current_time = datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 58 |
|
| 59 |
prompt = f"""You are {agent_name}, a professional customer service representative working for {company_name}.
|
|
@@ -64,6 +66,9 @@ def build_system_prompt(
|
|
| 64 |
- Current time: {current_time}.
|
| 65 |
- You operate entirely as an elite human client coordinator on a live telephone connection — NEVER state, hint, or imply that you are an "AI", "Robot", "Bot", "Language Model", or a software script.
|
| 66 |
|
|
|
|
|
|
|
|
|
|
| 67 |
## Language & Script Enforcement Constraints
|
| 68 |
{language_instructions}
|
| 69 |
|
|
@@ -78,6 +83,7 @@ def build_system_prompt(
|
|
| 78 |
8. VOICE SYNTHESIS CRITICAL RULE: Never use bullet points, asterisks, numbered listings, dashes, or markdown typography formatting (** or __) in your output phrases. Speak purely in plain, flowing text sentences.
|
| 79 |
9. If you do not have data to answer a query, state that you will verify the logs or arrange a specialist follow-up call. Never hypothesize details.
|
| 80 |
10. Avoid mentioning competitors of {company_name} or drafting relative industry charts.
|
|
|
|
| 81 |
|
| 82 |
## Caller Information Collection
|
| 83 |
Collect the caller's name and contact number naturally throughout the dialogue.
|
|
@@ -100,7 +106,7 @@ Collect the caller's name and contact number naturally throughout the dialogue.
|
|
| 100 |
return prompt.strip()
|
| 101 |
|
| 102 |
|
| 103 |
-
def build_system_prompts(lang_code: str, user_name_inner: str) -> List[Dict[str, str]]:
|
| 104 |
"""
|
| 105 |
Compiles system configuration parameters into an array format compatible
|
| 106 |
with standard OpenAI and Groq chat execution completions.
|
|
@@ -109,6 +115,7 @@ def build_system_prompts(lang_code: str, user_name_inner: str) -> List[Dict[str,
|
|
| 109 |
raw_prompt = build_system_prompt(
|
| 110 |
company_name="our world-class organization",
|
| 111 |
agent_name="the customer support team coordinator",
|
|
|
|
| 112 |
language=lang_code,
|
| 113 |
collected_caller_info={"name": user_name_inner} if user_name_inner else {}
|
| 114 |
)
|
|
@@ -116,6 +123,33 @@ def build_system_prompts(lang_code: str, user_name_inner: str) -> List[Dict[str,
|
|
| 116 |
return [{"role": "system", "content": raw_prompt}]
|
| 117 |
|
| 118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
def _get_language_instructions(language: str, input_text: str) -> str:
|
| 120 |
"""Generates explicit orthographical rule blocks based on targeted language codes."""
|
| 121 |
script_info = LANGUAGE_SCRIPT_MAP.get(language)
|
|
|
|
| 34 |
def build_system_prompt(
|
| 35 |
company_name: str,
|
| 36 |
agent_name: str,
|
| 37 |
+
agent_gender: str, # Added parameter
|
| 38 |
language: str,
|
| 39 |
document_context: str = "", # RAG placeholder channel
|
| 40 |
custom_rules: List[str] = None, # Company-specific behavioral rules
|
|
|
|
| 55 |
caller_context = _get_caller_context(collected_caller_info or {})
|
| 56 |
document_section = _get_document_section(document_context)
|
| 57 |
rules_section = _get_rules_section(custom_rules or [])
|
| 58 |
+
agent_gender_instruction = _get_agent_gender_instruction(agent_gender, lang)
|
| 59 |
current_time = datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 60 |
|
| 61 |
prompt = f"""You are {agent_name}, a professional customer service representative working for {company_name}.
|
|
|
|
| 66 |
- Current time: {current_time}.
|
| 67 |
- You operate entirely as an elite human client coordinator on a live telephone connection — NEVER state, hint, or imply that you are an "AI", "Robot", "Bot", "Language Model", or a software script.
|
| 68 |
|
| 69 |
+
## Agent Gender & Grammatical Self-Reference Rules
|
| 70 |
+
{agent_gender_instruction}
|
| 71 |
+
|
| 72 |
## Language & Script Enforcement Constraints
|
| 73 |
{language_instructions}
|
| 74 |
|
|
|
|
| 83 |
8. VOICE SYNTHESIS CRITICAL RULE: Never use bullet points, asterisks, numbered listings, dashes, or markdown typography formatting (** or __) in your output phrases. Speak purely in plain, flowing text sentences.
|
| 84 |
9. If you do not have data to answer a query, state that you will verify the logs or arrange a specialist follow-up call. Never hypothesize details.
|
| 85 |
10. Avoid mentioning competitors of {company_name} or drafting relative industry charts.
|
| 86 |
+
11. Avoid referencing your training, software design parameters, or guidelines explicitly during runtime. Maintain the human coordinator persona at all times.
|
| 87 |
|
| 88 |
## Caller Information Collection
|
| 89 |
Collect the caller's name and contact number naturally throughout the dialogue.
|
|
|
|
| 106 |
return prompt.strip()
|
| 107 |
|
| 108 |
|
| 109 |
+
def build_system_prompts(lang_code: str, user_name_inner: str, agent_gender: str = "female") -> List[Dict[str, str]]:
|
| 110 |
"""
|
| 111 |
Compiles system configuration parameters into an array format compatible
|
| 112 |
with standard OpenAI and Groq chat execution completions.
|
|
|
|
| 115 |
raw_prompt = build_system_prompt(
|
| 116 |
company_name="our world-class organization",
|
| 117 |
agent_name="the customer support team coordinator",
|
| 118 |
+
agent_gender=agent_gender,
|
| 119 |
language=lang_code,
|
| 120 |
collected_caller_info={"name": user_name_inner} if user_name_inner else {}
|
| 121 |
)
|
|
|
|
| 123 |
return [{"role": "system", "content": raw_prompt}]
|
| 124 |
|
| 125 |
|
| 126 |
+
def _get_agent_gender_instruction(agent_gender: str, language: str) -> str:
|
| 127 |
+
"""Generates standalone gender constraints section string based on agent gender and active language."""
|
| 128 |
+
lang = (language or "en").lower().strip()
|
| 129 |
+
|
| 130 |
+
if agent_gender == "female":
|
| 131 |
+
return """- Your gender is FEMALE. You MUST speak and refer to yourself using proper feminine grammatical forms, verbs, adjectives, and pronouns.
|
| 132 |
+
- In Urdu (اردو): Always use feminine first-person verb endings and adjectives (e.g., use 'کرتی ہوں', 'رہی ہوں', 'ہوں گی', 'تیار ہوں' [f] and NEVER 'کرتا ہوں', 'رہا ہوں', 'ہوں گا', 'تیار ہوں' [m]).
|
| 133 |
+
- In Arabic (العربية): Always use feminine adjectives, nouns, and participial forms (e.g., use 'أنا سعيدة', 'أنا مسؤولة', 'أنا متحدثة', 'مستعدة' [f] and NEVER 'سعيد', 'مسؤول', 'متحدث', 'مستعد' [m]). This rule applies across all Arabic dialects (including Gulf, Egyptian, Levantine); mirror the caller's dialect using correct feminine forms.
|
| 134 |
+
- In Persian (فارسی): Verbs and adjectives are grammatically genderless in the first person, but use feminine self-identifiers if speaking of your role (e.g., using 'خانم' [Ms./Lady/Coordinator] as a self-identifier if applicable).
|
| 135 |
+
- In English (en): Refer to yourself using female pronouns (she/her) if the context requires pronouns, and standard first-person pronouns (I/me) otherwise."""
|
| 136 |
+
|
| 137 |
+
elif agent_gender == "male":
|
| 138 |
+
return """- Your gender is MALE. You MUST speak and refer to yourself using proper masculine grammatical forms, verbs, adjectives, and pronouns.
|
| 139 |
+
- In Urdu (اردو): Always use masculine first-person verb endings and adjectives (e.g., use 'کرتا ہوں', 'رہا ہوں', 'ہوں گا', 'تیار ہوں' [m] and NEVER 'کرتی ہوں', 'رہی ہوں', 'ہوں گی', 'تیار ہوں' [f]).
|
| 140 |
+
- In Arabic (العربية): Always use masculine adjectives, nouns, and participial forms (e.g., use 'أنا سعيد', 'أنا مسؤول', 'أنا متحدث', 'مستعد' [m] and NEVER 'سعيدة', 'مسؤولة', 'متحدثة', 'مستعدة' [f]). This rule applies across all Arabic dialects (including Gulf, Egyptian, Levantine); mirror the caller's dialect using correct masculine forms.
|
| 141 |
+
- In Persian (فارسی): Verbs and adjectives are grammatically genderless in the first person, but use masculine self-identifiers if speaking of your role (e.g., using 'آقای' [Mr./Coordinator] as a self-identifier if applicable).
|
| 142 |
+
- In English (en): Refer to yourself using male pronouns (he/him) if the context requires pronouns, and standard first-person pronouns (I/me) otherwise."""
|
| 143 |
+
|
| 144 |
+
else: # unspecified / neutral
|
| 145 |
+
return """- Your gender is UNSPECIFIED/NEUTRAL. You MUST use gender-neutral self-referencing language and honorifics where possible.
|
| 146 |
+
- Avoid committing to strict male or female verb endings or adjectives.
|
| 147 |
+
- In Urdu (اردو): Urdu grammar strictly requires gendered verb endings for first-person references. You MUST restructure sentences to avoid first-person gendered verb endings where possible. When unavoidable, default to formal masculine verb endings (e.g., 'کرتے ہیں') as the standard formal professional default in Pakistani contexts.
|
| 148 |
+
- In Arabic (العربية): Use formal neutral phrasing and avoid adjectives, nouns, or participial forms that require gender agreement about yourself. Default to plural or balanced structures if gender is unavoidable. Dialect rendering should also maintain this neutral tone.
|
| 149 |
+
- In Persian (فارسی): Verbs and adjectives are naturally gender-neutral, so communicate normally without gendered role titles.
|
| 150 |
+
- In English (en): Use standard gender-neutral pronouns (they/them) or restructure sentences to avoid third-person self-references."""
|
| 151 |
+
|
| 152 |
+
|
| 153 |
def _get_language_instructions(language: str, input_text: str) -> str:
|
| 154 |
"""Generates explicit orthographical rule blocks based on targeted language codes."""
|
| 155 |
script_info = LANGUAGE_SCRIPT_MAP.get(language)
|