我是如何在 3 天內(nèi)零成本完成 AI 小程序開(kāi)發(fā)的
故事的起源
基于對(duì) AI 的愛(ài)好與興趣,我走上了獨(dú)自鉆研機(jī)器學(xué)習(xí)的道路。和所有熱愛(ài) AI 的人們一樣,在一段孤獨(dú)的摸索旅程中,我勉強(qiáng)完成了幾次深度學(xué)習(xí)模型的訓(xùn)練。
其中令我印象較深的成果就是情感分類(lèi)模型。他能夠根據(jù)你的文字生成其背后作者的喜怒哀樂(lè)。
深度學(xué)習(xí)模型展示出來(lái)的 "人性化"讓我感到驚喜,于是我開(kāi)始思考怎么將它的“人性化”轉(zhuǎn)化為幫助人們的工具。
在情感模型的基礎(chǔ)上建立一個(gè)上層應(yīng)用,讓它為人類(lèi)社會(huì)中增添不一樣的煙火。
基于多方面的考量,我最終選擇開(kāi)發(fā)一款 微信 "情感" 小程序。
故事拉開(kāi)序幕
在進(jìn)行小程序開(kāi)發(fā)之前,我們非常有必要先對(duì)小程序做一個(gè)充分的了解。
什么是小程序
簡(jiǎn)單來(lái)說(shuō),比起傳統(tǒng)的 App,微信小程序是一種全新的連接用戶(hù)與服務(wù)的方式,它具有非常出色的使用體驗(yàn),并且它可以在微信內(nèi)被便捷地獲取與傳播。
小程序發(fā)展史
實(shí)際上,小程序并非憑空而來(lái)的。當(dāng)微信逐漸流行、變成幾乎人人都離不開(kāi)的社交工具時(shí),承載微信的 WebView 也逐漸成為了量級(jí)最大的移動(dòng) Web 入口。每天訪問(wèn) WebView 的數(shù)量甚至超過(guò)了訪問(wèn)所有瀏覽器的總和。雖然無(wú)法通過(guò)第三方獲取到微信 WebView 的日活數(shù)據(jù),但這個(gè)客觀事實(shí)間接促進(jìn)了小程序的誕生。
其實(shí)在小程序正式步入人們視線之前,微信早已有了類(lèi)似的 js 調(diào)用接口,這里給大家展示一個(gè)調(diào)用了微信 js-bridge 原生組件去瀏覽圖片的例子:
WeixinJSBridge.invoke('imagePreview', {current: 'http://inews.com',urls: [ // 所有圖片的URL列表,數(shù)組格式 'https://img/1.jpg', 'https://img/2.jpg', 'https://img/3.jpg']}, function(res) { console.log(res.err_msg)})
此類(lèi) js 接口其實(shí)最開(kāi)始是專(zhuān)門(mén)給騰訊內(nèi)部人員去進(jìn)行調(diào)用的,但卻意外被許多個(gè)人開(kāi)發(fā)者發(fā)現(xiàn)很多并進(jìn)行了使用,這也慢慢成為了微信中網(wǎng)頁(yè)的標(biāo)準(zhǔn)。
在 15 年開(kāi)始的時(shí)候,微信官方發(fā)布了一套專(zhuān)門(mén)用于進(jìn)行網(wǎng)頁(yè)開(kāi)發(fā)的工具包,名為 js-sdk,在這個(gè)工具包內(nèi)開(kāi)放了如微信支付、錄音、語(yǔ)音識(shí)別、等數(shù)十個(gè)接口。這給所有的 Web 開(kāi)發(fā)者都打開(kāi)了一扇從未開(kāi)啟過(guò)的全新的大門(mén),讓所有的開(kāi)發(fā)者都可以自由地使用微信開(kāi)發(fā)的原生能力,這使得他們可以去完成一些之前無(wú)法完成或是難以做到的事情。
js-sdk 完美繼承了 WeixinJSBridge 的特性,并且由只對(duì)內(nèi)部開(kāi)放轉(zhuǎn)為了對(duì)外部開(kāi)放。并且它通過(guò)其暴露的微信調(diào)用接口使得所有 Web 開(kāi)發(fā)者有了更多操作微信功能的能力。但是,這個(gè)模式并沒(méi)有很好地解決移動(dòng)網(wǎng)頁(yè)的體驗(yàn)問(wèn)題:
- 用戶(hù)訪問(wèn)頁(yè)面時(shí),在頁(yè)面顯示前會(huì)有一段比較明顯能夠被感知的白屏過(guò)程。受限于網(wǎng)速與不同終端的性能,這個(gè)問(wèn)題會(huì)越來(lái)越明顯。
于是乎,js-sdk 的增強(qiáng)版本就誕生了,其中有一個(gè)非常重要的新特性,被稱(chēng)之為:微信 Web 資源離線存儲(chǔ)。
以下文字引用自?xún)?nèi)部的文檔(沒(méi)有最終對(duì)外開(kāi)放):
微信 Web 資源離線存儲(chǔ)是面向 Web 開(kāi)發(fā)者提供的基于微信內(nèi)的 Web 加速方案。
通過(guò)使用微信離線存儲(chǔ),Web 開(kāi)發(fā)者可借助微信提供的資源存儲(chǔ)能力,直接從微信本地加載 Web 資源而不需要再?gòu)姆?wù)端拉取,從而減少網(wǎng)頁(yè)加載時(shí)間,為微信用戶(hù)提供更優(yōu)質(zhì)的網(wǎng)頁(yè)瀏覽體驗(yàn)。每個(gè)公眾號(hào)下所有 Web App 累計(jì)最多可緩存 5M 的資源。
相信大家都已經(jīng)看明白了,這其實(shí)就是 HTML5 中 Application Cache 的加強(qiáng)版。
然而,在經(jīng)過(guò)了多次測(cè)試后發(fā)現(xiàn),還有問(wèn)題沒(méi)有被完全的解決:
- 頁(yè)面切換較為生硬;
- 點(diǎn)擊有明顯延滯的感覺(jué)。
最終微信意識(shí)到 js-sdk 無(wú)法處理這些問(wèn)題,這需要一個(gè)全新的系統(tǒng)去完成,而這個(gè)系統(tǒng)必須具備以下幾個(gè)能力:
- 加載速度快
- 原生的體驗(yàn)
- 易用且安全的微信數(shù)據(jù)開(kāi)放
- 兼顧開(kāi)發(fā)效率與開(kāi)發(fā)難度
而這就是小程序的由來(lái)。
故事開(kāi)始了
前言
首先請(qǐng)大家見(jiàn)諒,這一篇文章并不會(huì)教你如何零基礎(chǔ)開(kāi)發(fā)小程序。如果你是一個(gè)軟件開(kāi)發(fā)新手。那么我建議你先了解一些基礎(chǔ)的 js 語(yǔ)法 以及相應(yīng)的 前端知識(shí) 。
掌握前端基礎(chǔ)后,相信在 小程序前端組件官方文檔 的幫助下,任何人都可以快速上手開(kāi)發(fā)小程序。
下面我主要跟大家分享兩個(gè)最核心、最省錢(qián) 的兩個(gè)小程序開(kāi)發(fā)技巧:
- 搭建小程序云開(kāi)發(fā)環(huán)境;
- 如何使用云開(kāi)發(fā)調(diào)用 AI 模型接口。
小程序云開(kāi)發(fā)
在剛開(kāi)始考慮開(kāi)發(fā)小程序時(shí),和你們一樣,我有著許多的顧慮:
- 需要購(gòu)買(mǎi)域名、服務(wù)器嗎?
- 維護(hù)成本大嗎?
帶著這些顧慮,我小心翼翼地翻開(kāi)了 微信官方文檔。在大腦經(jīng)過(guò)分布式閱讀過(guò)后,我發(fā)現(xiàn)了 云開(kāi)發(fā) 這個(gè)關(guān)鍵詞。
什么是云開(kāi)發(fā)?
微信官方文檔中是這么解釋的:
開(kāi)發(fā)者可以使用云開(kāi)發(fā)開(kāi)發(fā)微信小程序、小游戲,無(wú)需搭建服務(wù)器,即可使用云端能力。
云開(kāi)發(fā)為開(kāi)發(fā)者提供完整的原生云端支持和微信服務(wù)支持,弱化后端和運(yùn)維概念,無(wú)需搭建服務(wù)器,使用平臺(tái)提供的 API 進(jìn)行核心業(yè)務(wù)開(kāi)發(fā),即可實(shí)現(xiàn)快速上線和迭代,同時(shí)這一能力,同開(kāi)發(fā)者已經(jīng)使用的云服務(wù)相互兼容,并不互斥。
云開(kāi)發(fā)提供了幾大基礎(chǔ)能力支持:
能力 作用 說(shuō)明 云函數(shù) 無(wú)需自建服務(wù)器 在云端運(yùn)行的代碼,微信私有協(xié)議天然鑒權(quán),開(kāi)發(fā)者只需編寫(xiě)自身業(yè)務(wù)邏輯代碼 數(shù)據(jù)庫(kù) 無(wú)需自建數(shù)據(jù)庫(kù) 一個(gè)既可在小程序前端操作,也能在云函數(shù)中讀寫(xiě)的 JSON 數(shù)據(jù)庫(kù) 存儲(chǔ) 無(wú)需自建存儲(chǔ)和 CDN 在小程序前端直接上傳/下載云端文件,在云開(kāi)發(fā)控制臺(tái)可視化管理 云調(diào)用 原生微信服務(wù)集成 基于云函數(shù)免鑒權(quán)使用小程序開(kāi)放接口的能力,包括服務(wù)端調(diào)用、獲取開(kāi)放數(shù)據(jù)等能力
簡(jiǎn)單來(lái)說(shuō),有了云開(kāi)發(fā), 我不需要購(gòu)買(mǎi)服務(wù)器就可以開(kāi)發(fā)一款全棧小程序。
嘿嘿,沒(méi)錯(cuò),這就是我想要的。
如何搭建小程序云開(kāi)發(fā)環(huán)境
那么如何搭建云開(kāi)發(fā)環(huán)境呢,綜合官方文檔,我總結(jié)了一套極簡(jiǎn)搭建教程,大家可以作為參考。
云開(kāi)發(fā)環(huán)境極簡(jiǎn)搭建四部曲:
- 首先,需要 注冊(cè)一個(gè)小程序賬號(hào) ,添加管理員 / 開(kāi)發(fā)者微信賬號(hào)并記錄下 APPID;

