Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 7 additions & 46 deletions src/api/opening/opening.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,20 @@
import { buildUrl } from '../utils'

// API Types for opening drill logging
export interface OpeningDrillSelection {

export interface LogOpeningDrillRequest {
opening_fen: string
side_played: string
}

export interface SelectOpeningDrillsRequest {
openings: OpeningDrillSelection[]
opponent: string
num_moves: number
num_drills: number
}

export interface SelectOpeningDrillsResponse {
session_id: string
}

export interface SubmitOpeningDrillRequest {
session_id: string
opening_fen: string
side_played: string
moves_played_uci: string[]
}

// API function to log opening drill selections and start a session
export const selectOpeningDrills = async (
request: SelectOpeningDrillsRequest,
): Promise<SelectOpeningDrillsResponse> => {
const res = await fetch(buildUrl('opening/select_opening_drills'), {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
})

if (res.status === 401) {
throw new Error('Unauthorized')
}

if (!res.ok) {
throw new Error(`Failed to select opening drills: ${res.statusText}`)
}

const data = await res.json()
return data as SelectOpeningDrillsResponse
}

// API function to submit a completed opening drill
export const submitOpeningDrill = async (
request: SubmitOpeningDrillRequest,
// API function to log a completed opening drill
export const logOpeningDrill = async (
request: LogOpeningDrillRequest,
): Promise<void> => {
const res = await fetch(buildUrl('opening/record_opening_drill'), {
const res = await fetch(buildUrl('opening/log_opening_drill'), {
method: 'POST',
headers: {
Accept: 'application/json',
Expand All @@ -67,6 +28,6 @@ export const submitOpeningDrill = async (
}

if (!res.ok) {
throw new Error(`Failed to submit opening drill: ${res.statusText}`)
throw new Error(`Failed to log opening drill: ${res.statusText}`)
}
}
2 changes: 1 addition & 1 deletion src/components/Analysis/MoveMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ export const MoveMap: React.FC<Props> = ({
tickMargin={0}
tickLine={false}
tickFormatter={(value) => `${value}%`}
domain={([dataMin, dataMax]) => [0, dataMax > 60 ? 100 : 60]}
domain={([dataMin, dataMax]) => [0, dataMax > 40 ? 100 : 40]}
>
<Label
value="← Unlikely"
Expand Down
87 changes: 29 additions & 58 deletions src/components/Openings/OpeningSelectionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
trackDrillConfigurationCompleted,
} from 'src/lib/analytics'
import { MAIA_MODELS_WITH_NAMES } from 'src/constants/common'
import { selectOpeningDrills } from 'src/api/opening'

type MobileTab = 'browse' | 'selected'

Expand Down Expand Up @@ -1073,66 +1072,38 @@ export const OpeningSelectionModal: React.FC<Props> = ({
if (selections.length > 0) {
const drillSequence = generateDrillSequence(selections, drillCount)

try {
// Prepare API request data
const openings = selections.map((selection) => ({
opening_fen: selection.variation
? selection.variation.fen
: selection.opening.fen,
side_played: selection.playerColor,
}))

// Call the backend API to log opening selections and get session ID
const response = await selectOpeningDrills({
openings,
opponent: selectedMaiaVersion.id,
num_moves: targetMoveNumber,
num_drills: drillCount,
})

const configuration: DrillConfiguration = {
selections,
drillCount,
drillSequence,
sessionId: response.session_id,
}
const configuration: DrillConfiguration = {
selections,
drillCount,
drillSequence,
}

// Track drill configuration completion
const uniqueOpenings = new Set(selections.map((s) => s.opening.id)).size
const averageTargetMoves =
selections.reduce((sum, s) => sum + s.targetMoveNumber, 0) /
selections.length
const maiaVersionsUsed = [
...new Set(selections.map((s) => s.maiaVersion)),
]
const colorDistribution = selections.reduce(
(acc, s) => {
acc[s.playerColor]++
return acc
},
{ white: 0, black: 0 },
)
// Track drill configuration completion
const uniqueOpenings = new Set(selections.map((s) => s.opening.id)).size
const averageTargetMoves =
selections.reduce((sum, s) => sum + s.targetMoveNumber, 0) /
selections.length
const maiaVersionsUsed = [
...new Set(selections.map((s) => s.maiaVersion)),
]
const colorDistribution = selections.reduce(
(acc, s) => {
acc[s.playerColor]++
return acc
},
{ white: 0, black: 0 },
)

trackDrillConfigurationCompleted(
selections.length,
drillCount,
uniqueOpenings,
averageTargetMoves,
maiaVersionsUsed,
colorDistribution,
)
trackDrillConfigurationCompleted(
selections.length,
drillCount,
uniqueOpenings,
averageTargetMoves,
maiaVersionsUsed,
colorDistribution,
)

onComplete(configuration)
} catch (error) {
console.error('Failed to start drilling session:', error)
// Still allow the drill to start even if API call fails
const configuration: DrillConfiguration = {
selections,
drillCount,
drillSequence,
}
onComplete(configuration)
}
onComplete(configuration)
}
}

Expand Down
44 changes: 22 additions & 22 deletions src/hooks/useOpeningDrillController/useOpeningDrillController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useMemo, useCallback, useEffect, useRef } from 'react'
import { Chess } from 'chess.ts'
import { getGameMove } from 'src/api/play/play'
import { submitOpeningDrill } from 'src/api/opening'
import { logOpeningDrill } from 'src/api/opening'
import { useTreeController } from '../useTreeController'
import { useLocalStorage } from '../useLocalStorage'
import {
Expand Down Expand Up @@ -530,21 +530,20 @@ export const useOpeningDrillController = (
currentMove: 'Preparing analysis...',
})

// Submit drill data to backend if session ID is available
if (configuration.sessionId) {
try {
await submitOpeningDrill({
session_id: configuration.sessionId,
opening_fen: drillGame.selection.variation
? drillGame.selection.variation.fen
: drillGame.selection.opening.fen,
side_played: drillGame.selection.playerColor,
moves_played_uci: drillGame.moves,
})
} catch (error) {
console.error('Failed to submit drill to backend:', error)
// Continue even if backend submission fails
}
// Submit drill data to backend
try {
await logOpeningDrill({
opening_fen: drillGame.selection.variation
? drillGame.selection.variation.fen
: drillGame.selection.opening.fen,
side_played: drillGame.selection.playerColor,
opponent: drillGame.selection.maiaVersion,
num_moves: drillGame.selection.targetMoveNumber,
moves_played_uci: drillGame.moves,
})
} catch (error) {
console.error('Failed to log drill to backend:', error)
// Continue even if backend submission fails
}

// Ensure all positions in the drill are analyzed to sufficient depth
Expand Down Expand Up @@ -593,23 +592,24 @@ export const useOpeningDrillController = (
setIsAnalyzingDrill(false)
}
},
[currentDrillGame, evaluateDrillPerformance, configuration.sessionId],
[currentDrillGame, evaluateDrillPerformance],
)

const moveToNextDrill = useCallback(async () => {
// Submit drill data to backend if session ID is available
if (configuration.sessionId && currentDrillGame) {
// Submit drill data to backend
if (currentDrillGame) {
try {
await submitOpeningDrill({
session_id: configuration.sessionId,
await logOpeningDrill({
opening_fen: currentDrillGame.selection.variation
? currentDrillGame.selection.variation.fen
: currentDrillGame.selection.opening.fen,
side_played: currentDrillGame.selection.playerColor,
opponent: currentDrillGame.selection.maiaVersion,
num_moves: currentDrillGame.selection.targetMoveNumber,
moves_played_uci: currentDrillGame.moves,
})
} catch (error) {
console.error('Failed to submit drill to backend:', error)
console.error('Failed to log drill to backend:', error)
}
}

Expand Down
Loading