interview-guide Documentation

基于 Spring Boot 4.1、Java 25、Spring AI 2.0、React、PostgreSQL/pgvector、Redis 和 RustFS 构建的开源 AI 面试平台,支持简历智能分析、模拟面试、语音面试和知识库 RAG。

3,405 stars Java Java 12 files · ~21,955 tokens #gradle#itext7#mapstruct#pgvector#postgresql#rag#redis#redisson
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy interview-guide on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name interview-guide -p 5432:5432 --restart always pgvector/pgvector:pg16
Configured Services & Ports
⚙️ postgres
image: pgvector/pgvector:pg16
🔌 Ports: 5432:5432
⚙️ redis
image: redis:7
🔌 Ports: 6379:6379
⚙️ minio
image: minio/minio
🔌 Ports: 9000:9000, 9001:9001
⚙️ createbuckets
image: minio/mc
⚙️ app
image: build locally
🔌 Ports: 8080:8080
⚙️ frontend
image: build locally
🔌 Ports: 80:80
docker-compose.yml
yaml (docker-compose.yml)
services:
  # =========================================
  # 1. PostgreSQL 数据库服务
  # -----------------------------------------
  # 作用:
  #   - 存储业务数据(用户、简历信息等)
  #   - 存储向量数据(基于 pgvector 插件),用于 RAG(检索增强生成)知识库检索
  #
  # 教程知识点:
  #   - 选用 pgvector/pgvector 镜像而不是标准的 postgres 镜像,是为了获得向量搜索能力。
  #   - 向量数据库是 LLM 应用开发中的核心基础设施。
  # =========================================
  postgres:
    # 使用带有 pgvector 插件的 PostgreSQL 16 镜像
    image: pgvector/pgvector:pg16
    container_name: interview-postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
      POSTGRES_DB: interview_guide
    volumes:
      # 数据持久化:确保容器重启或删除后,数据库数据不丢失
      - postgres_data:/var/lib/postgresql/data
      # 初始化脚本:容器首次启动时会自动执行 /docker-entrypoint-initdb.d/ 下的 .sql 文件
      - ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    # 健康检查:
    # 后端服务(app)需要等待数据库完全启动并准备好连接后才能启动。
    # 这里通过 pg_isready 命令检测数据库状态。
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  # =========================================
  # 2. Redis 缓存与消息队列服务
  # -----------------------------------------
  # 作用:
  #   - 缓存:存储 Session、临时数据,提升系统性能
  #   - 消息队列:利用 Redis Stream 实现异步任务处理(如简历分析、文档向量化)
  #
  # 教程知识点:
  #   - 在轻量级架构中,Redis Stream 是 Kafka/RabbitMQ 的优秀替代方案,运维成本更低。
  # =========================================
  redis:
    image: redis:7
    container_name: interview-redis
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

  # =========================================
  # 3. MinIO 对象存储服务
  # -----------------------------------------
  # 作用:
  #   - 存储非结构化数据:用户上传的简历(PDF/Word)、头像、知识库文档等
  #
  # 教程知识点:
  #   - MinIO 兼容 AWS S3 协议,这意味着代码中使用 S3 SDK 即可无缝切换到云厂商的对象存储。
  #   - 端口说明:
  #     - 9000: API 端口,代码通过此端口上传/下载文件
  #     - 9001: 控制台端口,浏览器访问此端口管理文件
  # =========================================
  minio:
    image: minio/minio
    container_name: interview-minio
    # 启动命令:指定数据目录和控制台地址
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - minio_data:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 5s
      timeout: 3s
      retries: 5

  # =========================================
  # 4. MinIO 初始化任务 (Init Container Pattern)
  # -----------------------------------------
  # 作用:
  #   - 自动创建项目所需的存储桶 (Bucket)
  #   - 设置存储桶的访问权限
  #
  # 教程知识点:
  #   - "初始化容器"模式:这是一个短生命周期的容器,任务完成后自动退出。
  #   - 解决了"谁来创建 Bucket"的问题,实现了基础设施的自动化配置,无需手动操作。
  # =========================================
  createbuckets:
    image: minio/mc
    depends_on:
      minio:
        condition: service_healthy # 必须等待 MinIO 服务健康(不仅仅是启动)
    entrypoint: >
      /bin/sh -c "
      set -eu;
      /usr/bin/mc alias set myminio http://minio:9000 minioadmin minioadmin &&
      (
        /usr/bin/mc ls myminio/interview-guide > /dev/null 2>&1 ||
        /usr/bin/mc mb myminio/interview-guide
      ) &&
      /usr/bin/mc anonymous set public myminio/interview-guide &&
      /usr/bin/mc ls myminio/interview-guide
      "

  # =========================================
  # 5. 后端应用服务 (Spring Boot)
  # -----------------------------------------
  # 作用:
  #   - 提供 RESTful API
  #   - 处理核心业务逻辑(简历分析、模拟面试、RAG)
  # =========================================
  app:
    build:
      context: .
      dockerfile: app/Dockerfile
    container_name: interview-app
    # 依赖管理:确保基础设施准备好后再启动后端
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      minio:
        condition: service_healthy
      createbuckets:
        condition: service_completed_successfully # 等待初始化任务完成
    environment:
      # === 数据库连接 ===
      # 使用服务名 'postgres' 作为主机名,Docker 内部 DNS 会自动解析
      POSTGRES_HOST: postgres
      POSTGRES_PORT: 5432
      POSTGRES_DB: interview_guide
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
      
      # === Redis 连接 ===
      REDIS_HOST: redis
      REDIS_PORT: 6379
      
      # === 对象存储配置 ===
      # 注意:后端在容器内访问 MinIO,使用 http://minio:9000
      APP_STORAGE_ENDPOINT: http://minio:9000
      APP_STORAGE_ACCESS_KEY: minioadmin
      APP_STORAGE_SECRET_KEY: minioadmin
      APP_STORAGE_BUCKET: interview-guide
      APP_STORAGE_REGION: us-east-1
      
      # === AI 模型配置 (必须配置) ===
      # 这里的变量值来自宿主机的环境变量或 .env 文件
      AI_BAILIAN_API_KEY: ${AI_BAILIAN_API_KEY}
      AI_MODEL: ${AI_MODEL:-qwen3.5-flash}
      APP_AI_CONFIG_ENCRYPTION_KEY: ${APP_AI_CONFIG_ENCRYPTION_KEY}

      # === 面试参数配置 ===
      APP_INTERVIEW_FOLLOW_UP_COUNT: ${APP_INTERVIEW_FOLLOW_UP_COUNT:-1}
      APP_INTERVIEW_EVALUATION_BATCH_SIZE: ${APP_INTERVIEW_EVALUATION_BATCH_SIZE:-8}
    ports:
      - "8080:8080"

  # =========================================
  # 6. 前端应用服务 (Vue/React + Nginx)
  # -----------------------------------------
  # 作用:
  #   - 提供用户界面
  #   - 反向代理 API 请求(通常在 Nginx 配置中处理)
  # =========================================
  frontend:
    build: ./frontend
    container_name: interview-frontend
    depends_on:
      - app
    ports:
      - "80:80"

