@jutge.org/toolkit 4.2.38 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -241,6 +241,7 @@ jtk generate problem # Create problem with AI
241
241
  jtk make # Build all problem elements
242
242
  jtk verify <program> # Test a solution
243
243
  jtk upload # Upload to Jutge.org
244
+ jtk submit -l <language> <solution> # Submit a solution to Jutge.org
244
245
  jtk clean # Clean temporary files
245
246
  jtk passcode # Manage problem passcode
246
247
 
package/docs/login.md ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,106 @@
1
+ # Notes for Windows
2
+
3
+ ## Installation
4
+
5
+ - Use PowerShell as terminal. Remember to reopen the terminal after the installation of each tool.
6
+
7
+ - Bun is a JavaScript runtime like Node.js but faster and lighter.
8
+ It is required to run the toolkit on Windows. Install `bun` from https://bun.sh/. It is easy.
9
+
10
+ - Install the toolkit using `bun`:
11
+
12
+ ```sh
13
+ bun install --global "@jutge.org/toolkit"
14
+ ```
15
+
16
+ The first time may take a while as `bun` needs to download and compile some dependencies. If it fails with a `mkdir` error, just try again, it seems to be a transient error.
17
+
18
+ - Check that the installation was successful:
19
+
20
+ ```sh
21
+ jtk
22
+ ```
23
+
24
+ It should show the help message. You can always add a `--help` flag to any command to get more information.
25
+
26
+ - Check the tools required by the toolkit:
27
+
28
+ ```sh
29
+ jtk doctor
30
+ ```
31
+
32
+ It should print information about the installed tools. If any tool is missing, consider installing it and try again. Depending on your workflow, some dependencies may not be necessary.
33
+
34
+ ## Upgrade
35
+
36
+ Try to use the latest version of the toolkit. Upgrade the toolkit to the latest version with the following command:
37
+
38
+ ```powershell
39
+ jtk upgrade
40
+ ```
41
+
42
+ Check the version after upgrading:
43
+
44
+ ```powershell
45
+ jtk --version
46
+ ```
47
+
48
+ ## Dependencies
49
+
50
+ - LaTeX: A LaTeX distribution is required to compile problem statements and get their PDFs. It is not necessary but strongly recommended.
51
+
52
+ For Windows, install MiKTeX from https://miktex.org/download. During installation, select the option to install missing packages on-the-fly.
53
+
54
+ - Pandoc: Pandoc with Lua support is required to convert problem statements to Markdown, Text and HTML. It is not necessary but recommended.
55
+
56
+ Install it easily using the Windows Package Manager (`winget`):
57
+
58
+ ```powershell
59
+ winget install --id JohnMacFarlane.Pandoc
60
+ ```
61
+
62
+ - Python 3: You only need Python 3 if you plan to use Python scripts in your problems.
63
+
64
+ Install Python from https://www.python.org/downloads/windows/. Make sure to check the option to add Python to the system PATH during installation. The toolkit uses `python3` command to run Python scripts.
65
+
66
+ - C/C++ Compiler: You only need a C/C++ compiler if you plan to use C/C++ programs in your problems. The toolkit uses `gcc` and `g++` commands to compile C and C++ programs, respectively.
67
+
68
+ We suggest using [w64devkit](https://github.com/skeeto/w64devkit), a portable C and C++ development kit for Windows. Here are the steps to install it:
69
+ 1. **Download** the latest `.exe` file from https://github.com/skeeto/w64devkit/releases.
70
+
71
+ 2. **Extract** by double-clicking the downloaded file and choosing a destination (e.g., `C:\w64devkit`).
72
+
73
+ 3. **Run** `w64devkit.exe` from the extracted folder to open a terminal with gcc and g++ available.
74
+
75
+ 4. **Test** by typing `gcc --version` in the terminal.
76
+
77
+ 5. **Compile programs:**
78
+
79
+ ```bash
80
+ gcc myprogram.c -o myprogram.exe
81
+ g++ myprogram.cpp -o myprogram.exe
82
+ ```
83
+
84
+ Other options are to install [MinGW-w64](http://mingw-w64.org/doku.php) or use the compiler provided by [MSYS2](https://www.msys2.org/).
85
+
86
+ - Java: You only need Java if you plan to use Java programs in your problems. The toolkit uses the `java` and `javac` commands to run and compile Java programs, respectively.
87
+
88
+ Install the Java Runtime Environment (JRE) from https://www.java.com/en/download/manual.jsp. Make sure to download the Windows version.
89
+
90
+ - Likewise, you may need to install Rust, Haskell and Clojure if you plan to use these languages in your problems. If you know how to install them on Windows, please consider contributing to the documentation.
91
+
92
+ ## Miscellaneous tips
93
+
94
+ - Open a file with its associated application with `start filename.extension`.
95
+
96
+ - Show environment variables with `echo $env:VARIABLE`.
97
+
98
+ - Set environment temporarly variables with `$env:VARIABLE=value`.
99
+
100
+ - Set environment variables permanently with `[System.Environment]::SetEnvironmentVariable('VARIABLE', 'value', 'User')`.
101
+
102
+ - Console font doesn't support Unicode: The default console font (Raster Fonts) doesn't support many Unicode characters. Change to a font like "Consolas", "Lucida Console", or "Cascadia Code" in your PowerShell window properties.
103
+
104
+ ```
105
+
106
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jutge.org/toolkit",
3
3
  "description": "Toolkit to prepare problems for Jutge.org",
4
- "version": "4.2.38",
4
+ "version": "4.3.0",
5
5
  "homepage": "https://jutge.org",
6
6
  "author": {
7
7
  "name": "Jutge.org",
@@ -84,6 +84,7 @@
84
84
  "pretty-ms": "^9.3.0",
85
85
  "radash": "^12.1.1",
86
86
  "semver": "^7.7.3",
87
+ "sharp": "^0.34.5",
87
88
  "terminal-link": "^5.0.0",
88
89
  "tree-node-cli": "^1.6.0",
89
90
  "yaml": "^2.8.2",
package/toolkit/ai.ts ADDED
@@ -0,0 +1,56 @@
1
+ import { Command } from '@commander-js/extra-typings'
2
+ import sharp from 'sharp'
3
+ import z from 'zod'
4
+ import { complete, generateImage, listModels } from '../lib/ai.ts'
5
+ import { settings } from '../lib/settings.ts'
6
+ import tui from '../lib/tui.ts'
7
+ import { convertStringToItsType } from '../lib/utils.ts'
8
+
9
+ export const aiCmd = new Command('ai')
10
+ .description('Query AI models')
11
+
12
+ .action(() => {
13
+ aiCmd.help()
14
+ })
15
+
16
+ aiCmd
17
+ .command('models')
18
+ .description('Show available AI models')
19
+
20
+ .action(async () => {
21
+ const models = await listModels()
22
+ tui.yaml(models)
23
+ })
24
+
25
+ aiCmd
26
+ .command('complete')
27
+ .description('Complete a prompt using an AI model')
28
+
29
+ .argument('<prompt>', 'the user prompt to complete')
30
+ .option('-s, --system-prompt <system>', 'the system prompt to use', 'You are a helpful assistant.')
31
+ .option('-m, --model <model>', 'the AI model to use', settings.defaultModel)
32
+
33
+ .action(async (prompt, { model, systemPrompt }) => {
34
+ prompt = prompt.trim()
35
+ systemPrompt = systemPrompt.trim()
36
+ const answer = await complete(model, systemPrompt, prompt)
37
+ tui.print(answer)
38
+ })
39
+
40
+ // TODO: generate with different aspect ratios
41
+ aiCmd
42
+ .command('image')
43
+ .description('Generate a square image using an AI model')
44
+
45
+ .argument('<prompt>', 'description of the image to generate')
46
+ .option('-m, --model <model>', 'the graphic AI model to use', 'openai/dall-e-3')
47
+ .option('-s, --size <size>', 'the size of the image (in pixels)', '1024')
48
+ .option('-o, --output <path>', 'the output image path', 'image.png')
49
+
50
+ .action(async (prompt, { model, size, output }) => {
51
+ const sizeInt = z.int().min(16).max(2048).parse(convertStringToItsType(size))
52
+ const image = await generateImage(model, prompt)
53
+ await sharp(image).resize(sizeInt, sizeInt).toFile(output)
54
+ tui.success(`Generated image saved to ${output}`)
55
+ await tui.image(output, 20, 10)
56
+ })
@@ -1,5 +1,8 @@
1
1
  import { Argument, Command } from '@commander-js/extra-typings'
2
+ import { join } from 'path'
3
+ import sharp from 'sharp'
2
4
  import { createProblemWithJutgeAI } from '../lib/create-with-jutgeai'
5
+ import { complete } from '../lib/aiclient'
3
6
  import { languageKeys, languageNames, proglangKeys, proglangNames } from '../lib/data'
4
7
  import {
5
8
  addAlternativeSolution,
@@ -10,6 +13,7 @@ import {
10
13
  import { newProblem } from '../lib/problem'
11
14
  import { settings } from '../lib/settings'
12
15
  import tui from '../lib/tui'
16
+ import { writeText } from '../lib/utils'
13
17
  import { getLoggedInJutgeClient } from '../lib/login'
14
18
 
15
19
  export const generateCmd = new Command('generate')
@@ -153,7 +157,7 @@ generateCmd
153
157
  if (all || efficiency) await generateTestCasesGenerator(jutge, model, problem, output, 'efficiency')
154
158
  })
155
159
  })
156
- /*
160
+
157
161
  generateCmd
158
162
  .command('award.png')
159
163
  .summary('Generate award.png using JutgeAI')
@@ -179,15 +183,25 @@ The new image will be saved as award.png in the problem directory, overriding an
179
183
  .argument('[prompt]', 'prompt to generate the image', '')
180
184
 
181
185
  .action(async (prompt, { directory, model }) => {
186
+ const jutge = await getLoggedInJutgeClient()
182
187
  const output = join(directory, 'award.png')
183
188
  const problem = await newProblem(directory)
184
- if (prompt.trim() === '') {
185
- prompt = problem.problemLangYmls[problem.originalLanguage!].title || 'A colorful award'
189
+ let imagePrompt = prompt.trim()
190
+ if (imagePrompt === '') {
191
+ imagePrompt = 'A colorful award on a white background'
186
192
  }
187
- const image = await generateImage(model, prompt)
188
- await sharp(image).resize(512, 512).toFile(output)
189
- await tui.image(output, 20, 10)
190
- tui.success(`Added ${output}`)
193
+ await tui.section('Generating award image', async () => {
194
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call -- generated API client
195
+ const download = await jutge.instructor.jutgeai.createImage({
196
+ model,
197
+ label: 'award',
198
+ prompt: imagePrompt,
199
+ size: '1024x1024',
200
+ })
201
+ await sharp(Buffer.from(download.data)).resize(512, 512).toFile(output)
202
+ await tui.image(output, 20, 10)
203
+ tui.success(`Added ${output}`)
204
+ })
191
205
  })
192
206
 
193
207
  generateCmd
@@ -217,11 +231,14 @@ The new message will be saved as award.html in the problem directory, overriding
217
231
  .option('-m, --model <model>', 'AI model to use', settings.defaultModel)
218
232
 
219
233
  .action(async (prompt, { directory, model }) => {
234
+ const jutge = await getLoggedInJutgeClient()
220
235
  const output = join(directory, 'award.html')
221
- const problem = await newProblem(directory)
222
- const message = await complete(model, '', prompt)
223
- tui.print(message)
224
- await writeText(output, message)
225
- tui.success(`Added ${output}`)
236
+ const systemPrompt =
237
+ 'You generate short textual award messages shown when a user solves a problem. Output only the message text, no markdown code blocks or explanation. If you like, use a famous quote by a famous person. In this case, use the name of the person in the message.'
238
+ await tui.section('Generating award message', async () => {
239
+ const message = await complete(jutge, model, 'award', systemPrompt, prompt)
240
+ tui.print(message)
241
+ await writeText(output, message)
242
+ tui.success(`Added ${output}`)
243
+ })
226
244
  })
227
- */
package/toolkit/index.ts CHANGED
@@ -18,6 +18,7 @@ import { quizCmd } from './quiz'
18
18
  import { upgradeCmd } from './upgrade'
19
19
  import { uploadCmd } from './upload'
20
20
  import { cmdPasscode } from './passcode'
21
+ import { submitCmd } from './submit'
21
22
  import { askCmd } from './ask'
22
23
  import { convertCmd } from './convert'
23
24
  import { stageCmd } from './stage'
@@ -36,6 +37,7 @@ program.addCommand(cleanCmd)
36
37
  program.addCommand(cloneCmd)
37
38
  program.addCommand(generateCmd)
38
39
  program.addCommand(verifyCmd)
40
+ program.addCommand(submitCmd)
39
41
  program.addCommand(convertCmd)
40
42
  program.addCommand(stageCmd)
41
43
  program.addCommand(doctorCmd)
@@ -0,0 +1,14 @@
1
+ import { Command } from '@commander-js/extra-typings'
2
+ import { submitInDirectory } from '../lib/submit'
3
+
4
+ export const submitCmd = new Command('submit')
5
+ .summary('Submit solutions to Jutge.org')
6
+
7
+ .argument('<programs...>', 'programs to submit (e.g. solution.cc slow.py buggy.py)')
8
+ .option('-d, --directory <directory>', 'problem directory', '.')
9
+ .option('-l, --language <code>', 'language code (ca, es, en, ...)', 'en')
10
+ .option('-n, --no-wait', 'do not wait for submissions to be judged')
11
+
12
+ .action(async (programs, { directory, language, wait }) => {
13
+ await submitInDirectory(directory, language, programs, !wait)
14
+ })