1
00:00:00,200 --> 00:00:02,480
So I have good news and bad news for you.

2
00:00:02,480 --> 00:00:09,840
The good news is that today, the last day of week two, it's going to be quick and easy and satisfying.

3
00:00:09,840 --> 00:00:11,920
So there's going to be fun stuff right away.

4
00:00:12,040 --> 00:00:14,960
The bad news is there's going to be a really hard challenge at the end of it.

5
00:00:14,960 --> 00:00:18,320
It's going to be hard, but really big and juicy and good.

6
00:00:18,360 --> 00:00:21,680
So I do hope that you will take on the challenge that's coming up.

7
00:00:21,680 --> 00:00:24,400
But first, let's just talk about what we're going to do today.

8
00:00:24,400 --> 00:00:26,800
We're going to take our deep research.

9
00:00:27,080 --> 00:00:29,920
The agent that we built last time in a notebook.

10
00:00:29,920 --> 00:00:33,880
And we're going to turn it into proper Python code in modules.

11
00:00:33,920 --> 00:00:36,760
Yes, with a user interface featuring Gradio.

12
00:00:36,920 --> 00:00:38,240
Let's go and do that right now.

13
00:00:38,680 --> 00:00:42,800
And so here we are in cursor and we're going into the OpenAI folder.

14
00:00:42,800 --> 00:00:48,960
But now we're going into another folder into the deep research folder that is beneath it.

15
00:00:49,160 --> 00:00:52,840
And you will see that there are some Python modules you'll be happy to see.

16
00:00:52,880 --> 00:00:57,440
Because I know you like Python modules, and I'm going to just talk you through them, and I hope going

17
00:00:57,480 --> 00:01:03,800
to be pleasantly surprised how easy it is, and also how natural it is to move from a notebook world

18
00:01:03,800 --> 00:01:05,320
into proper modules.

19
00:01:05,320 --> 00:01:07,080
And again, one more sales pitch.

20
00:01:07,120 --> 00:01:12,600
It's where I like to work experimentally, first in a notebook and then turn it into modules.

21
00:01:12,640 --> 00:01:17,720
As you've built out your prompts, as you've experimented and refined your agent architecture.

22
00:01:18,040 --> 00:01:24,520
So what we've got in here are some agent classes, some agent modules with a single agent class, and

23
00:01:24,520 --> 00:01:26,920
then a manager that packages it all together.

24
00:01:26,960 --> 00:01:32,200
And then finally, deep research is the user interface, which is a very simple user interface.

25
00:01:32,240 --> 00:01:36,280
So let's start with the classes that represent the agents.

26
00:01:36,280 --> 00:01:37,760
And it's going to be really simple.

27
00:01:37,760 --> 00:01:42,680
We will start with the planner agent, which is exactly where we started when we were in the notebook

28
00:01:42,840 --> 00:01:44,520
the planner agent.

29
00:01:44,560 --> 00:01:45,200
We've got this.

30
00:01:45,200 --> 00:01:46,320
How many searches?

31
00:01:46,320 --> 00:01:52,240
I've got it set to 20 now, but I'll turn it back to three before I check this in so that no one racks

32
00:01:52,240 --> 00:01:53,000
up a big bill.

33
00:01:53,000 --> 00:01:59,800
If you use it, and you'll recognize the same old instructions and the same pedantic objects for a web

34
00:01:59,800 --> 00:02:06,760
search item and a web search plan, which is the list of web search items in the single field searches.

35
00:02:06,920 --> 00:02:14,760
And here is our planner agent that takes our instructions and it uses the web search plan.

36
00:02:15,320 --> 00:02:16,200
There we go.

37
00:02:16,520 --> 00:02:22,040
Okay, next up, the search agent and I need to make one little change to this guy.

38
00:02:22,400 --> 00:02:25,000
So this is the search agent.

39
00:02:25,120 --> 00:02:29,320
The instructions you'll see here your research assistant.

40
00:02:29,560 --> 00:02:31,600
And it's got got this this format.

41
00:02:31,600 --> 00:02:35,760
You'll remember that we stole that format from OpenAI's documentation.

42
00:02:35,800 --> 00:02:38,920
A very nice set of instructions right there.

43
00:02:39,160 --> 00:02:44,480
I don't know if you spot the little change I have to make, but the tools in here, I need to add in

44
00:02:44,480 --> 00:02:46,560
that parameter to make it nice and cheap.

45
00:02:46,560 --> 00:02:47,840
So let's go and do that together.

46
00:02:47,840 --> 00:02:55,280
If we go to this lab, if we look at what that parameter was, that parameter was actually near the