# =========================================
# 定义 Docker 卷 (Volumes)
# -----------------------------------------
# 作用:声明命名卷,用于数据持久化。
# 即使删除了容器 (docker-compose down),这些卷中的数据依然存在。
# =========================================
volumes:
  postgres_data:
  redis_data:
  minio_data:

File: docs/voice-interview-architecture.md

AI 语音面试系统架构文档

最后更新: 2026-04-06
当前版本: Qwen3 实时语音模型

📋 系统概述

AI语音面试系统是一个实时语音交互的智能面试平台,集成了语音识别(ASR)、大语言模型(LLM)、语音合成(TTS)等AI能力,提供沉浸式的面试体验。

核心技术升级:项目已从 Aliyun NLS SDK 升级到 Qwen3 实时语音模型,实现更低延迟和更高准确率:

  • ASR 准确率: ~95%+(提升 5%+)
  • ASR 断句延迟: 400ms(减少 50%)
  • TTS 首包延迟: 200ms(减少 60%)
  • 配置简化: 从 9 个环境变量减少到 2 个(统一使用 AI_BAILIAN_API_KEY)

🏗️ 系统架构图

整体架构

mermaid
graph TB
    subgraph "前端层 (React)"
        A[VoiceInterviewPage] --> B[AudioRecorder]
        A --> C[RealtimeSubtitle]
        A --> D[PhaseSetupModal]
        B --> E[WebSocket Client]
        C --> E
    end

    subgraph "API层 (Spring Boot)"
        E <--> F[WebSocket Handler]
        G[REST Controller] --> H[Session Service]
        F --> H
    end

    subgraph "服务层"
        H --> I[QwenAsrService]
        H --> J[DashscopeLlmService]
        H --> K[QwenTtsService]
        H --> L[Prompt Service]
        H --> M[Evaluation Service]
    end

    subgraph "外部服务 (阿里云 DashScope)"
        I --> N[Qwen3 ASR]
        K --> O[Qwen3 TTS]
        J --> P[Qwen LLM]
    end

    subgraph "数据层"
        H --> Q[(PostgreSQL)]
        H --> R[(Redis Cache)]
    end

    style A fill:#e1f5ff
    style F fill:#fff4e1
    style H fill:#f0f0f0
    style N fill:#ffebf0
    style O fill:#ffebf0
    style P fill:#ffebf0

