Spaces:
Running
Running
| ## `/model` API | |
| λͺ¨λΈ λ€μ΄λ‘λ μλν¬μΈνΈλ μ΅μ λͺ¨λΈκ³Ό νΉμ λ²μ μ λͺ¨λΈμ λͺ¨λ μ 곡νλ©°, μλ΅ ν€λλ₯Ό ν΅ν΄ μ€μ λ²μ μ 보λ₯Ό νμΈν μ μμ΅λλ€. | |
| ### μμ² νμ | |
| ``` | |
| GET /model | |
| GET /model?version={λ²νΈ} | |
| GET /model?version={λ²νΈ}&filename={νμΌλͺ } | |
| ``` | |
| | νλΌλ―Έν° | νμ | μ€λͺ | | |
| | --- | --- | --- | | |
| | `version` (μ ν) | int | μλ΅νκ±°λ λΉ κ°μ΄λ©΄ μ΅μ λͺ¨λΈ. μ§μ νλ©΄ ν΄λΉ λ²μ νμΈ ν λ€μ΄λ‘λ. | | |
| | `filename` (μ ν) | string | λ΄λ €λ°μ νμΌλͺ . κΈ°λ³Έκ°μ νκ²½ λ³μ `HF_E2E_MODEL_FILE` (κΈ°λ³Έ `cnn_gru_fatigue.tflite`). | | |
| ### μλ΅ | |
| - λ³Έλ¬Έ: μμ²ν λͺ¨λΈ λ°μ΄λ리 (μ: `.tflite`, `.keras`, λ©νλ°μ΄ν° λ±) | |
| - ν€λ: | |
| - `X-Model-Version`: μ€μ λ€μ΄λ‘λλ λͺ¨λΈ λ²μ | |
| - `X-Model-Filename`: λ°νλ νμΌλͺ | |
| - μλ¬: | |
| - `404` β μμ²ν λ²μ μ΄ νμ¬ `model_version`λ³΄λ€ ν¬κ±°λ manifestμ μ‘΄μ¬νμ§ μμ λ | |
| - `500` β Hugging Face Hub λ€μ΄λ‘λ μ€ν¨ λ± λ΄λΆ μ€λ₯ | |
| ### λμ κ·μΉ | |
| 1. μλ²λ `training_state.json`μ `model_version` κ°μ μ½μ΄ νμ¬ νμ© κ°λ₯ν μ΅λ λ²μ μ νμΈν©λλ€. | |
| 2. `version`μ μ§μ νμ§ μμΌλ©΄ μ΅μ λͺ¨λΈ(νμ¬ λ²μ )μ λ€μ΄λ‘λν©λλ€. | |
| 3. `version`μ μ§μ νλ©΄ μλ²κ° νμ¬ `model_version` μ΄νμΈμ§ νμΈν λ€, λμΌν νμΌλͺ μ λ΄λ €μ€λλ€(λ²μ λ³λ‘ νμΌλͺ μ ꡬλΆνμ§ μμ΅λλ€). | |
| 4. μμ²ν λ²μ μ΄ νμ¬ λ²μ λ³΄λ€ ν¬κ±°λ νμΌμ΄ μ‘΄μ¬νμ§ μμΌλ©΄ `404`λ₯Ό λ°νν©λλ€. | |
| ### μ¬μ© μμ | |
| #### μ΅μ λͺ¨λΈ λ€μ΄λ‘λ | |
| ```bash | |
| curl -L -o cnn_gru_fatigue_latest.tflite \ | |
| "https://merry99-musclecare-train-ai.hf.space/model" | |
| ``` | |
| #### λ²μ 3 λͺ¨λΈ λ€μ΄λ‘λ | |
| ```bash | |
| curl -L -o cnn_gru_fatigue_v3.tflite \ | |
| "https://merry99-musclecare-train-ai.hf.space/model?version=3" | |
| ``` | |
| #### λ²μ 3 λ©νλ°μ΄ν° λ€μ΄λ‘λ | |
| ```bash | |
| curl -L -o metadata_v3.json \ | |
| "https://merry99-musclecare-train-ai.hf.space/model?version=3&filename=cnn_gru_fatigue_metadata.json" | |
| ``` | |
| #### ν€λ νμΈ | |
| ```bash | |
| curl -I "https://merry99-musclecare-train-ai.hf.space/model?version=3" | |
| ``` | |
| μλ΅ ν€λ μμ: | |
| ``` | |
| X-Model-Version: 3 | |
| X-Model-Filename: cnn_gru_fatigue.tflite | |
| ``` | |
| ### μ£Όμ μ¬ν | |
| - `training_state.json`μ `model_version` κ°μ΄ κΈ°μ€μ΄ λλ©°, κ·Έλ³΄λ€ λμ λ²μ μ μμ²νλ©΄ 404κ° λ°νλ©λλ€. | |
| - λ²μ λ³λ‘ λ€λ₯Έ νμΌμ μ μ§νμ§ μκ³ , κ°μ νμΌλͺ μ λ΄λ €μ£Όλ ν€λ(`X-Model-Version`)λ‘ μ€μ λ²μ μ νμΈν©λλ€. | |
| - μ€ν¨(μ: 404) μ JSON μλ΅μ΄ λ΄λ €μ€λ―λ‘, ν΄λΌμ΄μΈνΈλ μν μ½λλ₯Ό λ¨Όμ νμΈν λ€ **200μΌ λλ§** `body`λ₯Ό νμΌλ‘ μ μ₯νμΈμ. | |
| Flutter μμ (Dio): | |
| ```dart | |
| final response = await dio.get<List<int>>( | |
| 'https://merry99-musclecare-train-ai.hf.space/model', | |
| options: Options(responseType: ResponseType.bytes), | |
| ); | |
| if (response.statusCode == 200) { | |
| final version = response.headers.value('X-Model-Version'); | |
| final filename = response.headers.value('X-Model-Filename') ?? 'model.tflite'; | |
| await File('/path/$filename').writeAsBytes(response.data!); | |
| } else { | |
| final errorText = utf8.decode(response.data ?? []); | |
| // μλ¬ μ²λ¦¬ | |
| } | |
| ``` | |
| - Space νκ²½ λ³μ `HF_E2E_MODEL_TOKEN`, `HF_E2E_MODEL_REPO_ID`κ° μ¬λ°λ₯΄κ² μ€μ λΌ μμ΄μΌ `/model` λ° `/trigger`κ° μ μ λμν©λλ€. | |
| ## λͺ¨λΈ μ λ ₯ μ¬μ (Flutter μ°Έκ³ ) | |
| - μ λ ₯ νμ: `(batch_size, input_dim)`μ΄λ©° κΈ°λ³Έ `input_dim = 10 (FEATURE_COLUMNS) + embedding_dim`. | |
| - `FEATURE_COLUMNS`: `rms_acc`, `rms_gyro`, `mean_freq_acc`, `mean_freq_gyro`, `entropy_acc`, `entropy_gyro`, `jerk_mean`, `jerk_std`, `stability_index`, `fatigue_prev`. | |
| - `user_emb`: λ©νλ°μ΄ν°μ `embedding_dim`κ³Ό λμΌν κΈΈμ΄. λΆμ‘±νλ©΄ λ€λ₯Ό `0.0f`λ‘ ν¨λ©. | |
| - λ©νλ°μ΄ν°(`cnn_gru_fatigue_metadata.json`)μ `scaler.mean`, `scaler.scale`λ‘ νμ€νν λ€ λͺ¨λΈμ μ λ¬. | |
| ### Flutterμμ μ€ν μμ | |
| - **λ©νλ°μ΄ν° λ‘λ**: JSONμμ `feature_columns`, `scaler.mean`, `scaler.scale`, `embedding_dim`, `input_dim`μ μ½λλ€. | |
| - **νΉμ§ μΆμΆ**: μΈ‘μ λ²νΌμ λλ¬ μ»μ μλμ°μμ 10κ° νΌμ² κ°μ κ³μ°νλ€. | |
| - **νμ€ν**: `(value - mean) / scale`μ μννλ `scale`μ΄ 0μ΄λ©΄ 0μΌλ‘ λ체. | |
| - **μ λ ₯ λ²‘ν° κ΅¬μ±**: `[μ κ·νλ 10κ° νΌμ², user_emb(ν¨λ© ν¬ν¨)]`μ μ΄μ΄ λΆμ¬ `Float32List`λ‘ λ§λ λ€. | |
| - **TFLite μ€ν**: μ λ ₯μ `[1, input_dim]`μΌλ‘ reshape ν `interpreter.run(input, output)`μ νΈμΆνλ€. | |
| ```dart | |
| final meta = await loadMetadata(); // JSON νμ±: scaler, embedding_dim λ± | |
| final features = computeFeatureVector(); // κΈΈμ΄ 10, float | |
| final userEmb = ensureEmbeddingLength(rawEmb, meta.embeddingDim); // ν¨λ© | |
| final normalized = List<double>.generate(features.length, (i) { | |
| final scale = meta.scalerScale[i] == 0 ? 1.0 : meta.scalerScale[i]; | |
| return (features[i] - meta.scalerMean[i]) / scale; | |
| }); | |
| final inputVector = Float32List.fromList([ | |
| ...normalized, | |
| ...userEmb.map((e) => e.toDouble()), | |
| ]); | |
| final outputBuffer = Float32List(1); | |
| interpreter.run(inputVector.reshape([1, inputVector.length]), outputBuffer); | |
| final fatigueScore = outputBuffer[0]; | |
| ``` | |
| ### μ£Όμ | |
| - μ΅μ΄ μΈ‘μ λΆν° λ°λ‘ μμΈ‘ κ°λ₯νλ©°, λ μ΄μ 5κ° μλμ° λμ μ΄ νμνμ§ μμ΅λλ€. | |
| - `fatigue_prev`λ μ§μ μΈ‘μ μ νΌλ‘λ μ§νλ‘, κ°μ΄ μλ€λ©΄ `0` λλ μ§μ μμΈ‘μΉλ‘ μ΄κΈ°νν΄ μ£ΌμΈμ. | |
| - νΌμ² μΆμΆ λ‘μ§κ³Ό μλ² λ© μ°¨μμ λ°±μλ νμ΅ νμ΄νλΌμΈκ³Ό λμΌν΄μΌ ν©λλ€. | |