- 接著需要下載 小程序開(kāi)發(fā)工具;
- 然后使用管理員 / 開(kāi)發(fā)者賬號(hào)登錄開(kāi)發(fā)工具并填入小程序的 APPID 以及勾選 云開(kāi)發(fā) 選項(xiàng)后點(diǎn)擊新建;

- 點(diǎn)擊頁(yè)面中的云開(kāi)發(fā),跟著提示選擇 免費(fèi)版云開(kāi)發(fā)配額 。

至此一個(gè)云環(huán)境就算是搭建完畢了。
什么是云函數(shù)?
云開(kāi)發(fā)環(huán)境搭建完畢后,是時(shí)候看看什么是 云函數(shù) 了。
官方的定義如下:
云函數(shù)是一段運(yùn)行在云端的代碼,無(wú)需管理服務(wù)器,在開(kāi)發(fā)工具內(nèi)編寫(xiě)、一鍵上傳部署即可運(yùn)行后端代碼。
簡(jiǎn)單來(lái)說(shuō),云函數(shù)就是運(yùn)行在云端的函數(shù)。
云函數(shù)有什么用?
云函數(shù)大有用處。
有了它,就相當(dāng)于是有了一個(gè) "大后端",所有業(yè)務(wù)邏輯以及對(duì)數(shù)據(jù)庫(kù)的操作我們都可以封裝在云函數(shù)中調(diào)用,十分方便。
第一個(gè)云函數(shù)
說(shuō)了這么多大道理,是時(shí)候來(lái)實(shí)戰(zhàn)一下了。
右鍵點(diǎn)擊云函數(shù)環(huán)境 (cloudfunctions | xxxxxxx)后新建一個(gè)名為 test 的云函數(shù):

