Mostrando postagens com marcador programa. Mostrar todas as postagens
Mostrando postagens com marcador programa. Mostrar todas as postagens

quarta-feira, 1 de fevereiro de 2023

Curiosidade: Testei o ChatGPT! E ele NÃO sabe programação!!

Pessoal,


Aproveitando toda a hype do ChatGPT, resolvi fazer um teste também.

Eu já tinha testado algumas vezes e achei bem interessante. Mas tinha sido mais para observar a tão citada naturalidade de linguagem e ver como estava a conversação em inglês e português. Em inglês a coisa flui melhor, confesso.

O ChatGPT, caso você tenha passado os últimos meses em Plutão, é um chatbot com inteligência artificial desenvolvido pela OpenAI, com técnicas de aprendizado supervisionado e por reforço. Apesar de toda a empolgação da imprensa em geral, quando lemos a percepção da imprensa especializada, a coisa muda um pouco de figura, como vocês verão abaixo.

Para esse post, resolvi trazer uma conversa que tive com o ChatGPT sobre programação em MSX, coisa básica mesmo. Percebam que a resposta dele é bonita, mas não tão precisa ou correta.

Iniciei perguntando se ele sabe criar códigos para MSX, especificamente BASIC.


Legal! O código é tipo um "Hello, World!". Ele explica ainda como funciona, fala do comando 'END' para encerrar o programa (o que na prática é desnecessário, porque o MSX-BASIC termina o programa automaticamente quando chega no final) e ainda cita que deve ser apertado o botão 'RUN' ou digitar esse comando para iniciar o programa. Sim, o MSX tinha um botão para iniciar (na verdade era só um atalho de teclado, mas vá lá...).

Depois eu pedi a mesma função em MSX-Assembly, vulga "Linguagem de Máquina".  Aqui as coisas começam a apertar para a Inteligência Artifical. Vejam só:


Ele começa colocando o programa em $0100, que é realmente uma posição possível, pois não é acessível pelo BASIC (os programas em BASIC começam em $8000). Entretanto, geralmente começávamos em $C000, o ínicio da terceira página do bloco de memórias do MSX.

Ele cria uma alocação para colocar uma string ("Olá, eu sou o Jayme") e termina essa string com um caracter nulo (zero). Lá no começo e usa o registrador HL (um registrador de 16 bits muito utilizado para guardar posição de memória) para anotar onde está a string (algo como um ponteiro do C). Cria uma subrotina "print" e manda o processamento para lá. No final, acabando a função da subrotina "print", o processamento volta para a função principal e pula (veja o comando "jp", de jump) para a subrotina "end" que por sua vez está... vazia! O programa provavelmente ira travar ou apresentar um erro...

