تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Browser-Based Roast App0:00

All right, welcome back, everybody. So now, let's turn it up a notch. Let's figure out how we can take a response message from OpenAI and then convert it into speech. It's wild that we can do this, and even more wild, it's incredibly simple to do. I'll show you how. So let's see, in the last episode, we used a command line interface, so this time, let's go through the browser. And here's what I'm thinking. We'll have a homepage that shows a roast form. And yeah, that's what I'm thinking.

And here's what I'm thinking. We'll have a homepage that shows a roast form. And yeah, that's what I'm thinking. We're going to have a form that allows the User to request that AI roasts or behaves very sarcastically towards a given topic. So we'll call it a roast form, and then when you submit that form, it'll make a POST request to /roast, and this will then generate the prompt and fire it off to OpenAI. Okay, so let's do that now. Let's return, view, roast. And what I'll do is visit the welcome page and then rename this to roast so that we can reuse it.

Build Roast Form UI1:04

And what I'll do is visit the welcome page and then rename this to roast so that we can reuse it. Okay, so we're going to have a form here. The action will be /roast, and the method will be POST. And what I'm thinking is we'll have an input here with a placeholder of what would you or how about what do you want us to roast? All right, it's required, and we'll give it a couple classes. How about a border, a little padding, and make it rounded? All right, then we'll have a button, and we'll say roast. And then that should probably have some styling too,

All right, then we'll have a button, and we'll say roast. And then that should probably have some styling too, like once again, rounded, padding-2, maybe background-gray. Maybe when you hover over it, background-blue, maybe text-white. It doesn't matter, just something like this. All right, let's have a look in the browser. All right, and here is what we get. So it looks like it's not taking up enough space. It's probably because of the grid. Why don't we set a class of w-full?

It's probably because of the grid. Why don't we set a class of width-full? Yeah, but then it takes up, of course, the full area. So instead, we'll do a maximum width of max-w-small if we have a large screen, and then we will set the margins to auto to align it. So yeah, maybe medium. Ah, yeah, of course, on the input, here's what we'll do. On the div, we'll set a display of flex so that we can align these, and that will solve that alignment issue because it'll take the direct children of the flex container.

and that will solve that alignment issue because it'll take the direct children of the flex container, and it will stretch them to be the same height by default. Then what I can do is set a gap between them, and then on the input, I can say flex to take up all available space. And I think that should be okay. Yeah, that's perfect. Exactly what we want. Okay, so now imagine if I want to roast Laracast. When I submit this form, it's going to make a POST request to /roast

Okay, so now imagine if I want to roast Laracast. When I submit this form, it's going to make a POST request to /roast that will hit this endpoint, and why don't we just dd the input field? And I'm going to call it topic. So let's go back and give it a name of topic. All right, so roast Laracast, make a POST request, and of course, we get a 419. Sorry about that. It's because we need a CSRF field for Laravel. All right, one more time.

Validate and Send Prompt3:30

It's because we need a CSRF field for Laravel. All right, one more time. Very sorry about that. We make the POST request, we hit that endpoint, and then we dump the topic. Okay, so now we could generate the prompt, but first, let's validate the request. So I could say validate that the topic is required, and we'll do it as an array. Required a string, at least two characters, and a maximum of maybe 50 characters.

and we'll do it as an array. Required a string, at least two characters, and a maximum of maybe 50 characters, and that will give us our validated attributes. Okay, so now I can say our prompt will be um, please roast attributes topic in a sarcastic tone, or that is kind of redundant, but I just want to make it crystal clear what I mean by the word roast. So that is our prompt. And now let's generate a new instance of our Chat class that we've been working on. And I can then say chat send our prompt,

And now let's generate a new instance of our Chat class that we've been working on. And I can then say chat, send our prompt, and receive the response. And once again, just to check our work, I will die and dump that response message. All right, back to the browser. Roast, layer a cast, and now while this is doing its thing, keep in mind, it takes a number of seconds, right? And then further, when we generate the speech, it'll take even longer. So for a real life project, you should put this on a queue, and that way you can return early to the user.