核心流程时序图

mermaid
sequenceDiagram
    participant U as 用户
    participant F as 前端
    participant W as WebSocket
    participant S as Service
    participant STT as STT服务
    participant LLM as LLM服务
    participant TTS as TTS服务
    participant DB as 数据库

    Note over U,DB: 1. 创建会话
    U->>F: 配置面试参数
    F->>S: POST /api/voice-interview/sessions
    S->>DB: 创建Session记录
    S-->>F: 返回WebSocket URL

    Note over U,DB: 2. 建立WebSocket连接
    F->>W: 连接WebSocket
    W->>S: 注册会话
    S-->>W: 连接成功

    Note over U,DB: 3. 语音交互循环
    U->>F: 开始录音
    F->>W: 发送音频流
    W->>S: 处理音频
    S->>STT: 语音转文字
    STT-->>S: 返回文本
    S-->>W: 实时字幕
    W-->>F: 显示字幕

    Note over U,DB: 4. AI生成回复
    S->>LLM: 发送用户输入+上下文
    LLM-->>S: AI回复文本
    S->>TTS: 文字转语音
    TTS-->>S: 音频流
    S->>DB: 保存消息
    S-->>W: AI音频+字幕
    W-->>F: 播放AI回复

    Note over U,DB: 5. 结束会话
    U->>F: 点击结束
    F->>S: PUT /api/voice-interview/sessions/{id}/end
    S->>LLM: 生成评估报告
    S->>DB: 更新Session状态
    S-->>F: 返回评估结果

🎯 模块详解

1. 前端模块

VoiceInterviewPage

  • 职责: 主页面,协调所有子组件
  • 状态管理: 会话状态、消息历史、UI状态
  • 核心功能:
    • WebSocket连接管理
    • 面试阶段控制
    • 消息持久化显示

AudioRecorder

  • 职责: 音频录制和发送
  • 技术: Web Audio API + WebSocket
  • 核心功能:
    • PCM音频采集
    • 实时音频流传输
    • VAD语音活动检测
    • 录音状态管理

RealtimeSubtitle

  • 职责: 实时字幕显示
  • 核心功能:
    • 用户语音实时转写
    • AI回复文字展示
    • 双向字幕滚动

PhaseSetupModal

  • 职责: 面试配置
  • 核心功能:
    • 选择面试角色(阿里P8/字节算法/腾讯后端)
    • 配置面试阶段(自我介绍/技术/项目/HR)
    • 设置面试时长