可以看到默認(rèn)的文件(index.js)中已經(jīng)有了云函數(shù)代碼(獲取當(dāng)前微信用戶(hù)上下文,并返回用戶(hù)信息):
- // 云函數(shù)入口文件const cloud = require('wx-server-sdk')cloud.init()// 云函數(shù)入口函數(shù)exports.main = async (event, context) => { const wxContext = cloud.getWXContext() return { event, openid: wxContext.OPENID, appid: wxContext.APPID, unionid: wxContext.UNIONID, }}
這時(shí)候需要開(kāi)啟命令行并進(jìn)入到該目錄下運(yùn)行 npm install 安裝 wx-server-sdk ( 若目錄下沒(méi)有 node_modules 則需要先運(yùn)行 npm init ):

最后右鍵點(diǎn)擊該云函數(shù)并選擇 開(kāi)啟云函數(shù)本地調(diào)試 后點(diǎn)擊右下角調(diào)用:

可以看到函數(shù)執(zhí)行成功并拿到了返回值(openid 等信息……)
至此,恭喜我們快速完成了第一個(gè)云函數(shù)。
如何在小程序中快速調(diào)用 AI 模型
來(lái)自清晨的靈光一閃
相信大家都非常好奇,我是怎么做到在云函數(shù)中 "零成本" 調(diào)用 AI 能力的。
其實(shí)我開(kāi)始也非??鄲肋@個(gè)問(wèn)題,即使小程序有云函數(shù)的功能,但也沒(méi)辦法輕易 "零成本" 調(diào)用 AI 模型,原因如下:
- 小程序云函數(shù)目前僅支持 node.js,而我的模型調(diào)用接口代碼為 python;
- 不管再怎么 "云",想要運(yùn)行自己的 AI 模型必須得有一臺(tái) 16G 內(nèi)存以上的機(jī)器(成本巨大);
- 即使有了自己的服務(wù)器也需要域名備案,實(shí)在是太麻煩了;
但就在一個(gè)明媚的清晨,我翻身起床后突然靈光一閃:
- 可不可以調(diào)用騰訊自己的 AI 開(kāi)放接口間接達(dá)到這個(gè)目的呢?
想法再多不如動(dòng)手行動(dòng),于是我訪問(wèn)了 騰訊云控制臺(tái)的自然語(yǔ)言處理模塊 。
根據(jù)指引進(jìn)行服務(wù)開(kāi)通后,我進(jìn)入到 API 密鑰管理 并記錄下了 API 密鑰:

那么如何在小程序中調(diào)用它呢?我再一次陷入了深深的沉思……
云函數(shù)調(diào)用 AI 模型
在經(jīng)過(guò)漫長(zhǎng)的探索后我回到了 test 云函數(shù)目錄下的命令行,安裝了騰訊云服務(wù)調(diào)用包:
- npm install tencentcloud-sdk-nodejs

然后修改 test 云函數(shù) (index.js):
- // 云函數(shù)入口文件const cloud = require('wx-server-sdk')const tencentcloud = require("tencentcloud-sdk-nodejs");cloud.init()// 云函數(shù)入口函數(shù)exports.main = async (event, context) => { const NlpClient = tencentcloud.nlp.v20190408.Client; const models = tencentcloud.nlp.v20190408.Models; const Credential = tencentcloud.common.Credential; const ClientProfile = tencentcloud.common.ClientProfile; const HttpProfile = tencentcloud.common.HttpProfile; let cred = new Credential(event.secretId, event.secretKey); let httpProfile = new HttpProfile(); httpProfile.endpoint = "nlp.tencentcloudapi.com"; let clientProfile = new ClientProfile(); clientProfile.httpProfile = httpProfile; let client = new NlpClient(cred, "ap-guangzhou", clientProfile); let req = new models.SentimentAnalysisRequest(); let text = event.text let params = '{"Text":\"' + text + '\"}' console.log('待預(yù)測(cè)字符串: ' + text) req.from_json_string(params); client.SentimentAnalysis(req, function (errMsg, response) { if (errMsg) { console.log(errMsg) } console.log('AI 預(yù)測(cè)情緒正值: ' + response.Positive) console.log('AI 預(yù)測(cè)情緒負(fù)值: ' + response.Negative) })}
在這段代碼中,我通過(guò)騰訊云賬號(hào)中的密鑰連通了 AI 情感預(yù)測(cè)接口,最后將情感預(yù)測(cè)的結(jié)果打印了出來(lái)。
接下來(lái)我開(kāi)啟了本地云函數(shù)調(diào)用窗口并傳入相應(yīng)參數(shù):
- secretId (騰訊云 API 服務(wù)密鑰 Id )
- secretKey (騰訊云 API 服務(wù)密鑰 Key)
- text (待預(yù)測(cè)的字符串)
然后點(diǎn)擊調(diào)用后終于看到了 AI 模型的預(yù)測(cè)結(jié)果:

