55import io
66import json
77import os
8+
9+ from rich .console import Console
10+ from rich .live import Live
11+ from rich .markdown import Markdown
12+
813from llm import (
914 Attachment ,
1015 AsyncConversation ,
@@ -471,6 +476,7 @@ def cli():
471476 is_flag = True ,
472477 help = "Extract last fenced code block" ,
473478)
479+ @click .option ("--render" , is_flag = True , help = "Render for terminal" )
474480def prompt (
475481 prompt ,
476482 system ,
@@ -502,6 +508,7 @@ def prompt(
502508 usage ,
503509 extract ,
504510 extract_last ,
511+ render ,
505512):
506513 """
507514 Execute a prompt
@@ -830,42 +837,45 @@ def read_prompt():
830837 # Merge in options for the .prompt() methods
831838 kwargs .update (validated_options )
832839
840+ console = Console ()
841+
833842 try :
834843 if async_ :
835844
836845 async def inner ():
846+ response = prompt_method (
847+ prompt ,
848+ attachments = resolved_attachments ,
849+ system = system ,
850+ schema = schema ,
851+ fragments = resolved_fragments ,
852+ system_fragments = resolved_system_fragments ,
853+ ** kwargs ,
854+ )
855+
837856 if should_stream :
838- response = prompt_method (
839- prompt ,
840- attachments = resolved_attachments ,
841- system = system ,
842- schema = schema ,
843- fragments = resolved_fragments ,
844- system_fragments = resolved_system_fragments ,
845- ** kwargs ,
846- )
847- async for chunk in response :
848- print (chunk , end = "" )
849- sys .stdout .flush ()
850- print ("" )
857+ accumulated_text = ""
858+ with Live (accumulated_text , console = console , refresh_per_second = 10 ) as live :
859+ async for chunk in response :
860+ accumulated_text += chunk
861+
862+ if render :
863+ display_content = Markdown (accumulated_text )
864+ else :
865+ display_content = accumulated_text
866+
867+ live .update (display_content )
851868 else :
852- response = prompt_method (
853- prompt ,
854- fragments = resolved_fragments ,
855- attachments = resolved_attachments ,
856- schema = schema ,
857- system = system ,
858- system_fragments = resolved_system_fragments ,
859- ** kwargs ,
860- )
861869 text = await response .text ()
862870 if extract or extract_last :
863- text = (
864- extract_fenced_code_block (text , last = extract_last ) or text
865- )
866- print (text )
871+ text = extract_fenced_code_block (text , last = extract_last ) or text
872+ if render :
873+ text = Markdown (text )
874+ console .print (text )
875+
867876 return response
868877
878+
869879 response = asyncio .run (inner ())
870880 else :
871881 response = prompt_method (
@@ -877,16 +887,28 @@ async def inner():
877887 system_fragments = resolved_system_fragments ,
878888 ** kwargs ,
879889 )
890+
891+
892+
880893 if should_stream :
881- for chunk in response :
882- print (chunk , end = "" )
883- sys .stdout .flush ()
884- print ("" )
894+ accumulated_text = ""
895+ with Live (accumulated_text , console = console , refresh_per_second = 10 ) as live :
896+ for chunk in response :
897+ accumulated_text += chunk
898+
899+ if render :
900+ display_content = Markdown (accumulated_text )
901+ else :
902+ display_content = accumulated_text
903+
904+ live .update (display_content )
885905 else :
886906 text = response .text ()
887907 if extract or extract_last :
888908 text = extract_fenced_code_block (text , last = extract_last ) or text
889- print (text )
909+ if render :
910+ text = Markdown (text )
911+ console .print (text )
890912 # List of exceptions that should never be raised in pytest:
891913 except (ValueError , NotImplementedError ) as ex :
892914 raise click .ClickException (str (ex ))
0 commit comments