Javis OS
Javis OS is an Agentic AI that assists entrepreneurs in business tasks, helping them grow their work.
AI translation
Les nouveaux appels d'offres publics tunisiens chaque jour (source officielle HAICOP), triés par métier et par gouvernorat, avec date limite et caution. Gratuit, sans inscription. طلبات العروض العمومي
Translation pending
BusinessHTML · PythonGitHub @Ah6259OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Les nouveaux appels d'offres publics tunisiens chaque jour, tries par metier et par gouvernorat (source officielle HAICOP)
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Site gratuit, sans inscription : chaque jour, les nouveaux appels d'offres publics tunisiens,
triés par métier et par gouvernorat, avec la date limite (en rouge à moins de 7 jours),
la caution provisoire et le lien vers la fiche officielle. Français + arabe (?lang=ar).
Aussi : recherche par mots-clés (français et arabe, sans souci d'accents), résumé traduit des objets
(arabe -> français et inversement, glossaire maison, « traduction automatique approximative »), rappels « J-7 … J-1 /
Dernier jour » et section « Clôturent bientôt », ventes aux enchères de la Douane tunisienne (encheres/),
publication gratuite d'appels d'offres par les entreprises privées (publier/), alerte Telegram quotidienne.
Partie payante « Alertes Pro » (abonnement/) : alertes personnalisées (métiers + gouvernorats) chaque matin sur Telegram,
25 DT/mois ou 199 DT/an, sans essai gratuit (depuis le 20/10/2026), sans renouvellement automatique. La consultation reste gratuite.
| Étape | Fichier | Rôle |
|---|---|---|
| 1 | robot/lire_haicop.py | lit lentement les nouvelles fiches (1 page / 2,5 s), les classe par métier et gouvernorat → donnees/appels-offres.json |
| 1 b | robot/lire_douane.py | lit 1 page par jour de la Douane tunisienne (ventes aux enchères publiques) → donnees/encheres.json |
| 1 c | robot/prives.py | lit les réponses du formulaire Google des entreprises (CSV publié), les contrôle → donnees/prives.json |
| 2 | robot/construire_site.py | fabrique les 40 pages : accueil, 10 métiers, 26 gouvernorats, à propos, publier, enchères, sitemap.xml ; résumés traduits par robot/glossaire.py |
| 3 | tools/test_site.mjs + tools/test_pannes.py | tests (le robot ne publie rien si un test échoue) |
| 4 | robot/telegram.py | UN message court groupé sur le canal Telegram (nouveaux par métier + « ⏰ Clôturent dans 2 jours ») ; mémoire donnees/telegram-envoyes.json |
| 5 | .github/workflows/maj.yml | fait 1 → 4 chaque jour à 6h05 (heure de Tunis) puis commit ; GitHub Pages republie |
Réglages d'Ahmed : un seul fichier, robot/reglages.py (adresse publique du canal Telegram, du canal WhatsApp,
du formulaire Google et de son CSV). Vide = bouton caché / « Bientôt ». Les jetons secrets ne vont JAMAIS dans ce fichier.
Pages : index.html, metier/<métier>/, gouvernorat/<gouvernorat>/, a-propos/, publier/, encheres/, abonnement/, abonnement/conditions/.
Fichiers à la main : assets/style.css, assets/page.js (langue, en-tête, pied), assets/app.js (filtres, tri,
recherche, étiquettes J-N, dates selon le téléphone du visiteur), assets/logo.svg, assets/og-image-v6.jpg (source : tools/og-image.html).
Photo du bandeau : mosaïque de 4 vraies photos prises en Tunisie (BTP, informatique, santé, port de Radès), car les
marchés publics ne sont pas que la construction : assets/photos/marches-publics-mosaique.jpg (ordinateur, 4 côte à côte) et
-carre.jpg (téléphone, 2 × 2). Wikimedia Commons : Habib M'henni (CC BY 4.0 et CC BY-SA 3.0), Touzrimounir (CC BY-SA 4.0),
M. Rais (CC BY-SA 3.0) ; crédit de chaque photo sous le bandeau, dans « À propos » et sur l'image d'aperçu ; preuves hors dépôt.
Toutes les pages : translate="no" + <meta name="google" content="notranslate"> (Chrome proposait de traduire en anglais).
Icônes de métier et carte de la Tunisie : SVG faits maison.
Votre avis (accueil #avis, lien « Votre avis » dans le pied de page de toutes les pages) : note facultative (😀🙂😐🙁),
message (obligatoire, ≤ 1000 caractères), e-mail facultatif ; envoyé seulement au clic à Formspree (formulaire mwlpakqj,
commun à tous les sites d'Ahmed) avec les champs cachés site = « Alertes appels d'offres Tunisie » et page.
Code : assets/avis.js ; section : constante AVIS dans construire_site.py ; test : node tools/test_avis.mjs (envoi simulé).
python robot/lire_haicop.py --max 40
python robot/lire_douane.py
python robot/prives.py
python robot/telegram.py --essai (affiche le message Telegram sans l'envoyer)
python robot/construire_site.py
npm install --no-save --no-package-lock jsdom (une fois par PC)
node tools/test_site.mjs
node tools/test_sw.mjs
node tools/test_avis.mjs
python tools/test_pannes.py
bash tools/captures.sh (captures téléphone 340/390 px, FR + AR, dans captures/)
alertesaotunisie./newbot → nom « Alertes AO Tunisie », identifiant finissant par bot → il donne un jeton
(ne le donner à personne, ne jamais le coller dans le chat ni dans un fichier).appels-offres-tunisie → Settings → Secrets and variables → Actions → New repository secret :
TELEGRAM_BOT_TOKEN = le jeton ; TELEGRAM_CANAL = @alertesaotunisie (l'adresse du canal avec @).robot/reglages.py : TELEGRAM_CANAL_URL = "https://t.me/alertesaotunisie" → le bouton « Recevoir les alertes
sur Telegram » apparaît sur le site au prochain passage du robot.Sans ces secrets, le robot ne fait rien (et ne sonne pas en échec). Un appel d'offres n'est jamais annoncé deux fois.
Les abonnés ne sont jamais dans ce dépôt public : ils sont dans le dépôt privé Ah6259/appels-offres-abonnes
(voir son README : activer un abonné depuis l'application GitHub du téléphone, bouton activer-abonne).
TELEGRAM_BOT_TOKEN.robot/reglages.py : TELEGRAM_ROBOT_ALERTES = "AlertesAOTunisieBot".pour_activer) : son code reste « en attente » (rien n'est envoyé)
jusqu'au paiement. Plus d'essai gratuit depuis le 20/10/2026 (décision d'Ahmed) : l'action essai n'existe plus.activer-abonne, action paye, code + mois (1 ou 12) → facture ; le résumé
donne le CODE et un lien WhatsApp pour l'envoyer au client → le client envoie /start CODE au robot.
Nouvel abonné qui paie directement : action paye, code vide, avec nom, téléphone, métiers et gouvernorats.WhatsApp ne permet pas à un robot gratuit de publier dans un canal. Il faudra : créer un canal WhatsApp
(Actus → Canaux → Créer un canal), mettre son adresse dans WHATSAPP_CANAL_URL (robot/reglages.py) pour afficher
le bouton, puis recopier chaque jour le message Telegram (ou plus tard l'API WhatsApp Business, payante).
https://forms.google.com → Formulaire vide, titre « Publier un appel d'offres — Alertes appels d'offres Tunisie ». Paramètres → Réponses : ne pas collecter les adresses e-mail. Créer ces questions, dans cet ordre et avec ces mots (le robot reconnaît les colonnes grâce à eux) :
| Question | Type | Obligatoire |
|---|---|---|
| Nom de l'entreprise | Réponse courte | oui |
| Objet de l'appel d'offres | Réponse courte (15 à 300 caractères) | oui |
| Description (facultatif) | Paragraphe | non |
| Métier | Liste déroulante : BTP / génie civil, Électricité, Informatique, Fournitures et mobilier, Nettoyage / gardiennage, Alimentation, Médical / pharmacie, Transport / véhicules, Études / conseil, Autres | oui |
| Gouvernorat | Liste déroulante : Ariana, Béja, Ben Arous, Bizerte, Gabès, Gafsa, Jendouba, Kairouan, Kasserine, Kébili, Le Kef, Mahdia, La Manouba, Médenine, Monastir, Nabeul, Sfax, Sidi Bouzid, Siliana, Sousse, Tataouine, Tozeur, Tunis, Zaghouan, Plusieurs gouvernorats, Toute la Tunisie | oui |
| Date limite de réception des offres | Date | oui |
| Contact pour les candidats (e-mail ou téléphone de l'entreprise) | Réponse courte | oui |
| Je certifie que ces informations sont exactes et j'accepte leur publication | Cases à cocher (une case « Oui ») | oui |
Onglet Réponses → icône Sheets → Créer une feuille de calcul. Dans la feuille : Fichier → Paramètres → Paramètres régionaux France (dates jj/mm/aaaa).
Feuille : Fichier → Partager → Publier sur le Web → feuille « Réponses au formulaire 1 » → format CSV →
Publier → copier l'adresse (https://docs.google.com/spreadsheets/d/e/…/pub?…output=csv) dans CSV_PRIVES_URL.
Formulaire → Envoyer → lien → « Raccourcir l'URL » → copier () dans .
Objectif : le site reste en vie et honnête même si la source tombe en panne ou si personne ne s'en occupe.
Ce qui tourne tout seul
maj.yml chaque jour : lecture HAICOP → construction → tests → commit. Le ?v= des fichiers CSS/JS est
calculé automatiquement (empreinte des fichiers) : les téléphones ne gardent jamais un ancien style.battement-de-coeur.yml le 1er du mois : petit commit pour que GitHub ne mette pas les robots en pause
(pause automatique après 60 jours sans activité).tests.yml à chaque envoi (push) : les tests (site, service worker, pannes).maj-site (jamais deux commits en même temps).Ce qui protège le site
Source en panne, liste vide, < 30 % du volume habituel, format des fiches changé (champs introuvables) : c'est une panne, jamais « aucun appel d'offres ». Les anciennes annonces sont gardées ; seules les annonces dont la date limite est passée disparaissent (calcul fait aussi avec la date du téléphone du visiteur).
Fichier de données illisible, vide ou qui fond de plus de moitié : reprise de donnees/appels-offres.sauvegarde.json.
Sans sauvegarde : le site déjà publié n'est pas touché.
Bandeau daté « La source officielle n'a pas pu être lue depuis le … » dès que la dernière lecture réussie a 2 jours ou plus (vérifié dans la page ET par le JavaScript selon la date du visiteur). La pastille « Mis à jour le … » donne toujours la date de la dernière lecture réussie.
Textes de la source échappés, liens non officiels remplacés par le lien HAICOP de la fiche.
Ventes aux enchères (Douane) : page injoignable, tableau introuvable, < 30 % des lignes d'avant = panne ; anciennes ventes gardées (les expirées disparaissent), bandeau daté sur la page enchères après 2 jours sans lecture, « échec » au journal.
Entreprises privées : CSV injoignable, vide, corrompu ou colonnes changées = les publications déjà acceptées sont gardées. Les réponses refusées ne sont jamais publiées (seule la raison est gardée, sans leur contenu).
Telegram : secrets absents = rien ; Telegram en erreur = « échec » au journal, le site n'est pas touché, et les messages non partis repartent au passage suivant (jamais deux fois le même appel d'offres).
Réglages mal écrits (robot/reglages.py) : ignorés, bouton caché, « échec » au journal.
Sécurité : robots.txt (moteurs de recherche oui, robots d'IA et aspirateurs non), noai, CSP stricte en balise meta,
anti-iframe, protection légère contre la copie (numéros Tender, liens et champs restent copiables), aucun secret dans le
dépôt (vérifié par le test). Limite : un site GitHub Pages en sous-dossier n'a pas son propre robots.txt pour les robots
(seul ah6259.github.io/robots.txt compte) → le copier dans un dépôt Ah6259.github.io, ou plus tard avec un nom de domaine.
Ce qu'un visiteur voit peut toujours être recopié : la vraie protection = © + preuves datées.
Installation sur le téléphone : sw.js (service worker) = réseau d'abord pour les pages et les données (le cache
ne sert que hors connexion : jamais une vieille liste quand Internet marche) ; CSS/JS versionnés (?v=) = cache puis mise à jour.
Si un téléphone garde une vieille version : changer dans .
Ce qui alerte
donnees/etat-source.json.Quoi faire si une alerte arrive
lire_fiche() dans robot/lire_haicop.py, puis relancer les deux tests ;maj-appels-offres → « Run workflow »
(ou gh workflow run maj.yml -R Ah6259/appels-offres-tunisie).LICENSE « tous droits réservés ». Les annonces viennent du portail officiel de la HAICOP ; chaque carte renvoie à la fiche officielle, seule à faire foi.
https://forms.gle/…FORMULAIRE_PRIVES_URLEnsuite tout est automatique : chaque jour le robot contrôle (champs obligatoires, date limite à venir et ≤ 180 jours, pas de lien, pas de HTML, pas de publicité, pas de doublon, ≤ 3 par entreprise et par jour) et publie avec la mention « Publié par l'entreprise — non vérifié par HAICOP ». Pour retirer une annonce : supprimer sa ligne dans la feuille.
CACHE_VERSIONsw.js