So for a real life project, you should put this on a queue, and that way you can return early to the user. You can say processing, you can show a loading spinner, and it just provides a bit more feedback, rather than them submitting the form and wondering if it even worked. All right. Oh, Larrick asks, where do I even begin? What a fantastic platform if you enjoy tutorials from 10 years ago. All right, thank you very much for that. Okay, so let's clean this up now.

Add Speech Output Option5:13

All right, thank you very much for that. Okay, so let's clean this up now. I will simplify that. I will inline the instantiation. And now, here's a cool idea. If we want to turn the response into speech, maybe we could specify that's what we want. Like, what if I said the message is the prompt, but speech is true? And if we set that Boolean to true, it knows don't return the text response, create audio, and then return that.

And if we set that Boolean to true, it knows don't return the text response, create audio, and then return that. Okay, so let's go in here. And now we will have a Boolean for speech, and that will default to false. However, before we return, we could say, if we want speech, then why don't we call a speech method, pass through the response, otherwise return the text. All right, let's play around with this. speech, give us a message that will return an MP3, effectively. And yeah, check this out.

Speech, give us a message that will return an MP3, effectively. And yeah, check this out. This is how easy it is. I could say open AI, audio, and I want speech. All right, so I need to provide a number of parameters here. Let's click through. And yeah, this takes me to the underlying implementation. And they have a nice link to the actual open AI docs for creating speech. All right, here we go. So here is the request body.

All right, here we go. So here is the request body. We need to provide the model, the language model. And notice we have the option of TTS1 or an HD version. So TTS1 is fine for us. The input will be the text to generate audio from. And then we have a number of voices that we can choose from. And yeah, on your own, if you want, you can click through a number of these voices to try them out. Let's stick with, how about the one at the top, Alloy.

you can click through a number of these voices to try them out. Let's stick with, how about the one at the top, Alloy. All right, and that should do it. So let's switch back. And I'll say the model will be TTS1. The input will be the message. And the voice is going to be Alloy. All right, and that's it. So believe it or not, that's going to return an MP3 as a text string. Okay, so now at this point, we can decide what to do.

Save MP3 to Disk7:21

So believe it or not, that's going to return an MP3 as a text string. Okay, so now at this point, we can decide what to do. Like, should this method be responsible for writing to the file system? Or does it just return the MP3 itself? You can do whatever you want. In this case, why don't we, let's start by just returning it. And then if I go back to my routes file, response will now be the MP3. And yeah, right here, what I could do is say file_put_contents. How about the public_path? We'll put it in a roast folder.

How about the public path? We'll put it in a roast folder. And I will call it file.mp3. And the contents of that file will be the MP3 itself. Okay, so now why don't we just say dye and dump done. And then we can manually take a look. All right, let's roast. How about Ruby on Rails this time? All right, and yeah, just keep in mind, once again, it's going to take 10 or 15 seconds to complete.

All right, and yeah, just keep in mind, once again, it's going to take 10 or 15 seconds to complete. So you got to provide some better feedback than what we're currently doing. All right, that's done. So now if I open up my public directory, sure enough, we have our file. Perfect. But now I want to be careful about overriding that file. So it really should be unique. So with that in mind, I could generate a unique ID. I could do md5, whatever you want.

So with that in mind, I could generate a unique ID. I could do md5, whatever you want. Something like this might be fine, .mp3. And then I could say, you know, something like this. Or better yet, let's just pass file here and then say roast, like so. And then what I can do is concatenate it. Just to clean that up a little bit. All right, cool. So now here's what I'm thinking. Let's return a redirect back to the homepage.

Redirect and Download Link9:08

So now here's what I'm thinking. Let's return a redirect back to the homepage. But I'm going to add something to the session. We'll add a path to where the file is so that we can then offer a download button and then potentially a flash message like, boom, roasted. All right, cool. So now that's going to redirect back up here. And then within the view, we could very quickly just check to see if we have a file in the session. Else, and then, so yeah, in one condition, we show a download button.

