openapi: 3.0.0
info:
  title: Training Module API
  description: 考培练系统陪练模块API契约
  version: 1.0.0
  
servers:
  - url: http://localhost:8000/api/v1
    description: 本地开发服务器

paths:
  /training/scenes:
    get:
      summary: 获取陪练场景列表
      tags:
        - 陪练场景
      security:
        - bearerAuth: []
      parameters:
        - name: category
          in: query
          description: 场景分类
          schema:
            type: string
        - name: status
          in: query
          description: 场景状态
          schema:
            type: string
            enum: [draft, active, inactive]
        - name: is_public
          in: query
          description: 是否公开
          schema:
            type: boolean
        - name: search
          in: query
          description: 搜索关键词
          schema:
            type: string
        - name: page
          in: query
          description: 页码
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          description: 每页数量
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedScenesResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
          
    post:
      summary: 创建陪练场景（管理员）
      tags:
        - 陪练场景
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TrainingSceneCreate'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingSceneResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /training/scenes/{scene_id}:
    get:
      summary: 获取陪练场景详情
      tags:
        - 陪练场景
      security:
        - bearerAuth: []
      parameters:
        - name: scene_id
          in: path
          required: true
          description: 场景ID
          schema:
            type: integer
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingSceneResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
          
    put:
      summary: 更新陪练场景（管理员）
      tags:
        - 陪练场景
      security:
        - bearerAuth: []
      parameters:
        - name: scene_id
          in: path
          required: true
          description: 场景ID
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TrainingSceneUpdate'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingSceneResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
          
    delete:
      summary: 删除陪练场景（管理员）
      tags:
        - 陪练场景
      security:
        - bearerAuth: []
      parameters:
        - name: scene_id
          in: path
          required: true
          description: 场景ID
          schema:
            type: integer
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 200
                  message:
                    type: string
                    example: "删除陪练场景成功"
                  data:
                    type: boolean
                    example: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /training/sessions:
    post:
      summary: 开始陪练会话
      tags:
        - 陪练会话
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartTrainingRequest'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StartTrainingResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: 场景不存在
          
    get:
      summary: 获取用户的陪练会话列表
      tags:
        - 陪练会话
      security:
        - bearerAuth: []
      parameters:
        - name: scene_id
          in: query
          description: 场景ID
          schema:
            type: integer
        - name: status
          in: query
          description: 会话状态
          schema:
            type: string
            enum: [created, in_progress, completed, cancelled, error]
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedSessionsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /training/sessions/{session_id}:
    get:
      summary: 获取陪练会话详情
      tags:
        - 陪练会话
      security:
        - bearerAuth: []
      parameters:
        - name: session_id
          in: path
          required: true
          description: 会话ID
          schema:
            type: integer
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingSessionResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /training/sessions/{session_id}/end:
    post:
      summary: 结束陪练会话
      tags:
        - 陪练会话
      security:
        - bearerAuth: []
      parameters:
        - name: session_id
          in: path
          required: true
          description: 会话ID
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EndTrainingRequest'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EndTrainingResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /training/sessions/{session_id}/messages:
    get:
      summary: 获取陪练会话的消息列表
      tags:
        - 陪练消息
      security:
        - bearerAuth: []
      parameters:
        - name: session_id
          in: path
          required: true
          description: 会话ID
          schema:
            type: integer
        - name: skip
          in: query
          description: 跳过数量
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: limit
          in: query
          description: 返回数量
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                  message:
                    type: string
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TrainingMessage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /training/reports:
    get:
      summary: 获取用户的陪练报告列表
      tags:
        - 陪练报告
      security:
        - bearerAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: page_size
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedReportsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /training/reports/{report_id}:
    get:
      summary: 获取陪练报告详情
      tags:
        - 陪练报告
      security:
        - bearerAuth: []
      parameters:
        - name: report_id
          in: path
          required: true
          description: 报告ID
          schema:
            type: integer
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingReportResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /training/sessions/{session_id}/report:
    get:
      summary: 根据会话ID获取陪练报告
      tags:
        - 陪练报告
      security:
        - bearerAuth: []
      parameters:
        - name: session_id
          in: path
          required: true
          description: 会话ID
          schema:
            type: integer
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingReportResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  responses:
    Unauthorized:
      description: 未授权
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
            
    Forbidden:
      description: 禁止访问
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
            
    NotFound:
      description: 资源未找到
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  schemas:
    ErrorResponse:
      type: object
      properties:
        code:
          type: integer
        message:
          type: string
        detail:
          type: object
          
    BaseResponse:
      type: object
      properties:
        code:
          type: integer
          example: 200
        message:
          type: string
          example: "success"
        request_id:
          type: string
          
    PaginationMeta:
      type: object
      properties:
        total:
          type: integer
        page:
          type: integer
        page_size:
          type: integer
        pages:
          type: integer

    TrainingSceneCreate:
      type: object
      required:
        - name
        - category
      properties:
        name:
          type: string
          maxLength: 100
          description: 场景名称
        description:
          type: string
          description: 场景描述
        category:
          type: string
          maxLength: 50
          description: 场景分类
        ai_config:
          type: object
          description: AI配置
        prompt_template:
          type: string
          description: 提示词模板
        evaluation_criteria:
          type: object
          description: 评估标准
        is_public:
          type: boolean
          default: true
          description: 是否公开
        required_level:
          type: integer
          description: 所需用户等级
        status:
          type: string
          enum: [draft, active, inactive]
          default: draft

    TrainingSceneUpdate:
      type: object
      properties:
        name:
          type: string
          maxLength: 100
        description:
          type: string
        category:
          type: string
          maxLength: 50
        ai_config:
          type: object
        prompt_template:
          type: string
        evaluation_criteria:
          type: object
        status:
          type: string
          enum: [draft, active, inactive]
        is_public:
          type: boolean
        required_level:
          type: integer

    TrainingScene:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        category:
          type: string
        ai_config:
          type: object
        prompt_template:
          type: string
        evaluation_criteria:
          type: object
        status:
          type: string
          enum: [draft, active, inactive]
        is_public:
          type: boolean
        required_level:
          type: integer
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    TrainingSceneResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/TrainingScene'

    PaginatedScenesResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                items:
                  type: array
                  items:
                    $ref: '#/components/schemas/TrainingScene'
                total:
                  type: integer
                page:
                  type: integer
                page_size:
                  type: integer
                pages:
                  type: integer

    StartTrainingRequest:
      type: object
      required:
        - scene_id
      properties:
        scene_id:
          type: integer
          description: 场景ID
        config:
          type: object
          description: 会话配置

    StartTrainingResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                session_id:
                  type: integer
                coze_conversation_id:
                  type: string
                scene:
                  $ref: '#/components/schemas/TrainingScene'
                websocket_url:
                  type: string

    EndTrainingRequest:
      type: object
      properties:
        generate_report:
          type: boolean
          default: true
          description: 是否生成报告

    EndTrainingResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                session:
                  $ref: '#/components/schemas/TrainingSession'
                report:
                  $ref: '#/components/schemas/TrainingReport'

    TrainingSession:
      type: object
      properties:
        id:
          type: integer
        user_id:
          type: integer
        scene_id:
          type: integer
        coze_conversation_id:
          type: string
        start_time:
          type: string
          format: date-time
        end_time:
          type: string
          format: date-time
        duration_seconds:
          type: integer
        status:
          type: string
          enum: [created, in_progress, completed, cancelled, error]
        session_config:
          type: object
        total_score:
          type: number
        evaluation_result:
          type: object
        scene:
          $ref: '#/components/schemas/TrainingScene'
        message_count:
          type: integer
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    TrainingSessionResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/TrainingSession'

    PaginatedSessionsResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                items:
                  type: array
                  items:
                    $ref: '#/components/schemas/TrainingSession'
                total:
                  type: integer
                page:
                  type: integer
                page_size:
                  type: integer
                pages:
                  type: integer

    TrainingMessage:
      type: object
      properties:
        id:
          type: integer
        session_id:
          type: integer
        role:
          type: string
          enum: [user, assistant, system]
        type:
          type: string
          enum: [text, voice, system]
        content:
          type: string
        voice_url:
          type: string
        voice_duration:
          type: number
        metadata:
          type: object
        coze_message_id:
          type: string
        created_at:
          type: string
          format: date-time

    TrainingReport:
      type: object
      properties:
        id:
          type: integer
        session_id:
          type: integer
        user_id:
          type: integer
        overall_score:
          type: number
        dimension_scores:
          type: object
          additionalProperties:
            type: number
        strengths:
          type: array
          items:
            type: string
        weaknesses:
          type: array
          items:
            type: string
        suggestions:
          type: array
          items:
            type: string
        detailed_analysis:
          type: string
        transcript:
          type: string
        statistics:
          type: object
        session:
          $ref: '#/components/schemas/TrainingSession'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    TrainingReportResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/TrainingReport'

    PaginatedReportsResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                items:
                  type: array
                  items:
                    $ref: '#/components/schemas/TrainingReport'
                total:
                  type: integer
                page:
                  type: integer
                page_size:
                  type: integer
                pages:
                  type: integer