47
00:02:55,280 --> 00:02:55,560
top.

48
00:02:55,560 --> 00:02:57,840
I think we did at the very beginning.

49
00:02:57,840 --> 00:02:58,760
There we go.

50
00:02:59,000 --> 00:03:02,880
It is that the search context size is low.

51
00:03:03,160 --> 00:03:08,910
Let's go and put that in there right now so that no one spends unexpected amounts there.

52
00:03:08,910 --> 00:03:10,390
We have it done.

53
00:03:10,830 --> 00:03:15,910
Okay, so that is the search agent class in the search agent module.

54
00:03:16,190 --> 00:03:22,270
And now we've got a couple more, two more agents to talk about the writer agent again.

55
00:03:22,430 --> 00:03:26,710
And you know, the benefit of having these in Python modules, it looks very crisp and simple.

56
00:03:26,710 --> 00:03:28,550
You can see exactly what's going on.

57
00:03:28,590 --> 00:03:30,190
We've got our instructions.

58
00:03:30,310 --> 00:03:38,110
We've got the pedantic report data that has a short summary, a markdown report and follow up questions.

59
00:03:38,430 --> 00:03:45,430
And then our writer agent, which is the agent that will take all of the information from all of the

60
00:03:45,430 --> 00:03:49,990
searches and turn it into a report data object.

61
00:03:50,510 --> 00:03:53,790
And the final agent, if you remember, is of course, the email agent.

62
00:03:53,790 --> 00:03:54,630
Here it is.

63
00:03:54,750 --> 00:03:57,150
This is stuff that you will recognize.

64
00:03:57,270 --> 00:04:01,990
This is just the same thing that is going to send the email.

65
00:04:02,030 --> 00:04:10,870
You must remember, please to change this to be your verified sender here, not make put your verified

66
00:04:10,870 --> 00:04:14,990
sender here and then put some other email here.

67
00:04:15,030 --> 00:04:17,550
Put your recipient here, not me.

68
00:04:17,590 --> 00:04:20,790
I think I might change this before I check it in because otherwise someone's going to forget.

69
00:04:20,830 --> 00:04:24,550
Well, many people will forget and I'll be overloaded with spam email.

70
00:04:24,910 --> 00:04:26,990
All right, so this is the tool.

71
00:04:26,990 --> 00:04:37,310
And actually it's good to have a comment in here because that will send an email with the given subject

72
00:04:37,310 --> 00:04:38,270
in HTML body.

73
00:04:38,310 --> 00:04:39,310
Very nice.

74
00:04:39,710 --> 00:04:40,430
Okay.

75
00:04:40,630 --> 00:04:45,390
So that is our email agent and that is all four of our agents.

76
00:04:45,390 --> 00:04:48,670
What's coming next is research manager.

77
00:04:49,070 --> 00:04:49,430
Okay.

78
00:04:49,470 --> 00:04:51,790
So research manager is a class.

79
00:04:51,790 --> 00:04:59,150
And this contains those short functions that we had last time with a little bit of a twist spiced it

80
00:04:59,150 --> 00:04:59,550
up.

81
00:04:59,790 --> 00:05:05,310
So first of all there is a single method here run or it's a coroutine.

82
00:05:05,350 --> 00:05:11,590
If you want to be pedantic with me, this coroutine run an async def run.

83
00:05:11,830 --> 00:05:16,830
And this is just the same as the as the code that I had before.

84
00:05:16,830 --> 00:05:23,470
We've got a little trick here to, to generate a trace ID so that we can, we can print where to go

85
00:05:23,470 --> 00:05:27,310
to look at the precise trace that we're looking at here.

86
00:05:27,710 --> 00:05:31,670
Now you may wonder why we've got all of this yielding going on.

87
00:05:31,870 --> 00:05:38,630
We, uh, we're treating this as a generator that is going to yield various bits of text along the way.

88
00:05:38,990 --> 00:05:43,670
So that is going to become clear in a bit, but just take a look at what's going on here.

89
00:05:43,670 --> 00:05:47,590
I print some updates and I also yield those updates.

90
00:05:47,630 --> 00:05:51,150
And I end by yielding the full markdown report.

91
00:05:51,350 --> 00:05:53,950
Now hopefully you've done your intermediate.

92
00:05:53,950 --> 00:05:58,710
Either you already know all about generators or if you don't, then you've taken a look at the guide

93
00:05:58,710 --> 00:06:02,230
that explains generators so that there's no surprise.

94
00:06:03,070 --> 00:06:03,510
Okay.

95
00:06:03,550 --> 00:06:10,670
And then I've just got each of these functions plan searches, perform searches, search and write,

