1 points par GN⁺ 2023-06-26 | 2 commentaires | Partager sur WhatsApp
  • WinGPT est un projet qui vise à faire tourner un chatbot basé sur l’API OpenAI même sur Windows 3.1, avec un focus sur l’appel à des services d’IA modernes depuis de vieux PC comme les 386
  • L’implémentation repose sur C et l’API Windows standard, et grâce à Open Watcom v2 il est possible de compiler pour Windows 16 bits même depuis Windows 11
  • La connexion au serveur de l’API OpenAI se fait directement en TLS 1.3 sans proxy, mais il est explicitement indiqué que cette implémentation TLS n’est pas sûre
  • Les contrôles UI de base de Windows 3.1 étant limités, il a fallu implémenter directement des éléments comme la barre d’état ou modifier un ancien code du domaine public
  • À cause des contraintes mémoire, les réponses sont demandées courtes et les tours précédents de la conversation ne sont pas envoyés, ce qui empêche de conserver le contexte conversationnel

Expérience d’appel à l’API OpenAI depuis Windows 3.1

  • WinGPT est un assistant IA pour Windows 3.1, présenté comme pouvant servir à répondre à des questions, raconter des blagues, ou rédiger des brouillons de documents et de feuilles de calcul via l’API OpenAI
    • Une note de bas de page précise que cette description est satirique et qu’il ne faut pas s’y fier, car l’outil n’est pas capable d’exécuter ces fonctions de manière fiable
  • L’implémentation repose sur C et l’API Windows standard
    • Le compilateur utilisé est Open Watcom v2
    • Open Watcom v2 permet la compilation croisée vers Windows 16 bits même depuis Windows 11
  • La connexion au serveur de l’API OpenAI se fait directement en TLS 1.3
    • Aucun proxy terminant TLS sur une machine moderne n’est nécessaire
    • L’article “Modern TLS on 16-bit Windows” explique l’implémentation et les difficultés rencontrées, tout en précisant que cette implémentation TLS n’est pas sûre

Les difficultés d’implémentation UI dues à l’ancienneté de l’API Windows

  • Sous Windows 3.1, les possibilités de construction d’interface sont très limitées si l’on n’utilise que l’API Windows de base
    • L’essentiel de l’interface a été créé directement en C, avec en plus une logique de redimensionnement pour que chaque composant conserve la bonne taille lors du redimensionnement de la fenêtre
    • Les contrôles standard se limitent essentiellement aux push buttons, check boxes, radio buttons et edit boxes
  • Les limites de Windows 3.1 apparaissent particulièrement dans l’implémentation de la barre d’état
    • File Manager et Control Panel ont bien une barre d’état, mais Microsoft ne l’a pas largement mise à disposition des développeurs d’applications avant Windows 95
    • Lorsqu’on a demandé à ChatGPT comment utiliser une barre d’état, il a proposé des fichiers d’en-tête disponibles uniquement dans des versions ultérieures de Windows, puis, après une nouvelle question, a inventé le nom d’une bibliothèque UI qui semble ne pas exister
    • Au final, le projet a utilisé l’implémentation de barre d’état de 1997 de Philip J. Erdelsky, puis l’a modifiée pour qu’elle ressemble davantage, au pixel près, à celles des programmes Microsoft
  • Les icônes ont été créées avec Borland Image Editor
    • Sous Windows 3.1, les icônes de programme sont en 32x32 et s’affichent dans Program Manager et dans le sélecteur de tâches
    • Des icônes 16x16 distinctes ont aussi été réalisées pour l’affichage dans les versions ultérieures de Windows

Contraintes mémoire et conditions d’exécution

  • Les contraintes mémoire des machines Windows 3.1 imposent de réduire l’usage mémoire lors des requêtes API et du traitement des réponses
    • Les réponses JSON des API modernes ne sont pas optimisées pour être compactes, et l’API OpenAI ne fait pas exception
    • Pour garder des réponses petites, le modèle reçoit la consigne de répondre brièvement
    • Comme le texte des tours précédents n’est pas inclus dans les appels API, il est impossible d’exploiter le contexte des échanges précédents
  • WinGPT est distribué sous licence GNU GPL v2
    • Il fonctionne sur les versions 16 bits ou 32 bits de Windows postérieures à Windows 3.1
    • Une implémentation Winsock est nécessaire, et le logiciel a été testé sur Windows 3.11 for Workgroups avec Microsoft TCP/IP-32 3.11b installé, ainsi que sur un Windows 2000 standard
    • Il ne fonctionne pas sur Windows 64 bits, mais peut s’exécuter sous Wine
    • Une clé d’API OpenAI est nécessaire pour communiquer avec OpenAI, et elle doit être saisie après lancement via File | Options...
    • Téléchargement : Binaries for 16-bit and 32-bit Windows
    • Le code source est inclus dans le code source modifié de WolfSSL, à l’emplacement watcom16/wingpt

