简单三步做一个基于Embedding的单词小游戏

前言:无意中刷到是视频,说由大模型驱动的单词小游戏,我还特意进去官网看看,确实挺有意思的,但说是大模型驱动我觉得大材小用了点,我想用简单的NLP技术去实现这个小游戏的demo。

在这里插入图片描述

特意进去看了看,是挺好玩的
https://neal.fun/infinite-craft
infinite-craft
下面用简单三步做一个小demo。

第一步:创建静态网页

首先网页段这一块很久没碰的很多技术生疏了,这次的页面我尝试用大语言模型帮我生成。像它这样炫酷的效果做不到,做个简单的效果作为展示吧。

提示词:
1.你现在是高级前端网页工程师,精通HTML,JS, CSS, Jquery和Jquery的animate动画效果
2.我希望你能作为一个高级前端开发者。我会描述项目的细节,你将使用以下工具进行项目编码:Create React App、yarn、Ant Design、List、Redux Toolkit、createSlice、thunk、axios。你应该将文件合并到一个index.js文件中,不要有其他文件。不要写解释。
3.帮我写一个jQuery开发的网站,需求:1.有两个长方形div,两个div都有文字,而且文字居中。2.两个div有一根线连着,而且两个div都可以拖动。3.当我拖动一个div到另一个div时,他们就会融合成一个新的div,而且中间的连接线消失。
4.是有一条线连上了,但我移动多了,线就连不上两个div,这样怎么解决?
5.当我拖动div到远一点的位置时,连接线就会发生位移,不能连接在两个div上,请问怎么解决?
6.这段代码的直线特效很好,能不能加强一下这个特效:当两个div距离超过300px的时候,透明度逐渐降低,当两个div距离超过400px时,直线的透明度为0.

以上就是我的提示词, 我用了文心一言和GPT对比了一下,两个模型都能生成网页代码,但文心一言的代码有很多需要自己去修改。GPT也有自己的错误,但错误率很小,基本生成就能用。 如果大家有什么看法欢迎在评论区评论。
请添加图片描述
这是Copilot帮我生成的静态代码效果。代码在下面。

<!DOCTYPE html>
<html>
<head>
    <title>jQuery Div Interaction</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            border: 1px solid black;
            position: absolute;
            text-align: center;
            line-height: 100px;
            z-index: 2;
        }
        #box1 {
            top: 50px;
            left: 50px;
        }
        #box2 {
            top: 50px;
            left: 200px;
        }
        #line {
            position: absolute;
            background-color: black;
            height: 2px;
            transform-origin: 0 0;
            z-index: 1;
        }
    </style>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
</head>
<body>
<div id="box1" class="box">Box 1</div>
<div id="box2" class="box">Box 2</div>
<div id="line"></div>

<script>
        $(function() {
            function updateLine() {
                var offset1 = $("#box1").offset();
                var offset2 = $("#box2").offset();
                var dx = offset2.left - offset1.left;
                var dy = offset2.top - offset1.top;
                var angle = Math.atan2(dy, dx) * 180 / Math.PI;
                var distance = Math.sqrt(dx * dx + dy * dy);

                var opacity = 1;
                if (distance > 300) {
                    opacity = 1 - (distance - 300) / 100;
                }
                if (distance > 400) {
                    opacity = 0;
                }

                $("#line").css({
                    'transform': 'rotate(' + angle + 'deg)',
                    'width': distance,
                    'top': offset1.top + 50,
                    'left': offset1.left + 50,
                    'opacity': opacity
                });
            }

            $(".box").draggable({
                drag: function() {
                    var timer = setInterval(updateLine, 10);

                    var offset1 = $("#box1").offset();
                    var offset2 = $("#box2").offset();
                    var dx = offset1.left - offset2.left;
                    var dy = offset1.top - offset2.top;
                    var distance = Math.sqrt(dx * dx + dy * dy);

                    if (distance < 100) {
                        $("#box1").text("Merged Box");
                        $("#box2").remove();
                        $("#line").remove();
                        clearInterval(timer);
                    }
                }
            });

            updateLine();
        });
    </script>
</body>
</html>

第二步:训练自己的词嵌入模型

页面代码完了后我们训练自己的embedding模型。
我们将使用这个 text8数据集。该数据集摘自维基百 科,经常用于训练词嵌入和语言模型。

import requests
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence

# 下载数据
url = "https://realworldnlpbook.s3.amazonaws.com/data/text8/text8"
response = requests.get(url)
with open('text8', 'w') as f:
    f.write(response.text)

# 读取数据
sentences = LineSentence('text8')

# 训练模型
model = Word2Vec(sentences, vector_size=100, window=5, min_count=1, workers=4)

# 保存模型
model.save("model/word2vec.model")

测试模型,这里寻找每个单词相近的1000个单词

from gensim.models import Word2Vec

# 加载模型
model = Word2Vec.load("model/word2vec.model")
#
# # 查询相近的词
word1 = "water"
word1_similar_words = [word for word, similarity in model.wv.most_similar(word1, topn=1000)]
word2 = "fire"
word2_similar_words = [word for word, similarity in model.wv.most_similar(word2, topn=1000)]

def find_first_common_word(list1, list2):

    # 遍历第二个列表,检查每个单词是否在第一个列表中出现过
    for word1 in list1:
        for word2 in list2:
            if word1 == word2:
                return word1

    # 如果没有找到相同的单词,返回None
    return None

print(find_first_common_word(word1_similar_words,word2_similar_words))

输出

moisture

Process finished with exit code 0

第三步:搭建前后台

