Update src/utils.py
Browse files- src/utils.py +69 -6
src/utils.py
CHANGED
|
@@ -34,18 +34,25 @@ def has_meaningful_content(text):
|
|
| 34 |
|
| 35 |
def remove_reasoning_and_sources(text):
|
| 36 |
"""
|
| 37 |
-
Remove reasoning and sources sections from the main response text.
|
| 38 |
|
| 39 |
Args:
|
| 40 |
text (str): The text to clean
|
| 41 |
|
| 42 |
Returns:
|
| 43 |
-
str: Text without reasoning and sources sections
|
| 44 |
"""
|
|
|
|
|
|
|
|
|
|
| 45 |
# First, remove any reasoning sections
|
| 46 |
-
pattern_reasoning = r'(?i)(\n+\s*reasoning:|\n+\s*\*{0,2}reasoning\*{0,2}:?|\n+\s*#{1,3}\s*reasoning).*?(?=\n+\s*(?:#{1,3}|sources:|references:|\Z))'
|
| 47 |
cleaned_text = re.sub(pattern_reasoning, '', text, flags=re.DOTALL)
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
# Then, remove any sources/references sections
|
| 50 |
pattern_sources = r'(?i)(\n+\s*sources:|\n+\s*references:|\n+\s*\*{0,2}sources\*{0,2}:?|\n+\s*\*{0,2}references\*{0,2}:?|\n+\s*#{1,3}\s*sources|\n+\s*#{1,3}\s*references).*?(?=\n+\s*(?:#{1,3}|\Z))'
|
| 51 |
cleaned_text = re.sub(pattern_sources, '', cleaned_text, flags=re.DOTALL)
|
|
@@ -59,8 +66,8 @@ def remove_reasoning_and_sources(text):
|
|
| 59 |
skip_section = False
|
| 60 |
|
| 61 |
for line in lines:
|
| 62 |
-
# Check if we should skip this line (part of reasoning or sources)
|
| 63 |
-
if re.search(r'(?i)^(\s*reasoning:|\s*sources:|\s*references:|\s*\*{0,2}reasoning\*{0,2}:?|\s*\*{0,2}sources\*{0,2}:?|\s*\*{0,2}references\*{0,2}:?|\s*#{1,3}\s*reasoning|\s*#{1,3}\s*sources|\s*#{1,3}\s*references)', line):
|
| 64 |
skip_section = True
|
| 65 |
continue
|
| 66 |
# Check if we're entering a new section
|
|
@@ -75,6 +82,11 @@ def remove_reasoning_and_sources(text):
|
|
| 75 |
result = '\n'.join(filtered_lines).strip()
|
| 76 |
result = re.sub(r'\[([^\]]+)\]\(https?://[^)]+\)', r'\1', result)
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
return result
|
| 79 |
|
| 80 |
|
|
@@ -214,4 +226,55 @@ def format_conversation_history(history, patient_info=None):
|
|
| 214 |
if explanation:
|
| 215 |
formatted_text += f"REASONING: {explanation}\n\n"
|
| 216 |
|
| 217 |
-
return formatted_text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
def remove_reasoning_and_sources(text):
|
| 36 |
"""
|
| 37 |
+
Remove reasoning, follow-up questions, and sources sections from the main response text.
|
| 38 |
|
| 39 |
Args:
|
| 40 |
text (str): The text to clean
|
| 41 |
|
| 42 |
Returns:
|
| 43 |
+
str: Text without reasoning, follow-up questions, and sources sections
|
| 44 |
"""
|
| 45 |
+
if not text:
|
| 46 |
+
return text
|
| 47 |
+
|
| 48 |
# First, remove any reasoning sections
|
| 49 |
+
pattern_reasoning = r'(?i)(\n+\s*reasoning:|\n+\s*\*{0,2}reasoning\*{0,2}:?|\n+\s*#{1,3}\s*reasoning).*?(?=\n+\s*(?:#{1,3}|follow[ -]?up questions:|sources:|references:|\Z))'
|
| 50 |
cleaned_text = re.sub(pattern_reasoning, '', text, flags=re.DOTALL)
|
| 51 |
|
| 52 |
+
# Remove any follow-up questions sections
|
| 53 |
+
pattern_followup = r'(?i)(\n+\s*follow[ -]?up questions:|\n+\s*\*{0,2}follow[ -]?up questions\*{0,2}:?|\n+\s*#{1,3}\s*follow[ -]?up questions).*?(?=\n+\s*(?:#{1,3}|reasoning:|sources:|references:|\Z))'
|
| 54 |
+
cleaned_text = re.sub(pattern_followup, '', cleaned_text, flags=re.DOTALL)
|
| 55 |
+
|
| 56 |
# Then, remove any sources/references sections
|
| 57 |
pattern_sources = r'(?i)(\n+\s*sources:|\n+\s*references:|\n+\s*\*{0,2}sources\*{0,2}:?|\n+\s*\*{0,2}references\*{0,2}:?|\n+\s*#{1,3}\s*sources|\n+\s*#{1,3}\s*references).*?(?=\n+\s*(?:#{1,3}|\Z))'
|
| 58 |
cleaned_text = re.sub(pattern_sources, '', cleaned_text, flags=re.DOTALL)
|
|
|
|
| 66 |
skip_section = False
|
| 67 |
|
| 68 |
for line in lines:
|
| 69 |
+
# Check if we should skip this line (part of reasoning, follow-up questions, or sources)
|
| 70 |
+
if re.search(r'(?i)^(\s*reasoning:|\s*follow[ -]?up questions:|\s*sources:|\s*references:|\s*\*{0,2}reasoning\*{0,2}:?|\s*\*{0,2}follow[ -]?up questions\*{0,2}:?|\s*\*{0,2}sources\*{0,2}:?|\s*\*{0,2}references\*{0,2}:?|\s*#{1,3}\s*reasoning|\s*#{1,3}\s*follow[ -]?up questions|\s*#{1,3}\s*sources|\s*#{1,3}\s*references)', line):
|
| 71 |
skip_section = True
|
| 72 |
continue
|
| 73 |
# Check if we're entering a new section
|
|
|
|
| 82 |
result = '\n'.join(filtered_lines).strip()
|
| 83 |
result = re.sub(r'\[([^\]]+)\]\(https?://[^)]+\)', r'\1', result)
|
| 84 |
|
| 85 |
+
# Also remove any sections starting with the headers Immediate Response or Main Response
|
| 86 |
+
# We want to preserve this content but remove the header itself
|
| 87 |
+
result = re.sub(r'(?i)^(\s*#{1,3}\s*)?immediate response:?\s*\n', '', result)
|
| 88 |
+
result = re.sub(r'(?i)^(\s*#{1,3}\s*)?main response:?\s*\n', '', result)
|
| 89 |
+
|
| 90 |
return result
|
| 91 |
|
| 92 |
|
|
|
|
| 226 |
if explanation:
|
| 227 |
formatted_text += f"REASONING: {explanation}\n\n"
|
| 228 |
|
| 229 |
+
return formatted_text
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def format_follow_up_questions(questions_text):
|
| 233 |
+
"""
|
| 234 |
+
Format follow-up questions text for display.
|
| 235 |
+
|
| 236 |
+
Args:
|
| 237 |
+
questions_text (str): Raw follow-up questions text
|
| 238 |
+
|
| 239 |
+
Returns:
|
| 240 |
+
str: Formatted follow-up questions
|
| 241 |
+
"""
|
| 242 |
+
if not questions_text:
|
| 243 |
+
return ""
|
| 244 |
+
|
| 245 |
+
# Clean up any header text
|
| 246 |
+
cleaned_text = re.sub(r'(?i)^(\s*#{1,3}\s*)?follow[ -]?up questions:?\s*\n', '', questions_text)
|
| 247 |
+
|
| 248 |
+
# Ensure questions are numbered consistently
|
| 249 |
+
lines = cleaned_text.split('\n')
|
| 250 |
+
formatted_lines = []
|
| 251 |
+
question_num = 1
|
| 252 |
+
|
| 253 |
+
for line in lines:
|
| 254 |
+
# Check if this is a question line (starts with a number or bullet)
|
| 255 |
+
question_match = re.match(r'^\s*(?:\d+\.|\-|\•|\*)\s*(.*)', line)
|
| 256 |
+
if question_match:
|
| 257 |
+
# Replace the existing number/bullet with a consistent format
|
| 258 |
+
formatted_lines.append(f"{question_num}. {question_match.group(1).strip()}")
|
| 259 |
+
question_num += 1
|
| 260 |
+
elif line.strip():
|
| 261 |
+
# If it's not empty and doesn't look like a numbered question,
|
| 262 |
+
# treat it as a continuation of the previous question or a new question
|
| 263 |
+
if formatted_lines and formatted_lines[-1].endswith('?'):
|
| 264 |
+
# If the previous line ends with a question mark, this is likely a new question
|
| 265 |
+
formatted_lines.append(f"{question_num}. {line.strip()}")
|
| 266 |
+
question_num += 1
|
| 267 |
+
elif formatted_lines:
|
| 268 |
+
# Otherwise it's a continuation of the previous question
|
| 269 |
+
formatted_lines[-1] += " " + line.strip()
|
| 270 |
+
else:
|
| 271 |
+
# If there's no previous line, start a new question
|
| 272 |
+
formatted_lines.append(f"{question_num}. {line.strip()}")
|
| 273 |
+
question_num += 1
|
| 274 |
+
|
| 275 |
+
# Ensure each question ends with a question mark
|
| 276 |
+
for i in range(len(formatted_lines)):
|
| 277 |
+
if not formatted_lines[i].endswith('?'):
|
| 278 |
+
formatted_lines[i] += '?'
|
| 279 |
+
|
| 280 |
+
return '\n'.join(formatted_lines)
|