2 commentaires

 
cosine20 2023-06-28

MDRRRRRRRRRRRRRRRR

 
GN⁺ 2023-06-26
Avis Hacker News
  • Ça irait bien aussi intégré à une version de MS Office de l’époque
    On pourrait même en faire un personnage anthropomorphique façon skeuomorphisme à partir d’un vrai accessoire de bureau, par exemple un élastique… ou bien… un trombone…

    • Bonne idée :) Cela dit, Clippy n’est arrivé qu’après Office 97, donc il faudrait sans doute créer une version qui colle davantage à l’ambiance Windows 95/98 ou Windows Me
    • Microsoft Bob pourrait aussi très bien convenir : https://en.m.wikipedia.org/wiki/Microsoft_Bob
    • Du trombone au paperclip maximizer, l’IA a en quelque sorte bouclé la boucle
  • Il y a aussi toute une partie sur le fait d’avoir fait fonctionner TLS 1.2 et 1.3 sous Windows 3.1 pour que WinGPT puisse se connecter directement aux serveurs d’OpenAI sans dépendre de la terminaison TLS d’une machine moderne : https://www.dialup.net/wingpt/tls.html
    Cela vaut largement la lecture. Dans des environnements embarqués très contraints comme l’IoT, et même sur des CPU 8 bits utilisant du bank switching, on voit souvent une prise en charge de TLS 1.2, donc il est surprenant qu’il ait été difficile de faire tenir une implémentation TLS dans 64KB de code et de données

    • Ravi de voir quelqu’un travailler sur TLS 1.3 pour Windows 3.1
      C’est un peu triste de voir de vieux systèmes d’exploitation avoir du mal à accéder à Internet
    • Certaines de ces puces ont peut-être un support matériel pour la cryptographie
  • L’époque de Windows 3.1, 95 et 98 me manque vraiment. J’ai l’impression que l’interface n’a fait qu’empirer depuis
    Chaque fois que j’allume un 386 ou un Pentium, je suis frappé par la propreté de l’interface graphique et par le peu de stress qu’elle générait. J’en ai vraiment assez de l’enfer des pop-ups à faible contraste façon Apple/Google

    • Les Windows Interface Guidelines de 1995 valent le détour : https://www.ics.uci.edu/~kobsa/courses/ICS104/course-notes/M...
    • Vous vous souvenez qu’à l’époque on pouvait vraiment redimensionner les éléments ? Les barres latérales, les barres d’outils, ce genre de choses
      Aujourd’hui, après localisation, la moitié de l’interface affiche des libellés du genre "Tap to....". Avec tous ces formidables outils UI modernes et ces développeurs stars qui les manipulent, beaucoup n’arrivent même pas à faire une simple barre latérale redimensionnable
  • Pour échanger de l’espace contre du temps CPU, on peut utiliser un parsing de type SAX
    Le parsing de type SAX parcourt l’arbre de haut en bas et déclenche des événements à la visite de chaque nœud. La mémoire nécessaire est négligeable par rapport à un parsing JSON complet, et écrire un parseur JSON personnalisé de type SAX ne semble pas très difficile. Il existe aussi des parseurs JSON SAX dont on peut s’inspirer
    [1]: https://en.wikipedia.org/wiki/Simple_API_for_XML
    [2]: https://rapidjson.org/md_doc_sax.html

    • Exact. J’utilise JSMN(https://github.com/zserge/jsmn), qui est un parseur en streaming visitant les tokens l’un après l’autre, donc il n’existe qu’une seule copie de la réponse JSON en mémoire
      J’évite aussi autant que possible les nouvelles allocations mémoire intermédiaires. Par exemple, quand je déséchappe les antislashs dans une chaîne JSON, j’utilise une boucle destructive qui déplace les caractères sans antislash vers l’avant en mémoire, puis avance aussi le terminateur nul pour tronquer la chaîne. Ce n’est quasiment plus le genre de chose qu’on fait aujourd’hui, mais comme vous le dites, on peut économiser un peu d’espace en dépensant plus de temps CPU :)

      void DestructivelyUnescapeStr(LPSTR lpInput) {
      int offset = 0;
      int i = 0;
      while (lpInput[i] != '\0') {
      if (lpInput[i] == '\') {
      offset++;
      } else {
      lpInput[i - offset] = lpInput[i];
      }
      i++;
      }
      lpInput[i - offset] = '\0';
      }

  • Il est fort possible que l’infrastructure de support du contrôle de zone de texte dans lequel je tape en ce moment consomme plus de ressources système que l’ensemble de WinGPT
    Cela montre à quel point on gaspille littéralement plusieurs ordres de grandeur de mémoire pour un léger gain de productivité développeur. Bien sûr, programmer directement avec les contrôles Windows purs est difficile, mais on peut aussi soutenir que Delphi ou VB sous Win95 étaient bien plus productifs que les toolkits UI modernes, et que les applications produites consommaient bien moins de ressources. Ce qui manquait surtout, c’était le support mobile et la prise en compte du DPI

    • Honnêtement, parler d’un « petit gain de productivité développeur » est à mon avis très en dessous de la réalité
      Les choses sur lesquelles je peinais en code natif quand j’étais plus jeune peuvent désormais être faites par presque n’importe qui avec des bibliothèques et des outils prêts à l’emploi ciblant le navigateur web. En soi, c’est un accomplissement remarquable, et ce n’est pas une mauvaise chose. Le plus regrettable, c’est que le navigateur, devenu l’option globalement « meilleure », est en train de tuer les applications natives

      Aujourd’hui, dans les entreprises logicielles, on considère comme allant de soi qu’il faut fournir un accès web à un service réseau, donc on commence par le web. Ensuite, on veut aussi prendre en charge l’iPhone, Windows, Android, macOS et Linux. Il existe bien des options qui couvrent partiellement chaque plateforme, mais à ce stade on a déjà au moins une preuve de concept dans le navigateur, et avec une simple installation NPM, on peut l’emballer dans une fenêtre séparée avec installateur et système de distribution, puis l’expédier. Ce n’est pas formidable, mais c’est faisable

      S’il existait un framework GUI natif efficace, de qualité production, capable de cibler efficacement le DOM ainsi que les interfaces natives de Windows, macOS, Android et iPhone, avec prise en charge de la saisie de texte native via IME et des sémantiques propres à chaque plateforme, de l’accessibilité intégrée aux lecteurs d’écran, de l’adaptation responsive aux différentes tailles d’écran, et d’éléments visuels robustes, rapides et indépendants du DPI gérant correctement les facteurs d’échelle fractionnaires, le problème serait moins grave. Facile, non ?

