头图

我正在参加Trae「超级体验官」创意实践征文,本文所使用的 Trae 免费下载链接:www.trae.com.cn/?utm_source…

本文简介

如今,不了解一些互联网流行语的人,会显得像个刚通网的新手。从早期的"神马都是浮云"到"2333",再到"尊嘟假嘟"、"偷感"、"班味"、"city不city",互联网新词每年都层出不穷。

这些新词不仅有趣,更能体现群体认同感,只有圈内人才能心领神会。

说到这个,我想起前两年有一款很火的「兽音译者」工具,它可以将自然语言转换成猛兽咆哮的声音(拟声词),同时也能将这些兽音解译回人类的自然语言。

举个例子,它可以将 你好 转换成 ~呜嗷呜嗷嗷嗷啊嗷嗷~啊呜~啊~呜呜嗷啊,反之亦然。

在这款工具爆火后也出现了其他变体,比如"新佛曰"。这种形式很有意思,非常符合当今的"佛系"潮流。

虽然这类工具看似不是刚需产品,但在某些场景下却是很实用的神器。比如当你想在某平台分享其他平台的链接时,可以用它来加密内容,读者解密后就能食用。又或者,你想在小群里吐槽老板却担心被截图,那就先加密再发,懂的人自然能理解。

由于这类工具多数是网页形式,移动端体验并不理想,相比起“兽音”我更喜欢“佛曰”,它们的原理都是一样的。所以我用 Trae 仿了一个「佛曰」微信小程序出来。

虽然我不太明白它的加密原理,但现在已经进入AI时代,是工具井喷时期,我们有了更便捷的解决方案,直接让AI来根据原文和加密内容实现一个类似“兽音译者”的加密解密算法。

当回产品经理过过瘾吧~

07.gif

开始动手

在”微信开发者工具“创建一个小程序项目。我用的是JS版本,该项目都是纯前端就可以实现字符串的加密解密功能,所以不需要使用云服务。

项目名字就起一个二次元一点的,就叫“光刻符文”吧。

01.png

现在预览看到的界面是这样的,这是小程序项目初始化的界面。

02.png

项目里面的代码看不懂也没关系,你只要知道怎么在 Trae 里给 AI 提需求就行了。

在 Trae 打开刚刚创建好的小程序项目,按 command + u 打开聊天面板(windows用户按 ctrl + u ),输入第一个需求。

仿照"兽音译者",制作一个基于佛经用语的加密小程序。比如,当输入"雷猴"时,加密后会生成类似"佛曰:金慧涅量无界法若"这样的结果。该程序需要具备双向转换功能:既能加密原文,也能将加密文本解析回原文。特别要求:同一段文字每次加密可生成不同的结果,但所有加密结果都能被正确解析为相同的原文。

03.png

我使用的模型是 Claude-3.7-Sonnet ,它接受完需求后就开始思考如何实现,过一阵子就给出具体的实现代码。

04.jpg

提醒一下,本文使用的是 Trae 1.3.5 版本(当前最新版)。此版本生成的代码需要手动点击代码段右上角的"应用"按钮才能写入项目文件,不会自动写入。

最后还会很贴心的给出一份简单的使用说明和加密原理的讲解,生怕你的PPT没东西可以写😆

05.png

令我意外的是,居然只输入了一次提示词就把具体的功能实现了。AI还在我没提出"复制结果"这个需求的情况下,主动优化了产品功能。

一起来看看效果。

06.gif

html 代码:pages/index/index.wxml

<!--index.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
  <view class="container">
    <view class="title">佛经加密器</view>
    
    <view class="input-area">
      <textarea class="text-input" placeholder="请输入要转换的文字" bindinput="onInputChange" value="{{inputText}}"></textarea>
    </view>
    
    <view class="button-group">
      <button class="encrypt-btn" bindtap="encrypt">加密</button>
      <button class="decrypt-btn" bindtap="decrypt">解密</button>
    </view>
    
    <view class="result-area" wx:if="{{resultText}}">
      <view class="result-title">{{isEncrypted ? '加密结果' : '解密结果'}}</view>
      <view class="result-content">{{resultText}}</view>
      <button class="copy-btn" bindtap="copyResult">复制结果</button>
    </view>
  </view>