2. 后端API层

VoiceInterviewController (REST)

text
POST   /api/voice-interview/sessions           # 创建会话
GET    /api/voice-interview/sessions/{id}      # 获取会话
PUT    /api/voice-interview/sessions/{id}/end  # 结束会话
PUT    /api/voice-interview/sessions/{id}/pause  # 暂停会话
PUT    /api/voice-interview/sessions/{id}/resume # 恢复会话
GET    /api/voice-interview/sessions           # 获取所有会话
GET    /api/voice-interview/sessions/{id}/messages # 获取消息历史
GET    /api/voice-interview/sessions/{id}/evaluation # 获取评估报告

VoiceInterviewWebSocketHandler

  • 职责: WebSocket连接和消息处理
  • 协议: 自定义JSON消息格式
  • 消息类型:
    • AUDIO: 音频数据
    • SUBTITLE: 字幕数据
    • CONTROL: 控制消息(开始/暂停/结束)

3. 服务层

VoiceInterviewService

  • 核心职责: 会话生命周期管理
  • 关键方法:
    • createSession(): 创建会话,初始化状态
    • processAudio(): 处理音频流,调用STT
    • handleUserInput(): 处理用户输入,调用LLM
    • generateResponse(): 生成AI回复,调用TTS
    • endSession(): 结束会话,生成评估
    • pauseSession(): 暂停会话,保存状态
    • resumeSession(): 恢复会话,恢复状态

QwenAsrService

  • 职责: 实时语音识别
  • 技术: Qwen3 ASR Flash Realtime (DashScope SDK 2.22.7)
  • 模型: qwen3-asr-flash-realtime
  • 功能:
    • PCM音频流转文字
    • 实时中间结果和最终结果
    • 服务端 VAD(语音活动检测)
    • 自动断句(400ms 静音阈值)
  • 性能:
    • 识别准确率: ~95%+
    • 断句延迟: 400ms(比传统方案快 50%)

DashscopeLlmService

  • 职责: LLM对话生成
  • 技术: 阿里云DashScope (qwen3.5-flash)
  • 功能:
    • 角色扮演(面试官角色)
    • 多轮对话上下文
    • 简历上下文注入
    • 流式响应(SSE)
  • 支持: 多 LLM 提供商(DashScope/MiniMax/OpenAI/DeepSeek/LM Studio)

QwenTtsService

  • 职责: 实时语音合成
  • 技术: Qwen3 TTS Flash Realtime (DashScope SDK 2.22.7)
  • 模型: qwen3-tts-flash-realtime
  • 音色: Cherry(温柔女声)
  • 功能:
    • 文字转语音流
    • 流式合成(边合成边播放)
    • 中文优化
    • PCM格式输出
  • 性能:
    • 首包延迟: 200ms(快 60%)
    • 语速/音量可配置

VoiceInterviewPromptService

  • 职责: 提示词管理
  • 功能:
    • 角色提示词模板(ST格式)
    • 简历上下文注入
    • 动态提示词生成

VoiceInterviewEvaluationService

  • 职责: 面试评估
  • 功能:
    • 多维度评分(技术/沟通/逻辑等)
    • 结构化输出
    • 评估报告生成

4. 数据模型

VoiceInterviewSessionEntity

java
- id: Long                    # 会话ID
- roleType: String            # 角色类型(ali-p8/byteance-algo/tencent-backend)
- resumeId: Long              # 关联简历ID
- currentPhase: InterviewPhase # 当前阶段(INTRO/TECH/PROJECT/HR/COMPLETED)
- status: SessionStatus       # 状态(IN_PROGRESS/PAUSED/COMPLETED)
- plannedDuration: Integer    # 计划时长(分钟)
- startTime: LocalDateTime    # 开始时间
- endTime: LocalDateTime      # 结束时间
- pausedAt: LocalDateTime     # 暂停时间
- resumedAt: LocalDateTime    # 恢复时间
- actualDuration: Integer     # 实际时长(秒)

