Skip to content

Commit b86af3e

Browse files
authored
Merge pull request #3 from gpu-mode/feat/pre-launch-update
feat/pre launch update
2 parents e2ae16d + 37759d6 commit b86af3e

File tree

5 files changed

+161
-83
lines changed

5 files changed

+161
-83
lines changed

main.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,12 @@ import (
77
"github.com/S1ro1/popcorn-cli/src/cmd"
88
)
99

10-
func displayAsciiArt() {
11-
art := `
12-
_ __ _ ______ _
13-
| | / / | | | ___ \ | |
14-
| |/ / ___ _ __ _ __ ___ | | | |_/ / ___ _| |_
15-
| \ / _ \ '__| '_ \ / _ \| | | ___ \ / _ \| | __|
16-
| |\ \ __/ | | | | | __/| | | |_/ /| (_) | | |_
17-
\_| \_/\___|_| |_| |_|\___|_/ \____/ \___/|_|\__|
18-
19-
POPCORN CLI - GPU MODE
20-
21-
┌───────────────────────────────────────┐
22-
│ ┌─────┐ ┌─────┐ ┌─────┐ │
23-
│ │ooOoo│ │ooOoo│ │ooOoo│ │▒
24-
│ │oOOOo│ │oOOOo│ │oOOOo│ │▒
25-
│ │ooOoo│ │ooOoo│ │ooOoo│ ┌────────┐ │▒
26-
│ └─────┘ └─────┘ └─────┘ │████████│ │▒
27-
│ │████████│ │▒
28-
│ ┌────────────────────────┐ │████████│ │▒
29-
│ │ │ │████████│ │▒
30-
│ │ POPCORN GPU COMPUTE │ └────────┘ │▒
31-
│ │ │ │▒
32-
│ └────────────────────────┘ │▒
33-
│ │▒
34-
└───────────────────────────────────────┘▒
35-
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
36-
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
37-
`
38-
fmt.Println(art)
39-
}
4010

4111
func main() {
4212

4313
if os.Getenv("POPCORN_API_URL") == "" {
4414
fmt.Println("POPCORN_API_URL is not set. Please set it to the URL of the Popcorn API.")
4515
os.Exit(1)
4616
}
47-
displayAsciiArt()
4817
cmd.Execute()
4918
}

src/cmd/popcorn-cli.go

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"fmt"
55
"os"
6+
"strings"
67

78
"github.com/charmbracelet/bubbles/list"
89
"github.com/charmbracelet/bubbles/spinner"
@@ -11,14 +12,11 @@ import (
1112
"github.com/S1ro1/popcorn-cli/src/models"
1213
"github.com/S1ro1/popcorn-cli/src/service"
1314

15+
"github.com/S1ro1/popcorn-cli/src/utils"
16+
1417
tea "github.com/charmbracelet/bubbletea"
1518
)
1619

