Luis-Filipe commited on
Commit
36c62b2
·
verified ·
1 Parent(s): 1ef2a3c

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +142 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import tempfile
4
+ import os
5
+ import time
6
+ import base64
7
+ from PIL import Image
8
+ import io
9
+
10
+ def run_pcbasic_code(code, timeout=30):
11
+ """Executa o código PCBasic e captura a saída gráfica"""
12
+ # Criar arquivo temporário para o código BASIC
13
+ with tempfile.NamedTemporaryFile(suffix=".bas", delete=False, mode="w") as tmp:
14
+ tmp.write(code)
15
+ tmp_filename = tmp.name
16
+
17
+ # Criar pasta temporária para capturas de tela
18
+ screenshot_dir = tempfile.mkdtemp()
19
+ screenshot_path = os.path.join(screenshot_dir, "output.png")
20
+
21
+ try:
22
+ # Configurar PCBasic para salvar captura de tela periodicamente
23
+ env = os.environ.copy()
24
+ env["SDL_VIDEODRIVER"] = "dummy" # Usar driver de vídeo "dummy"
25
+
26
+ # Executar PCBasic com os argumentos necessários
27
+ process = subprocess.Popen(
28
+ [
29
+ "pcbasic",
30
+ f"--run={tmp_filename}",
31
+ "--interface=sdl2",
32
+ f"--output={screenshot_path}",
33
+ "--shell=none",
34
+ "--mount=none",
35
+ ],
36
+ env=env,
37
+ stdout=subprocess.PIPE,
38
+ stderr=subprocess.PIPE
39
+ )
40
+
41
+ # Esperar um tempo para execução
42
+ start_time = time.time()
43
+ output_images = []
44
+
45
+ while process.poll() is None and time.time() - start_time < timeout:
46
+ # Capturar imagem a cada segundo
47
+ time.sleep(1)
48
+ if os.path.exists(screenshot_path):
49
+ try:
50
+ img = Image.open(screenshot_path)
51
+ output_images.append(img.copy())
52
+ except:
53
+ pass
54
+
55
+ # Se o processo ainda estiver em execução após o timeout, matá-lo
56
+ if process.poll() is None:
57
+ process.terminate()
58
+ try:
59
+ process.wait(timeout=2)
60
+ except:
61
+ process.kill()
62
+
63
+ # Capturar saída de texto
64
+ stdout, stderr = process.communicate()
65
+ text_output = stdout.decode('utf-8', errors='replace')
66
+
67
+ # Se não houver imagens capturadas, retornar apenas a saída de texto
68
+ if not output_images:
69
+ return text_output, None
70
+
71
+ # Retornar a última imagem capturada e a saída de texto
72
+ return text_output, output_images[-1]
73
+
74
+ except Exception as e:
75
+ return f"Erro ao executar o programa: {str(e)}", None
76
+ finally:
77
+ # Limpar arquivos temporários
78
+ try:
79
+ os.unlink(tmp_filename)
80
+ if os.path.exists(screenshot_path):
81
+ os.unlink(screenshot_path)
82
+ os.rmdir(screenshot_dir)
83
+ except:
84
+ pass
85
+
86
+ def process_basic_code(code):
87
+ """Processa o código BASIC e retorna a saída formatada"""
88
+ text_output, image_output = run_pcbasic_code(code)
89
+
90
+ if image_output:
91
+ # Converter imagem para bytes
92
+ img_byte_arr = io.BytesIO()
93
+ image_output.save(img_byte_arr, format='PNG')
94
+ img_byte_arr = img_byte_arr.getvalue()
95
+
96
+ return text_output, img_byte_arr
97
+ else:
98
+ return text_output, None
99
+
100
+ # Exemplos de código BASIC
101
+ examples = [
102
+ ["10 PRINT \"HELLO WORLD\"\n20 FOR I = 1 TO 10\n30 PRINT I; \"* 5 =\"; I*5\n40 NEXT I\n50 PRINT \"GOODBYE!\"\n60 END"],
103
+ ["10 REM JOGO DE ADIVINHAÇÃO\n20 PRINT \"JOGO DE ADIVINHAÇÃO\"\n30 PRINT \"===================\"\n40 PRINT\n50 PRINT \"Estou pensando em um número entre 1 e 100.\"\n60 LET N = INT(RND(1) * 100) + 1\n70 LET T = 0\n80 PRINT \"Tente adivinhar!\"\n90 PRINT\n100 LET T = T + 1\n110 PRINT \"Tentativa #\"; T;\n120 INPUT G\n130 IF G = N THEN GOTO 200\n140 IF G < N THEN PRINT \"Muito baixo! Tente novamente.\": GOTO 100\n150 IF G > N THEN PRINT \"Muito alto! Tente novamente.\": GOTO 100\n200 PRINT\n210 PRINT \"Parabéns! Você acertou em\"; T; \"tentativas!\"\n220 PRINT\n230 PRINT \"Deseja jogar novamente? (S/N)\";\n240 INPUT R$\n250 IF R$ = \"S\" OR R$ = \"s\" THEN GOTO 40\n260 PRINT \"Obrigado por jogar!\"\n270 END"],
104
+ ["10 REM DESENHO DE MANDALA\n20 SCREEN 1\n30 CLS\n40 COLOR 1, 0\n50 PI = 3.14159\n60 FOR R = 10 TO 100 STEP 10\n70 FOR A = 0 TO 2*PI STEP PI/8\n80 X1 = 160 + R*COS(A)\n90 Y1 = 100 + R*SIN(A)\n100 X2 = 160 + R*COS(A+PI/16)\n110 Y2 = 100 + R*SIN(A+PI/16)\n120 LINE (X1, Y1)-(X2, Y2), (R/10) MOD 4 + 1\n130 NEXT A\n140 NEXT R\n150 LOCATE 23, 10\n160 PRINT \"Pressione qualquer tecla para sair\";\n170 END"]
105
+ ]
106
+
107
+ # Criar interface Gradio
108
+ with gr.Blocks(title="PCBasic Interpreter Online") as demo:
109
+ gr.Markdown("# PCBasic Interpreter Online")
110
+ gr.Markdown("Digite seu código BASIC e veja a execução.")
111
+
112
+ with gr.Row():
113
+ with gr.Column(scale=1):
114
+ code_input = gr.Textbox(
115
+ label="Código BASIC",
116
+ placeholder="Digite seu código BASIC aqui...",
117
+ lines=15
118
+ )
119
+ run_button = gr.Button("Executar Código")
120
+
121
+ with gr.Column(scale=1):
122
+ text_output = gr.Textbox(label="Saída de Texto", lines=10)
123
+ image_output = gr.Image(label="Saída Gráfica")
124
+
125
+ gr.Examples(examples, inputs=code_input)
126
+
127
+ run_button.click(fn=process_basic_code, inputs=code_input, outputs=[text_output, image_output])
128
+
129
+ gr.Markdown("""
130
+ ## Sobre o PCBasic
131
+
132
+ PCBasic é um interpretador de GW-BASIC, BASICA, PCjr Cartridge Basic e compatíveis. Suporta:
133
+
134
+ - Todos os comandos e funções do GW-BASIC
135
+ - Operações gráficas (SCREEN, LINE, CIRCLE, etc.)
136
+ - Som (SOUND, PLAY)
137
+ - Entrada de usuário (INPUT)
138
+
139
+ Para mais informações, visite [PCBasic no GitHub](https://github.com/robhagemans/pcbasic).
140
+ """)
141
+
142
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio>=3.36.0
2
+ pcbasic>=2.0.3
3
+ pillow>=9.5.0