import re import time from config import logger class ParserState: __slots__ = ['answer', 'thought', 'in_think', 'in_answer', 'start_time', 'last_pos', 'total_think_time'] def __init__(self): self.answer = "" self.thought = "" self.in_think = False self.in_answer = False self.start_time = 0 self.last_pos = 0 self.total_think_time = 0.0 def format_time(seconds_float): total_seconds = int(round(seconds_float)) hours = total_seconds // 3600 remaining_seconds = total_seconds % 3600 minutes = remaining_seconds // 60 seconds = remaining_seconds % 60 if hours > 0: return f"{hours}h {minutes}m {seconds}s" elif minutes > 0: return f"{minutes}m {seconds}s" else: return f"{seconds}s" def parse_response(text, state): buffer = text[state.last_pos:] state.last_pos = len(text) while buffer: if not state.in_think and not state.in_answer: think_start = buffer.find('') reasoning_start = buffer.find('') answer_start = buffer.find('') starts = [] if think_start != -1: starts.append((think_start, '', 7, 'think')) if reasoning_start != -1: starts.append((reasoning_start, '', 11, 'think')) if answer_start != -1: starts.append((answer_start, '', 8, 'answer')) if not starts: state.answer += buffer break start_pos, start_tag, tag_length, mode = min(starts, key=lambda x: x[0]) state.answer += buffer[:start_pos] if mode == 'think': state.in_think = True state.start_time = time.perf_counter() else: state.in_answer = True buffer = buffer[start_pos + tag_length:] elif state.in_think: think_end = buffer.find('') reasoning_end = buffer.find('') ends = [] if think_end != -1: ends.append((think_end, '', 8)) if reasoning_end != -1: ends.append((reasoning_end, '', 12)) if ends: end_pos, end_tag, tag_length = min(ends, key=lambda x: x[0]) state.thought += buffer[:end_pos] duration = time.perf_counter() - state.start_time state.total_think_time += duration state.in_think = False buffer = buffer[end_pos + tag_length:] if end_tag == '': state.answer += buffer break else: state.thought += buffer break elif state.in_answer: answer_end = buffer.find('') if answer_end != -1: state.answer += buffer[:answer_end] state.in_answer = False buffer = buffer[answer_end + 9:] else: state.answer += buffer break elapsed = time.perf_counter() - state.start_time if state.in_think else 0 return state, elapsed def format_response(state, elapsed): answer_part = state.answer collapsible = [] collapsed = "
" if state.thought or state.in_think: if state.in_think: total_elapsed = state.total_think_time + elapsed formatted_time = format_time(total_elapsed) status = f"💭 Thinking for {formatted_time}" else: formatted_time = format_time(state.total_think_time) status = f"✅ Thought for {formatted_time}" collapsed = "
" collapsible.append( f"{collapsed}{status}\n\n
\n{state.thought}\n
\n
" ) return collapsible, answer_part def remove_tags(text): if text is None: return None return re.sub(r'<[^>]+>', ' ', text).strip()