77
88# ANSI colors
99YELLOW = "\033 [93m"
10+ ANSWER_COLOR = "\033 [96m"
1011RESET = "\033 [0m"
1112
1213
@@ -34,6 +35,77 @@ def compose_prompt(system_prompt, user_prompt, data):
3435 parts .append (part .strip ("\n " ))
3536 return "\n \n " .join (parts )
3637
38+
39+ def colorize_response (text ):
40+ """Return the response string with ANSI colors applied to think segments."""
41+ if not text :
42+ return ""
43+
44+ idx = 0
45+ in_think = False
46+ output = []
47+
48+ while idx < len (text ):
49+ if in_think :
50+ close_idx = text .find ("</think>" , idx )
51+ if close_idx == - 1 :
52+ output .append (f"{ YELLOW } { text [idx :]} { RESET } " )
53+ break
54+
55+ if close_idx > idx :
56+ output .append (f"{ YELLOW } { text [idx :close_idx ]} { RESET } " )
57+ output .append (f"{ YELLOW } </think>{ RESET } " )
58+ idx = close_idx + len ("</think>" )
59+ in_think = False
60+ else :
61+ open_idx = text .find ("<think>" , idx )
62+ if open_idx == - 1 :
63+ output .append (f"{ ANSWER_COLOR } { text [idx :]} { RESET } " )
64+ break
65+
66+ if open_idx > idx :
67+ output .append (f"{ ANSWER_COLOR } { text [idx :open_idx ]} { RESET } " )
68+ output .append (f"{ YELLOW } <think>{ RESET } " )
69+ idx = open_idx + len ("<think>" )
70+ in_think = True
71+
72+ return "" .join (output )
73+
74+
75+ def print_stream_chunk (text , in_think ):
76+ """Stream a chunk of text with think/final color separation."""
77+ idx = 0
78+ while idx < len (text ):
79+ if in_think :
80+ close_idx = text .find ("</think>" , idx )
81+ if close_idx == - 1 :
82+ segment = text [idx :]
83+ if segment :
84+ print (f"{ YELLOW } { segment } { RESET } " , end = "" , flush = True )
85+ idx = len (text )
86+ else :
87+ segment = text [idx :close_idx ]
88+ if segment :
89+ print (f"{ YELLOW } { segment } { RESET } " , end = "" , flush = True )
90+ print (f"{ YELLOW } </think>{ RESET } " , end = "" , flush = True )
91+ idx = close_idx + len ("</think>" )
92+ in_think = False
93+ else :
94+ open_idx = text .find ("<think>" , idx )
95+ if open_idx == - 1 :
96+ segment = text [idx :]
97+ if segment :
98+ print (f"{ ANSWER_COLOR } { segment } { RESET } " , end = "" , flush = True )
99+ idx = len (text )
100+ else :
101+ segment = text [idx :open_idx ]
102+ if segment :
103+ print (f"{ ANSWER_COLOR } { segment } { RESET } " , end = "" , flush = True )
104+ print (f"{ YELLOW } <think>{ RESET } " , end = "" , flush = True )
105+ idx = open_idx + len ("<think>" )
106+ in_think = True
107+ return in_think
108+
37109def call_ollama_batch (api_url , model , prompt , temperature ):
38110 """Send a prompt to Ollama API and return response text (batch mode)."""
39111 try :
@@ -57,7 +129,7 @@ def call_ollama_batch(api_url, model, prompt, temperature):
57129 output .append (data .get ("response" , "" ))
58130 except Exception :
59131 pass
60- return "" .join (output )
132+ return colorize_response ( "" .join (output ) )
61133
62134 except requests .RequestException as e :
63135 return f"[Error contacting Ollama API: { e } ]"
@@ -85,19 +157,7 @@ def call_ollama_stream(api_url, model, prompt, temperature):
85157 data = json .loads (line .decode ("utf-8" ))
86158 text = data .get ("response" , "" )
87159 if text :
88- # Detect <think> start
89- if "<think>" in text :
90- in_think = True
91- # Detect </think> end
92- if "</think>" in text :
93- in_think = False
94- print (f"{ YELLOW } { text } { RESET } " , end = "" , flush = True )
95- continue
96-
97- if in_think :
98- print (f"{ YELLOW } { text } { RESET } " , end = "" , flush = True )
99- else :
100- print (f"{ text } " , end = "" , flush = True )
160+ in_think = print_stream_chunk (text , in_think )
101161
102162 if data .get ("done" , False ):
103163 break
0 commit comments