Cómo hacer una función de sobre rojo de contraseña de programa pequeño

En el proceso de hacer soporte de back-end para programas pequeños, he encontrado muchas funciones interesantes. Algunas comparan su capacidad real de distribuir el pensamiento y resolver problemas. Aquí hay un extracto para registrarlo. Es para ayudar a otros. Si puede ayudar a otros, naturalmente es Es lo mejor.

Primero ponga algunos dibujos de diseño para ver la función aproximada:

1

2

3

4 4

5 5

6 6

7 7

8

Este es probablemente el caso.

Como puede ver en la imagen, los puntos de función ligeramente más complicados involucrados son: reconocimiento de voz y texto, algoritmo de distribución de envolvente roja, algoritmo de envoltura roja periférica, etc. El resto son operaciones CRUD simples. Utilicé CODING + TESTING durante casi una semana. La siguiente es una idea general y un método para implementar cada punto de función.

Reconocimiento de voz:

El escenario de aplicación de esta función es: el usuario A establece un sobre rojo de contraseña en chino, y el usuario B que recibe el sobre rojo debe pronunciar la contraseña en voz, y si coinciden exactamente, se obtendrá una cierta cantidad del sobre rojo.

La grabación se llama naturalmente la interfaz nativa proporcionada por el applet, pero lo que más se destaca aquí es que el formato de grabación de WeChat es .silk. El método de búsqueda en línea es convertir el formato .silk a formato wav o MP3, y luego llamar a las interfaces de las principales plataformas de servicios en la nube para realizar la función de reconocimiento de voz.

Utilizado aquí https://github.com/kn007/silk..La biblioteca proporcionada se usa para convertir a formato wav y luego usa la interfaz abierta de reconocimiento de voz de Baiduhttps: //ai.baidu.com/tech/spe ... para reconocer los resultados de voz.

Los pasos de realización del negocio son los siguientes:

1. El front-end implementa la función de grabación
2. La interfaz de carga carga el archivo de voz .silk e ingresa a la biblioteca
3. Activa la tarea de reconocimiento de voz y devuelve el éxito al front-end (asíncrono)
4. El front-end sondea el resultado del reconocimiento.

Debido a que es una operación que lleva mucho tiempo desde la carga hasta el reconocimiento para devolver el resultado, el proceso de reconocimiento es preferiblemente una operación asincrónica. (Paso 3)

Código parcial de la interfaz de voz de carga:

// ... 业务代码略
$voice = $this->getCreatedVoiceByBody(); // 上传并入库
$this->identifyVoice($voice); // 触发语音识别task
 
// ...
 
public function identifyVoice($voice)
{
    WorkerUtil::sendTaskByRouteAndParams('task/detectvoice', ['voiceid' => $voice->id, 'type' =>'redpack']);
}

Como puede ver arriba, se envía una identificación de registro y un tipo que contiene la dirección del archivo de voz al servicio de tareas de fondo.

El servicio de tareas de fondo se procesa de la siguiente manera:

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);
            }
        }
    }
    ...
}

La lógica de procesamiento del servicio de tareas también es muy clara: recibe el voiceid que necesita ser identificado, busca el registro, descarga el archivo de voz a un directorio tmp local, llama al shell para convertir el formato, llama al formato convertido para llamar a la interfaz de voz de Baidu para identificar, y luego Almacenaje

La estructura de la tabla de voz es la siguiente:

Descripción de la imagen

De esta manera, se completa la función de reconocimiento de voz.

Distribución de sobres rojos

Escenario de aplicación: al crear un sobre rojo

En general, hay dos métodos de distribución para abrir sobres rojos: uno es asignar cada recurso compartido cuando se crea. Una es la asignación dinámica cuando se abre, y la primera se adopta aquí.

La discusión específica se puede encontrar en:https: //www.zhihu.com/questio ... encontrado.

Para ser honesto, después de leer esta respuesta, todavía aprendí algunas cosas, como la implementación de la arquitectura de sobre rojo WeChat, la escritura de distribución, etc.

Debido a que nuestra aplicación no tiene la magnitud de WeChat, naturalmente no necesitamos considerar demasiado (carga, concurrencia, etc.), y los requisitos del producto son solo para decir que la cantidad de dinero debe asignarse al método de distribución de sobre rojo WeChat. Por lo tanto, considerando la expansión, el rendimiento y el tiempo, adopté directamente la redacción en la respuesta de Chen Peng, pero se convirtió en la versión PHP. Además, redis se usa como almacenamiento para los recursos compartidos de sobres rojos y una solución para posibles problemas de concurrencia.

Primero ve al código (redpack / create):

$redpack = $this->getCreatedRedPackByBody();
// ... 业务逻辑代码略
// 设置随机红包份额
$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;
}

La lógica de esta parte del código es relativamente simple, principalmente:

Pase la cantidad actual y el número de copias a la función (getRandomMoney), después de calcular la cantidad aleatoria actual, escriba la cantidad en una lista de redis (key = redpack: id), y luego reste la cantidad total y el número total de copias , Hasta que se haya reducido.

Hay algunos puntos que vale la pena señalar:

1. El método de generación de números aleatorios en la respuesta original usa java.math.BigDecimal, pero PHP no tiene una función correspondiente, y el número aleatorio que viene con él no es fácil de usar. El método de generación de números aleatorios autoescrito utilizado aquí (tome 6 números aleatorios y luego divídalos por el número de bits para obtener un número aleatorio similar a 0.608948)
2. Cada recurso compartido de sobre rojo tiene un tiempo de vencimiento de un día, que Es realizar la función de vencimiento del sobre rojo.

Los resultados en redis (en puntos):

15 yuanes por 10 yuanes

Descripción de la imagen

7 por 100 yuanes:

Descripción de la imagen

25 yuanes por 50 yuanes:

Descripción de la imagen

Se puede ver que la asignación aleatoria se realiza básicamente, y el requisito de la mejor suerte también se tiene en cuenta.

También es fácil de usar: al abrir el sobre rojo para obtener recursos compartidos, simplemente use el lado izquierdo de esta lista para que aparezca uno por uno.

Mapa de sobres rojos

Escenario de aplicación: vea los sobres rojos publicados alrededor

La clave de esta implementación es el algoritmo de coordenadas circundante. Primero, el requisito previo es obtener las coordenadas de latitud y longitud al crear la envoltura roja. Esto se implementa por el extremo frontal y solo necesitamos registrar.

Luego, cuando llame a esta interfaz, pase la latitud y longitud actuales del usuario. Calcule el rango periférico basado en esta latitud y longitud, y luego busque los registros en este rango periférico en la tabla.

El código es el siguiente:

/**
*
* @param double $lng 经度
* @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 经度
* @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];
}

La clave es el algoritmo getAroundByCoordinates. Calcula las coordenadas de las esquinas superior izquierda, inferior izquierda, superior derecha e inferior derecha en función de la latitud, longitud y rango ingresados. Si están marcados en el mapa, son un rango rectangular.

Si estás interesado, puedes http://lbs.qq.com/tool/getpoint/ Esta herramienta, puede tomar una coordenada al azar, calcular las cuatro esquinas de acuerdo con el método anterior y ver si es exactamente el rango especificado por $ raidus.

Cabe señalar que este método no fue escrito por mí, pero realmente no recuerdo de dónde vino. Solo recuerdo cambiar el método de implementación de Java a PHP. Lo siento por el autor original.

Supongo que te gusta

Origin www.cnblogs.com/10manongit/p/12728002.html
Recomendado
Clasificación