国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何做一個(gè)小程序口令紅包功能

zhiwei / 2964人閱讀

摘要:語(yǔ)音識(shí)別該功能的應(yīng)用場(chǎng)景是用戶設(shè)置了一個(gè)中文的口令紅包,接收到該紅包的用戶需要用語(yǔ)音說(shuō)出該口令,完全匹配的話則獲取該紅包的某個(gè)比例金額。表結(jié)構(gòu)如下如此,便完成了語(yǔ)音識(shí)別功能。

在做小程序后端支持的過(guò)程中遇到不少有意思的功能,有些比較考你的思維散發(fā)及解決問(wèn)題的實(shí)際能力,這里摘錄一下記錄下來(lái),是為拋磚引玉、如能幫到別人,自然是最好不過(guò)了。

先放幾張?jiān)O(shè)計(jì)圖看下大概功能:

大概便是如此。

通過(guò)圖片可以看到,涉及到的稍微復(fù)雜一點(diǎn)的功能點(diǎn)有:語(yǔ)音文字識(shí)別、紅包分配算法,周邊紅包算法等等。 其余的都是些簡(jiǎn)單的CRUD操作。我CODING+TESTING用了差不多一周,以下說(shuō)下各個(gè)功能點(diǎn)的大概實(shí)現(xiàn)思路及方法。

語(yǔ)音識(shí)別:

該功能的應(yīng)用場(chǎng)景是:A用戶設(shè)置了一個(gè)中文的口令紅包,接收到該紅包的B用戶需要用語(yǔ)音說(shuō)出該口令,完全匹配的話則獲取該紅包的某個(gè)比例金額。

錄音自然是調(diào)用小程序提供的原生接口,不過(guò)這里比較坑的是微信的錄音格式是 .silk。網(wǎng)上搜索的方法是先將.silk格式轉(zhuǎn)成wav或者M(jìn)P3格式,然后再調(diào)用各大云服務(wù)平臺(tái)的接口實(shí)現(xiàn)語(yǔ)音識(shí)別功能。

這里使用了 https://github.com/kn007/silk... 提供的庫(kù)用來(lái)轉(zhuǎn)成wav格式,然后使用百度的語(yǔ)音識(shí)別開(kāi)放接口 https://ai.baidu.com/tech/spe... 來(lái)識(shí)別語(yǔ)音結(jié)果。

業(yè)務(wù)實(shí)現(xiàn)步驟如下:

1.前端實(shí)現(xiàn)錄音功能
2.upload接口上傳.silk語(yǔ)音文件,入庫(kù)
3.觸發(fā)語(yǔ)音識(shí)別task,返回成功給前端(異步)
4.前端輪詢識(shí)別結(jié)果。

因?yàn)閺纳蟼鞯阶R(shí)別到返回結(jié)果是一個(gè)耗時(shí)操作,所以識(shí)別過(guò)程最好是異步操作。(第三步)

upload語(yǔ)音接口部分代碼:

// ... 業(yè)務(wù)代碼略
$voice = $this->getCreatedVoiceByBody(); // 上傳并入庫(kù)
$this->identifyVoice($voice); // 觸發(fā)語(yǔ)音識(shí)別task
 
// ...
 
public function identifyVoice($voice)
{
    WorkerUtil::sendTaskByRouteAndParams("task/detectvoice", ["voiceid" => $voice->id, "type" =>"redpack"]);
}

如上可見(jiàn),將一條包含了語(yǔ)音文件地址的記錄id及類型發(fā)送到了后端task服務(wù)。

后端task服務(wù)處理如下:

class DetectVoice extends Action
{
    public function run($voiceid, $type = "redpack")
    {
        if ($type == "redpack") {
            $voice = Voices::findOne($voiceid);
            $url = $voice->voice;
            $saveName = "/runtime/redpack-".$voiceid.".silk";
            $convertName = "/runtime/redpack-".$voiceid.".wav";
        }
        $this->saveToLocalByRemoteVoiceUrlAndLocalFileName($url, $saveName);
        $cfg = [
            "appKey" => "xxx",
            "appSecret" => "xxx",
            "appId" => "xxx",
        ];
        $util = new BaiduVoiceUtil($cfg);
        $code = exec("bash /www/silk-v3-decoder/converter.sh {$saveName} wav");
        if ($code == 0) {
            $result = $util->asr($convertName);
            if ($result["err_no"] == 0) {
                $voicesResult = json_encode($result["result"], JSON_UNESCAPED_UNICODE);
                $voice->result = $voicesResult;
                $voice->save();
                @unlink($saveName);
                @unlink($convertName);
            }
        }
    }
    ...
}