最后我成功地使用云函數(shù)調(diào)用了免費(fèi)的 AI 開(kāi)放接口。
這時(shí)我已經(jīng)熱淚盈眶,除了感動(dòng)還有一絲小滿(mǎn)意,原來(lái)云開(kāi)發(fā)還能這么玩。
故事的結(jié)尾
文章到這里,相信最重要的兩個(gè)部分大家已經(jīng)了解并掌握了:
- 搭建云開(kāi)發(fā)環(huán)境
- 快速調(diào)用 AI 模型
回頭望去,整個(gè)小程序開(kāi)發(fā)過(guò)程大概歷經(jīng)三天兩夜,整段經(jīng)歷大概與 "編程馬拉松" 類(lèi)似。
編程馬拉松,又稱(chēng)黑客日、黑客節(jié)或編程節(jié),是一個(gè)流傳于黑客當(dāng)中的新詞匯。編程馬拉松是一種活動(dòng)。
在該活動(dòng)當(dāng)中,計(jì)算機(jī)程序員以及其他與軟件發(fā)展相關(guān)的人員,如圖形設(shè)計(jì)師、界面設(shè)計(jì)師與項(xiàng)目經(jīng)理,相聚在一起,以緊密合作的形式去進(jìn)行某項(xiàng)軟件項(xiàng)目。
編程馬拉松的靈魂是合作地編寫(xiě)程序和應(yīng)用。編程馬拉松的時(shí)長(zhǎng)一般在幾天到一周不等 。
--維基百科
于是乎,在經(jīng)過(guò) "瘋狂" 開(kāi)發(fā)后,一個(gè)日記小程序的雛形就誕生了。

雖然說(shuō)前端頁(yè)面并沒(méi)有多復(fù)雜,但是確實(shí)傾注了許多開(kāi)發(fā)心血。
開(kāi)發(fā)完成的那一刻我已經(jīng)不在乎是否有人真正去使用他。因?yàn)槲乙呀?jīng)從他身上收獲到了全身心投入開(kāi)發(fā)的快樂(lè)。
最后預(yù)祝所有用心實(shí)踐的讀者都能開(kāi)發(fā)出有特色的 AI 小程序~