</scroll-view>

css 代码:代码:pages/index/index.wxss

/**index.wxss**/
page {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #f8f8f8;
}

.scrollarea {
  flex: 1;
  overflow-y: hidden;
}

.container {
  padding: 30rpx;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.title {
  font-size: 48rpx;
  font-weight: bold;
  margin-bottom: 40rpx;
  color: #333;
  text-align: center;
}

.input-area {
  width: 100%;
  margin-bottom: 30rpx;
}

.text-input {
  width: 100%;
  height: 200rpx;
  border: 1px solid #ddd;
  border-radius: 8rpx;
  padding: 20rpx;
  box-sizing: border-box;
  background-color: #fff;
}

.button-group {
  display: flex;
  width: 100%;
  justify-content: space-between;
  margin-bottom: 30rpx;
}

.encrypt-btn, .decrypt-btn {
  width: 48%;
  background-color: #4a90e2;
  color: white;
}

.result-area {
  width: 100%;
  background-color: #fff;
  border-radius: 8rpx;
  padding: 20rpx;
  box-sizing: border-box;
  margin-top: 20rpx;
  border: 1px solid #ddd;
}

.result-title {
  font-size: 32rpx;
  font-weight: bold;
  margin-bottom: 20rpx;
  color: #333;
}

.result-content {
  word-break: break-all;
  margin-bottom: 20rpx;
  color: #666;
  font-size: 28rpx;
}

.copy-btn {
  margin-top: 20rpx;
  background-color: #4a90e2;
  color: white;
  font-size: 28rpx;
}
.userinfo {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #aaa;
  width: 80%;
}

.userinfo-avatar {
  overflow: hidden;
  width: 128rpx;
  height: 128rpx;
  margin: 20rpx;
  border-radius: 50%;
}

.usermotto {
  margin-top: 200px;
}

.avatar-wrapper {
  padding: 0;
  width: 56px !important;
  border-radius: 8px;
  margin-top: 40px;
  margin-bottom: 40px;
}

.avatar {
  display: block;
  width: 56px;
  height: 56px;
}

.nickname-wrapper {
  display: flex;
  width: 100%;
  padding: 16px;
  box-sizing: border-box;
  border-top: .5px solid rgba(0, 0, 0, 0.1);
  border-bottom: .5px solid rgba(0, 0, 0, 0.1);
  color: black;
}

.nickname-label {
  width: 105px;
}

.nickname-input {
  flex: 1;
}

js 代码:pages/index/index.js

// index.js

Page({
  data: {
    inputText: '',
    resultText: '',
    isEncrypted: false
  },

  onInputChange(e) {
    this.setData({
      inputText: e.detail.value
    });
  },

  // 加密函数
  encrypt() {
    const text = this.data.inputText;
    if (!text) {
      wx.showToast({
        title: '请输入要加密的文字',
        icon: 'none'
      });
      return;
    }

    // 佛经用语字典
    const buddhistTerms = [
      '佛', '法', '僧', '戒', '定', '慧', '忍', '精进', '禅', '慈', '悲', '喜', '舍',
      '空', '无相', '无愿', '无量', '真如', '实相', '涅槃', '菩提', '般若', '智慧', '解脱',
      '缘起', '中道', '如来', '菩萨', '罗汉', '因果', '轮回', '业力', '六度', '四谛', '八正道'
    ];

    // 将文本转换为Unicode码点
    let encryptedText = '';
    for (let i = 0; i < text.length; i++) {
      const charCode = text.charCodeAt(i);
      // 随机选择3-5个佛经词汇
      const termCount = Math.floor(Math.random() * 3) + 3;
      for (let j = 0; j < termCount; j++) {
        const randomIndex = Math.floor(Math.random() * buddhistTerms.length);
        encryptedText += buddhistTerms[randomIndex];
      }
      // 将字符编码嵌入到加密文本中
      encryptedText += String.fromCharCode(charCode + 20); // 简单偏移加密
    }

    // 添加佛经前缀
    encryptedText = '佛曰:' + encryptedText;

    this.setData({
      resultText: encryptedText,
      isEncrypted: true
    });
  },

  // 解密函数
  decrypt() {
    let text = this.data.inputText;
    if (!text) {
      wx.showToast({
        title: '请输入要解密的文字',
        icon: 'none'
      });
      return;
    }

    // 移除佛经前缀
    if (text.startsWith('佛曰:')) {
      text = text.substring(3);
    }

    // 佛经用语字典中的所有字符
    const buddhistChars = '佛法僧戒定慧忍精进禅慈悲喜舍空无相愿量真如实相涅槃菩提般若智慧解脱缘起中道如来菩萨罗汉因果轮回业力六度四谛八正道';
    
    let decryptedText = '';
    let i = 0;
    
    while (i < text.length) {
      // 跳过佛经用语字符
      while (i < text.length && buddhistChars.includes(text[i])) {
        i++;
      }
      
      // 如果还有字符,解密它
      if (i < text.length) {
        const charCode = text.charCodeAt(i) - 20; // 反向偏移解密
        decryptedText += String.fromCharCode(charCode);
        i++;
      }
    }

    this.setData({
      resultText: decryptedText,
      isEncrypted: false
    });
  },

  // 复制结果到剪贴板
  copyResult() {
    wx.setClipboardData({
      data: this.data.resultText,
      success: () => {
        wx.showToast({
          title: '复制成功',
          icon: 'success'
        });
      }
    });
  }
});

优化交互

大家在手机上发送文字时都习惯了微信这样的聊天界面,直接模仿微信的交互方式是不是更好呢?🤔

于是我向AI提供了新的提示词,让它设计成微信聊天页的样式。不过这样做也带来了一个新问题:程序需要判断什么时候该加密,什么时候该解密。

观察加密结果可以发现,以"佛曰:"开头的就是加密文本,其他则是需要加密的自然语言。

基于这个发现,我给出了以下提示词。

加密解密算法虽然正确,但交互体验需要改进。采用类似微信聊天的界面布局:用户在输入框中输入内容并点击发送按钮后,输入内容会在聊天记录面板靠右侧显示。程序的加密或解密结果则紧随其后(下方),靠左侧显示。程序自动判断处理方式,如果用户输入以"佛曰:"开头,则执行解密;否则执行加密。

07.gif

从结果上可以看出,它真的可以比较精确的按照我的需求去实现了。

本轮的代码:

html 代码:pages/index/index.wxml

<!--index.wxml-->
<view class="container">
  <view class="header">
    <text class="title">佛经加密器</text>
  </view>
  
  <scroll-view 
    class="chat-container" 
    scroll-y="true" 
    scroll-top="{{scrollTop}}"
    id="chat-container"
  >
    <view class="messages">
      <block wx:for="{{chatMessages}}" wx:key="index">
        <view class="message-wrapper {{item.type === 'user' ? 'user-message-wrapper' : 'system-message-wrapper'}}">
          <view class="message {{item.type === 'user' ? 'user-message' : 'system-message'}}" bindtap="copyMessage" data-index="{{index}}">
            <text>{{item.content}}</text>
          </view>
        </view>
      </block>
    </view>
  </scroll-view>
  
  <view class="input-area">
    <input 
      class="message-input" 
      placeholder="输入文字加密或解密" 
      value="{{inputText}}" 
      bindinput="onInputChange"
      confirm-type="send"
      bindconfirm="sendMessage"
    />
    <button class="send-button" bindtap="sendMessage">发送</button>
  </view>
</view>

html 代码:pages/index/index.wxss

/**index.wxss**/
page {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #f1f1f1;
}

.container {
  display: flex;
  flex-direction: column;
  height: 100%;
  box-sizing: border-box;
}

.header {
  padding: 20rpx;
  text-align: center;
  background-color: #4a90e2;
  color: white;
}

.title {
  font-size: 36rpx;
  font-weight: bold;
}

.chat-container {
  flex: 1;
  padding: 20rpx;
  box-sizing: border-box;
  overflow-y: auto;
}

.messages {
  display: flex;
  flex-direction: column;
}

.message-wrapper {
  margin-bottom: 20rpx;
  display: flex;
  width: 100%;
}

.user-message-wrapper {
  justify-content: flex-end;
}

.system-message-wrapper {
  justify-content: flex-start;
}

.message {
  max-width: 70%;
  padding: 20rpx;
  border-radius: 10rpx;
  word-break: break-all;
  font-size: 28rpx;
}

.user-message {
  background-color: #9eea6a;
  color: #333;
}

.system-message {
  background-color: white;
  color: #333;
}

.input-area {
  display: flex;
  padding: 20rpx;
  background-color: #f8f8f8;
  border-top: 1rpx solid #e0e0e0;
}

.message-input {
  flex: 1;
  height: 80rpx;
  background-color: white;
  border-radius: 8rpx;
  padding: 0 20rpx;
  margin-right: 20rpx;
  font-size: 28rpx;
}

.send-button {
  width: 120rpx;
  height: 80rpx;
  line-height: 80rpx;
  font-size: 28rpx;
  padding: 0;
  background-color: #4a90e2;
  color: white;
}

.scrollarea {
  flex: 1;
  overflow-y: hidden;
}

.container {
  padding: 30rpx;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.title {
  font-size: 48rpx;
  font-weight: bold;
  margin-bottom: 40rpx;
  color: #333;
  text-align: center;
}

.input-area {
  width: 100%;
  margin-bottom: 30rpx;
}

.text-input {
  width: 100%;
  height: 200rpx;
  border: 1px solid #ddd;
  border-radius: 8rpx;
  padding: 20rpx;
  box-sizing: border-box;
  background-color: #fff;
}

.button-group {
  display: flex;
  width: 100%;
  justify-content: space-between;
  margin-bottom: 30rpx;
}

.encrypt-btn, .decrypt-btn {
  width: 48%;
  background-color: #4a90e2;
  color: white;
}

.result-area {
  width: 100%;
  background-color: #fff;
  border-radius: 8rpx;
  padding: 20rpx;
  box-sizing: border-box;
  margin-top: 20rpx;
  border: 1px solid #ddd;
}

.result-title {
  font-size: 32rpx;
  font-weight: bold;
  margin-bottom: 20rpx;
  color: #333;
}

.result-content {
  word-break: break-all;
  margin-bottom: 20rpx;
  color: #666;
  font-size: 28rpx;
}

.copy-btn {
  margin-top: 20rpx;
  background-color: #4a90e2;
  color: white;
  font-size: 28rpx;
}
.userinfo {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #aaa;
  width: 80%;
}

.userinfo-avatar {
  overflow: hidden;
  width: 128rpx;
  height: 128rpx;
  margin: 20rpx;
  border-radius: 50%;
}

.usermotto {
  margin-top: 200px;
}

.avatar-wrapper {
  padding: 0;
  width: 56px !important;
  border-radius: 8px;
  margin-top: 40px;
  margin-bottom: 40px;
}

.avatar {
  display: block;
  width: 56px;
  height: 56px;
}

.nickname-wrapper {
  display: flex;
  width: 100%;
  padding: 16px;
  box-sizing: border-box;
  border-top: .5px solid rgba(0, 0, 0, 0.1);
  border-bottom: .5px solid rgba(0, 0, 0, 0.1);
  color: black;
}

.nickname-label {
  width: 105px;
}

.nickname-input {
  flex: 1;
}

html 代码:pages/index/index.js

// index.js
Page({
  // index.js
  data: {
    inputText: '',
    chatMessages: [],
    scrollTop: 0
  },

  onInputChange(e) {
    this.setData({
      inputText: e.detail.value
    });
  },

  // 发送消息
  sendMessage() {
    const text = this.data.inputText.trim();
    if (!text) {
      wx.showToast({
        title: '请输入内容',
        icon: 'none'
      });
      return;
    }

    // 添加用户消息到聊天记录
    const userMessage = {
      content: text,
      type: 'user'
    };

    let messages = [...this.data.chatMessages, userMessage];
    this.setData({
      chatMessages: messages,
      inputText: ''
    });

    // 自动判断处理方式
    if (text.startsWith('佛曰:')) {
      this.processDecrypt(text, messages);
    } else {
      this.processEncrypt(text, messages);
    }
  },

  // 处理加密
  processEncrypt(text, messages) {
    // 佛经用语字典
    const buddhistTerms = [
      '佛', '法', '僧', '戒', '定', '慧', '忍', '精进', '禅', '慈', '悲', '喜', '舍',
      '空', '无相', '无愿', '无量', '真如', '实相', '涅槃', '菩提', '般若', '智慧', '解脱',
      '缘起', '中道', '如来', '菩萨', '罗汉', '因果', '轮回', '业力', '六度', '四谛', '八正道'
    ];

    // 将文本转换为Unicode码点
    let encryptedText = '';
    for (let i = 0; i < text.length; i++) {
      const charCode = text.charCodeAt(i);
      // 随机选择3-5个佛经词汇
      const termCount = Math.floor(Math.random() * 3) + 3;
      for (let j = 0; j < termCount; j++) {
        const randomIndex = Math.floor(Math.random() * buddhistTerms.length);
        encryptedText += buddhistTerms[randomIndex];
      }
      // 将字符编码嵌入到加密文本中
      encryptedText += String.fromCharCode(charCode + 20); // 简单偏移加密
    }

    // 添加佛经前缀
    encryptedText = '佛曰:' + encryptedText;

    // 添加系统回复消息
    const systemMessage = {
      content: encryptedText,
      type: 'system'
    };

    messages.push(systemMessage);
    this.setData({
      chatMessages: messages
    }, () => {
      this.scrollToBottom();
    });
  },

  // 处理解密
  processDecrypt(text, messages) {
    // 移除佛经前缀
    if (text.startsWith('佛曰:')) {
      text = text.substring(3);
    }

    // 佛经用语字典中的所有字符
    const buddhistChars = '佛法僧戒定慧忍精进禅慈悲喜舍空无相愿量真如实相涅槃菩提般若智慧解脱缘起中道如来菩萨罗汉因果轮回业力六度四谛八正道';
    
    let decryptedText = '';
    let i = 0;
    
    while (i < text.length) {
      // 跳过佛经用语字符
      while (i < text.length && buddhistChars.includes(text[i])) {
        i++;
      }
      
      // 如果还有字符,解密它
      if (i < text.length) {
        const charCode = text.charCodeAt(i) - 20; // 反向偏移解密
        decryptedText += String.fromCharCode(charCode);
        i++;
      }
    }

    // 添加系统回复消息
    const systemMessage = {
      content: decryptedText,
      type: 'system'
    };

    messages.push(systemMessage);
    this.setData({
      chatMessages: messages
    }, () => {
      this.scrollToBottom();
    });
  },

  // 复制消息内容
  copyMessage(e) {
    const index = e.currentTarget.dataset.index;
    const content = this.data.chatMessages[index].content;
    
    wx.setClipboardData({
      data: content,
      success: () => {
        wx.showToast({
          title: '复制成功',
          icon: 'success'
        });
      }
    });
  },

  // 滚动到底部
  scrollToBottom() {
    wx.createSelectorQuery()
      .select('#chat-container')
      .boundingClientRect(rect => {
        this.setData({
          scrollTop: rect.height
        });
      })
      .exec();
  },

  onLoad() {
    // 添加欢迎消息
    this.setData({
      chatMessages: [{
        content: '欢迎使用佛经加密器!\n输入文字进行加密,或输入以"佛曰:"开头的文字进行解密。',
        type: 'system'
      }]
    });
  }
});

最后聊两句

代码写得好不好我不知道,但对于一个不懂编程的产品经理来说,想在业余时间实现一个自己的小工具,Trae 提供的能力是完全达标了。

当然啦,前端技术我是略懂的,最后我对页面的提示信息和配色方案做了一些调整才发布到线上的。

感兴趣的工友可以搜搜“光刻符文”小程序。

Trae 发布的半年里,我一直在使用它。作为一个产品经理,这个工具确实帮了我很多忙。平时需要写爬虫脚本或者数据分析小工具时,我都是用 Trae 来生成代码的。由于我不需要每天编程,相比付费使用 Cursor,免费的 Trae 对我来说更实惠。况且两者功能相近,一个要付费,一个免费,当然选择免费的啦😁

Trae 的出现并非为了取代程序员。纵观历史,每一次工业革命都提升了全人类的生产力,但该打工的人类仍旧继续打工。Trae 只是一个能力增强工具,能让门外汉快速入门,能帮助60分的人快速达到80分水平,仅此而已。


德育处主任
192 声望25 粉丝