VoiceInterviewMessageEntity

java
- id: Long                    # 消息ID
- sessionId: Long             # 会话ID
- role: MessageRole           # 角色(USER/ASSISTANT)
- content: String             # 消息内容
- audioUrl: String            # 音频URL(可选)
- timestamp: LocalDateTime    # 时间戳

VoiceInterviewEvaluationEntity

java
- id: Long                    # 评估ID
- sessionId: Long             # 会话ID
- technicalScore: Integer     # 技术评分
- communicationScore: Integer # 沟通评分
- logicScore: Integer         # 逻辑评分
- overallScore: Integer       # 综合评分
- strengths: String           # 优势
- improvements: String        # 改进建议
- summary: String             # 总结

🔄 核心流程

1. 会话创建流程

mermaid
flowchart TD
    A[用户配置面试参数] --> B{选择角色类型}
    B -->|阿里P8| C[加载阿里P8提示词]
    B -->|字节算法| D[加载字节算法提示词]
    B -->|腾讯后端| E[加载腾讯后端提示词]

    C --> F[创建Session记录]
    D --> F
    E --> F

    F --> G{是否关联简历?}
    G -->|是| H[加载简历上下文]
    G -->|否| I[使用默认上下文]

    H --> J[生成WebSocket URL]
    I --> J

    J --> K[缓存Session到Redis]
    K --> L[返回Session信息给前端]

2. 实时对话流程

mermaid
flowchart LR
    A[用户语音] --> B[AudioRecorder采集]
    B --> C[WebSocket发送]
    C --> D[STT识别]
    D --> E[显示字幕]

    E --> F[LLM生成回复]
    F --> G[TTS合成语音]
    G --> H[WebSocket推送]

    H --> I[前端播放音频]
    H --> J[显示AI字幕]

    I --> K[等待用户下次发言]
    J --> K
    K --> A

3. 评估生成流程

mermaid
flowchart TD
    A[用户结束会话] --> B[收集所有消息]
    B --> C[构建评估提示词]
    C --> D[调用LLM生成评估]

    D --> E{结构化输出成功?}
    E -->|是| F[解析评估结果]
    E -->|否| G[重试(最多3次)]

    G --> E
    F --> H[保存评估记录]
    H --> I[更新Session状态]
    I --> J[返回评估结果]

🗂️ 数据流向

音频流向

text
麦克风 → AudioRecorder (PCM) → WebSocket → Service → Qwen3 ASR
    ↓
AI回复文本 → Qwen3 TTS → PCM音频 → WebSocket → AudioPlayer → 扬声器

文本流向

text
用户语音 → STT → 文本 → 字幕显示
    ↓
文本 + 上下文 → LLM → AI回复文本 → 字幕显示
    ↓
AI回复文本 → DB持久化

控制流向

text
用户操作 → REST API → Service → DB状态更新
    ↓
WebSocket消息 → Service → 状态变更 → WebSocket通知

🔐 安全与性能

安全措施

  1. API密钥保护: 环境变量存储,不提交代码
  2. 会话隔离: 每个用户独立会话
  3. 输入验证: DTO校验,防止注入
  4. 异常处理: 统一异常处理,敏感信息不泄露

性能优化

  1. Redis缓存: 活跃会话缓存,减少DB查询
  2. WebSocket长连接: 避免频繁建立连接
  3. 流式处理: 音频流实时处理,不等待完整录音
  4. 异步评估: 结束后异步生成评估,不阻塞用户

📊 监控指标

业务指标

  • 会话创建成功率
  • 平均会话时长
  • STT识别准确率
  • LLM响应时间
  • TTS合成时间
  • 用户满意度评分

技术指标

  • WebSocket连接数
  • API响应时间
  • 数据库查询性能
  • Redis缓存命中率
  • 外部服务调用延迟

🚀 部署架构

