Refactor: unify render_segments logic, add streaming cursor animation, and clean up unused container parameter
This commit is contained in:
@@ -74,7 +74,7 @@ def fold_turns(text):
|
|||||||
if parts[0].strip(): segments.append({'type': 'text', 'content': parts[0]})
|
if parts[0].strip(): segments.append({'type': 'text', 'content': parts[0]})
|
||||||
turns = []
|
turns = []
|
||||||
for i in range(1, len(parts), 2):
|
for i in range(1, len(parts), 2):
|
||||||
marker = parts[i].strip('*')
|
marker = parts[i]
|
||||||
content = parts[i+1] if i+1 < len(parts) else ''
|
content = parts[i+1] if i+1 < len(parts) else ''
|
||||||
turns.append((marker, content))
|
turns.append((marker, content))
|
||||||
for idx, (marker, content) in enumerate(turns):
|
for idx, (marker, content) in enumerate(turns):
|
||||||
@@ -84,17 +84,25 @@ def fold_turns(text):
|
|||||||
title = m.group(1).strip()
|
title = m.group(1).strip()
|
||||||
title = title.split('\n')[0]
|
title = title.split('\n')[0]
|
||||||
if len(title) > 50: title = title[:50] + '...'
|
if len(title) > 50: title = title[:50] + '...'
|
||||||
else: title = marker
|
else: title = marker.strip('*')
|
||||||
segments.append({'type': 'fold', 'title': title, 'content': content})
|
segments.append({'type': 'fold', 'title': title, 'content': content})
|
||||||
else: segments.append({'type': 'text', 'content': marker + content})
|
else: segments.append({'type': 'text', 'content': marker + content})
|
||||||
return segments
|
return segments
|
||||||
def render_segments(segments, container=None):
|
def render_segments(segments, placeholders=None, rendered_cache=None, suffix='', force_text=False):
|
||||||
"""Render fold_turns output using st.expander (no unsafe_allow_html needed)."""
|
def _render_seg(target, seg, suf=''):
|
||||||
c = container or st
|
|
||||||
for seg in segments:
|
|
||||||
if seg['type'] == 'fold':
|
if seg['type'] == 'fold':
|
||||||
with c.expander(seg['title'], expanded=False): st.markdown(seg['content'])
|
with target.expander(seg['title'], expanded=False): st.markdown(seg['content'])
|
||||||
else: c.markdown(seg['content'])
|
else: target.markdown(seg['content'] + suf, unsafe_allow_html=not not suf)
|
||||||
|
if placeholders is not None:
|
||||||
|
while len(placeholders) < len(segments):
|
||||||
|
placeholders.append(st.empty()); rendered_cache.append(None)
|
||||||
|
for i, seg in enumerate(segments):
|
||||||
|
if rendered_cache[i] != (seg, suffix):
|
||||||
|
if not force_text or seg['type'] == 'text':
|
||||||
|
with placeholders[i].container(): _render_seg(st, seg, suffix)
|
||||||
|
rendered_cache[i] = (seg, suffix)
|
||||||
|
else:
|
||||||
|
for seg in segments: _render_seg(st, seg)
|
||||||
|
|
||||||
def agent_backend_stream(prompt):
|
def agent_backend_stream(prompt):
|
||||||
display_queue = agent.put_task(prompt, source="user")
|
display_queue = agent.put_task(prompt, source="user")
|
||||||
@@ -127,21 +135,10 @@ if prompt := st.chat_input("请输入指令"):
|
|||||||
with st.chat_message("user"): st.markdown(prompt)
|
with st.chat_message("user"): st.markdown(prompt)
|
||||||
|
|
||||||
with st.chat_message("assistant"):
|
with st.chat_message("assistant"):
|
||||||
turn_placeholders = []
|
turns = []; cache = []; response = ''
|
||||||
rendered_segments = []
|
|
||||||
response = ''
|
|
||||||
for response in agent_backend_stream(prompt):
|
for response in agent_backend_stream(prompt):
|
||||||
segments = fold_turns(response)
|
render_segments(fold_turns(response), placeholders=turns, rendered_cache=cache, suffix='<span style="animation: blink 1s step-start infinite; color: #0066cc;">▌</span><style>@keyframes blink { 50% { opacity: 0; } }</style>')
|
||||||
while len(turn_placeholders) < len(segments):
|
render_segments(fold_turns(response), placeholders=turns, rendered_cache=cache, force_text=True)
|
||||||
turn_placeholders.append(st.empty())
|
|
||||||
rendered_segments.append(None)
|
|
||||||
for i, seg in enumerate(segments):
|
|
||||||
if rendered_segments[i] != seg:
|
|
||||||
with turn_placeholders[i].container():
|
|
||||||
if seg['type'] == 'fold':
|
|
||||||
with st.expander(seg['title']): st.markdown(seg['content'])
|
|
||||||
else: st.markdown(seg['content'])
|
|
||||||
rendered_segments[i] = seg
|
|
||||||
st.session_state.messages.append({"role": "assistant", "content": response})
|
st.session_state.messages.append({"role": "assistant", "content": response})
|
||||||
st.session_state.last_reply_time = int(time.time())
|
st.session_state.last_reply_time = int(time.time())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user