

# **宝来威 人脸提交接口优化说明文档**

**处理流程说明图例：**



```mermaid
flowchart TD
    A[入驻流程开始]:::startEnd --> B[开房信息录入]
    B --> C[调用PMS接口 获取CheckInID]
    C --> D[照片截取]
    D --> E[调用图片质量检测模块]:::critical
    E --> F{图片质量分值合格}
    F -- 否 --> D
    F -- 是 --> G[调用UploadPhoto接口上传图片]
    G --> H{返回成功}
    H -- 否 --> I[提示人脸机不可用 向前台索取门卡开门]:::warning
    H -- 是 --> J[入驻流程完成]:::startEnd
    I --> J
    
    classDef startEnd fill:#D8BFD8,stroke:#333,stroke-width:1px;
    classDef critical fill:#FFC0CB,stroke:#333,stroke-width:1px;
    classDef warning fill:#FFA500,stroke:#333,stroke-width:1px;
    class E critical
```

# 一、UploadPhoto 修改说明

这部分将说明如何调用`faceidtest.exe`可执行文件进行人脸验证，并提人脸验证工具调用说明

**修改返回值 `Msg` 规则：**

- 有问题时返回对应错误信息
- 同时确认图片分辨率和人脸机在线状态
- 二者都满足时直接返回 `OK (200)`

新增返回值代码表：

| Code | Msg                |
| ---- | ------------------ |
| 200  | 图片上传成功       |
| 301  | 图片分辨率过高     |
| 302  | 图片分辨率过低     |
| 403  | 人脸机离线或不可用 |

# 二、图片质量检测模块调用说明

这部分将说明如何调用`faceidtest.exe`可执行文件进行人脸验证，并提供C#调用示例代码。

**说明**：本应用生成的quality值，是一个相对参考值，推荐值：*** > 0.5**

## 📍 准备工作

1. **放置可执行文件**
    确保`faceidtest.exe`位于项目的 `ValRel` 子目录中：

   ```cmake
   Project_Root/
   ├── ValRel/
   │   └── faceidtest.exe
   ├── Controllers/
   └── ...
   ```

2. **NuGet 包依赖（C#环境）**
    安装以下依赖包：

   ```json
   Install-Package CliWrap
   ```

## ⚙️ 执行流程概述

```mermaid
flowchart TD
    A[接收图片路径] --> B{参数校验}
    B -- 路径为空 --> C[返回400错误]
    B -- 文件不存在 --> D[返回400错误]
    B -- 参数有效 --> E[准备执行环境]
    E --> F{exe文件校验}
    F -- 不存在 --> G[返回500错误]
    F -- 存在 --> H[执行外部进程]
    H --> I[解析输出]
    I --> J{验证结果}
    J -- 成功 --> K[返回质量分数]
    J -- 失败 --> L[返回错误]
```

## 📝 调用参数说明

| 参数           | 类型   | 必需 | 说明                              |
| -------------- | ------ | ---- | --------------------------------- |
| localImagePath | string | 是   | 本地图片文件的**绝对路径**        |
| exeArguments   | string | 是   | 固定参数格式：`{图片路径} 80x v3` |

## 🧩 C# 完整调用示例

```c#
[HttpPost]
public async Task<IActionResult> FaceValidator(string localImagePath)
{
    // 1. 参数基础校验
    if (string.IsNullOrWhiteSpace(localImagePath))
    {
        return BadRequest("图片路径不能为空");
    }
    if (!File.Exists(localImagePath))
    {
        return BadRequest($"图片文件不存在: {localImagePath}");
    }

    // 2. 确定exe执行路径
    var exePath = Path.Combine(_hostingEnvironment.ContentRootPath, "ValRel", "faceidtest.exe");
    var exeDirectory = Path.GetDirectoryName(exePath);
    
    if (!File.Exists(exePath))
    {
        _logger.LogError($"可执行文件缺失: {exePath}");
        return StatusCode(500, "人脸验证程序未找到");
    }

    try
    {
        // 3. 配置输出捕获
        var stdOutBuffer = new StringBuilder();
        var stdErrBuffer = new StringBuilder();
        var arguments = $"{localImagePath} 80x v3";  // 固定参数格式

        // 4. 执行外部进程（20秒超时）
        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
        
        // 核心执行方法
        var result = await Cli.Wrap(exePath)
            .WithArguments(arguments)
            .WithWorkingDirectory(exeDirectory)
            .WithValidation(CommandResultValidation.None)
            .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdOutBuffer))
            .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stdErrBuffer))
            .ExecuteAsync(cts.Token);

        // 5. 处理输出结果
        var fullOutput = $"{stdErrBuffer}{stdOutBuffer}";
        string[] lines = fullOutput.Split(["\r\n", "\r", "\n"], StringSplitOptions.None);
        
        var validationResult = "";
        foreach (var line in lines)
        {
            if (line.Contains("quality:"))
            {
                validationResult = line.Split(':')[2].Trim();
                break;
            }
        }

        // 6. 构造返回数据
        var baseUrl = "http://your-domain.com/upload/";  // 替换为实际地址
        var imageUrl = baseUrl + Path.GetFileName(localImagePath);
        
        if (double.TryParse(validationResult, out double qualityScore))
        {
            return Ok(new
            {
                Success = true,
                Quality = qualityScore,
                ImageUrl = imageUrl
            });
        }
        return Ok(new
        {
            Success = false,
            Message = "验证结果解析失败",
            ImageUrl = imageUrl
        });
    }
    catch (OperationCanceledException)
    {
        _logger.LogError("验证超时");
        return StatusCode(504, "验证超时");
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "验证异常");
        return StatusCode(500, $"系统错误: {ex.Message}");
    }
}
```

## 🔍 关键功能说明

### 参数校验

- 空路径检查：确保传入有效的文件路径
- 文件存在性检查：验证图片实际存在于磁盘

### 安全执行

- **绝对路径构造**：使用`ContentRootPath`确保路径可靠性
- **工作目录设置**：在exe所在目录执行避免路径问题
- **超时控制**：20秒执行超时机制（可根据需要调整）

### 结果解析

1. 合并标准输出和错误流
2. 识别关键行：查找包含`quality:`的输出行
3. 提取质量分数：从`quality:value`格式的第三部分获取数值

## ⚠️ 重要注意事项

1. **输出格式依赖**
    结果解析基于特定输出格式：

   ```c#
   [输出行示例] <文件名>.jpg quality: 0.66
   ```

2. **权限要求**
    应用需要以下权限：

   - 读取`ValRel`目录的执行权限
   - 访问图片文件的读权限
   - 写入日志文件的权限

3. **URL构造**
    替换示例中的`baseUrl`为实际图片服务地址：

   ```c#
   var baseUrl = "http://your-actual-service.com/uploads/";
   ```

4. **超时调整**
    根据实际硬件性能调整超时时间：

   ```c#
   // 调整超时为30秒
   new CancellationTokenSource(TimeSpan.FromSeconds(30))
   ```

5. **日志监控**
    建议添加详细日志记录：

   ```c#
   _logger.LogInformation($"启动人脸验证: {localImagePath}");
   _logger.LogDebug($"完整输出: {fullOutput}");
   ```