96
00:06:10,670 --> 00:06:12,630
report and send email.

97
00:06:12,910 --> 00:06:17,950
These are the five functions that are exactly the same as the five functions we talked through before,

98
00:06:17,990 --> 00:06:19,950
except a little bit beefed up.

99
00:06:19,950 --> 00:06:26,150
They've got more type hints put in, as one should do for proper checked in Python modules.

100
00:06:26,310 --> 00:06:28,670
And there's a bit more exception handling.

101
00:06:28,790 --> 00:06:34,950
And this is a little bit fancier to handle the being able to print a status update while it's going

102
00:06:34,950 --> 00:06:39,390
through the different searches, but otherwise it is much the same.

103
00:06:39,590 --> 00:06:45,670
So it's just a bit tidied up, which is the kind of practice you should do when you move from the notebook

104
00:06:45,710 --> 00:06:51,310
environment, when you're being more experimental into something that's more well baked code, but it's

105
00:06:51,310 --> 00:06:52,590
the same functionality.

106
00:06:53,230 --> 00:06:56,550
And that finally brings us to Deepresearch.

107
00:06:57,630 --> 00:06:58,350
Here we are.

108
00:06:58,390 --> 00:07:00,430
This is our Gradio app.

109
00:07:00,750 --> 00:07:03,550
This is where the magic happens.

110
00:07:03,710 --> 00:07:05,630
So Gradio which we import here.

111
00:07:05,950 --> 00:07:12,550
This is the the the package which you may know I love, which lets data scientists build great UIs without

112
00:07:12,550 --> 00:07:14,430
needing to know anything about front end.

113
00:07:14,740 --> 00:07:20,100
And I'm going to give you just some, some insights into how this works without I'm not giving you a

114
00:07:20,100 --> 00:07:21,220
full radio lesson here.

115
00:07:21,260 --> 00:07:22,420
And radio has great docs.

116
00:07:22,420 --> 00:07:25,220
It's really easy to read up about it and build build your own.

117
00:07:25,220 --> 00:07:29,220
But just very briefly, this this code here is where the user interface is defined.

118
00:07:29,260 --> 00:07:37,380
And we're used to using things like chat interface which is the super canned simple one where you just

119
00:07:37,380 --> 00:07:39,300
you can create an interface out of nothing.

120
00:07:39,300 --> 00:07:44,500
If you want to actually build your own user interface from scratch, then you have to use a slightly

121
00:07:44,500 --> 00:07:52,580
more detailed version when you do with great blocks as and then something like UI, and then you put

122
00:07:52,580 --> 00:07:58,540
your your code in there and then you say UI dot launch at the end and that that's the way to do it,

123
00:07:58,580 --> 00:08:00,740
that that will then build your user interface.

124
00:08:00,740 --> 00:08:02,740
So that is exactly what we've got here.

125
00:08:02,740 --> 00:08:04,980
We say with great blocks.

126
00:08:05,340 --> 00:08:10,100
And then you can pass in a theme if you want to have a different theme to the to the standard theme,

127
00:08:10,100 --> 00:08:12,820
and you can find the different colors that you can have in here.

128
00:08:13,100 --> 00:08:16,700
And then you simply put down the fields that you want.

129
00:08:16,740 --> 00:08:21,940
So we're going to start with a heading GR markdown gives us a heading and we want to have the word deep

130
00:08:21,940 --> 00:08:23,340
research as a big heading.

131
00:08:23,340 --> 00:08:27,140
Then we want a text box that says what topic would you like to research.

132
00:08:27,300 --> 00:08:31,660
And we're associating that text box with a field called query.

133
00:08:31,780 --> 00:08:34,220
So this this is a is a field.

134
00:08:34,260 --> 00:08:38,100
It might be a bit query clearer if we call this query text box.

135
00:08:38,460 --> 00:08:40,180
Let's say that query text box.

136
00:08:40,740 --> 00:08:46,140
And then here the next field we're going to put on a user interface is called run button.

137
00:08:46,140 --> 00:08:47,700
It's a button.

138
00:08:47,700 --> 00:08:50,580
It says run on it and it's a primary button.

139
00:08:50,580 --> 00:08:55,020
So it'll be nice and blue because blue is the sky, blue is the color we've chosen.

140
00:08:55,580 --> 00:09:01,180
And then the next one is going to be report, which is going to be our actual report text.

141
00:09:01,220 --> 00:09:04,740
It's a markdown and its label is report.

142
00:09:05,460 --> 00:09:08,940
Okay I'm going to change this here to query text box.

