# fitlog-server
**Repository Path**: mml520/fitlog-server
## Basic Information
- **Project Name**: fitlog-server
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-01-06
- **Last Updated**: 2026-01-07
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# FitLog AI 系统后端文档
## 1. 项目简介
**FitLog AI** 是一个专为健身爱好者设计的全栈式训练与饮食追踪应用。它集成了 Google Gemini AI 能力,支持自然语言日志解析、食物图片识别以及基于个人历史数据的流式 AI 教练指导。
## 2. 核心功能模块
### A. 训练管理 (Workout Tracking)
- **手动录入**:支持选择训练部位(胸、背、肩、腿等)、记录动作名称、组数、次数及备注。
- **多媒体记录**:支持为每个动作上传训练快照(图片)。
- **智能解析 (Smart Input)**:用户输入一段话(如:“今天练胸,卧推100kg 5x5”),AI 自动解析并填充表单。
- **可视化统计**:通过饼图展示训练部位占比,通过柱状图展示近期的训练频率与强度。
### B. 饮食追踪 (Diet Tracking)
- **每日饮食记录**:记录早餐、午餐、晚餐及加餐。
- **AI 食物识别**:拍摄或上传食物图片,AI 自动识别食物名称并估算热量(kcal)。
- **补水记录**:追踪每日饮水量。
### C. AI 教练对话 (AI Analysis & Coach)
- **流式对话 (SSE)**:基于个人训练和饮食历史,提供实时的改进建议。
- **深度复盘**:一键生成本周/本月的训练报告。
- **分享海报**:支持将 AI 生成的专业分析报告转化为精美海报并分享。
### D. 离线与体验 (PWA)
- **离线访问**:支持 Service Worker 缓存,具备基础的 PWA 能力。
- **手势操作**:列表支持左滑删除,交互流畅。
------
## 3. 接口规范 (API Reference)
所有接口的基础地址为:https://aaa.kiss666.site/api
### 3.1 训练相关
| 接口名称 | 方法 | 路径 | 描述 |
| ------------- | ------ | -------------- | ------------------------------ |
| 获取训练列表 | GET | /workouts | 获取所有已保存的训练日志 |
| 保存/更新训练 | POST | /workouts | 提交新的训练日志或更新现有日志 |
| 删除训练 | DELETE | /workouts/{id} | 根据 ID 删除指定训练记录 |
### 3.2 饮食相关
| 接口名称 | 方法 | 路径 | 描述 |
| ------------- | ------ | ----------- | ------------------------ |
| 获取饮食列表 | GET | /diets | 获取所有饮食记录 |
| 保存/更新饮食 | POST | /diets | 提交每日饮食与补水数据 |
| 删除饮食 | DELETE | /diets/{id} | 根据 ID 删除指定饮食记录 |
### 3.3 AI 服务 (核心逻辑)
| 接口名称 | 方法 | 路径 | 描述 |
| ---------------- | ---- | ------------------ | ------------------------------------------------------------ |
| **AI 流式对话** | POST | /ai/chat | 传入历史记录、训练数据、饮食数据。采用 **SSE (Server-Sent Events)** 返回流式文本。 |
| **食物识别** | POST | /ai/recognize-food | 传入图片的 Base64 数据。返回食物描述及预估热量。 |
| **自然语言解析** | POST | /ai/parse-log | 传入一段非结构化文本。返回解析后的 JSON 结构化训练数据。 |
### 3.4 文件服务
| 接口名称 | 方法 | 路径 | 描述 |
| -------- | ---- | --------------------------------------- | ------------------------------------------------------ |
| 文件上传 | POST | /files/upload | 上传图片文件(multipart/form-data)。返回文件名/路径。 |
| 图片访问 | GET | https://aaa.kiss666.site/uploads/{path} | 通过拼接路径直接访问静态资源图片。 |
## 4. 后端代码与架构
提供的是整体的代码
1. pom.xml
```xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.7.18
com.fitlog
fitlog-ai-server
0.0.1-SNAPSHOT
fitlog-ai-server
FitLog AI Backend Service
17
3.5.9
org.springframework.boot
spring-boot-starter-web
com.baomidou
mybatis-plus-boot-starter
${mybatis-plus.version}
com.mysql
mysql-connector-j
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-validation
org.springframework.boot
spring-boot-starter-test
test
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
${java.version}
${java.version}
org.projectlombok
lombok
${lombok.version}
org.springframework.boot
spring-boot-maven-plugin
```
2. application.yml
```yml
spring:
application:
name: fitlog-ai-server
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.175.101:3306/fitlog?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: root
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 开启下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 输出 SQL 日志到控制台
global-config:
db-config:
id-type: assign_id # 使用雪花算法生成 ID
logic-delete-field: deleted # 逻辑删除字段名(如需要)
server:
port: 8080
```
3. CorsConfig.java
```java
package com.fitlog.ai.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.io.File;
/**
* 全局跨域配置
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*") // 使用 pattern 允许所有来源且支持 credentials
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 动态识别操作系统并设置路径
String os = System.getProperty("os.name").toLowerCase();
String path = os.contains("win") ? "D:/fitlog/uploads/" : "/home/fitlog/uploads/";
// 确保物理目录存在
File dir = new File(path);
if (!dir.exists()) dir.mkdirs();
// 将 /uploads/** 映射到物理路径
registry.addResourceHandler("/uploads/**")
.addResourceLocations("file:" + path);
}
}
```
4. AIController.java
```java
package com.fitlog.ai.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/ai")
public class AIController {
// 注意:Gemini 2.0 Flash 响应速度极快,建议使用
private final String API_KEY = "AIzaSyBENvqY_pIUiWJ88jUn9C8txhNAPaUcMLM";
private final String MODEL_NAME = "gemini-3-flash-preview";
private final ObjectMapper objectMapper = new ObjectMapper();
private final ExecutorService executor = Executors.newCachedThreadPool();
private final RestTemplate restTemplate;
// 代理设置
private final String PROXY_HOST = "127.0.0.1";
private final int PROXY_PORT = 10809;
public AIController() {
org.springframework.http.client.SimpleClientHttpRequestFactory factory = new org.springframework.http.client.SimpleClientHttpRequestFactory();
factory.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, PROXY_PORT)));
factory.setConnectTimeout(10000);
factory.setReadTimeout(30000);
this.restTemplate = new RestTemplate(factory);
}
/**
* 构建系统指令和上下文
*/
private String getContextPrompt(List