task服務(wù)的處理邏輯也很清晰:接收需要識(shí)別的voiceid,查找記錄,把語(yǔ)音文件下到本地某個(gè)tmp目錄,調(diào)用shell轉(zhuǎn)換格式,將轉(zhuǎn)換后的格式調(diào)用baidu的語(yǔ)音接口進(jìn)行識(shí)別,再將結(jié)果入庫(kù)。

voice表結(jié)構(gòu)如下:

如此,便完成了語(yǔ)音識(shí)別功能。

紅包分配

應(yīng)用場(chǎng)景:創(chuàng)建紅包時(shí)

打開(kāi)紅包一般有兩種分配方法,一種是使用創(chuàng)建時(shí)便分配好每一份的份額。一種是打開(kāi)時(shí)再動(dòng)態(tài)分配,這里采取的是第一種。

具體討論可在知乎:https://www.zhihu.com/questio... 找到。

說(shuō)實(shí)話,看完這個(gè)答案還是學(xué)到了一些東西的,如微信紅包的架構(gòu)實(shí)現(xiàn),分配寫(xiě)法等等。

因?yàn)槲覀兊膽?yīng)用沒(méi)有微信的量級(jí),自然不需要考慮太多(負(fù)載,并發(fā)等),產(chǎn)品的要求也只是說(shuō)金額這方面要實(shí)現(xiàn)類微信紅包的分配方法即可。因此,考慮到擴(kuò)展及性能以及時(shí)間,分配寫(xiě)法我直接采用了 陳鵬 的答案里的寫(xiě)法,不過(guò)是變成了PHP的版本。并且搭配了redis 作為紅包份額的存儲(chǔ)及可能的并發(fā)問(wèn)題處理方案。

先上代碼(redpack/create):

$redpack = $this->getCreatedRedPackByBody();
// ... 業(yè)務(wù)邏輯代碼略
// 設(shè)置隨機(jī)紅包份額
$this->setRedPackOpenOdds($redpack);
 
protected function setRedPackOpenOdds($rp)
{
    $remainNum = $rp->num;
    $remainMoney = $rp->fee;
    $key = "redpack:".$rp->id;
    $redis = yii::$app->redis;
    while (!empty($remainNum)) {
        $money = $this->getRandomMoney($remainNum, $remainMoney);
        $redis->executeCommand("RPUSH", [$key, $money]);
    }
    $redis->executeCommand("expire", [$key, 259200]);
}
 
protected function getRandomMoney(&$remainNum, &$remainMoney)
{
    if ($remainNum == 1) {
        $remainNum--;
        return $remainMoney;
    }
    $randomNum = StringUtil::getRandom(6, 1);
    $seed = $randomNum / 1000000;
    $min = 1;
    $max = $remainMoney / $remainNum * 2;
    $money = $seed * $max;
    $money = $money <= $min ? $min : ceil($money);
    $remainNum--;
    $remainMoney -= $money;
    return $money;
}

這部分代碼邏輯也相對(duì)簡(jiǎn)單,主要就是:

將當(dāng)前金額和份數(shù)傳入函數(shù)( getRandomMoney),在計(jì)算出當(dāng)次的隨機(jī)金額后,將該金額寫(xiě)入redis的一個(gè)list (key=redpack:id),然后將總金額和總份數(shù)減去,一直減完為止。

有幾點(diǎn)值得注意的地方:

1.原答案里的隨機(jī)數(shù)生成法使用了 java.math.BigDecimal. 可php沒(méi)有對(duì)應(yīng)的函數(shù),自帶的隨機(jī)數(shù)也不好用。這里用的自己寫(xiě)的隨機(jī)數(shù)生成方法 (獲取6位的隨機(jī)數(shù)字,然后除以它們的位數(shù),就得到類似于 0.608948的隨機(jī)數(shù))
2.每個(gè)紅包的份額設(shè)置了一天的過(guò)期時(shí)間,這是為了實(shí)現(xiàn)紅包過(guò)期的功能。

redis里的結(jié)果(單位為分):

10元分配15個(gè)

100元分配7個(gè):

50元分配25個(gè):

可以看到基本實(shí)現(xiàn)了隨機(jī)分配,也兼顧了手氣最佳的要求。

使用也簡(jiǎn)單,打開(kāi)紅包獲取份額的時(shí)候,使用這個(gè)list左邊一個(gè)個(gè)出棧就行了。

紅包地圖

應(yīng)用場(chǎng)景:查看周圍發(fā)布的紅包

這個(gè)實(shí)現(xiàn)的關(guān)鍵之處就是周邊的坐標(biāo)算法。首先,前提條件是創(chuàng)建紅包時(shí)要獲取到經(jīng)緯度坐標(biāo),這個(gè)交由前端實(shí)現(xiàn),我們只記錄即可。

然后在調(diào)用這個(gè)接口時(shí),把用戶當(dāng)前的經(jīng)緯度傳過(guò)來(lái)。根據(jù)這個(gè)經(jīng)緯度計(jì)算出周邊范圍,然后查找表中在這個(gè)周邊范圍的記錄即可。

代碼如下:

/**
*
* @param double $lng 經(jīng)度
* @param double $lat 緯度
* @param integer $radius 范圍
* @return array
*/
public function run($lng, $lat, $radius = 500)
{
    $coordinates = $this->getAroundByCoordinates($lng, $lat, $radius);
    $field = "id,lat,lng";
    $data = (new Query())
            ->select($field)
            ->from("{{app_redpack}}")
            ->where(sprintf("`lat` BETWEEN %f AND %f AND `lng` BETWEEN %f AND %f AND `ishandle` = 1 AND `isexpire` = 0", $coordinates[0], $coordinates[2], $coordinates[1], $coordinates[3]))
            ->all();
    return ResponseUtil::getOutputArrayByCodeAndData(Api::SUCCESS, $data);
}
 
/**
* 地球的圓周是24901英里。
* 24,901/360度 = 69.17 英里 / 度
* @param double $longitude 經(jīng)度
* @param double $latitude 緯度
* @param integer $raidus 范圍。單位米。
* @return array
*/
public function getAroundByCoordinates($longitude, $latitude, $raidus)
{
    (double) $degree = (24901 * 1609) / 360.0;
    (double) $dpmLat = 1 / $degree;
    (double) $radiusLat = $dpmLat * $raidus;
    (double) $minLat = $latitude - $radiusLat;
    (double) $maxLat = $latitude + $radiusLat;
    (double) $mpdLng = $degree * cos($latitude * (pi() / 180));
    (double) $dpmLng = 1 / $mpdLng;
    (double) $radiusLng = $dpmLng * $raidus;
    (double) $minLng = $longitude - $radiusLng;
    (double) $maxLng = $longitude + $radiusLng;
    return [$minLat, $minLng, $maxLat, $maxLng];
}

關(guān)鍵就是getAroundByCoordinates 這個(gè)算法,它根據(jù)輸入的經(jīng)緯度及范圍大小,計(jì)算出左上,左下,右上,右下四個(gè)角的坐標(biāo),在地圖上標(biāo)出來(lái)的話就是 一個(gè)長(zhǎng)方形的范圍。

有興趣的可以根據(jù) http://lbs.qq.com/tool/getpoint/ 這個(gè)工具,隨意點(diǎn)取一個(gè)坐標(biāo),根據(jù)以上的方法算出四個(gè)角,看看是不是剛好是$raidus指定的范圍。

需要說(shuō)明的是這個(gè)方法不是我寫(xiě)的,但是我實(shí)在不記得出處在哪了。我只是記得把java的實(shí)現(xiàn)方法改成了php。對(duì)原作者說(shuō)聲抱歉。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/25778.html

