Non, merci et au revoir.
Ok, tout d’abord, je m’excuse pour le titre de style click-bait. De temps en temps, quand j'ai une idée de démo, ça ne marche pas. Mais parfois , cela ne fonctionne pas de manière amusante et intéressante, et je pense que c'est quand même une bonne idée de le partager. (De plus, il y a toujours de fortes chances que cela n'ait pas fonctionné parce que j'ai fait quelque chose de mal !) La démo d'aujourd'hui en est un parfait exemple, je pense.
Plus tôt cette année, j'ai créé un jeu de Blackjack en utilisant Alpine.js et l'excellente API Deck of Cards . Hier, je pensais au jeu et je me demandais : que se passerait-il si j'utilisais l'IA générative pour demander de l'aide en y jouant ? Ainsi, par exemple, je suis allé à mon jeu et j'ai vu ceci :
Dans l'application PaLM Makersuite de Google, j'ai écrit :
Je joue au blackjack et le croupier a un six de carreau. J'ai un valet de trèfle et un valet de cœur. Dois-je frapper ou dois-je rester ?
Et j'ai eu cette réponse :
Vous en avez 20, ce qui est une bonne main. Le concessionnaire en possède 16, ce qui est inférieur à la moyenne. Si vous frappez, vous risquez d'obtenir une carte qui vous fera perdre. Il vaut donc mieux rester et espérer que le dealer fasse faillite.
Ce qui, ok, est assez évident. Vous ne frapperiez jamais avec deux Valets. Mais j'ai adoré la réponse descriptive qui renforce les principes du jeu. J'ai pensé : et si j'ajoutais un bouton au jeu qui vous permet de demander de l'aide à GenAI ? Voici comment j'ai procédé :
Sur le front-end, j’ai gardé les modifications de l’interface utilisateur assez minimes. J'ai commencé par ajouter un simple bouton :
En cliquant dessus, vous devez faire deux choses importantes. Premièrement, il doit « traduire » l’état du jeu en une invite ; Ensuite, il doit transmettre cela à un service qui gérera l'appel gen AI . J'ai créé une nouvelle fonction, askForHelp
, qui le gère :
async askForHelp() { this.aiHelp = '<i>Asking our AI friend...</i>'; // first, "translate" the cards to English let q = `I'm playing blackjack and the dealer currently has ${this.pcCards[1].value} of ${this.pcCards[1].suit.toLowerCase()}. I've got a ${this.playerCards[0].value} of ${this.playerCards[0].suit.toLowerCase()} and a ${this.playerCards[1].value} of ${this.playerCards[1].suit.toLowerCase()}. Should I hit or should I stay?`; console.log(q); let resp = await fetch(`https://eo8dkukowewth66.m.pipedream.net?text=${encodeURIComponent(q)}`); let help = await resp.json(); /* note that help has line breaks and stuff in and in theory we should map to br or something, but im fine ignoring. */ this.aiHelp = ''; alert(help); },
Je stocke les cartes du joueur et du PC dans deux variables contenant un tableau de cartes représentant leurs mains. Chaque carte a une « valeur », qui est soit un nombre, soit un nom, comme Jack. Chaque carte a également une couleur. En théorie, ce n’est probablement pas une information critique, mais j’ai pensé que cela ne pouvait pas faire de mal. Voici un exemple d'invite générée par un jeu :
I'm playing blackjack and the dealer currently has 8 of clubs. I've got a 7 of spades and a QUEEN of hearts. Should I hit or should I stay?
Ceci est transmis à mon service backend (plus de détails dans une seconde), et le résultat est ensuite affiché dans une alerte JavaScript, qui est 100% horrible UX, mais comme il s'agissait d'une expérience, j'ai pensé que c'était assez bon.
Si vous êtes curieux, voici la réponse :
Rester. Vous en avez un total de 17, ce qui est une bonne main. Le 8 du croupier n'est pas une carte haute, il est donc peu probable que vous perdiez si vous restez.
Pour mon back-end, j'ai mis au point un workflow Pipedream rapide. Mon flux de travail ne comprenait littéralement que trois étapes.
Le premier est mon déclencheur, un point de terminaison HTTP. Vous pouvez voir l'URL dans le code frontal ci-dessus.
La deuxième étape est l'action intégrée de l'API Google PaLM. Tout ce que j'avais à faire était de lui dire quoi utiliser pour une invite : {{steps.trigger.event.query.text}}
Ma dernière étape a simplement renvoyé le résultat :
export default defineComponent({ async run({ steps, $ }) { await $.respond({ status: 200, headers: { "Content-Type":"application/json" }, body: JSON.stringify(steps.generate_text.$return_value[0].candidates[0].output), }) }, })
Donc voilà. Mes premiers tests ont très bien fonctionné, et puis... les choses ont déraillé. Voici un exemple. Le croupier avait un sept de cœur. J'avais une dame de pique et un huit de carreau. Lorsque j'ai demandé de l'aide, j'ai obtenu :
La carte visible du croupier est le 7, ce qui est un 17 « dur ». Cela signifie que le croupier doit rester debout, quoi que vous fassiez. Vous avez un 19 « doux », ce qui signifie que vous avez un as qui peut compter pour 1 ou 11. Vous devriez rester.
Ok, bien sûr, je devrais rester, mais qu'en est-il dans la vraie affaire ? J'en ai 19 ? Le croupier en a 17 ? Et ça va mieux. Une fois, alors que j'en avais 18, j'ai obtenu ce qui suit :
Je recommanderais de frapper. Avec un total de 18, vous n'êtes qu'à un point du 21, qui est la main gagnante au blackjack. Le sept de cœur du croupier leur donne un total de 17, ce qui est inférieur au seuil des 21. Par conséquent, il y a de fortes chances que le croupier fasse faillite s'il frappe, ce qui vous donnerait la victoire. Cependant, si vous restez, vous ne pourrez pas améliorer votre main et devrez espérer que le croupier fasse faillite.
Frapper sur 18. Je ne suis pas un joueur professionnel, mais je suis presque sûr que c'est un mauvais conseil.
Cela m'a fait réfléchir un peu plus à mon invite. J'ai fait quelques ajustements, comme mettre la combinaison en minuscules, car je craignais que cela n'ait pu confondre l'IA. J'ai parcouru certaines options de Makersuite et, de manière constante, il semblait parfois avoir du mal avec les mathématiques de base. Même quand j'étais explicite :
J'ai un valet de trèfle (qui vaut dix) et un huit de cœur (qui vaut 8).
Il pensait toujours que j'en avais 19. J'ai eu plus de chance avec ceci :
J'ai un valet de trèfle (qui vaut dix) et un huit de cœur (qui vaut 8). Mon total de main est de 18.
Et j'ai aussi essayé ceci :
J'ai un as de trèfle et un huit de cœur. Mon total de main est de 9 ou 19.
Et cela semblait toujours fonctionner correctement. Donc, dans cet esprit, je suis revenu à ma génération d'invites et j'y ai mis à jour ma logique. Voici la version mise à jour :
async askForHelp() { this.aiHelp = '<i>Asking our AI friend...</i>'; let totalOb = this.getCount(this.playerCards); let totalStr = 'My hand has a total of '; if(totalOb.lowCount === totalOb.highCount) { totalStr += totalOb.lowCount; } else { totalStr += `${totalOb.lowCount} or ${totalOb.highCount}`; } // first, "translate" the cards to English let q = `I'm playing blackjack and the dealer currently has ${this.pcCards[1].value} of ${this.pcCards[1].suit.toLowerCase()}. I've got a ${this.playerCards[0].value} of ${this.playerCards[0].suit.toLowerCase()} and a ${this.playerCards[1].value} of ${this.playerCards[1].suit.toLowerCase()}. ${totalStr}. Should I hit or should I stay?`; console.log(q); let resp = await fetch(`https://eo8dkukowewth66.m.pipedream.net?text=${encodeURIComponent(q)}`); let help = await resp.json(); console.log('RESP', help); /* note that help has line breaks and stuff in and in theory we should map to br or something, but im fine ignoring. */ this.aiHelp = ''; alert(help); },
Mon jeu de Blackjack a une fonction utilitaire, getCount
, qui renvoie un objet contenant deux valeurs lowCount
, où les As sont traités comme un, et highCount
, où un As au plus est considéré comme onze. Avec cela, j'ajoute à mon invite des informations sur le total.
Cela a beaucoup aidé, mais j'ai quand même parfois renvoyé des réponses délirantes.
Alors... peut-être considérez-le comme votre ami ivre à la table de jeu qui vous donne des conseils ?
J'adorerais partager publiquement cette version de la démo, et je peux bien sûr partager le code, mais je désactive le flux de travail Pipedream afin de ne pas être facturé pour cela. N'hésitez pas à consulter le code front-end ici :
https://codepen.io/cfjedimaster/pen/QWYpQjY/905e31ed6d9e3539c041044b308f5f06?editors=1011
Comme toujours, dites-moi ce que vous en pensez !
Également publié ici .