(modelName: string, serverAddress: string)
| 54 | } |
| 55 | |
| 56 | const pullModel = async (modelName: string, serverAddress: string) => { |
| 57 | if (state.status === 'pulling') { |
| 58 | Logger.warn('PULL_MANAGER', 'A pull is already in progress.'); |
| 59 | return; |
| 60 | } |
| 61 | |
| 62 | abortController = new AbortController(); |
| 63 | setState({ |
| 64 | status: 'pulling', |
| 65 | modelName, |
| 66 | statusText: 'Preparing to download...', |
| 67 | progress: 0, |
| 68 | completedBytes: 0, |
| 69 | totalBytes: 0, |
| 70 | errorText: '' |
| 71 | }); |
| 72 | |
| 73 | Logger.info('PULL_MANAGER', `Starting pull for model: ${modelName} from ${serverAddress}`); |
| 74 | |
| 75 | try { |
| 76 | const response = await platformFetch(`${serverAddress}/api/pull`, { |
| 77 | method: 'POST', |
| 78 | headers: { 'Content-Type': 'application/json' }, |
| 79 | body: JSON.stringify({ name: modelName, stream: true }), |
| 80 | signal: abortController.signal, |
| 81 | }); |
| 82 | |
| 83 | if (!response.body) throw new Error('Response body is empty.'); |
| 84 | if (response.status !== 200) { |
| 85 | const errorData = await response.json(); |
| 86 | throw new Error(errorData.error || `Server responded with status ${response.status}`); |
| 87 | } |
| 88 | |
| 89 | const reader = response.body.getReader(); |
| 90 | const decoder = new TextDecoder(); |
| 91 | |
| 92 | while (true) { |
| 93 | const { done, value } = await reader.read(); |
| 94 | if (done) { |
| 95 | setState({ statusText: 'Verifying checksum...' }); |
| 96 | break; |
| 97 | } |
| 98 | |
| 99 | const chunk = decoder.decode(value); |
| 100 | const jsonLines = chunk.split('\n').filter(line => line.trim() !== ''); |
| 101 | |
| 102 | jsonLines.forEach(line => { |
| 103 | try { |
| 104 | const data = JSON.parse(line); |
| 105 | const newState: Partial<PullState> = { statusText: data.status }; |
| 106 | if (data.total && data.completed) { |
| 107 | newState.progress = Math.round((data.completed / data.total) * 100); |
| 108 | newState.completedBytes = data.completed; |
| 109 | newState.totalBytes = data.total; |
| 110 | } |
| 111 | setState(newState); |
| 112 | if (data.error) throw new Error(data.error); |
| 113 | } catch(e) { |
nothing calls this directly
no test coverage detected