相關(guān)文章

  • 10分鐘上線 - 利用函數(shù)計(jì)算構(gòu)建微信程序的Server端

    摘要:本文以開(kāi)發(fā)一個(gè)類似語(yǔ)音口令紅包小程序?yàn)槔蚰v解如何使用阿里云函數(shù)計(jì)算快速構(gòu)建微信小程序的服務(wù)端。 前言 這篇文章適合所有的想微信小程序開(kāi)發(fā)新手、老鳥(niǎo)以及想準(zhǔn)備學(xué)習(xí)開(kāi)發(fā)微信小程序的程序猿。本文以開(kāi)發(fā)一個(gè)類似語(yǔ)音口令紅包小程序?yàn)槔蚰v解如何使用阿里云函數(shù)計(jì)算快速構(gòu)建微信小程序的服務(wù)端。通過(guò)本文,您將會(huì)了解以下內(nèi)容: demo概覽 傳統(tǒng)服務(wù)器架構(gòu) VS Serverless架構(gòu) S...

    levinit 評(píng)論0 收藏0
  • 10分鐘上線 - 利用函數(shù)計(jì)算構(gòu)建微信程序的Server端

    摘要:本文以開(kāi)發(fā)一個(gè)類似語(yǔ)音口令紅包小程序?yàn)槔蚰v解如何使用阿里云函數(shù)計(jì)算快速構(gòu)建微信小程序的服務(wù)端。 前言 這篇文章適合所有的想微信小程序開(kāi)發(fā)新手、老鳥(niǎo)以及想準(zhǔn)備學(xué)習(xí)開(kāi)發(fā)微信小程序的程序猿。本文以開(kāi)發(fā)一個(gè)類似語(yǔ)音口令紅包小程序?yàn)槔蚰v解如何使用阿里云函數(shù)計(jì)算快速構(gòu)建微信小程序的服務(wù)端。通過(guò)本文,您將會(huì)了解以下內(nèi)容: demo概覽 傳統(tǒng)服務(wù)器架構(gòu) VS Serverless架構(gòu) S...

    darryrzhong 評(píng)論0 收藏0
  • 10分鐘上線 - 利用函數(shù)計(jì)算構(gòu)建微信程序的Server端

    摘要:摘要阿里云函數(shù)計(jì)算是一個(gè)事件驅(qū)動(dòng)的全托管計(jì)算服務(wù)。微信小程序是一種不需要下載安裝即可使用的應(yīng)用,它可以在微信內(nèi)被便捷地獲取和傳播。本文以開(kāi)發(fā)一個(gè)類似語(yǔ)音口令紅包小程序?yàn)槔蚰v解如何使用阿里云函數(shù)計(jì)算快速構(gòu)建微信小程序的服務(wù)端。 摘要: 阿里云函數(shù)計(jì)算是一個(gè)事件驅(qū)動(dòng)的全托管計(jì)算服務(wù)。通過(guò)函數(shù)計(jì)算,您無(wú)需管理服務(wù)器等基礎(chǔ)設(shè)施,只需編寫(xiě)代碼并上傳。微信小程序是一種不需要下載安裝即可使用的...

    geekzhou 評(píng)論0 收藏0
  • 10分鐘上線 - 利用函數(shù)計(jì)算構(gòu)建微信程序的Server端

    摘要:摘要阿里云函數(shù)計(jì)算是一個(gè)事件驅(qū)動(dòng)的全托管計(jì)算服務(wù)。微信小程序是一種不需要下載安裝即可使用的應(yīng)用,它可以在微信內(nèi)被便捷地獲取和傳播。本文以開(kāi)發(fā)一個(gè)類似語(yǔ)音口令紅包小程序?yàn)槔蚰v解如何使用阿里云函數(shù)計(jì)算快速構(gòu)建微信小程序的服務(wù)端。 摘要: 阿里云函數(shù)計(jì)算是一個(gè)事件驅(qū)動(dòng)的全托管計(jì)算服務(wù)。通過(guò)函數(shù)計(jì)算,您無(wú)需管理服務(wù)器等基礎(chǔ)設(shè)施,只需編寫(xiě)代碼并上傳。微信小程序是一種不需要下載安裝即可使用的...

    galois 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<