#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Test : extraction de specs via GPT-4o-mini (API REST, sans dépendance).""" import json, os, urllib.request, urllib.error # charge la clé depuis .env for line in open(".env", encoding="utf-8"): if line.startswith("OPENAI_API_KEY="): os.environ["OPENAI_API_KEY"] = line.split("=", 1)[1].strip() KEY = os.environ["OPENAI_API_KEY"] SCHEMA = { "type": "object", "additionalProperties": False, "properties": { "condition": {"type": "string", "enum": ["a_renover","original","bon","renove","refait_neuf","neuf","inconnu"]}, "turnkey": {"type": "boolean"}, "recently_renovated": {"type": "boolean"}, "flooring": {"type": "array", "items": {"type": "string", "enum": ["bois_franc","ceramique","plancher_flottant","tapis","vinyle","beton","autre"]}}, "countertop": {"type": "string", "enum": ["granit","quartz","marbre","stratifie","bois","autre","inconnu"]}, "heating": {"type": "array", "items": {"type": "string", "enum": ["electrique","plinthes","thermopompe","bois","gaz","mazout","radiant","geothermie","autre"]}}, "garage": {"type": "boolean"}, "pool": {"type": "boolean"}, "waterfront": {"type": "boolean"}, "view": {"type": "string", "enum": ["eau","montagne","ville","aucune","inconnu"]}, "finished_basement":{"type": "boolean"}, "fireplace": {"type": "boolean"}, "central_ac": {"type": "boolean"}, "new_construction":{"type": "boolean"}, "income_property": {"type": "boolean"}, "highlights": {"type": "array", "items": {"type": "string"}, "description": "3-6 mots-clés de vente saillants"} }, "required": ["condition","turnkey","recently_renovated","flooring","countertop", "heating","garage","pool","waterfront","view","finished_basement", "fireplace","central_ac","new_construction","income_property","highlights"] } SYS = ("Tu es un extracteur d'attributs immobiliers. À partir de la description " "d'une propriété (français ou anglais), renvoie les specs au format JSON " "strict. Base-toi UNIQUEMENT sur le texte ; si une info est absente, mets " "false / 'inconnu' / [] selon le champ. highlights = 3 à 6 mots-clés.") def extract(desc): body = { "model": "gpt-4o-mini", "temperature": 0, "messages": [{"role": "system", "content": SYS}, {"role": "user", "content": desc[:4000]}], "response_format": {"type": "json_schema", "json_schema": {"name": "specs", "strict": True, "schema": SCHEMA}}, } req = urllib.request.Request( "https://api.openai.com/v1/chat/completions", data=json.dumps(body).encode(), headers={"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}) with urllib.request.urlopen(req, timeout=60) as r: out = json.load(r) return out["choices"][0]["message"]["content"], out.get("usage") # 3 descriptions du dataset data = json.load(open("data/processed/maisons_avec_prix.json", encoding="utf-8")) descs = [d["description"] for d in data if d.get("description")][:3] for i, dsc in enumerate(descs): try: content, usage = extract(dsc) print(f"\n=== Exemple {i+1} (tokens: {usage}) ===") print("DESC:", dsc[:160].replace("\n", " "), "...") print("SPECS:", json.dumps(json.loads(content), ensure_ascii=False)) except urllib.error.HTTPError as e: print("HTTP", e.code, e.read().decode()[:400]); break