This script streams structured responses from GPT-4 about whales, validates the data
and displays it as a dynamic table using rich as the data is received.
fromtypingimportAnnotatedimportlogfirefrompydanticimportField,ValidationErrorfromrich.consoleimportConsolefromrich.liveimportLivefromrich.tableimportTablefromtyping_extensionsimportNotRequired,TypedDictfrompydantic_aiimportAgent# 'if-token-present' means nothing will be sent (and the example will work) if you don't have logfire configuredlogfire.configure(send_to_logfire='if-token-present')classWhale(TypedDict):name:strlength:Annotated[float,Field(description='Average length of an adult whale in meters.')]weight:NotRequired[Annotated[float,Field(description='Average weight of an adult whale in kilograms.',ge=50),]]ocean:NotRequired[str]description:NotRequired[Annotated[str,Field(description='Short Description')]]agent=Agent('openai:gpt-4',output_type=list[Whale],instrument=True)asyncdefmain():console=Console()withLive('\n'*36,console=console)aslive:console.print('Requesting data...',style='cyan')asyncwithagent.run_stream('Generate me details of 5 species of Whale.')asresult:console.print('Response:',style='green')asyncformessage,lastinresult.stream_structured(debounce_by=0.01):try:whales=awaitresult.validate_structured_output(message,allow_partial=notlast)exceptValidationErrorasexc:ifall(e['type']=='missing'ande['loc']==('response',)foreinexc.errors()):continueelse:raisetable=Table(title='Species of Whale',caption='Streaming Structured responses from GPT-4',width=120,)table.add_column('ID',justify='right')table.add_column('Name')table.add_column('Avg. Length (m)',justify='right')table.add_column('Avg. Weight (kg)',justify='right')table.add_column('Ocean')table.add_column('Description',justify='right')forwid,whaleinenumerate(whales,start=1):table.add_row(str(wid),whale['name'],f'{whale["length"]:0.0f}',f'{w:0.0f}'if(w:=whale.get('weight'))else'…',whale.get('ocean')or'…',whale.get('description')or'…',)live.update(table)if__name__=='__main__':importasyncioasyncio.run(main())