A subrotina "print" é bem interessante. Ele carrega ("ld", de load) o conteúdo do endereço registrado em HL para o registrador "a", incrementa em um o endereço de HL ("inc hl), faz um teste lógico com o conteúdo de "a" e toma um decisão: se o conteúdo de "a" é zero/nulo (lembra que ele colocou um zero no final da string?), chegou ao final da string e aí ele desvia para a subrotina "endprint"; se o conteúdo de "a" não é nulo, ele chama um função da BIOS ($bb18) para imprimir um caractere na tela e depois volta para o início da subrotina "print" para imprimir o próximo caractere da string.

Tem outros modos mais rápidos e que gastam menos bytes para fazer isso, como mostrarei abaixo.

De todo modo, algumas cosiderações são pertinentes e devem ser feitas:

* - "or a, a" - Esse é um teste que ele sugere para saber se o caractere de "a" é zero. 

(Linguagem de Máquina, Rossini-Figueredo, 1a edição - 1987 - Ed. Aleph)

Ou seja, ele compara "a" com "a"; se "a" já tiver chegado ao zero e for zero, essa operação da zero e ele salta a subrotina "endprint", caso contrário segue em frente. Só que a sintaxe correta é apenas OR A, uma vez que ele faz a operação de A com o que você pedir (no caso A). Assim, OR A, A escreve-se apenas OR A. O mesmo se fôssemos comparar B, seria OR B (de OR A, B). A lógica está correta, a sintaxe está errada.

* - "$bb18" - Em Assembly, muitas vezes, usamos os números invertidos para representar os endereços. Esse endereço aí $bb18, confesso que nunca vi.

Imaginei então que seria $18bb. Fui procurar nos livros aqui em casa porque realmente não me lembrava qual a rotina da BIOS que imprimia caractere na tela. E... não é essa, até porque essa não existe :(

O correto era usar o ponteiro para indicar a subrotina e não o endereço direto. A função que eu usava era a WRTVRM (Write To VRAM), acessível com um CALL $004D, onde o byte a ser impresso estava no registrador (acumulador) "a" e o endereço da VRAM era o de HL. Então vemos que o programa tem alguns erro... E erros sérios!

Além disso, a subrotina "endprint" contém o comando "ret", de Return. Mas não é retorno para onde estava quando foi acessado, é retorno para o MSX-BASIC. Ou seja, acaba o programa. Esse final deveria ser na subrotina "end", que como disse acima, está vazia.

Confesso que não consultei na hora o valor da função da BIOS mas questionei a subrotina e o comando "ret". Então ele corrigiu:


Depois, tivemos uma longa conversa onde eu expliquei todos esses problema.

A função da BIOS talvez devesse ter sido a WRTVRM ($004D), como eu citei acima, desde o início, mas o ChatGPT ainda tentou usar a função RDSLT que apenas lê o byte do endereço apontado pelo registrador HL.

(Fonte: Livro Vermelho do MSX)

Depois tentou fazer outro código usando a mesma lógica, mas com a função da BIOS correta. Exceto que usou o registrador HL para apontar para o endereço da string enquanto, nessa função, ele aponta para o endereço da VRAM.

Bom, abaixo eu mostro o que eu faria de diferente (e que funciona!).

Esse primeiro caso usa a função WRTVRM, carrega o programa para a posição correta na memória e faz a sequência correta dos passos:
WRTVRM: EQU $4D             ;ponteiro para a função WRTVRM
        ORG $C000           ;inicia o programa
        LD HL,0             ;endereço da VRAM - posição 0x0 da tela
        LD BC, MESSAGE      ;endereço do início da mensagem
INICIO: LD A, (BC)          ;carrega a primeira letra em A
        CALL WRTVRM         ;chama a função
        INC HL              ;próxima posição na tela
        INC BC              ;próximo caracter
        OR A                ;se A for nulo,
        JR Z, END           ;vai para o fim
        JR INICIO           ;se A não for nulo, reinicia
END:    RET
MESSAGE:DEFM "Olá, eu sou o Jayme"
        DEFB 0
Outra opção seria trocar a condicional: ao invés de "OR A", fazer um "CP 0":

WRTVRM: EQU $4D             ;ponteiro para a função WRTVRM
        ORG $C000           ;inicia o programa
        LD HL,0             ;endereço da VRAM - posição 0x0 da tela
        LD BC, MESSAGE      ;endereço do início da mensagem
INICIO: LD A, (BC)          ;carrega a primeira letra em A
        CALL WRTVRM         ;chama a função
        INC HL              ;próxima posição na tela
        INC BC              ;próximo caracter
        CP 0                ;testa para saber se A é nulo
        JR NZ, INICIO       ;se A não for nulo, reinicia
        RET                 ;fim 
MESSAGE:DEFM "Olá, eu sou o Jayme"
        DEFB 0

Essa última opção economiza alguns bytes. Muito importante se a gente usa um computador lá da década de 1980 com escassos 64KB...

Outra opção seria usar a função LDRIKVM, que copia um bloco inteiro da RAM para a VRAM (ou seja, copia a string inteira). Aqui precisamos de alguns outros registradores. 

(Fonte: Livro Vermelho do MSX)

Veja que usaremos outros registradores agora. Como iremos copiar um bloco da RAM, precisamos saber o tamanho da string.

O

l

á

,


e

u


s

o

u


o


J

a

y

m

e

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20


Aí está, nossa string tem 19 caracteres (20 se fossemos contar o caracter nulo).


LDIRVM: EQU $5C             ;ponteiro para a função WRTVRM
        ORG $C000           ;inicia o programa
        LD DE, 0            ;endereço da VRAM - posição 0x0 da tela
        LD HL, MESSAGE      ;endereço do início da mensagem
	LD BC, 19	    ;tamanho da string
        CALL LDIRVM         ;chama a função
RET ;fim MESSAGE:DEFM "Olá, eu sou o Jayme"
Vejam como essa fica bem mais enxuta. Tem um ponto aqui que definimos o tamanho da string no código. Poderíamos ter criado uma subrotina que contaria o tamanho da string até o nulo (daria 20) e retiraríamos o nulo (20 - 1 = 19). Outra opção.

E uma última opção seria a função CHPUT ($00A2). Essa função imprime o byte presente no acumulador em modo texto (seja Screen 0, 40x24 ou Screen 1, 32x24).  Nesse caso, o processo é similar ao que ele estava fazendo.

(Fonte: Livro Vermelho do MSX)

Aqui seria mais ou menos igual as anteriores, imprimindo um caracter por vez, só que obrigatoriamente em modo texto (Screen 0 ou 1).

CHPUT:  EQU $A2             ;ponteiro para a função CHPUT
        ORG $C000           ;inicia o programa
        LD HL, MESSAGE      ;endereço do ínicio da mensagem
INICIO: LD A, (HL)          ;carrega a primeira letra em A
        CALL CHPUT          ;chama a função
        INC HL              ;próximo caracter
        CP 0                ;testa para saber se A é nulo
        JR NZ, INICIO       ;se A não for nulo, reinicia
        RET                 ;fim 
MESSAGE:DEFM "Olá, eu sou o Jayme"
        DEFB 0


Quando joguei este código no ChatGPT, ele escreveu isso:


Ele falou exatamente o que o programa faz e o que eu havia pedido lá no início...

Concluindo: a ferramenta é muito poderosa, inquestionável. Mas ainda está longe de ser autosuficiente.  A ferramenta parece genial, de outro mundo, desde que você não domine o assunto a ser discutido. Neste caso, você consegue encontrar vários erros.

Cabe lembrar que o ChatGPT está funcionando desde novembro de 2022, ou seja, menos de 3 meses do dia em que escrevo esse post. Imagine como estará em um ou em dez anos...

Em tempo: não me lembrava como era gostoso programar em Assembly!

Caso queiram fazer alguma brincadeira, testem os códigos no vários emuladores online:





Por enquanto é isso!

domingo, 29 de janeiro de 2023

Tutorial e Dica: Como Fazer Download no YouTube - 3 modos diferentes!!! E ainda crie um programa para baixar vídeos você mesmo!

Pessoal,


Com frequência nos deparamos com algum vídeo no YouTube que julgamos necessário guardar para consulta futuro.

Nesse momento, a única opção que temos é fazer o download do vídeo. O vídeo pode ser retirado, sua internet pode cair, o YouTube pode ser proibido no país, sei lá. Ene possibilidades.

Pensei em mostrar aqui três formas de fazer downloads de vídeos do YouTube: usando um site, usando Docker e usando um programa em Python.

Vamos começar pelo site.


1 - savefrom.net

Esse é um serviço clássico e que todos já devem conhecer. O site savefrom.net faz o download de videos do YT. É só colar o endereço do vídeo do YT e pronto.


O site ainda permite que você escolha algumas opções de resolução para download. Algumas, nem todas.



Repare que apenas duas opções (720 e 360) têm áudio. As outras você baixa o vídeo, mas não terá áudio... O site do YT tem várias outras resoluções para assistir, até 4k.


E também não tem a opção de baixar apenas áudio (vai que era apenas um vídeo para tirar uma música?).

O site ainda tem duas outras opções para download, todas levando ao mesmo lugar: adicionar uma extensão ao navegador (o que eu me recuso a fazer, pois você autoriza o site a monitorar seu tráfego pela internet, deixa o navegador mais pesado e consumindo mais recursos, etc) e o famoso "ss" (onde você coloca as letras "ss" antes do "youtube" no link e manda carregar a página novamente.

No caso do link anterior, ao invés de "https://www.youtube.com/watch?v=VK7bCs4Ho_I" ficaria assim: "https://www.ssyoutube.com/watch?v=VK7bCs4Ho_I". Esse link leva para a página do SaveFrom.net. Claro, quando funciona...


Próximo!


2 - Docker

Esta opção é bem interessante. Você instala um container docker e acessa a página do container para baixar o vídeo.

Existem várias opções boas:

 - TubeSync, que funciona como o Sonarr, baixando canais e playlists inteiras. Atualizou o canal? Ele baixa automaticamente.

 - MeTube: é um fork do yt-dlp. Você coloca o link do video do YT (e vários outros serviços) e ele baixa automaticamente.

- Alltube: tipo o MeTube, mas com o layout mais feinho.

 - TubeArchivist: tipo o TubeSync, mas com o layout bem poluído. Baixa um vídeo, playlist e canal todo...

 - Youtube Downloader: excelente opção. Permite escolher a resolução, baixar apenas áudio, etc.

Eu pessoalmente tenho instalado o MeTube e o Youtube Downloader.

Para instalar o MeTube, usei o docker-compose do Portainer (Stack):
version: "3"
services:
  metube:
    image: alexta69/metube
    restart: always
    ports:
      - "5992:8081"
    volumes:
      - /volume3/Download/NAS Downloads:/downloads
    user: "1026:100"
Para acessar o serviço, digite o IP do container pela porta 5992.


Funciona muito bem, você pode escolher a resolução, o download é rápido, baixar um vídeo, uma playlist ou apenas o áudio... Muito bom! Também tem modo escuro, se quiser.

Para instalar o YouTube Downloader já dá um pouco mais de trabalho. Como estou instalando no Synology, vou mostar como fazer por ele.

Primeiro você deve ir no File Station, na pasta Docker e criar uma pasa com o nome "youtubedl" (tudo em minúsculo mesmo". Dentro desta pasta, crie outras cinco pastas: "appdata", "audio", "subscriptions", "users" e "video". Novamente, tudo em minúsculo.


Mesmo que você faça por outro sistema ou outro modo, deverá criar as pastas.

version: "2.1"
services:
  youtube_downloader:
    image: tzahi12345/youtubedl-material
    container_name: youtube_downloader
    volumes:
      - /volume3/docker/youtubedl/appdata:/app/appdata \
      - /volume3/docker/youtubedl/audio:/app/audio \
      - /volume3/docker/youtubedl/subscriptions:/app/subscriptions \
      - /volume3/docker/youtubedl/users:/app/users \
      - /volume3/docker/youtubedl/video:/app/video \
    ports:
      - 8084:17442
    restart: always
Pronto! Você já recebeu mastigado, no Stack, bem diferente do que eu achei :)

Para acessar, digite o IP com a porta 8084.


Veja que também é possivel mudar a qualidade do download, baixar apenas audio e baixar playlists. Tem também opção de usar modo escuro.

Achei um pouco estranho porque não achei onde estava o vídeo do download. Entendi que, após fazer o dowload, para efetivamente ter ele no seu computador você precisa tocar o vídeo no player embutido para, então, conseguir copiá-lo para o seu computador.

Mas isso me deixou preocupado: onde está o vídeo baixado? Penso que ele está em alguma pasta do NAS mas eu não consegui encontrá-lo... Depois de muitos e muitos downloads, será que vou torrar meu espaço de armazenamento?

Ele tem muitas configurações, permite editar uma série de metadados, enfim, é muito bom. Mas esse questão do download me deixou com uma pulga atrás da orelha... :\

Vamos agora para a cereja do bolo: um bom programinha em Python!


3 - Python

É aqui que as coisas ficam interessantes! Não vou ensinar aqui a instalar o Python nem as dependências do programa. Se você optou por isso, imagino que saiba resolver essas questões ou que terá interesse em aprender. O site do Python ensina isso muito melhor do eu seria capaz de fazer.

Basicamente o programa usa a biblioteca "pytube" para fazer o download do vídeo e de algumas informações (título do vídeo, tamanho do arquivo e duração do vídeo). 

Ele pede a URL do vídeo, apresenta uma barra de progressão do vídeo e ao final avisa que o vídeo foi baixado e mostra as informações.
from pytube import YouTube
from pytube.cli import on_progress
import pytube.request

pytube.request.default_range_size = 500000

def completou_download(a, b):
completo = '\n\nDownload Completo!\n'
titulo = 'Título: ' + stream.title + '\n'
tamanho = 'Tamanho: ' + str(stream.filesize / 1000000) + ' Mb\n'
duracao = 'Duração: ' + str(yt.length) + ' Segundos\n'

lista_inf = [completo, titulo, tamanho, duracao]

for t in lista_inf:
print(t)
print('-*' * 30)


url = input('\nDigite a URL do vídeo: ')
try:
yt = YouTube(url, on_progress_callback=on_progress, on_complete_callback=completou_download)
stream = yt.streams.filter(progressive=True, file_extension='mp4').get_highest_resolution()
print('\nIniciando Download...\n')
stream.download()
except:
print('\nOoops! Algo deu errado!\n')
Duas dicas para instalação do Python e da biblioteca "pytube":

    1 - às vezes você pode encontrar um erro do tipo 'urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1108)'. Para resolver isso, ao menos no MacOS, abra a pasta /Aplicativos/Python 3.x (onde x é a versão que você está usando) e clique duas vezes no arquivo "Install Certificates.command". Se você tiver mais de uma versão instalada, faça isso em todas as versões.


    2 - para instalar o "pytube", digite o comando:  
# pip install pytube
Porém, às vezes, você pode se deparar com este erro ao depurar e executar o programa:
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import pytube
ImportError: No module named 'pytube'
Aqui provavemente é porque deve haver mais de uma versão do pip e do Python instaladas.


No meu caso, repare que eu tenho a versão 3.9.1 do Python instalada e a versão 22.3.1 do pip que está no Python 3.9

No meu caso, digitando pip ou pip3 já corresponde à única versão instalada do Pyhton. Portanto, o comando para instalar o "pytube" pra mim mostra isso:


Se você tiver mais de uma versão instalada, precisará digitar "pip install pytube" e "pip3 install pytube" para baixar o "pytube" em ambas as versões do Python instaladas.

Bom, com todas as dependências resolvidas, a reposta é essa aqui:


Pronto!

Existe mais uma dica extra. Na verdade eu já dei essa dica lá atrás, há dois anos!! Veja ela aqui. Essa dica trata do cxfreeze, uma biblioteca do Python que cria um executável. Depois de digitar esse programa em Python para baixar vídeos do Youtube, vá no link acima (esse aqui) e crie um executável desse programa.

Nesse post você viu três formas de fazer download de vídeos do Youtube! Escolha a sua e seja feliz!