17-
var runnerItems = []list.Item{
18-
models.RunnerItem{TitleText: "Modal", DescriptionText: "Submit a solution to be evaluated on Modal runners.", Value: "modal"},
19-
models.RunnerItem{TitleText: "Github", DescriptionText: "Submit a solution to be evaluated on Github runners. This can take a little longer to spin up.", Value: "github"},
20-
}
21-
2220
var submissionModeItems = []list.Item{
2321
models.SubmissionModeItem{TitleText: "Test", DescriptionText: "Test the solution and give detailed results about passed/failed tests.", Value: "test"},
2422
models.SubmissionModeItem{TitleText: "Benchmark", DescriptionText: "Benchmark the solution, this also runs the tests and afterwards runs the benchmark, returning detailed timing results", Value: "benchmark"},
@@ -35,8 +33,6 @@ type model struct {
3533
filepath string
3634
leaderboardsList list.Model
3735
selectedLeaderboard string
38-
runnersList list.Model
39-
selectedRunner string
4036
gpusList list.Model
4137
selectedGpu string
4238
submissionModeList list.Model
@@ -58,6 +54,17 @@ func (m model) Init() tea.Cmd {
5854
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5955
var cmd tea.Cmd
6056

57+
if len(m.gpusList.Items()) == 0 && m.modalState == models.ModelStateGpuSelection {
58+
gpus, err := service.GetListItems(func() ([]models.GpuItem, error) {
59+
return service.FetchAvailableGpus(m.selectedLeaderboard)
60+
})
61+
if err != nil {
62+
m.SetError(fmt.Sprintf("Error fetching GPUs: %s", err))
63+
return m, tea.Quit
64+
}
65+
m.gpusList = list.New(gpus, list.NewDefaultDelegate(), m.width-2, m.height-2)
66+
m.gpusList.SetSize(m.width-2, m.height-2)
67+
}
6168
if !m.finishedOkay {
6269
return m, tea.Quit
6370
}
@@ -72,25 +79,26 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7279
case models.ModelStateLeaderboardSelection:
7380
if i := m.leaderboardsList.SelectedItem(); i != nil {
7481
m.selectedLeaderboard = i.(models.LeaderboardItem).TitleText
75-
m.modalState = models.ModelStateRunnerSelection
76-
m.runnersList.SetSize(m.width-2, m.height-2)
77-
}
78-
case models.ModelStateRunnerSelection:
79-
if i := m.runnersList.SelectedItem(); i != nil {
80-
m.selectedRunner = i.(models.RunnerItem).Value
81-
m.modalState = models.ModelStateGpuSelection
82-
gpus, err := service.GetListItems(func() ([]models.GpuItem, error) {
83-
return service.FetchAvailableGpus(m.selectedLeaderboard, m.selectedRunner)
84-
})
85-
if err != nil {
86-
m.SetError(fmt.Sprintf("Error fetching GPUs: %s", err))
87-
return m, tea.Quit
82+
// No gpu selected in popcorn directives, fetch gpus and move to gpu selection
83+
if m.selectedGpu == "" {
84+
gpus, err := service.GetListItems(func() ([]models.GpuItem, error) {
85+
return service.FetchAvailableGpus(m.selectedLeaderboard)
86+
})
87+
if err != nil {
88+
m.SetError(fmt.Sprintf("Error fetching GPUs: %s", err))
89+
return m, tea.Quit
90+
}
91+
if len(gpus) == 0 {
92+
m.SetError("No GPUs available for this leaderboard.")
93+
return m, tea.Quit
94+
}
95+
m.gpusList = list.New(gpus, list.NewDefaultDelegate(), m.width-2, m.height-2)
96+
m.gpusList.SetSize(m.width-2, m.height-2)
97+
m.modalState = models.ModelStateGpuSelection
98+
} else {
99+
m.modalState = models.ModelStateSubmissionModeSelection
100+
m.submissionModeList.SetSize(m.width-2, m.height-2)
88101
}
89-
if len(gpus) == 0 {
90-
m.SetError("No GPUs available for this runner and leaderboard.")
91-
return m, tea.Quit
92-
}
93-
m.gpusList = list.New(gpus, list.NewDefaultDelegate(), m.width-2, m.height-2)
94102
}
95103
case models.ModelStateGpuSelection:
96104
if i := m.gpusList.SelectedItem(); i != nil {
@@ -119,8 +127,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
119127
switch m.modalState {
120128
case models.ModelStateLeaderboardSelection:
121129
m.leaderboardsList.SetSize(listWidth, listHeight)
122-
case models.ModelStateRunnerSelection:
123-
m.runnersList.SetSize(listWidth, listHeight)
124130
case models.ModelStateGpuSelection:
125131
m.gpusList.SetSize(listWidth, listHeight)
126132
case models.ModelStateSubmissionModeSelection:
@@ -131,8 +137,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
131137
switch m.modalState {
132138
case models.ModelStateLeaderboardSelection:
133139
m.leaderboardsList, cmd = m.leaderboardsList.Update(msg)
134-
case models.ModelStateRunnerSelection:
135-
m.runnersList, cmd = m.runnersList.Update(msg)
136140
case models.ModelStateGpuSelection:
137141
m.gpusList, cmd = m.gpusList.Update(msg)
138142
case models.ModelStateSubmissionModeSelection:
@@ -159,8 +163,6 @@ func (m model) View() string {
159163
switch m.modalState {
160164
case models.ModelStateLeaderboardSelection:
161165
content = m.leaderboardsList.View()
162-
case models.ModelStateRunnerSelection:
163-
content = m.runnersList.View()
164166
case models.ModelStateGpuSelection:
165167
content = m.gpusList.View()
166168
case models.ModelStateSubmissionModeSelection:
@@ -182,12 +184,14 @@ func (m model) Submit() tea.Cmd {
182184
go func() {
183185
fileContent, err := os.ReadFile(m.filepath)
184186
if err != nil {
187+
p.Send(models.ErrorMsg{Err: fmt.Errorf("error reading file: %s", err)})
185188
m.SetError(fmt.Sprintf("Error reading file: %s", err))
186189
return
187190
}
188191

189-
prettyResult, err := service.SubmitSolution(m.selectedLeaderboard, m.selectedRunner, m.selectedGpu, m.selectedSubmissionMode, m.filepath, fileContent)
192+
prettyResult, err := service.SubmitSolution(m.selectedLeaderboard, m.selectedGpu, m.selectedSubmissionMode, m.filepath, fileContent)
190193
if err != nil {
194+
p.Send(models.ErrorMsg{Err: fmt.Errorf("error submitting solution: %s", err)})
191195
m.SetError(fmt.Sprintf("Error submitting solution: %s", err))
192196
return
193197
}
@@ -213,28 +217,53 @@ func Execute() {
213217
return
214218
}
215219

220+
popcornDirectives, err := utils.GetPopcornDirectives(filepath)
221+
if err != nil {
222+
fmt.Println("Error:", err)
223+
var input string
224+
fmt.Scanln(&input)
225+
if strings.ToLower(input) != "y" {
226+
return
227+
}
228+
}
229+
230+
var modalState models.ModelState
231+
if popcornDirectives.LeaderboardName != "" && len(popcornDirectives.Gpus) > 0 {
232+
modalState = models.ModelStateSubmissionModeSelection
233+
} else if popcornDirectives.LeaderboardName != "" {
234+
modalState = models.ModelStateGpuSelection
235+
} else {
236+
modalState = models.ModelStateLeaderboardSelection
237+
}
238+
239+
var selectedGpu string
240+
if len(popcornDirectives.Gpus) > 0 {
241+
selectedGpu = popcornDirectives.Gpus[0]
242+
}
243+
216244
leaderboardItems, err := service.GetListItems(service.FetchLeaderboards)
217245
if err != nil {
218246
fmt.Println("Error fetching leaderboards:", err)
219-
return
247+
220248
}
221249

222250
s := spinner.New()
223251
s.Spinner = spinner.Dot
224252
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
225253

226254
m := model{
227-
filepath: filepath,
228-
leaderboardsList: list.New(leaderboardItems, list.NewDefaultDelegate(), 0, 0),
229-
runnersList: list.New(runnerItems, list.NewDefaultDelegate(), 0, 0),
230-
submissionModeList: list.New(submissionModeItems, list.NewDefaultDelegate(), 0, 0),
231-
spinner: s,
232-
modalState: models.ModelStateLeaderboardSelection,
233-
finishedOkay: true,
234-
finalStatus: "",
255+
filepath: filepath,
256+
leaderboardsList: list.New(leaderboardItems, list.NewDefaultDelegate(), 0, 0),
257+
submissionModeList: list.New(submissionModeItems, list.NewDefaultDelegate(), 0, 0),
258+
gpusList: list.New([]list.Item{}, list.NewDefaultDelegate(), 0, 0),
259+
spinner: s,
260+
modalState: modalState,
261+
finishedOkay: true,
262+
finalStatus: "",
263+
selectedLeaderboard: popcornDirectives.LeaderboardName,
264+
selectedGpu: selectedGpu,
235265
}
236266
m.leaderboardsList.Title = "Leaderboards"
237-
m.runnersList.Title = "Runners"
238267

239268
p = tea.NewProgram(m)
240269
finalModel, err := p.Run()
@@ -244,6 +273,7 @@ func Execute() {
244273
}
245274

246275
m, ok := finalModel.(model)
276+
utils.DisplayAsciiArt()
247277
if ok && m.finishedOkay {
248278
fmt.Printf("\nResult:\n\n%s\n", m.finalStatus)
249279
} else if ok && !m.finishedOkay {

src/models/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package models
22

33
type LeaderboardItem struct {
4-
TitleText string
4+
TitleText string
55
TaskDescription string
66
}
77

src/service/api.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,20 @@ func FetchLeaderboards() ([]models.LeaderboardItem, error) {
4141
return nil, err
4242
}
4343

44-
4544
leaderboardNames := make([]models.LeaderboardItem, len(leaderboards))
4645
for i, lb := range leaderboards {
4746
task := lb["task"].(map[string]interface{})
4847
leaderboardNames[i] = models.LeaderboardItem{
49-
TitleText: lb["name"].(string),
50-
TaskDescription: task["description"].(string),
48+
TitleText: lb["name"].(string),
49+
TaskDescription: task["description"].(string),
5150
}
5251
}
5352

5453
return leaderboardNames, nil
5554
}
5655

57-
func FetchAvailableGpus(leaderboard string, runner string) ([]models.GpuItem, error) {
58-
resp, err := http.Get(BASE_URL + "/" + leaderboard + "/" + runner + "/gpus")
56+
func FetchAvailableGpus(leaderboard string) ([]models.GpuItem, error) {
57+
resp, err := http.Get(BASE_URL + "/gpus/" + leaderboard)
5958
if err != nil {
6059
return nil, err
6160
}
@@ -84,7 +83,7 @@ func FetchAvailableGpus(leaderboard string, runner string) ([]models.GpuItem, er
8483
return gpuItems, nil
8584
}
8685

87-
func SubmitSolution(leaderboard string, runner string, gpu string, submissionMode string, filename string, fileContent []byte) (string, error) {
86+
func SubmitSolution(leaderboard string, gpu string, submissionMode string, filename string, fileContent []byte) (string, error) {
8887
body := &bytes.Buffer{}
8988
writer := multipart.NewWriter(body)
9089

@@ -101,10 +100,9 @@ func SubmitSolution(leaderboard string, runner string, gpu string, submissionMod
101100
return "", fmt.Errorf("error closing form: %s", err)
102101
}
103102

104-
url := fmt.Sprintf("%s/%s/%s/%s/%s",
103+
url := fmt.Sprintf("%s/%s/%s/%s",
105104
BASE_URL,
106105
strings.ToLower(leaderboard),
107-
strings.ToLower(runner),
108106
strings.ToLower(gpu),
109107
strings.ToLower(submissionMode))
110108

@@ -161,4 +159,3 @@ func GetListItems[T list.Item](fetchFn func() ([]T, error)) ([]list.Item, error)
161159

162160
return listItems, nil
163161
}
164-

src/utils/utils.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
)
8+
9+
type PopcornDirectives struct {
10+
LeaderboardName string
11+
Gpus []string
12+
}
13+
14+
func GetPopcornDirectives(filepath string) (*PopcornDirectives, error) {
15+
var err error = nil
16+
content, err := os.ReadFile(filepath)
17+
18+
var gpus []string = []string{}
19+
var leaderboard_name string = ""
20+
21+
if err != nil {
22+
return nil, err
23+
}
24+
25+
lines := strings.Split(string(content), "\n")
26+
for _, line := range lines {
27+
if !strings.HasPrefix(line, "//") && !strings.HasPrefix(line, "#") {
28+
continue
29+
}
30+
31+
parts := strings.Split(line, " ")
32+
if parts[0] == "//!POPCORN" || parts[0] == "#!POPCORN" {
33+
arg := strings.ToLower(parts[1])
34+
if arg == "gpu" || arg == "gpus" {
35+
gpus = parts[2:]
36+
} else if arg == "leaderboard" {
37+
leaderboard_name = parts[2]
38+
}
39+
}
40+
}
41+
42+
if len(gpus) > 1 {
43+
err = fmt.Errorf("multiple GPUs are not yet supported, continue with the first gpu? (%s) [y/N]", gpus[0])
44+
gpus = []string{gpus[0]}
45+
}
46+
47+
return &PopcornDirectives{
48+
LeaderboardName: leaderboard_name,
49+
Gpus: gpus,
50+
}, err
51+
}
52+
53+
func DisplayAsciiArt() {
54+
art := `
55+
_ __ _ ______ _
56+
| | / / | | | ___ \ | |
57+
| |/ / ___ _ __ _ __ ___ | | | |_/ / ___ _| |_
58+
| \ / _ \ '__| '_ \ / _ \| | | ___ \ / _ \| | __|
59+
| |\ \ __/ | | | | | __/| | | |_/ /| (_) | | |_
60+
\_| \_/\___|_| |_| |_|\___|_/ \____/ \___/|_|\__|
61+
62+
POPCORN CLI - GPU MODE
63+
64+
┌───────────────────────────────────────┐
65+
│ ┌─────┐ ┌─────┐ ┌─────┐ │
66+
│ │ooOoo│ │ooOoo│ │ooOoo│ │▒
67+
│ │oOOOo│ │oOOOo│ │oOOOo│ │▒
68+
│ │ooOoo│ │ooOoo│ │ooOoo│ ┌────────┐ │▒
69+
│ └─────┘ └─────┘ └─────┘ │████████│ │▒
70+
│ │████████│ │▒
71+
│ ┌────────────────────────┐ │████████│ │▒
72+
│ │ │ │████████│ │▒
73+
│ │ POPCORN GPU COMPUTE │ └────────┘ │▒
74+
│ │ │ │▒
75+
│ └────────────────────────┘ │▒
76+
│ │▒
77+
└───────────────────────────────────────┘▒
78+
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
79+
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
80+
`
81+
fmt.Println(art)
82+
}

0 commit comments

Comments
 (0)