if we have a file in the session. Else, and then, so yeah, in one condition, we show a download button. Otherwise, if there is nothing in the session, we can display the form. And that's a nice and quick way that we can tackle this. So maybe something like this. We'll have a link that will download the assets. So I can use the asset function and then provide the file name. And then I can say download audio. And then check this out. Right above it, I'm going to add a little GIF.

And then check this out. Right above it, I'm going to add a little GIF. And I think I have it in my clipboard, so I can paste it here. And you can take a look at that in just a second. All right, finally, let's add some styling. Let's make it block level. It'll take up the full space, although I guess it should already do that. text-center. Once again, background-gray. And actually, let's just grab all of that and we can repeat it.

Once again, background gray. And actually, let's just grab all of that and we can repeat it. Like that. Okay, why don't we stub it real quick? So by stub it, I just mean represent that we have something in the session. So I could say $file equals stub.mp3. And that way, I don't have to wait for us to submit that form again. Refresh. And yeah, there we go. So we got boom, roasted, and then a download button below it.

And yeah, there we go. So we got boom, roasted, and then a download button below it. And when you click it, it'll download it to your downloads directory, of course. All right, so if I switch back, let's just add a little margin above. Maybe 3. And yeah, that's effectively what I want. Okay, so let's see if I don't have anything in the session. Oh, it's still there because I didn't flash it. Okay, let's do this. Sorry about that.

Okay, let's do this. Sorry about that. Session forget file. And now we see this. All right, so I can remove this. Then we can roast something. We submit the form. That will hit this endpoint. We validate the request. We generate a prompt.

We validate the request. We generate a prompt. I can inline that now. That will specify that it should return the response as speech. We then specify where to save it. So I could even, I sometimes do this just to clean it up a little bit. Even though I think some people would say that's a big no-no. I don't know. I think it's fine. And then we turn a redirect by putting the file in the session.

I think it's fine. And then we turn a redirect by putting the file in the session where we then, back on the homepage, fetch it out of the session and display a download button. Finally, on the Chat class itself, our send method has a new speech Boolean. And if that is set to true, we then call the speech method that makes another request to the speech API and returns the response as an MP3. Now, yeah, something you could do on your own if you want is add like a save path.

Now, yeah, something you could do on your own if you want is add like a savePath. That could be a string or a boolean, maybe. And if that is set, that is our indication that we also want this method to write the MP3 to the file system. So that would be an option as well, if you want. Okay, but yeah. Otherwise, let's do our final run through. Roast Lyricast. We download the audio.

Roast Lyricast. We download the audio. Ooh, that's not right. Real quick. asset file. Oh, yeah, I'm sorry. asset session file. All right. This time we should be able to download it, and it works. Okay, so now I will wrap up this video by letting you listen.

This is just a simple explanation with no code.

It's pure magic, I tell you. And let's not forget about the riveting visuals. A simple slide deck with text that looks like it was designed in Microsoft Paint truly takes my breath away. Who needs fancy graphics or animations when you can have a plain white background and Times New Roman font? It's like stepping back into the early 2000s, where web design was at its peak. But perhaps my favorite part about Lyricasts is the way it tackles complex topics.

But perhaps my favorite part about Lyricasts is the way it tackles complex topics. Why bother with clear explanations or real-life examples when you can just throw out some random code snippets and hope for the best? It's like a treasure hunt, trying to decipher what on earth is happening on the screen. Who needs clarity and comprehension when you can have confusion and frustration? And let's not forget the overuse of jargon and technical terms.

when you can have confusion and frustration? And let's not forget the overuse of jargon and technical terms. Seriously, who needs plain English when you can sprinkle your sentences with acronyms and developer lingo? It's like a secret language that only the chosen few can understand. Ah, the exclusivity. But despite all my sarcastic remarks, I have to admit, Lyricasts does have a certain charm. It's like that quirky friend who always comes up with strange ideas and questionable fashion choices.

It's like that quirky friend who always comes up with strange ideas and questionable fashion choices. You can't help but laugh and shake your head, wondering how on earth they've come this far. So here's to you, Lyricasts. May you continue to entertain and confuse us with your unique blend of monotone speeches, outdated visuals, and cryptic code snippets. Cheers.

Cheers.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