Mais il n’existe rien de tel. J’aime Delphi VCL et le pur Win32, mais eux non plus ne couvrent pas la plupart des besoins. Il est très difficile de prendre en charge toutes ces plateformes. Le navigateur fait plutôt bien ce travail, et c’est aussi l’une des meilleures sources d’exemples de code quand on écrit du code profondément spécifique à une plateforme. En plus, comme de toute façon on vise surtout le web et que le moteur de navigateur est lui aussi du "code natif", il est bien plus simple de distribuer un navigateur ou au moins un moteur JS avec une plateforme qui exécute déjà du code natif, que de créer une solution de code natif isomorphe qui tourne aussi dans un environnement de navigateur.

Au final, ça finira sans doute par s’améliorer, mais avant cela, il y a de fortes chances que ça empire
  • Tu peux développer un peu la partie "on peut aussi considérer qu’on était bien plus productifs" ?

  • La notion de productivité doit aussi inclure le déploiement. À l’époque, Delphi/VB ignorait complètement cette question selon les standards du moment.
    Pour un simple utilitaire zip, il suffisait de copier un EXE unique quelque part sur un montage réseau d’un LAN derrière un pare-feu, et c’était réglé. Windows intégrait dans le binaire une sorte de pseudo-système de fichiers capable de charger des icônes et des chaînes, et cela suffisait. Pour des applications plus complexes nécessitant des DLL et des entrées de registre, il fallait dépenser plusieurs centaines de dollars pour acheter InstallShield puis apprendre InstallScript. Il n’y avait rien entre les deux jusqu’à l’arrivée de MSI et WiX, et jusque vers le milieu des années 1990, Microsoft considérait encore Internet comme une mode exotique, jugeant la distribution de logiciels par le réseau peu pratique à cause de la faible bande passante. Les logiciels étaient faits pour le CD-ROM, et « expédier » voulait littéralement dire mettre quelque chose sur un bateau.

    Le problème, c’est que les gens accordaient une importance presque supérieure à tout le reste à la vitesse d’itération, encore plus qu’à la productivité pure. Le monde changeait plus vite que Delphi. Borland aurait pu voir que cette tentative de forcer le navigateur à se comporter comme une application révélait un besoin fondamental non formulé, et construire quelque chose comme un interpréteur Object Pascal. Un « Delphi Browser », par exemple, aurait pu être adopté, mais la base de code était fondamentalement conçue pour produire des applications Windows natives, donc une telle transition aurait été difficile. En plus, Borland était presque un invité sur la plateforme Windows et suivait plutôt la direction donnée par Microsoft. Microsoft poussait ActiveX comme moyen de relier le monde du web et celui de Windows, et Borland a compris beaucoup trop tard qu’ActiveX ne répondrait pas aux besoins réels des gens. Au début, ils n’ont pas vu le web comme un concurrent, puis l’ont considéré comme un simple vecteur de transport pour les applications Delphi, puis plus tard ont poussé Delphi pour faire des serveurs web, alors que ses points forts n’étaient pas du tout là.

    La leçon à en tirer, c’est l’importance des préférences non formulées, qu’on découvre en observant ce que les gens font réellement plutôt que ce qu’ils disent, ainsi que l’importance écrasante du déploiement. Le déploiement reste encore aujourd’hui un angle mort chez la plupart des concurrents du web. Jusqu’à l’an dernier, il n’existait pratiquement aucune plateforme de type Delphi dotée d’un déploiement à la manière du web, avec rafraîchissement systématique à chaque lancement de l’application. Même Electron ne propose que des mises à jour de style desktop, entièrement asynchrones. Je dirige une petite entreprise qui fabrique un produit pour corriger le déploiement des applications desktop dans les contraintes des plateformes natives, et j’y ai ajouté un mode de déploiement de type web appelé aggressive updates (https://hydraulic.dev/). Dans ce mode, une vérification de mise à jour est faite à chaque exécution, ce qui permet d’itérer très vite si les utilisateurs redémarrent parfois l’application, ou si on peut forcer un redémarrage au bon moment. Ce n’est pas si différent d’une SPA à laquelle on demande de fermer l’onglet puis de recharger.

    Donc je ne suis pas d’accord avec l’idée que le cœur du manque, c’était le mobile et le DPI. Delphi, VB, GTK, Cocoa, etc. avaient déjà perdu le desktop avant même que les smartphones deviennent importants. Ils n’avaient pas de bon système de déploiement et de mise à jour, et la capacité à pousser immédiatement des correctifs et des changements comptait plus que toutes les autres fonctionnalités réunies.

  • Le rythme du progrès technologique est devenu tellement rapide qu’on a l’impression de commencer à subir un choc culturel venant de notre propre culture, une sorte de choc du futur. Et ce rythme va encore accélérer au cours de notre vie.
    C’est agréable de revoir des logiciels Windows 3.1. Je laisse aussi ça ici pour les amateurs de rétro : https://www.xfce-look.org/p/1016410

  • La partie la plus impressionnante, c’est le TLS natif.
    Il me semble avoir entendu dire que la cryptographie moderne était inutilisable sur d’anciens CPU à cause de la quantité de calcul numérique difficile à optimiser. Quelque chose comme : certaines étapes des algorithmes d’échange de clés prennent tellement de temps que le serveur peut expirer. Mais apparemment, sur un vieux et lent 386, ce n’est pas un problème ?

    • Quand on pense au nombre d’appareils embarqués encore utilisés, et au fait qu’une part importante d’entre eux repose sur des microcontrôleurs 8 bits avec le strict minimum de RAM, concevoir les systèmes de cette manière est irresponsable.
      C’est peut-être vrai pour certains systèmes sans usage embarqué, comme le chiffrement vidéo en temps réel, mais tout le monde ne se connecte pas à Internet avec le dernier iPhone.
  • Vraiment génial. Je vais probablement l’essayer sur une vraie machine Windows 3.1 :)
    Une suggestion : ce serait bien de permettre la personnalisation du prompt système dans la boîte de dialogue Options. Le réglage de 1992 est amusant, mais un peu limité. Si on essaie de résoudre un problème sur un ordinateur rétro, utiliser ceci à la place d’un ordinateur moderne ou d’un smartphone pourrait avoir un certain sens.

  • Sous Windows 3.1, avec Win32s, on peut éviter de se soucier du modèle mémoire segmenté, et ça pourrait même fonctionner sur Windows 64 bits.

    • Certes, mais Win32s ou WinG donnent l’impression d’un savoir transmis entre anciens qui achetaient régulièrement de vieux magazines de programmation.