File size: 5,447 Bytes
ae232df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Piper ONNX Converter</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center">
    <div class="container mx-auto px-4">
        <h1 class="text-3xl font-bold mb-8 text-center">Piper ONNX Converter</h1>
        <form id="converterForm" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
            <div class="mb-4">
                <label class="block text-gray-700 text-sm font-bold mb-2" for="repo_id">
                    Hugging Face Repository ID:
                </label>
                <input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="repo_id" name="repo_id" type="text" required>
            </div>
            <div class="mb-4">
                <label class="block text-gray-700 text-sm font-bold mb-2" for="token">
                    Hugging Face Token:
                </label>
                <input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="token" name="token" type="password" required>
            </div>
            <div class="mb-6">
                <label class="block text-gray-700 text-sm font-bold mb-2" for="model_name">
                    Model Name:
                </label>
                <input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="model_name" name="model_name" type="text" required>
            </div>
            <div class="flex items-center justify-between">
                <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit">
                    Convert and Download
                </button>
            </div>
        </form>

        <div id="progress" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" style="display: none;">
            <h2 class="text-2xl font-bold mb-4">Processing...</h2>
            <div id="log" class="bg-gray-100 p-4 rounded-lg h-64 overflow-y-auto mb-4"></div>
            <a id="downloadLink" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" style="display: none;">Download Converted Model</a>
        </div>
    </div>

    <script>
        const form = document.getElementById('converterForm');
        const progress = document.getElementById('progress');
        const log = document.getElementById('log');
        const downloadLink = document.getElementById('downloadLink');

        const socket = io();

        socket.on('task_update', function(data) {
            const logEntry = document.createElement('p');
            logEntry.textContent = data.message;
            log.appendChild(logEntry);
            log.scrollTop = log.scrollHeight;

            // Check if the message contains the download URL
            if (data.message.includes("Processing completed. Download URL:")) {
                const url = data.message.split("Download URL: ")[1];
                downloadLink.href = url;
                downloadLink.style.display = 'inline-block';
            }
        });

        form.addEventListener('submit', async (e) => {
            e.preventDefault();
            const formData = new FormData(form);
            
            try {
                const response = await fetch('/', {
                    method: 'POST',
                    body: formData
                });
                const data = await response.json();
                
                if (data.task_id) {
                    form.style.display = 'none';
                    progress.style.display = 'block';
                    pollStatus(data.task_id);
                }
            } catch (error) {
                console.error('Error:', error);
            }
        });

        async function pollStatus(taskId) {
            while (true) {
                try {
                    const response = await fetch(`/status/${taskId}`);
                    const data = await response.json();
                    
                    if (data.status === 'completed') {
                        // We don't need to set the download link here anymore
                        // as it's now handled in the socket.on('task_update') function
                        break;
                    } else if (data.status === 'error') {
                        const errorMsg = document.createElement('p');
                        errorMsg.textContent = 'An error occurred during processing.';
                        errorMsg.classList.add('text-red-500', 'font-bold');
                        log.appendChild(errorMsg);
                        break;
                    }
                    
                    await new Promise(resolve => setTimeout(resolve, 5000)); // Poll every 5 seconds
                } catch (error) {
                    console.error('Error polling status:', error);
                    break;
                }
            }
        }
    </script>
</body>
</html>