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

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -114
app.py CHANGED
@@ -3,140 +3,97 @@ 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()
 
3
  import tempfile
4
  import os
5
  import time
 
6
  from PIL import Image
7
  import io
8
 
9
  def run_pcbasic_code(code, timeout=30):
10
+ """Executa o código PCBasic e captura saída gráfica usando framebuffer"""
11
+ with tempfile.TemporaryDirectory() as tmpdir:
12
+ code_path = os.path.join(tmpdir, "code.bas")
13
+ img_path = os.path.join(tmpdir, "output.png")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ with open(code_path, "w") as f:
16
+ f.write(code)
 
 
 
 
 
 
 
17
 
18
+ # Usar framebuffer virtual para captura de tela
19
+ env = os.environ.copy()
20
+ env["SDL_VIDEODRIVER"] = "dummy"
21
+ env["SDL_FBDEV"] = "/dev/fb0" # Dispositivo framebuffer virtual
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
 
 
 
 
23
  try:
24
+ process = subprocess.run(
25
+ [
26
+ "pcbasic",
27
+ f"--run={code_path}",
28
+ "--interface=sdl2",
29
+ "--video=SDL2",
30
+ "--fullscreen",
31
+ "--output",
32
+ img_path
33
+ ],
34
+ env=env,
35
+ timeout=timeout,
36
+ capture_output=True
37
+ )
38
+
39
+ # Capturar saída de texto
40
+ text_output = process.stdout.decode('utf-8', errors='replace')
41
+
42
+ # Verificar se imagem foi criada
43
+ if os.path.exists(img_path):
44
+ img = Image.open(img_path)
45
+ return text_output, img
46
+ else:
47
+ return text_output, None
48
+
49
+ except subprocess.TimeoutExpired:
50
+ return "Erro: Tempo limite de execução excedido", None
51
+ except Exception as e:
52
+ return f"Erro: {str(e)}", None
53
 
54
  def process_basic_code(code):
55
+ """Processa o código BASIC e prepara saídas para Gradio"""
56
+ text, img = run_pcbasic_code(code)
57
 
58
+ # Converter imagem PIL para formato compatível com Gradio
59
+ if img:
60
+ img_byte = io.BytesIO()
61
+ img.save(img_byte, format="PNG")
62
+ return text, img_byte.getvalue()
63
+ return text, None
 
 
 
 
 
 
 
 
 
 
64
 
65
+ # Configuração da interface Gradio
66
+ with gr.Blocks(title="PCBasic Interpreter") as demo:
67
  gr.Markdown("# PCBasic Interpreter Online")
 
68
 
69
  with gr.Row():
70
+ with gr.Column():
71
  code_input = gr.Textbox(
72
  label="Código BASIC",
73
+ placeholder="Digite seu código aqui...",
74
  lines=15
75
  )
76
+ run_btn = gr.Button(".Executar")
77
 
78
+ with gr.Column():
79
+ text_out = gr.Textbox(label="Saída de Texto", lines=10)
80
+ image_out = gr.Image(label="Saída Gráfica", type="filepath")
81
+
82
+ # Exemplos pré-definidos
83
+ examples = gr.Examples(
84
+ examples=[
85
+ ["10 PRINT \"OLÁ MUNDO!\""],
86
+ ["10 FOR I=1 TO 10\n20 PRINT I*2\n30 NEXT I"],
87
+ ["10 SCREEN 1\n20 CIRCLE (160,100),50\n30 PAINT (160,100)"]
88
+ ],
89
+ inputs=code_input
90
+ )
 
 
 
 
91
 
92
+ # Conectar botão às funções
93
+ run_btn.click(
94
+ fn=process_basic_code,
95
+ inputs=code_input,
96
+ outputs=[text_out, image_out]
97
+ )
98
 
99
  demo.launch()