feat: Add debug prompt logging functionality with environment variable support
Browse files- config/__init__.py +6 -0
- config/environments/default.yaml +1 -0
- config/environments/development.yaml +1 -0
- config/environments/production.yaml +1 -0
- config/settings.py +1 -0
- main.py +49 -0
config/__init__.py
CHANGED
|
@@ -156,6 +156,11 @@ else:
|
|
| 156 |
}
|
| 157 |
}
|
| 158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
# Required files - from YAML
|
| 160 |
REQUIRED_FILES = _get_settings_attr('required_files', [
|
| 161 |
'docstore_es_filter.json',
|
|
@@ -233,6 +238,7 @@ __all__ = [
|
|
| 233 |
'GENERATION_TEMPERATURE',
|
| 234 |
'LEGAL_POSITION_SCHEMA',
|
| 235 |
'REQUIRED_FILES',
|
|
|
|
| 236 |
'ModelProvider',
|
| 237 |
'GenerationModelName',
|
| 238 |
'AnalysisModelName',
|
|
|
|
| 156 |
}
|
| 157 |
}
|
| 158 |
|
| 159 |
+
# Debug prompt logging - env var overrides YAML setting
|
| 160 |
+
_debug_prompts_yaml = _get_settings_attr('app.debug_prompts', False)
|
| 161 |
+
_debug_prompts_env = os.getenv("DEBUG_PROMPTS", "").lower() in ("1", "true", "yes")
|
| 162 |
+
DEBUG_PROMPTS: bool = _debug_prompts_env or bool(_debug_prompts_yaml)
|
| 163 |
+
|
| 164 |
# Required files - from YAML
|
| 165 |
REQUIRED_FILES = _get_settings_attr('required_files', [
|
| 166 |
'docstore_es_filter.json',
|
|
|
|
| 238 |
'GENERATION_TEMPERATURE',
|
| 239 |
'LEGAL_POSITION_SCHEMA',
|
| 240 |
'REQUIRED_FILES',
|
| 241 |
+
'DEBUG_PROMPTS',
|
| 242 |
'ModelProvider',
|
| 243 |
'GenerationModelName',
|
| 244 |
'AnalysisModelName',
|
config/environments/default.yaml
CHANGED
|
@@ -5,6 +5,7 @@ app:
|
|
| 5 |
version: "1.0.0"
|
| 6 |
debug: false
|
| 7 |
environment: "production"
|
|
|
|
| 8 |
|
| 9 |
# AWS S3 Configuration
|
| 10 |
aws:
|
|
|
|
| 5 |
version: "1.0.0"
|
| 6 |
debug: false
|
| 7 |
environment: "production"
|
| 8 |
+
debug_prompts: false
|
| 9 |
|
| 10 |
# AWS S3 Configuration
|
| 11 |
aws:
|
config/environments/development.yaml
CHANGED
|
@@ -3,6 +3,7 @@
|
|
| 3 |
app:
|
| 4 |
debug: true
|
| 5 |
environment: "development"
|
|
|
|
| 6 |
|
| 7 |
# AWS S3 Configuration - use local files in development
|
| 8 |
aws:
|
|
|
|
| 3 |
app:
|
| 4 |
debug: true
|
| 5 |
environment: "development"
|
| 6 |
+
debug_prompts: true
|
| 7 |
|
| 8 |
# AWS S3 Configuration - use local files in development
|
| 9 |
aws:
|
config/environments/production.yaml
CHANGED
|
@@ -3,6 +3,7 @@
|
|
| 3 |
app:
|
| 4 |
debug: false
|
| 5 |
environment: "production"
|
|
|
|
| 6 |
|
| 7 |
# AWS S3 Configuration - use production index
|
| 8 |
aws:
|
|
|
|
| 3 |
app:
|
| 4 |
debug: false
|
| 5 |
environment: "production"
|
| 6 |
+
debug_prompts: false
|
| 7 |
|
| 8 |
# AWS S3 Configuration - use production index
|
| 9 |
aws:
|
config/settings.py
CHANGED
|
@@ -13,6 +13,7 @@ class AppConfig(BaseModel):
|
|
| 13 |
version: str
|
| 14 |
debug: bool
|
| 15 |
environment: str
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
class AWSConfig(BaseModel):
|
|
|
|
| 13 |
version: str
|
| 14 |
debug: bool
|
| 15 |
environment: str
|
| 16 |
+
debug_prompts: bool = False
|
| 17 |
|
| 18 |
|
| 19 |
class AWSConfig(BaseModel):
|
main.py
CHANGED
|
@@ -35,6 +35,7 @@ from config import (
|
|
| 35 |
GENERATION_TEMPERATURE,
|
| 36 |
LEGAL_POSITION_SCHEMA,
|
| 37 |
REQUIRED_FILES,
|
|
|
|
| 38 |
ModelProvider,
|
| 39 |
AnalysisModelName,
|
| 40 |
DEEPSEEK_API_KEY,
|
|
@@ -50,6 +51,26 @@ from utils import (
|
|
| 50 |
)
|
| 51 |
from embeddings import GeminiEmbedding
|
| 52 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
# Initialize embedding model and settings BEFORE importing components
|
| 54 |
# Priority: OpenAI > Gemini > None
|
| 55 |
embed_model = None
|
|
@@ -352,6 +373,9 @@ class LLMAnalyzer:
|
|
| 352 |
completion_params["verbosity"] = "medium"
|
| 353 |
completion_params["store"] = False
|
| 354 |
|
|
|
|
|
|
|
|
|
|
| 355 |
# Retry logic for OpenAI analysis
|
| 356 |
max_retries = 3
|
| 357 |
last_error = None
|
|
@@ -401,6 +425,12 @@ class LLMAnalyzer:
|
|
| 401 |
completion_params["response_format"] = {'type': 'json_object'}
|
| 402 |
completion_params["temperature"] = self.temperature
|
| 403 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 404 |
# Retry logic for DeepSeek analysis
|
| 405 |
max_retries = 3
|
| 406 |
last_error = None
|
|
@@ -429,6 +459,7 @@ class LLMAnalyzer:
|
|
| 429 |
async def _analyze_with_anthropic(self, prompt: str, response_schema: dict) -> str:
|
| 430 |
"""Analyze text using Anthropic."""
|
| 431 |
try:
|
|
|
|
| 432 |
response = self.client.messages.create(
|
| 433 |
model=self.model_name,
|
| 434 |
max_tokens=self.max_tokens or MAX_TOKENS_ANALYSIS,
|
|
@@ -465,6 +496,9 @@ class LLMAnalyzer:
|
|
| 465 |
|
| 466 |
formatted_prompt = f"{prompt}\n\n{json_instruction}"
|
| 467 |
|
|
|
|
|
|
|
|
|
|
| 468 |
# Use new google.genai API
|
| 469 |
contents = [
|
| 470 |
types.Content(
|
|
@@ -771,6 +805,9 @@ def generate_legal_position(
|
|
| 771 |
# For other reasoning models (gpt-4.1, o1, etc.)
|
| 772 |
completion_params["reasoning_effort"] = thinking_level.lower()
|
| 773 |
|
|
|
|
|
|
|
|
|
|
| 774 |
# Execute with retries
|
| 775 |
for attempt in range(max_retries):
|
| 776 |
try:
|
|
@@ -867,6 +904,12 @@ def generate_legal_position(
|
|
| 867 |
if not is_reasoning:
|
| 868 |
completion_params["temperature"] = temperature
|
| 869 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 870 |
# Execute with retries
|
| 871 |
for attempt in range(max_retries):
|
| 872 |
try:
|
|
@@ -947,6 +990,9 @@ def generate_legal_position(
|
|
| 947 |
}
|
| 948 |
message_params["temperature"] = 1.0
|
| 949 |
|
|
|
|
|
|
|
|
|
|
| 950 |
# Retry logic for connection errors
|
| 951 |
max_retries = 3
|
| 952 |
last_error = None
|
|
@@ -1063,6 +1109,9 @@ def generate_legal_position(
|
|
| 1063 |
|
| 1064 |
generate_content_config = types.GenerateContentConfig(**config_params)
|
| 1065 |
|
|
|
|
|
|
|
|
|
|
| 1066 |
response = client.models.generate_content(
|
| 1067 |
model=model_name,
|
| 1068 |
contents=contents,
|
|
|
|
| 35 |
GENERATION_TEMPERATURE,
|
| 36 |
LEGAL_POSITION_SCHEMA,
|
| 37 |
REQUIRED_FILES,
|
| 38 |
+
DEBUG_PROMPTS,
|
| 39 |
ModelProvider,
|
| 40 |
AnalysisModelName,
|
| 41 |
DEEPSEEK_API_KEY,
|
|
|
|
| 51 |
)
|
| 52 |
from embeddings import GeminiEmbedding
|
| 53 |
|
| 54 |
+
# ============ Debug Prompt Logging ============
|
| 55 |
+
# DEBUG_PROMPTS is loaded from config (YAML env setting + DEBUG_PROMPTS env var override).
|
| 56 |
+
_PROMPT_SEP = "=" * 80
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def _log_prompt(provider: str, model: str, system: str, user: str) -> None:
|
| 60 |
+
"""Print full system + user prompts when DEBUG_PROMPTS is enabled."""
|
| 61 |
+
if not DEBUG_PROMPTS:
|
| 62 |
+
return
|
| 63 |
+
print(f"\n{_PROMPT_SEP}")
|
| 64 |
+
print(f"[PROMPT DEBUG] Provider: {provider} | Model: {model}")
|
| 65 |
+
print(f"{_PROMPT_SEP}")
|
| 66 |
+
if system:
|
| 67 |
+
print("[PROMPT DEBUG] ── SYSTEM PROMPT ──────────────────────────────────")
|
| 68 |
+
print(system)
|
| 69 |
+
print("[PROMPT DEBUG] ── USER PROMPT ────────────────────────────────────")
|
| 70 |
+
print(user)
|
| 71 |
+
print(f"{_PROMPT_SEP}\n")
|
| 72 |
+
# ============ End Debug Prompt Logging ============
|
| 73 |
+
|
| 74 |
# Initialize embedding model and settings BEFORE importing components
|
| 75 |
# Priority: OpenAI > Gemini > None
|
| 76 |
embed_model = None
|
|
|
|
| 373 |
completion_params["verbosity"] = "medium"
|
| 374 |
completion_params["store"] = False
|
| 375 |
|
| 376 |
+
# Log full prompts in debug mode
|
| 377 |
+
_log_prompt("openai-analyzer", model_val, SYSTEM_PROMPT, prompt)
|
| 378 |
+
|
| 379 |
# Retry logic for OpenAI analysis
|
| 380 |
max_retries = 3
|
| 381 |
last_error = None
|
|
|
|
| 425 |
completion_params["response_format"] = {'type': 'json_object'}
|
| 426 |
completion_params["temperature"] = self.temperature
|
| 427 |
|
| 428 |
+
# Log full prompts in debug mode
|
| 429 |
+
if is_reasoning:
|
| 430 |
+
_log_prompt("deepseek-analyzer", model_val, "", f"{SYSTEM_PROMPT}\n\n{prompt}")
|
| 431 |
+
else:
|
| 432 |
+
_log_prompt("deepseek-analyzer", model_val, SYSTEM_PROMPT, prompt)
|
| 433 |
+
|
| 434 |
# Retry logic for DeepSeek analysis
|
| 435 |
max_retries = 3
|
| 436 |
last_error = None
|
|
|
|
| 459 |
async def _analyze_with_anthropic(self, prompt: str, response_schema: dict) -> str:
|
| 460 |
"""Analyze text using Anthropic."""
|
| 461 |
try:
|
| 462 |
+
_log_prompt("anthropic-analyzer", str(self.model_name), SYSTEM_PROMPT, prompt)
|
| 463 |
response = self.client.messages.create(
|
| 464 |
model=self.model_name,
|
| 465 |
max_tokens=self.max_tokens or MAX_TOKENS_ANALYSIS,
|
|
|
|
| 496 |
|
| 497 |
formatted_prompt = f"{prompt}\n\n{json_instruction}"
|
| 498 |
|
| 499 |
+
# Log full prompts in debug mode
|
| 500 |
+
_log_prompt("gemini-analyzer", str(self.model_name), SYSTEM_PROMPT, formatted_prompt)
|
| 501 |
+
|
| 502 |
# Use new google.genai API
|
| 503 |
contents = [
|
| 504 |
types.Content(
|
|
|
|
| 805 |
# For other reasoning models (gpt-4.1, o1, etc.)
|
| 806 |
completion_params["reasoning_effort"] = thinking_level.lower()
|
| 807 |
|
| 808 |
+
# Log full prompts in debug mode
|
| 809 |
+
_log_prompt("openai", model_name, system_prompt, content)
|
| 810 |
+
|
| 811 |
# Execute with retries
|
| 812 |
for attempt in range(max_retries):
|
| 813 |
try:
|
|
|
|
| 904 |
if not is_reasoning:
|
| 905 |
completion_params["temperature"] = temperature
|
| 906 |
|
| 907 |
+
# Log full prompts in debug mode
|
| 908 |
+
if is_reasoning:
|
| 909 |
+
_log_prompt("deepseek", model_name, "", combined_content)
|
| 910 |
+
else:
|
| 911 |
+
_log_prompt("deepseek", model_name, system_prompt, content)
|
| 912 |
+
|
| 913 |
# Execute with retries
|
| 914 |
for attempt in range(max_retries):
|
| 915 |
try:
|
|
|
|
| 990 |
}
|
| 991 |
message_params["temperature"] = 1.0
|
| 992 |
|
| 993 |
+
# Log full prompts in debug mode
|
| 994 |
+
_log_prompt("anthropic", model_name, system_prompt, content)
|
| 995 |
+
|
| 996 |
# Retry logic for connection errors
|
| 997 |
max_retries = 3
|
| 998 |
last_error = None
|
|
|
|
| 1109 |
|
| 1110 |
generate_content_config = types.GenerateContentConfig(**config_params)
|
| 1111 |
|
| 1112 |
+
# Log full prompts in debug mode
|
| 1113 |
+
_log_prompt("gemini", model_name, system_prompt, content)
|
| 1114 |
+
|
| 1115 |
response = client.models.generate_content(
|
| 1116 |
model=model_name,
|
| 1117 |
contents=contents,
|