SPB Git forge

spb/wp14_uqo

Public
2commits 1branches 1releases
909.0 KBsize
maindefault branch
56 min agolast push
Python 57% TeX 42.9%
3.6 KB · 72 lines python
Raw Blame History
1#!/usr/bin/env python32# -*- coding: utf-8 -*-3"""Test : extraction de specs via GPT-4o-mini (API REST, sans dépendance)."""4import json, os, urllib.request, urllib.error56# charge la clé depuis .env7for line in open(".env", encoding="utf-8"):8    if line.startswith("OPENAI_API_KEY="):9        os.environ["OPENAI_API_KEY"] = line.split("=", 1)[1].strip()10KEY = os.environ["OPENAI_API_KEY"]1112SCHEMA = {13    "type": "object",14    "additionalProperties": False,15    "properties": {16        "condition":       {"type": "string", "enum": ["a_renover","original","bon","renove","refait_neuf","neuf","inconnu"]},17        "turnkey":         {"type": "boolean"},18        "recently_renovated": {"type": "boolean"},19        "flooring":        {"type": "array", "items": {"type": "string", "enum": ["bois_franc","ceramique","plancher_flottant","tapis","vinyle","beton","autre"]}},20        "countertop":      {"type": "string", "enum": ["granit","quartz","marbre","stratifie","bois","autre","inconnu"]},21        "heating":         {"type": "array", "items": {"type": "string", "enum": ["electrique","plinthes","thermopompe","bois","gaz","mazout","radiant","geothermie","autre"]}},22        "garage":          {"type": "boolean"},23        "pool":            {"type": "boolean"},24        "waterfront":      {"type": "boolean"},25        "view":            {"type": "string", "enum": ["eau","montagne","ville","aucune","inconnu"]},26        "finished_basement":{"type": "boolean"},27        "fireplace":       {"type": "boolean"},28        "central_ac":      {"type": "boolean"},29        "new_construction":{"type": "boolean"},30        "income_property": {"type": "boolean"},31        "highlights":      {"type": "array", "items": {"type": "string"}, "description": "3-6 mots-clés de vente saillants"}32    },33    "required": ["condition","turnkey","recently_renovated","flooring","countertop",34                 "heating","garage","pool","waterfront","view","finished_basement",35                 "fireplace","central_ac","new_construction","income_property","highlights"]36}3738SYS = ("Tu es un extracteur d'attributs immobiliers. À partir de la description "39       "d'une propriété (français ou anglais), renvoie les specs au format JSON "40       "strict. Base-toi UNIQUEMENT sur le texte ; si une info est absente, mets "41       "false / 'inconnu' / [] selon le champ. highlights = 3 à 6 mots-clés.")4243def extract(desc):44    body = {45        "model": "gpt-4o-mini",46        "temperature": 0,47        "messages": [{"role": "system", "content": SYS},48                     {"role": "user", "content": desc[:4000]}],49        "response_format": {"type": "json_schema", "json_schema":50            {"name": "specs", "strict": True, "schema": SCHEMA}},51    }52    req = urllib.request.Request(53        "https://api.openai.com/v1/chat/completions",54        data=json.dumps(body).encode(),55        headers={"Authorization": f"Bearer {KEY}",56                 "Content-Type": "application/json"})57    with urllib.request.urlopen(req, timeout=60) as r:58        out = json.load(r)59    return out["choices"][0]["message"]["content"], out.get("usage")6061# 3 descriptions du dataset62data = json.load(open("data/processed/maisons_avec_prix.json", encoding="utf-8"))63descs = [d["description"] for d in data if d.get("description")][:3]64for i, dsc in enumerate(descs):65    try:66        content, usage = extract(dsc)67        print(f"\n=== Exemple {i+1} (tokens: {usage}) ===")68        print("DESC:", dsc[:160].replace("\n", " "), "...")69        print("SPECS:", json.dumps(json.loads(content), ensure_ascii=False))70    except urllib.error.HTTPError as e:71        print("HTTP", e.code, e.read().decode()[:400]); break72