143
00:09:09,380 --> 00:09:13,660
So what we can now do is register an event.

144
00:09:13,940 --> 00:09:17,900
We want to register an event with the run button.

145
00:09:18,220 --> 00:09:23,380
We're going to say if the run button is clicked and we register that event by calling a function, click

146
00:09:23,380 --> 00:09:28,380
on run button and we just have to tell Gradio we want you to call us back.

147
00:09:28,420 --> 00:09:31,340
If that run button is clicked, then call this callback.

148
00:09:31,420 --> 00:09:34,620
And that callback is going to be something called run.

149
00:09:34,940 --> 00:09:37,620
And spoiler alert, run is right up here.

150
00:09:38,180 --> 00:09:42,060
So if if run button is clicked then call that callback.

151
00:09:42,060 --> 00:09:42,580
Run.

152
00:09:42,820 --> 00:09:48,900
The inputs that you should use should be the contents of the query text box.

153
00:09:49,780 --> 00:09:55,980
So the inputs to this callback should be whatever's in the text box when they press the run button,

154
00:09:56,020 --> 00:09:58,140
when they click the run button, and the outputs.

155
00:09:58,140 --> 00:10:04,180
Whatever comes out of this callback should go into, I want you to hook that up Gradio hook it up into

156
00:10:04,180 --> 00:10:06,020
this report markdown.

157
00:10:06,540 --> 00:10:09,780
And then for the this, this next one is really the same thing.

158
00:10:09,900 --> 00:10:15,380
It's, it's saying that if they're in the query text box and they hit the enter key to submit, then

159
00:10:15,380 --> 00:10:16,740
again call the run.

160
00:10:17,100 --> 00:10:22,860
The input should be the contents of the query text box, and the output should be the report.

161
00:10:23,220 --> 00:10:30,540
So this is a way that you can hook up gradio so that the widgets that you've constructed here get associated

162
00:10:30,540 --> 00:10:35,340
with inputs and outputs of a callback function that's getting called.

163
00:10:35,540 --> 00:10:40,740
And this this method here is going to generate front end code that's going to run in a browser.

164
00:10:40,740 --> 00:10:46,500
And when they press that button it's actually going to call back this Python code in our class populating

165
00:10:46,500 --> 00:10:48,300
it with the right the right fields.

166
00:10:48,940 --> 00:10:54,660
So it doesn't matter if you didn't follow all of that, or you don't get or even care how Gradio hooks

167
00:10:54,660 --> 00:11:00,700
things up together, just have some general intuition for it and know that UI launch is the thing that

168
00:11:00,700 --> 00:11:06,100
is then going to generate the front end code based on that, and figure out how to make sure that our

169
00:11:06,100 --> 00:11:11,580
callback gets called in browser equals true means that it's going to bring up a browser window right

170
00:11:11,580 --> 00:11:11,900
away.

171
00:11:11,940 --> 00:11:13,740
You don't need to have that if you don't wish.

172
00:11:14,220 --> 00:11:18,820
So the only remaining thing for me to mention is what then is this?

173
00:11:18,820 --> 00:11:22,100
What is going on with the with the run up here?

174
00:11:22,220 --> 00:11:30,610
So This is the callback that gets called, and you can see that as part of this I am calling the research

175
00:11:30,650 --> 00:11:37,130
manager Dot run, and that is the the long function that we looked at a moment ago that had lots of

176
00:11:37,130 --> 00:11:38,330
yields in there.

177
00:11:38,450 --> 00:11:43,010
And that brings me to the final part of the puzzle, which is normally in Gradio.

178
00:11:43,010 --> 00:11:48,490
With these callbacks, you just return a result, the chat function that we've worked on in the past,

179
00:11:48,530 --> 00:11:50,610
that's an example of a callback.

180
00:11:50,770 --> 00:11:57,530
Chat just returns the result, but you can also, instead of doing that, have your callback functions

181
00:11:57,570 --> 00:12:03,530
be generators that Gradio needs to needs to iterate over and they will yield back results.

182
00:12:03,530 --> 00:12:09,010
And if you do that, then Gradio will show that incrementally in the user interface, so that you don't

183
00:12:09,010 --> 00:12:12,170
have to sit there and wait for a long time and suddenly see an output.

184
00:12:12,210 --> 00:12:14,610
You can see interim results as well.

185
00:12:14,610 --> 00:12:20,530
And that is why we had a bunch of yields, and that is why we have them here in our callback.

186
00:12:20,890 --> 00:12:24,370
I hope that makes some sense, but it certainly will do when we actually see it.

187
00:12:24,410 --> 00:12:26,170
If it works, let's find out.