做完简单的测试后,我们正式搭建网站
根据第一步做的静态页面,我们做了一些小的修改,加入了异步Ajax和后台数据通信。

<!DOCTYPE html>
<html>
<head>
  <title>Word Game</title>
  <style>
        .box {
            width: 100px;
            height: 100px;
            border: 1px solid black;
            position: absolute;
            text-align: center;
            line-height: 100px;
            z-index: 2;
            background-color: white;
        }
        #element1 {
            top: 50px;
            left: 50px;
        }
        #element2 {
            top: 50px;
            left: 200px;
        }
        #line {
            position: absolute;
            background-color: black;
            height: 2px;
            transform-origin: 0 0;
            z-index: 1;
        }
    </style>
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
</head>
<body>
<div id="element1" class="box">plant</div>
<div id="element2" class="box">fire</div>
<div id="line"></div>

<script>
        $(function() {
            var needUpdateLine = true;
            function updateLine() {
              if(needUpdateLine){
                var offset1 = $("#element1").offset();
                  var offset2 = $("#element2").offset();
                  var dx = offset2.left - offset1.left;
                  var dy = offset2.top - offset1.top;
                  var angle = Math.atan2(dy, dx) * 180 / Math.PI;
                  var distance = Math.sqrt(dx * dx + dy * dy);

                  var opacity = 1;
                  if (distance > 300) {
                      opacity = 1 - (distance - 300) / 100;
                  }
                  if (distance > 400) {
                      opacity = 0;
                  }

                  $("#line").css({
                      'transform': 'rotate(' + angle + 'deg)',
                      'width': distance,
                      'top': offset1.top + 50,
                      'left': offset1.left + 50,
                      'opacity': opacity
                  });
              }
            }

            $(".box").draggable({
                drag: function() {
                  var offset1 = $("#element1").offset();
                  var offset2 = $("#element2").offset();
                  if(offset2 != null){
                    var timer = setInterval(updateLine, 10);

                    var dx = offset1.left - offset2.left;
                    var dy = offset1.top - offset2.top;
                    var distance = Math.sqrt(dx * dx + dy * dy);

                    if (distance < 100) {
                      var element1 = $("#element1").text();
                      var element2 = $("#element2").text();

                      $.ajax({
                          url: '/game',
                          type: 'post',
                          data: {
                              'element1': element1,
                              'element2': element2
                          },
                          success: function(data) {
                              $("#element1").text(data);
                              $("#element2").remove();
                              $("#line").remove();
                              clearInterval(timer);
                              needUpdateLine = false;
                          },
                          error: function(err) {
                              console.log(err);
                          }
                      });
                    }
                  }

                }
            });

            updateLine();


        });
    </script>
</body>
</html>

根据第二步做的model,把它嵌入到后台。这里多加了一个方法find_first_common_word(list1, list2),作用就是寻找两个列表中第一个相识的单词。

from flask import Flask, request, jsonify, redirect, url_for

import torch
from torch.nn import functional
from gensim.models import Word2Vec

app = Flask(__name__, static_url_path='', static_folder='static')

# 加载模型
model = Word2Vec.load("model/word2vec.model")


@app.route('/')
def index():
    return redirect('index.html')

@app.route('/game', methods=['POST'])
def game():
    if request.method == 'POST':
        element1 = request.form['element1']
        element2 = request.form['element2']
        # # 查询相近的词
        element1_similar_words = [word for word, similarity in model.wv.most_similar(element1, topn=1000)]
        element2_similar_words = [word for word, similarity in model.wv.most_similar(element2, topn=1000)]
        similar_word = find_first_common_word(element1_similar_words,element2_similar_words)
        print(similar_word)
        return similar_word
    else:
        return app.send_static_file('login.html')

def find_first_common_word(list1, list2):

    # 遍历第二个列表,检查每个单词是否在第一个列表中出现过
    for word1 in list1:
        for word2 in list2:
            if word1 == word2:
                return word1

    # 如果没有找到相同的单词,返回None
    return None

if __name__ == '__main__':
    app.run(port=5000)

项目架构
在这里插入图片描述

最终效果

请添加图片描述

项目连接

Embedding-WordGame

写在后面

1.每个词嵌入模型不一样,下面是infinite-craft的词嵌入模型和我这次训练的词向量模型的对比
infinite-craft我训练的
fire 碰撞 water= steam(蒸汽)fire 碰撞 water= moisture(水汽)
fire 碰撞 plant= smoke(烟雾)fire 碰撞 plant= charcoal(木炭)
fire 碰撞 tea= chai(茶)fire 碰撞 tea= fresh(新鲜)
water 碰撞 wind= wave(波浪)water 碰撞 wind= moisture(水汽)
wind 碰撞 plant= dandelion(蒲公英)wind 碰撞 plant= sediment(沉积物)
。。。。。。
2.另外我觉得这个infinite-craft应该是用固定的单词,可以1000个或100个,因为每个单词都有logo,它可能是用embedding的模型去查已经准备好的单词。反反复复可能又会变回原来的单词。
3.另一个我想说的是Copilot,这次我让它简单生成一个页面代码,还带有点小特效。效果还不错,但要它继续做出6个div,每个div都有连接线,每两个div碰撞就能合并成一个div。对于这样复杂的逻辑,Copilot就显得有点乱,生成的代码有错漏,但你指出它的错漏时,它会意识到自己错误并加以改正,效果好了,但还是没有达到想要的效果。可能暂时GPT的极限就到这吧。

但总体上还是挺有意思的,你也可以基于词嵌入开发出不同的游戏,欢迎和我一起分享~

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值