mermaid
graph TB
    subgraph "用户端"
        A[浏览器]
    end

    subgraph "应用服务器"
        B[Nginx反向代理]
        C[Spring Boot App]
        D[WebSocket Server]
    end

    subgraph "数据层"
        E[(PostgreSQL)]
        F[(Redis)]
    end

    subgraph "外部服务 (阿里云 DashScope)"
        G[Qwen3 ASR]
        H[Qwen3 TTS]
        I[Qwen LLM]
    end

    A -->|HTTPS/WSS| B
    B --> C
    B --> D
    C --> E
    C --> F
    D --> F
    C --> G
    C --> H
    C --> I

🔧 配置说明

必需配置

yaml
# 统一 API Key(LLM + ASR + TTS 共用)
ai.bailian.api-key: ${AI_BAILIAN_API_KEY}
spring.ai.openai.api-key: ${AI_BAILIAN_API_KEY}

# AI 模型配置
ai.model: qwen3.5-flash  # 可选: qwen3.5-plus, qwen-max 等

语音服务配置

yaml
app:
  voice-interview:
    # LLM 提供商(默认: dashscope)
    llm-provider: dashscope

    # Qwen3 ASR 配置
    qwen:
      asr:
        url: wss://dashscope.aliyuncs.com/api-ws/v1/realtime
        model: qwen3-asr-flash-realtime
        api-key: ${AI_BAILIAN_API_KEY}
        language: zh
        format: pcm
        sample-rate: 16000
        enable-turn-detection: true
        turn-detection-type: server_vad
        turn-detection-silence-duration-ms: 400

      # Qwen3 TTS 配置
      tts:
        url: wss://dashscope.aliyuncs.com/api-ws/v1/realtime
        model: qwen3-tts-flash-realtime
        api-key: ${AI_BAILIAN_API_KEY}
        voice: Cherry
        format: pcm
        sample-rate: 16000

可选配置

yaml
# 面试配置
app:
  interview:
    follow-up-count: 1
    evaluation-batch-size: 8

  voice-interview:
    # 阶段时长配置(分钟)
    phase:
      intro:
        min-duration: 3
        suggested-duration: 5
        max-duration: 8
        min-questions: 2
        max-questions: 5

    # 音频规格
    audio:
      codec: opus
      sample-rate: 16000
      bit-rate: 24000

    # WebSocket配置
    user-utterance-debounce-ms: 1600

📝 开发指南

添加新角色

  1. 创建提示词模板: app/src/main/resources/prompts/voice-interview/{role-type}.st
  2. 更新 VoiceInterviewPromptService 支持新角色
  3. 前端添加角色选项

扩展评估维度

  1. 更新 EvaluationResponseDTO 添加新字段
  2. 更新数据库表 voice_interview_evaluations
  3. 更新评估提示词模板
  4. 更新前端评估展示

集成新的AI服务

  1. 实现 LlmService 接口
  2. 添加配置类
  3. 使用 @ConditionalOnProperty 切换实现

🐛 常见问题

1. WebSocket连接失败

  • 检查防火墙是否允许WebSocket连接
  • 确认Nginx配置支持WebSocket代理
  • 检查Session ID是否有效

2. STT识别不准确

  • 检查音频采样率(应为16kHz)
  • 确认音频格式为PCM
  • 检查网络延迟

3. LLM响应慢

  • 检查DashScope服务状态
  • 考虑使用流式响应
  • 优化提示词长度

4. TTS合成长度限制

  • 单次合成不超过500字符
  • 长文本需要分段合成
  • 考虑使用流式TTS

📚 相关文档


File: frontend/README.md

React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.

Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

js
export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...

      // Remove tseslint.configs.recommended and replace with this
      tseslint.configs.recommendedTypeChecked,
      // Alternatively, use this for stricter rules
      tseslint.configs.strictTypeChecked,
      // Optionally, add this for stylistic rules
      tseslint.configs.stylisticTypeChecked,

      // Other configs...
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])

You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:

js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...
      // Enable lint rules for React
      reactX.configs['recommended-typescript'],
      // Enable lint rules for React DOM
      reactDom.configs.recommended,
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])