LLM FLOW - Example 2
Simon-Pierre Boucher
2024-09-14

OpenAI Powered by OpenAI Using OpenAI OpenAI GPT-4 GPT-3 Anthropic Mistral

Overview

The following code implements a modular framework for interacting with different language model APIs (OpenAI, Anthropic, and Mistral) to generate text, retrieve embeddings, perform semantic searches, and process multi-step prompt flows. This code is designed to facilitate dynamic text generation and data processing using various models in a structured workflow.

Step-by-Step Breakdown

  1. Importing Libraries and Setting Up the Environment

    • Imports necessary modules, including asyncio, aiohttp (for async HTTP requests), and logging for logging messages.
    • Loads environment variables using dotenv to manage API keys securely.
    • Initializes colorama for text styling in console output and applies nest_asyncio for async functionality in Jupyter environments.
  2. Logging and Environment Variable Loading

    • Configures logging to display messages with the time and level (INFO, WARNING, ERROR).
    • Loads API keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, MISTRAL_API_KEY) from the environment variables to interact with different model APIs.
    • Warns if any of the API keys are not set.
  3. Utility Function

    • num_tokens_from_string: Calculates the number of tokens in a string based on the specified model using tiktoken. This helps in managing input length for different models.
  4. Custom Exception Class

    • APIException: Defines a custom exception to handle API-related errors gracefully.
  5. Abstract Base Class (ModelAPI)

    • Implements an abstract class to define a common interface for model APIs. It includes abstract methods generate_text (to generate text) and extract_text_from_response (to parse the response).
  6. API Implementations

    • OpenAIAPI, AnthropicAPI, and MistralAPI: Concrete classes implementing the ModelAPI abstract base class. Each has:
      • An __init__ method to store the API key.
      • An async method generate_text to send requests to the respective model API.
      • A method extract_text_from_response to extract the generated text from the API's response.
      • The OpenAI class includes an additional method get_embeddings to retrieve text embeddings.
  7. APIClient Class

    • Initializes instances of the API classes (OpenAIAPI, AnthropicAPI, MistralAPI).
    • generate_text: Determines which API to use based on the model name and handles token limit constraints. Calls the generate_text method of the respective API.
    • split_and_process: If the prompt exceeds the token limit, splits the prompt into smaller parts, processes them, and combines the responses. Summarizes the response if the combined text exceeds the token limit.
    • get_embeddings: Uses the OpenAI API to fetch embeddings for a list of texts.
  8. PromptBlock Class

    • Represents a unit of work (block) in the prompt flow. Each block has properties like prompt, model, max_tokens, and temperature.
    • Stores external data (e.g., URL) or semantic search settings.
    • add_input: Specifies input connections from other blocks.
    • load_external_data: Fetches and processes external data (API, website, PDF) asynchronously.
  9. Step Class

    • Contains a list of PromptBlock objects to represent an individual step in the workflow.
    • add_block: Adds a PromptBlock to the step.
  10. SemanticSearch Class

    • Handles semantic search using text embeddings.
    • split_text: Splits text into smaller chunks.
    • cosine_similarity: Calculates cosine similarity between two vectors.
    • search: Asynchronously performs semantic search on chunks of text to find the most relevant segments.
  11. FlowManager Class

    • Manages the overall workflow consisting of multiple steps and blocks.
    • Initializes an APIClient and SemanticSearch instance.
    • add_step: Adds a Step object to the workflow.
    • process_step: Processes all blocks in a given step, fetching input texts, external data, and performing semantic searches if specified. Executes the prompts using the API client.
    • collect_input_texts: Gathers input texts from connected blocks in previous steps.
    • run_flow: Executes the entire workflow, processing each step in order.
    • display_step_results: Displays the results of each block in a step.
    • visualize_flow and generate_dot_code: Generates a graphical representation of the workflow using Graphviz.
  12. Helper Function (create_modular_flow)

    • Accepts a configuration for steps and blocks, constructs a FlowManager with steps and blocks based on the configuration, and returns the FlowManager object for execution.

Summary

The code implements an asynchronous framework to interact with multiple language model APIs (OpenAI, Anthropic, Mistral). It defines classes to structure and manage the input prompts, data processing, and text generation in a multi-step flow. This modular design allows for flexible addition of steps, blocks, and API interactions, making it a versatile tool for complex prompt flows.

In [2]:
import asyncio
import aiohttp
import nest_asyncio
import os
import logging
from dotenv import load_dotenv
from colorama import init, Fore, Style
from graphviz import Source
from IPython.display import display
from bs4 import BeautifulSoup
from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional, Tuple
import numpy as np
import json
import re
import tiktoken

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Initialize colorama and nest_asyncio for Jupyter environments
init(autoreset=True)
nest_asyncio.apply()

# Load environment variables
load_dotenv()

# Check if API keys are set
api_keys = {
    "openai": os.getenv("OPENAI_API_KEY"),
    "anthropic": os.getenv("ANTHROPIC_API_KEY"),
    "mistral": os.getenv("MISTRAL_API_KEY")
}

for api, key in api_keys.items():
    if not key:
        logging.warning(f"{api.upper()}_API_KEY is not set in the environment variables.")

def num_tokens_from_string(string: str, model_name: str) -> int:
    encoding = tiktoken.encoding_for_model(model_name)
    return len(encoding.encode(string))

class APIException(Exception):
    """Custom exception for API-related errors."""
    pass

class ModelAPI(ABC):
    @abstractmethod
    async def generate_text(self, session: aiohttp.ClientSession, model: str, prompt: str, 
                            temperature: float, max_tokens: int) -> Dict[str, Any]:
        pass

    @abstractmethod
    def extract_text_from_response(self, response: Dict[str, Any]) -> str:
        pass

class OpenAIAPI(ModelAPI):
    def __init__(self, api_key: str):
        self.api_key = api_key

    async def generate_text(self, session: aiohttp.ClientSession, model: str, prompt: str, 
                            temperature: float, max_tokens: int) -> Dict[str, Any]:
        url = "https://api.openai.com/v1/chat/completions"
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        data = {
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": temperature,
            "max_tokens": max_tokens,
        }
        async with session.post(url, headers=headers, json=data) as response:
            if response.status != 200:
                raise APIException(f"OpenAI API error: {await response.text()}")
            return await response.json()

    def extract_text_from_response(self, response: Dict[str, Any]) -> str:
        return response["choices"][0]["message"]["content"].strip()

    async def get_embeddings(self, session: aiohttp.ClientSession, texts: List[str]) -> List[List[float]]:
        url = "https://api.openai.com/v1/embeddings"
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        data = {
            "model": "text-embedding-ada-002",
            "input": texts
        }
        async with session.post(url, headers=headers, json=data) as response:
            if response.status != 200:
                raise APIException(f"OpenAI Embedding API error: {await response.text()}")
            result = await response.json()
            return [item['embedding'] for item in result['data']]

class AnthropicAPI(ModelAPI):
    def __init__(self, api_key: str):
        self.api_key = api_key

    async def generate_text(self, session: aiohttp.ClientSession, model: str, prompt: str, 
                            temperature: float, max_tokens: int) -> Dict[str, Any]:
        url = "https://api.anthropic.com/v1/messages"
        headers = {
            "Content-Type": "application/json",
            "x-api-key": self.api_key,
            "anthropic-version": "2023-06-01"
        }
        data = {
            "model": model,
            "max_tokens": max_tokens,
            "temperature": temperature,
            "messages": [{"role": "user", "content": prompt}]
        }
        async with session.post(url, headers=headers, json=data) as response:
            if response.status != 200:
                raise APIException(f"Anthropic API error: {await response.text()}")
            return await response.json()

    def extract_text_from_response(self, response: Dict[str, Any]) -> str:
        return response["content"][0]["text"].strip()

class MistralAPI(ModelAPI):
    def __init__(self, api_key: str):
        self.api_key = api_key

    async def generate_text(self, session: aiohttp.ClientSession, model: str, prompt: str, 
                            temperature: float, max_tokens: int) -> Dict[str, Any]:
        url = "https://api.mistral.ai/v1/chat/completions"
        headers = {
            "Content-Type": "application/json",
            "Accept": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        data = {
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": temperature,
            "max_tokens": max_tokens,
        }
        async with session.post(url, headers=headers, json=data) as response:
            if response.status != 200:
                raise APIException(f"Mistral API error: {await response.text()}")
            return await response.json()

    def extract_text_from_response(self, response: Dict[str, Any]) -> str:
        return response["choices"][0]["message"]["content"].strip()

class APIClient:
    def __init__(self, api_keys: Dict[str, str]):
        self.apis = {
            "openai": OpenAIAPI(api_keys.get("openai")),
            "anthropic": AnthropicAPI(api_keys.get("anthropic")),
            "mistral": MistralAPI(api_keys.get("mistral")),
        }

    async def generate_text(self, session: aiohttp.ClientSession, model: str, prompt: str, 
                            temperature: float, max_tokens: int) -> str:
        if model.startswith(("gpt", "text-davinci")):
            api_type = "openai"
        elif model.startswith("claude"):
            api_type = "anthropic"
        elif model.startswith("mistral"):
            api_type = "mistral"
        else:
            raise ValueError(f"Unsupported model: {model}")
        
        try:
            token_limit = 16000  # Adjust based on the model
            if num_tokens_from_string(prompt, model) > token_limit:
                logging.info(f"Prompt exceeds token limit. Splitting into multiple parts.")
                return await self.split_and_process(session, model, prompt, temperature, max_tokens, token_limit)
            else:
                response = await self.apis[api_type].generate_text(session, model, prompt, temperature, max_tokens)
                return self.apis[api_type].extract_text_from_response(response)
        except APIException as e:
            logging.error(f"API error: {str(e)}")
            return "Error: Unable to generate text."

    async def split_and_process(self, session: aiohttp.ClientSession, model: str, prompt: str, 
                                temperature: float, max_tokens: int, token_limit: int) -> str:
        parts = self.split_prompt(prompt, token_limit)
        responses = []

        for i, part in enumerate(parts):
            logging.info(f"Processing part {i+1} of {len(parts)}")
            response = await self.generate_text(session, model, part, temperature, max_tokens // len(parts))
            responses.append(response)
            logging.info(f"Completed processing part {i+1}")

        combined_response = " ".join(responses)
        logging.info("All parts processed. Combining responses.")

        if len(combined_response) > token_limit:
            logging.info("Combined response exceeds token limit. Generating summary.")
            summary_prompt = f"Summarize the following text:\n\n{combined_response}"
            final_response = await self.generate_text(session, model, summary_prompt, temperature, max_tokens)
            logging.info("Summary generated.")
            return final_response
        else:
            logging.info("Returning combined response.")
            return combined_response

    def split_prompt(self, prompt: str, token_limit: int) -> List[str]:
        words = prompt.split()
        parts = []
        current_part = []
        current_tokens = 0

        for word in words:
            word_tokens = num_tokens_from_string(word, "gpt-3.5-turbo")
            if current_tokens + word_tokens > token_limit:
                parts.append(" ".join(current_part))
                current_part = [word]
                current_tokens = word_tokens
            else:
                current_part.append(word)
                current_tokens += word_tokens

        if current_part:
            parts.append(" ".join(current_part))

        return parts

    async def get_embeddings(self, session: aiohttp.ClientSession, texts: List[str]) -> List[List[float]]:
        return await self.apis["openai"].get_embeddings(session, texts)

class PromptBlock:
    def __init__(self, prompt: str, model: str = "gpt-3.5-turbo", max_tokens: int = 2000, 
                 temperature: float = 0.7, external_data: Optional[Dict[str, str]] = None,
                 semantic_search: Optional[Dict[str, Any]] = None):
        self.prompt = prompt
        self.model = model
        self.max_tokens = max_tokens
        self.temperature = temperature
        self.output = None
        self.input_blocks: List[Tuple[int, int]] = []
        self.external_data = external_data
        self.semantic_search = semantic_search

    def add_input(self, step_index: int, block_index: int):
        self.input_blocks.append((step_index, block_index))

    async def load_external_data(self, session: aiohttp.ClientSession) -> str:
        if not self.external_data:
            return ""

        data_type = self.external_data.get('type')
        url = self.external_data.get('url')

        try:
            async with session.get(url, timeout=30) as response:
                response.raise_for_status()
                if data_type == 'api':
                    data = await response.json()
                    return json.dumps(data, indent=2)
                elif data_type == 'site web':
                    text = await response.text()
                    soup = BeautifulSoup(text, 'html.parser')
                    
                    all_text = soup.get_text(separator='\n', strip=True)
                    all_text = re.sub(r'<[^>]+>', '', all_text)
                    all_text = re.sub(r'\s+', ' ', all_text).strip()
                    
                    links = [a.get('href') for a in soup.find_all('a', href=True)]
                    
                    tables = []
                    for table in soup.find_all('table'):
                        table_data = []
                        for row in table.find_all('tr'):
                            row_data = [cell.get_text(strip=True) for cell in row.find_all(['th', 'td'])]
                            table_data.append(row_data)
                        tables.append(table_data)
                    
                    combined_data = {
                        "text_content": all_text,
                        "links": links,
                        "tables": tables
                    }
                    
                    return json.dumps(combined_data, indent=2)
                elif data_type == 'pdf':
                    content = await response.read()
                    return f"PDF content (bytes): {len(content)}"
        except Exception as e:
            logging.error(f"Error loading external data from {url}: {str(e)}")
            return f"Error loading external data: {str(e)}"

class Step:
    def __init__(self):
        self.blocks: List[PromptBlock] = []

    def add_block(self, block: PromptBlock):
        self.blocks.append(block)

class SemanticSearch:
    def __init__(self, api_client: APIClient, words_per_chunk: int = 100):
        self.api_client = api_client
        self.words_per_chunk = words_per_chunk

    @staticmethod
    def split_text(text: str, words_per_chunk: int) -> List[str]:
        words = text.split()
        return [' '.join(words[i:i+words_per_chunk]) for i in range(0, len(words), words_per_chunk)]

    @staticmethod
    def cosine_similarity(vec1: List[float], vec2: List[float]) -> float:
        return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))

    async def search(self, session: aiohttp.ClientSession, query: str, text: str, top_k: int) -> List[Tuple[str, float]]:
        chunks = self.split_text(text, self.words_per_chunk)
        query_embedding = await self.api_client.get_embeddings(session, [query])
        chunk_embeddings = await self.api_client.get_embeddings(session, chunks)
        
        similarities = [self.cosine_similarity(query_embedding[0], chunk_emb) for chunk_emb in chunk_embeddings]
        top_indices = np.argsort(similarities)[-top_k:][::-1]
        return [(chunks[i], similarities[i]) for i in top_indices]

class FlowManager:
    def __init__(self, api_keys: Dict[str, str], words_per_chunk: int = 100, default_top_k: int = 3):
        self.steps: List[Step] = []
        self.api_client = APIClient(api_keys)
        self.semantic_search = SemanticSearch(self.api_client, words_per_chunk)
        self.default_top_k = default_top_k

    def add_step(self, step: Step):
        self.steps.append(step)

    async def process_step(self, step_index: int):
        if step_index == 0:
            for block in self.steps[step_index].blocks:
                if block.input_blocks:
                    logging.warning(f"Step 1, Block cannot have inputs from other blocks.")
                    return

        async with aiohttp.ClientSession() as session:
            tasks = []
            for block in self.steps[step_index].blocks:
                all_input_texts = self.collect_input_texts(step_index, block)
                
                external_data_text = await block.load_external_data(session)
                logging.info(f"External data for Step {step_index + 1}, Block {len(tasks) + 1}: {external_data_text[:100]}...")
                
                if block.semantic_search:
                    query = block.semantic_search.get('query', '')
                    top_k = block.semantic_search.get('top_k', self.default_top_k)
                    search_inputs = block.semantic_search.get('inputs', ['all'])
                    
                    relevant_chunks = []
                    
                    if 'all' in search_inputs or 'previous' in search_inputs:
                        input_search_text = '\n'.join(all_input_texts)
                        relevant_input_chunks = await self.semantic_search.search(session, query, input_search_text, top_k)
                        relevant_chunks.extend(relevant_input_chunks)
                    
                    if 'all' in search_inputs or 'external' in search_inputs:
                        if external_data_text:
                            relevant_external_chunks = await self.semantic_search.search(session, query, external_data_text, top_k)
                            relevant_chunks.extend(relevant_external_chunks)
                    
                    input_texts = [chunk for chunk, _ in relevant_chunks]
                    logging.info(f"Semantic search results: {[(chunk[:100], score) for chunk, score in relevant_chunks[:2]]}")
                else:
                    input_texts = all_input_texts + ([external_data_text] if external_data_text else [])

                if input_texts:
                    merged_input = "\n".join(input_texts)
                    block.prompt = f"{merged_input}\n\n{block.prompt}"

                logging.info(f"Processing Step {step_index + 1}, Block {len(tasks) + 1}")
                logging.info(f"Prompt: {block.prompt[:100]}...")

                task = self.api_client.generate_text(
                    session, block.model, block.prompt, block.temperature, block.max_tokens
                )
                tasks.append(task)

            results = await asyncio.gather(*tasks)
            for block, result in zip(self.steps[step_index].blocks, results):
                block.output = result

    def collect_input_texts(self, step_index: int, block: PromptBlock) -> List[str]:
        return [self.steps[input_step].blocks[input_block].output 
                for input_step, input_block in block.input_blocks 
                if input_step < step_index]

    async def run_flow(self):
        self.visualize_flow()
        for i in range(len(self.steps)):
            await self.process_step(i)
            self.display_step_results(i)

    def display_step_results(self, step_index: int):
        print(f"\n{Fore.GREEN}{Style.BRIGHT}Step {step_index + 1} Results:{Style.RESET_ALL}")
        for j, block in enumerate(self.steps[step_index].blocks):
            print(f"{Fore.BLUE}{Style.BRIGHT}Block {j + 1} (Model: {block.model}, Max Tokens: {block.max_tokens}):{Style.RESET_ALL}")
            print(f"\n{Fore.YELLOW}Output:{Style.RESET_ALL} {block.output}\n")

    def visualize_flow(self):
        dot_code = self.generate_dot_code()
        graph = Source(dot_code)
        display(graph)

    def generate_dot_code(self) -> str:
        dot_code = """
        digraph G {
            node [style="filled", fontname="Arial", shape="box", margin="0.2,0.1"];
            edge [fontname="Arial"];
        """
        
        colors = ["#FFB3BA", "#BAFFC9", "#BAE1FF", "#FFFFBA", "#FFD8B9"]
        
        for i, step in enumerate(self.steps):
            step_color = colors[i % len(colors)]
            for j, block in enumerate(step.blocks):
                node_id = f"Block{i+1}_{j+1}"
                external_data_info = f"\\nExternal Data: {block.external_data.get('type', '').upper()}" if block.external_data else ""
                semantic_search_info = "\\nSemantic Search" if block.semantic_search else ""
                label = f"Step {i+1}, Block {j+1}\\nModel: {block.model}{external_data_info}{semantic_search_info}\\nPrompt: {block.prompt[:50]}..."
                dot_code += f'    {node_id} [label="{label}", fillcolor="{step_color}"];\n'
                for input_step, input_block in block.input_blocks:
                    input_id = f"Block{input_step+1}_{input_block+1}"
                    dot_code += f"    {input_id} -> {node_id};\n"
        
        dot_code += "}"
        return dot_code

def create_modular_flow(steps_config: List[Dict[str, Any]], api_keys: Dict[str, str], words_per_chunk: int = 100, default_top_k: int = 3) -> FlowManager:
    flow_manager = FlowManager(api_keys, words_per_chunk=words_per_chunk, default_top_k=default_top_k)
    
    for step_config in steps_config:
        step = Step()
        for block_config in step_config['blocks']:
            block = PromptBlock(
                prompt=block_config['prompt'],
                model=block_config.get('model', 'gpt-3.5-turbo'),
                max_tokens=block_config.get('max_tokens', 2000),
                temperature=block_config.get('temperature', 0.7),
                external_data=block_config.get('external_data'),
                semantic_search=block_config.get('semantic_search')
            )
            for input_ref in block_config.get('inputs', []):
                block.add_input(input_ref[0], input_ref[1])
            step.add_block(block)
        flow_manager.add_step(step)
    
    return flow_manager
In [6]:
steps_config = [
    # Étape 1 : Extraction des propriétés des pages 1 à 10
    {
        'blocks': [
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 1.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=1&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 2.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=2&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 3.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=3&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 4.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=4&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 5.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=5&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 6.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=6&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 7.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=7&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 8.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=8&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 9.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=9&sort=-published_at'
                }
            },
            {
                'prompt': "Extraire les informations des propriétés récemment mises en vente à partir du contenu de la page 10.",
                'model': 'gpt-4o-mini',
                'max_tokens': 1000,
                'temperature': 0.7,
                'external_data': {
                    'type': 'site web',
                    'url': 'https://duproprio.com/fr/rechercher/liste?search=true&online_since=2&parent=1&pageNumber=10&sort=-published_at'
                }
            }
        ]
    },
    # Étape 2 : Analyse des propriétés
    {
        'blocks': [
            {
                'prompt': "Créer un tableau avec toutes les propriétés de l'étape précédente",
                'model': 'gpt-4o-mini',
                'max_tokens': 4000,
                'temperature': 0.8,
                'inputs': [(0,0), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (0,7), (0,8), (0,9)]  # Utilise les 10 blocs de l'étape 1
            }
        ]
    },
    {
        'blocks': [
            {
                'prompt': "Calcule le prix moyen pour toute les propriétés",
                'model': 'gpt-4o-mini',
                'max_tokens': 4000,
                'temperature': 0.8,
                'inputs': [(1,0)]  
            },
            {
                'prompt': "Calcule le prix moyen pour toute les propriétés de type condo",
                'model': 'gpt-4o-mini',
                'max_tokens': 4000,
                'temperature': 0.8,
                'inputs': [(1,0)]  
            },
            {
                'prompt': "Calcule le prix moyen pour toute les propriétés de type bungalow",
                'model': 'gpt-4o-mini',
                'max_tokens': 4000,
                'temperature': 0.8,
                'inputs': [(1,0)]  
            },
            {
                'prompt': "Calcule le prix moyen pour toute les propriétés de type maison deux étages",
                'model': 'gpt-4o-mini',
                'max_tokens': 4000,
                'temperature': 0.8,
                'inputs': [(1,0)]  
            }

        ]
    }
    
]
# Create and run the flow
flow_manager = create_modular_flow(steps_config, api_keys, words_per_chunk=150, default_top_k=3)

async def main():
    await flow_manager.run_flow()

# Run the example
asyncio.run(main())
No description has been provided for this image
2024-09-18 10:58:28,385 - INFO - External data for Step 1, Block 1: {
  "text_content": "Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u2019accueil...
2024-09-18 10:58:28,386 - INFO - Processing Step 1, Block 1
2024-09-18 10:58:28,386 - INFO - Prompt: {
  "text_content": "Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u2019accueil...
2024-09-18 10:58:29,043 - INFO - External data for Step 1, Block 2: {
  "text_content": "Page 2 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:29,044 - INFO - Processing Step 1, Block 2
2024-09-18 10:58:29,044 - INFO - Prompt: {
  "text_content": "Page 2 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:29,511 - INFO - External data for Step 1, Block 3: {
  "text_content": "Page 3 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:29,512 - INFO - Processing Step 1, Block 3
2024-09-18 10:58:29,512 - INFO - Prompt: {
  "text_content": "Page 3 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:30,023 - INFO - External data for Step 1, Block 4: {
  "text_content": "Page 4 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:30,023 - INFO - Processing Step 1, Block 4
2024-09-18 10:58:30,024 - INFO - Prompt: {
  "text_content": "Page 4 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:30,624 - INFO - External data for Step 1, Block 5: {
  "text_content": "Page 5 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:30,625 - INFO - Processing Step 1, Block 5
2024-09-18 10:58:30,625 - INFO - Prompt: {
  "text_content": "Page 5 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:31,187 - INFO - External data for Step 1, Block 6: {
  "text_content": "Page 6 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:31,187 - INFO - Processing Step 1, Block 6
2024-09-18 10:58:31,188 - INFO - Prompt: {
  "text_content": "Page 6 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:31,731 - INFO - External data for Step 1, Block 7: {
  "text_content": "Page 7 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:31,731 - INFO - Processing Step 1, Block 7
2024-09-18 10:58:31,732 - INFO - Prompt: {
  "text_content": "Page 7 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:32,266 - INFO - External data for Step 1, Block 8: {
  "text_content": "Page 8 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:32,266 - INFO - Processing Step 1, Block 8
2024-09-18 10:58:32,266 - INFO - Prompt: {
  "text_content": "Page 8 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:32,883 - INFO - External data for Step 1, Block 9: {
  "text_content": "Page 9 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:32,883 - INFO - Processing Step 1, Block 9
2024-09-18 10:58:32,883 - INFO - Prompt: {
  "text_content": "Page 9 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u20...
2024-09-18 10:58:33,325 - INFO - External data for Step 1, Block 10: {
  "text_content": "Page 10 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u2...
2024-09-18 10:58:33,325 - INFO - Processing Step 1, Block 10
2024-09-18 10:58:33,325 - INFO - Prompt: {
  "text_content": "Page 10 - Condos, maisons \u00e0 vendre, Qu\u00e9bec Retour \u00e0 la page d\u2...
Step 1 Results:
Block 1 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations extraites des propriétés récemment mises en vente :

1. **Propriété à Drummondville**
   - **Prix**: 820 000 $
   - **Adresse**: 150, rue Joly
   - **Type**: Maison 2 étages
   - **Chambres**: 5
   - **Salles de bain + Salles d’eau**: 2 + 1
   - **Aire habitable**: 2 108 pi² (s-sol exclu)
   - **Taille du terrain**: 8 607 pi²
   - **Visite 3D**: Oui

2. **Propriété à St-Elzéar-de-Beauce**
   - **Prix**: 295 000 $
   - **Adresse**: 735, rue des Rosiers
   - **Type**: Jumelé
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 2 + 1
   - **Aire habitable**: 832 pi² (s-sol exclu)
   - **Taille du terrain**: 5 202 pi²
   - **Visite 3D**: Oui

3. **Propriété à Terrebonne**
   - **Prix**: 180 000 $
   - **Adresse**: 8, rue de la Châtelaine
   - **Type**: Maison mobile
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable**: 840 pi² (s-sol exclu)
   - **Taille du terrain**: 3 575 pi²
   - **Visite 3D**: Oui

4. **Propriété à Gatineau**
   - **Prix**: 889 000 $
   - **Adresse**: 318, boulevard des Trembles
   - **Type**: Maison 2 étages
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 3 + 1
   - **Aire habitable**: 2 277 pi² (s-sol exclu)
   - **Taille du terrain**: 5 304 pi²
   - **Visite 3D**: Oui

5. **Propriété à St-Lin-Laurentides**
   - **Prix**: 474 900 $
   - **Adresse**: 86, rue Xavier
   - **Type**: Bungalow
   - **Chambres**: 4
   - **Salles de bain + Salles d’eau**: 1 + 1
   - **Aire habitable**: 1 200 pi² (s-sol exclu)
   - **Taille du terrain**: 16 500 pi²
   - **Visite 3D**: Oui

6. **Propriété à Val-Des-Monts**
   - **Prix**: 445 000 $
   - **Adresse**: 185, Chemin des Trois Lacs
   - **Type**: Bungalow Surélevé
   - **Chambres**: 4
   - **Salles de bain + Salles d’eau**: 1 + 1
   - **Aire habitable**: 1 000 pi² (s-sol exclu)
   - **Taille du terrain**: 96 410 pi²
   - **Visite 3D**: Oui

7. **Propriété à St-Alphonse-Rodriguez**
   - **Prix**: 140 000 $
   - **Adresse**: 98, JOSÉE
   - **Type**: Bungalow
   - **Chambres**: 1
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable**: 629 pi² (s-sol exclu)
   - **Taille du terrain**: 7 500 pi²
   - **Visite 3D**: Oui

8. **Propriété à Le Plateau-Mont-Royal**
   - **Prix**: 599 000 $
   - **Adresse**: 4454, avenue de Lorimier
   - **Type**: Condo
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable**: 1 150 pi² (s-sol exclu)
   - **Visite 3D**: Oui

9. **Pro

Block 2 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations des propriétés récemment mises en vente extraites du contenu de la page 2 :

1. **Jumelé à vendre - St-Nicolas**
   - **Prix** : 485 000 $
   - **Adresse** : 1113, rue de Grenoble
   - **Chambres** : 3
   - **Salles de bain + Salles d’eau** : 2 + 1
   - **Aire habitable (s-sol exclu)** : 1 560 pi²
   - **Taille du terrain** : 4 726 pi²

2. **Condo à vendre - Brossard**
   - **Prix** : 850 000 $
   - **Adresse** : 1715-5905, boulevard du Quartier
   - **Chambres** : 3
   - **Salles de bain + Salles d’eau** : 3
   - **Aire habitable (s-sol exclu)** : 1 395 pi²

3. **Maison à vendre - Brossard**
   - **Prix** : 885 000 $
   - **Adresse** : 1756, croissant Turgeon
   - **Chambres** : 4
   - **Salles de bain + Salles d’eau** : 1 + 2
   - **Aire habitable (s-sol exclu)** : 1 251 pi²
   - **Taille du terrain** : 10 168 pi²

4. **Maison à vendre - Auteuil**
   - **Prix** : 939 000 $
   - **Adresse** : 85, Corriveau
   - **Chambres** : 3
   - **Salles de bain + Salles d’eau** : 2
   - **Aire habitable (s-sol exclu)** : 1 805 pi²
   - **Taille du terrain** : 25 510 pi²

5. **Maison modulaire à vendre - St-Lin-Laurentides**
   - **Prix** : 410 000 $
   - **Adresse** : 739, rue Auger
   - **Chambres** : 2
   - **Salles de bain + Salles d’eau** : 1
   - **Aire habitable (s-sol exclu)** : 1 472 pi²
   - **Taille du terrain** : 11 600 pi²

6. **Bungalow à vendre - St-Pie**
   - **Prix** : 499 000 $
   - **Adresse** : 86, Rue Ernest-Despars
   - **Chambres** : 3
   - **Salles de bain + Salles d’eau** : 2 + 1
   - **Aire habitable (s-sol exclu)** : 1 064 pi²
   - **Taille du terrain** : 7 567 pi²

7. **Maison à vendre - La Malbaie**
   - **Prix** : 422 000 $
   - **Adresse** : 785, boulevard Malcolm-Fraser
   - **Chambres** : 6
   - **Salles de bain + Salles d’eau** : 2 + 1
   - **Aire habitable (s-sol exclu)** : 3 100 pi²
   - **Taille du terrain** : 16 600 pi²

8. **Bungalow à vendre - Dunham**
   - **Prix** : 749 900 $
   - **Adresse** : 198, rue Guy
   - **Chambres** : 2
   - **Salles de bain + Salles d’eau** : 1
   - **Aire habitable (s-sol exclu)** : 1 810 pi²
   - **Taille du terrain** : 26 046 pi²

9. **Triplex à vendre - Mercier / Hochelaga / Maisonneuve**
   - **Prix** : 1 380 000 $
   - **Adresse** : 4489, rue Dickson
   - **Chambres** : 9
   - **Salles de bain + Salles d’eau** : 4
   - **Taille du terrain** : 2 196 pi²

10. **Jumelé à vendre - Boucherville**
    - **Prix** : 649 000 $
    - **Adresse** : 565, rue Henri-De Tonti
    - **Chambres** : 3
    - **Salles de bain + Salles d’eau** : 1 + 1
    - **Aire habitable (s-sol exclu)**

Block 3 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations extraites des propriétés récemment mises en vente à partir du contenu de la page 3 :

1. **Propriété 1**
   - **Type**: Terrain résidentiel
   - **Prix**: 130 000 $
   - **Localisation**: Ste-Rose-De-Watford, 159, chemin du Lac Algonquin
   - **Description**: Rare et magnifique localisation. Lot constructible divisé à...
   - **Taille du terrain**: 77 000 pi²

2. **Propriété 2**
   - **Type**: Bungalow
   - **Prix**: 764 500 $
   - **Localisation**: St-Bruno-De-Montarville, 1050, rue de la Madeleine
   - **Description**: Charmant bungalow très lumineux de 4 chambres.
   - **Chambres**: 4
   - **Salles de bain + Salles d’eau**: 1 + 1
   - **Aire habitable**: 1 142 pi²
   - **Taille du terrain**: 7 480 pi²

3. **Propriété 3**
   - **Type**: Jumelé
   - **Prix**: 280 000 $
   - **Localisation**: St-Bernard, 333, RUE LEMAY
   - **Description**: Beau petit jumelé construit en 2018. Secteur paisible et idéal.
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 2 + 1
   - **Aire habitable**: 768 pi²
   - **Taille du terrain**: 4 340 pi²

4. **Propriété 4**
   - **Type**: Terrain résidentiel
   - **Prix**: 239 000 $
   - **Localisation**: Bromont, 77, carré des Pionnières
   - **Description**: LE MOINS CHER À BROMONT!!! Superbe terrain résidentiel.
   - **Taille du terrain**: 6 134 pi²

5. **Propriété 5**
   - **Type**: Terrain résidentiel
   - **Prix**: 150 000 $
   - **Localisation**: St-Michel-Des-Saints, 41, chemin Lamarche
   - **Description**: Dernier grand terrain plat dans la Baie Morissette, riverain.
   - **Taille du terrain**: 70 493 pi²

6. **Propriété 6**
   - **Type**: Bungalow
   - **Prix**: 389 000 $
   - **Localisation**: Otter Lake, 24, Rue 2
   - **Description**: CLÉ EN MAIN - DISPONIBLE...
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable**: 1 024 pi²
   - **Taille du terrain**: 33 637 pi²

7. **Propriété 7**
   - **Type**: Bungalow
   - **Prix**: 92 500 $
   - **Localisation**: Lac Frontière, 9, rue du Lac Nord
   - **Description**: Résidence desservie par les services municipaux (aqueduc, égouts).
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable**: 841 pi²
   - **Taille du terrain**: 7 199 pi²

8. **Propriété 8**
   - **Type**: Jumelé
   - **Prix**: 395 000 $
   - **Localisation**: Beauport, 207, rue Laurelou
   - **Description**: Magnifique jumelé construit en 1993 dans un secteur paisible.
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 1 + 1
   - **Aire habitable**: 1 431 pi²
   - **Taille du terrain**: 4 858 pi²

9. **Propriété 9**
   - **Type**: Bungalow
   - **Prix**: 569 900 $
   - **Localisation**: Mirabel (St-Janvier), 13530-13532, rue du Blizzard
   - **Description**: Propriété située dans un quartier paisible à proximité des écoles.
   - **Chambres

Block 4 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations extraites des propriétés récemment mises en vente sur la page 4 :

1. **Condo à vendre - Le Plateau-Mont-Royal**
   - **Prix**: 599 000 $
   - **Adresse**: 4423, rue Messier
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable**: 1 011 pi²
   - **Taille du terrain**: 1 210 pi²
   - **Visite 3D**: Oui
   - [Lien](https://duproprio.com/fr/montreal/le-plateau-mont-royal/condo-a-vendre/hab-4423-rue-messier-1079137)

2. **Bungalow à vendre - St-Lin-Laurentides**
   - **Prix**: 519 500 $
   - **Adresse**: 1031, rue Rivest
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1 + 1
   - **Aire habitable**: 784 pi²
   - **Taille du terrain**: 16 184 pi²
   - **Visite 3D**: Oui
   - [Lien](https://duproprio.com/fr/lanaudiere/st-lin-laurentides/bungalow-a-vendre/hab-1031-rue-rivest-1084708)

3. **Bungalow à vendre - Gatineau (Hull)**
   - **Prix**: 644 500 $
   - **Adresse**: 22, rue du Frimas
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 2
   - **Aire habitable**: 1 087 pi²
   - **Taille du terrain**: 5 043 pi²
   - **Visite 3D**: Oui
   - [Lien](https://duproprio.com/fr/outaouais/gatineau-hull/bungalow-a-vendre/hab-22-rue-du-frimas-1084751)

4. **Maison à vendre - La Baie**
   - **Prix**: 549 000 $
   - **Adresse**: 1215, RUE P.-O.-GAGNON
   - **Chambres**: 6
   - **Salles de bain + Salles d’eau**: 3
   - **Aire habitable**: 1 615 pi²
   - **Taille du terrain**: 8 623 pi²
   - **Visite 3D**: Oui
   - [Lien](https://duproprio.com/fr/saguenay-lac-saint-jean/la-baie/maison-a-vendre/hab-1215-rue-p-o-gagnon-1083238)

5. **Chalet à vendre - St-Ferréol-les-Neiges**
   - **Prix**: 399 500 $
   - **Adresse**: 18, rue du Refuge
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable**: 768 pi²
   - **Taille du terrain**: 8 322 pi²
   - **Visite 3D**: Oui
   - [Lien](https://duproprio.com/fr/quebec-rive-nord/st-ferreol-les-neiges/chalet-a-vendre/hab-18-rue-du-refuge-1062693)

6. **Condo à vendre - ND-Des-Prairies**
   - **Prix**: 410 000 $
   - **Adresse**: 3-12, avenue des Champs-Elysées
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 1 + 1
   - **Aire habitable**: 1 139 pi²
   - **Taille du terrain**: 13 165 pi²
   - **Visite 3D**: Oui
   - [Lien](https://duproprio.com/fr/lanaudiere/nd-des-prairies/condo-a-vendre/hab-3-12-avenue-des-champs-elysees-1084998)

7. **Condo à vendre - Joliette**
   - **Prix**: 394 000 $
   - **Adresse**: 43, rue Beaudry Nord

Block 5 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations extraites concernant les propriétés récemment mises en vente à partir du contenu de la page 5 :

1. **Terrain résidentiel à vendre**
   - **Prix** : 449 000 $
   - **Localisation** : Mont-Laurier, Chemin du Tour du Lac des Iles
   - **Taille du terrain** : 2 613 600 pi²

2. **Maison à deux paliers à vendre**
   - **Prix** : 360 000 $
   - **Localisation** : Victoriaville, 6, rue Vidal
   - **Chambres** : 2
   - **Salles de bain** : 2
   - **Aire habitable** : 1 138 pi²
   - **Taille du terrain** : 7 005 pi²

3. **Maison mobile à vendre**
   - **Prix** : 323 500 $
   - **Localisation** : Drummondville (St-Charles-De-Drummond), 1685, rue des Abénakis
   - **Chambres** : 2
   - **Salles de bain** : 1
   - **Aire habitable** : 868 pi²
   - **Taille du terrain** : 9 109 pi²

4. **Bungalow à vendre**
   - **Prix** : 499 000 $
   - **Localisation** : Sherbrooke (St-Élie-d'Orford), 34, rue Hémond
   - **Négociable**
   - **Chambres** : 4
   - **Salles de bain** : 2
   - **Aire habitable** : 1 181 pi²
   - **Taille du terrain** : 35 454 pi²

5. **Chalet à vendre**
   - **Prix** : 831 000 $
   - **Localisation** : St-Boniface, 5380, chemin du Lac-Héroux
   - **Bord de l'eau**
   - **Chambres** : 3
   - **Salles de bain** : 2
   - **Aire habitable** : 1 807 pi²
   - **Taille du terrain** : 15 843 pi²

6. **Bungalow à vendre**
   - **Prix** : 479 000 $
   - **Localisation** : St-Ambroise, 15, 8e chemin du Lac-Ambroise
   - **Bord de l'eau**
   - **Chambres** : 2
   - **Salles de bain** : 2 + 4
   - **Aire habitable** : 803 pi²
   - **Taille du terrain** : 54 861 pi²

7. **Maison 2 étages à vendre**
   - **Prix** : 694 000 $
   - **Localisation** : Granby, 850, rue Marcil
   - **Bi-génération**
   - **Chambres** : 4
   - **Salles de bain** : 3
   - **Aire habitable** : 3 000 pi²
   - **Taille du terrain** : 36 000 pi²

8. **Duplex à vendre**
   - **Prix** : 277 000 $
   - **Localisation** : St-Romuald, 255-265, rue de Lauzon
   - **Agents s'abstenir**
   - **Chambres** : 2
   - **Salles de bain** : 1
   - **Taille du terrain** : 5 031 pi²

9. **Bungalow à vendre**
   - **Prix** : 711 000 $
   - **Localisation** : St-Philippe, 265, rue Lucien
   - **Bord de l'eau**
   - **Chambres** : 4
   - **Salles de bain** : 2
   - **Aire habitable** : 1 670 pi²
   - **Taille du terrain** : 5 225 pi²

10. **Bungalow à vendre**
    - **Prix** : 399 900 $
    - **Localisation** : Henryville, 108, rue de la Lagune
    - **Bord de l'eau**
    - **Chambres** : 2
    - **Salles de bain** : 2
    - **Aire habitable** : 1 101 pi²
    - **Taille du terrain** : 10 108 pi²

11. **Maison 2 étages

Block 6 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici un résumé des propriétés récemment mises en vente extraites du contenu de la page 6 :

1. **Maison en rangée / de ville à vendre - Breakeyville**
   - Prix : 369 000 $
   - Adresse : 1-38, rue des Seigneurs
   - Chambres : 2
   - Salles de bain + Salles d’eau : 1 + 1
   - Aire habitable (s-sol exclu) : 1 461 pi²
   - Taille du terrain : 3 755 pi²
   - [Voir l'annonce](https://duproprio.com/fr/quebec-rive-sud/breakeyville/maison-en-rangee-de-ville-a-vendre/hab-1-38-rue-des-seigneurs-870451)

2. **Jumelé neuf à vendre - Drummondville**
   - Prix : 419 000 $ (taxes incluses)
   - Adresse : 330, rue du Cabernet
   - Chambres : 3
   - Salles de bain + Salles d’eau : 1 + 1
   - Aire habitable (s-sol exclu) : 1 236 pi²
   - Taille du terrain : 4 238 pi²
   - [Voir l'annonce](https://duproprio.com/fr/centre-du-quebec/drummondville-drummondville/jumele-a-vendre/hab-330-rue-du-cabernet-1085234)

3. **Duplex à vendre - Mercier / Hochelaga / Maisonneuve**
   - Prix : 849 000 $
   - Adresse : 6165-6165A-6167, avenue de Carignan
   - Chambres : 7
   - Salles de bain + Salles d’eau : 3
   - Taille du terrain : 3 000 pi²
   - [Voir l'annonce](https://duproprio.com/fr/montreal/mercier-hochelaga-maisonneuve/duplex-a-vendre/hab-6165-6165a-6167-avenue-de-cari-1057554)

4. **Maison en rangée / de ville neuve à vendre - Ste-Clotilde-De-Chateauguay**
   - Prix : 299 000 $
   - Adresse : rue des Colibris
   - Chambres : 2
   - Salles de bain + Salles d’eau : 1 + 1
   - Aire habitable (s-sol exclu) : 1 192 pi²
   - [Voir l'annonce](https://duproprio.com/fr/monteregie-rive-sud-montreal/ste-clotilde-de-chateauguay/maison-en-rangee-de-ville-a-vendre/hab-rue-des-colibris-1075643)

5. **Maison à vendre - Ste-Dorothée**
   - Prix : 799 000 $
   - Adresse : 783, rue Marie-Reine Clermont
   - Chambres : 4
   - Salles de bain + Salles d’eau : 1 + 1
   - Aire habitable (s-sol exclu) : 1 210 pi²
   - Taille du terrain : 4 208 pi²
   - [Voir l'annonce](https://duproprio.com/fr/laval/ste-dorothee/maison-a-vendre/hab-783-rue-marie-reine-clermont-1084335)

6. **Jumelé à vendre - Bois-Des-Filion**
   - Prix : 545 000 $
   - Adresse : 44, 32e Avenue
   - Chambres : 3
   - Salles de bain + Salles d’eau : 2
   - Aire habitable (s-sol exclu) : 1 060 pi²
   - Taille du terrain : 3 121 pi²
   - [Voir l'annonce](https://duproprio.com/fr/laurentides/bois-des-filion/jumele-a-vendre/hab-44-32e-avenue-1084242)

7. **Bungalow à vendre - Drummondville**
   - Prix : 359 900 $ (taxes en sus / terrain inclus)
   - Adresse : 180, rue de l'Aligoté
   - Chambres : 2
   - Salles de bain + Salles d’eau : 1 + 1
   - Aire habitable (s-sol exclu) : 1 088 pi²
   - Taille du terrain : 5 293 pi²
   - [Voir l'annonce](https://duproprio.com/fr/centre-du-queb

Block 7 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations extraites des propriétés récemment mises en vente à partir du contenu de la page 7 :

1. **Jumelé à vendre**
   - **Prix** : 379 800 $
   - **Localisation** : Drummondville (Drummondville)
   - **Adresse** : 2400, rue du Troubadour
   - **Chambres** : 3
   - **Salles de bain** : 2
   - **Aire habitable** : 893 pi²
   - **Taille du terrain** : 4 004 pi²
   - **Visite 3D** : Oui

2. **Maison en rangée / de ville neuve à vendre**
   - **Prix** : 563 751 $
   - **Localisation** : Blainville
   - **Adresse** : rue Carmelle-Boutin
   - **Chambres** : 3
   - **Salles de bain** : 2 + 1
   - **Aire habitable** : 1 597 pi²
   - **Visite 3D** : Oui

3. **Condo à vendre**
   - **Prix** : 357 200 $
   - **Localisation** : Granby
   - **Adresse** : 300-232, rue Principale
   - **Chambres** : 1
   - **Salles de bain** : 1 + 1
   - **Aire habitable** : 1 162 pi²
   - **Taille du terrain** : 1 554 pi²
   - **Visite 3D** : Oui

4. **Bungalow à vendre**
   - **Prix** : 749 000 $
   - **Localisation** : Bromont
   - **Adresse** : 337, rue de l'Artisan
   - **Chambres** : 3
   - **Salles de bain** : 2
   - **Aire habitable** : 1 382 pi²
   - **Taille du terrain** : 7 265 pi²
   - **Visite 3D** : Oui

5. **Maison 2 étages à vendre**
   - **Prix** : 750 000 $
   - **Localisation** : Neufchatel
   - **Adresse** : 9710, avenue du Patrimoine-Mondial
   - **Chambres** : 4
   - **Salles de bain** : 1 + 1
   - **Aire habitable** : 1 831 pi²
   - **Taille du terrain** : 6 295 pi²
   - **Visite libre** : Dimanche 22 septembre
   - **Visite 3D** : Oui

6. **Chalet à vendre**
   - **Prix** : 629 000 $
   - **Localisation** : St-Côme
   - **Adresse** : 61, 199e avenue de la Merci
   - **Chambres** : 3
   - **Salles de bain** : 2
   - **Aire habitable** : 1 065 pi²
   - **Taille du terrain** : 59 497 pi²
   - **Visite 3D** : Oui

7. **Duplex à vendre**
   - **Prix** : 775 000 $
   - **Localisation** : Verdun
   - **Adresse** : 439, rue Galt
   - **Chambres** : 4
   - **Salles de bain** : 2 + 1
   - **Taille du terrain** : 2 369 pi²
   - **Visite 3D** : Oui

8. **Jumelé à vendre**
   - **Prix** : 415 000 $
   - **Localisation** : Trois-Rivières (Trois-Rivières)
   - **Adresse** : 7140, rue Gabrielle-Roy
   - **Chambres** : 3
   - **Salles de bain** : 1 + 1
   - **Aire habitable** : 1 615 pi²
   - **Taille du terrain** : 5 183 pi²
   - **Visite 3D** : Oui

9. **Condo à vendre**
   - **Prix** : 549 000 $
   - **Localisation** : Brossard
   - **Adresse** : 1708-60, rue de l'Éclipse
   - **Chambres** : 2
   - **Salles de bain** : 2

Block 8 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations extraites des propriétés récemment mises en vente à partir du contenu de la page 8 :

1. **Terrain résidentiel à vendre**
   - **Prix** : 115 000 $
   - **Localisation** : Ulverton, 185, chemin Bernier
   - **Description** : Terrain à bâtir dégagé de 1 acre, avec érables matures.
   - **Taille du terrain** : 44 445 pi²
   - **Lien** : [Détails](https://duproprio.com/fr/estrie/ulverton/terrain-a-vendre/hab-185-chemin-bernier-1085004)

2. **Bungalow à vendre**
   - **Prix** : 518 000 $
   - **Localisation** : Alma, 338, avenue Albert-Rousseau
   - **Description** : Bungalow CLÉ EN MAIN sur dalle de béton. Construction de qualité. Deux chambres.
   - **Chambres** : 2
   - **Salles de bain + Salles d’eau** : 1 + 1
   - **Aire habitable (s-sol exclu)** : 1 313 pi²
   - **Taille du terrain** : 7 750 pi²
   - **Lien** : [Détails](https://duproprio.com/fr/saguenay-lac-saint-jean/alma/bungalow-a-vendre/hab-338-avenue-albert-rousseau-1059445)

3. **Maison à vendre**
   - **Prix** : 690 000 $
   - **Localisation** : St-Nicolas, 2100, chemin Filteau
   - **Description** : Charmante maison centenaire entièrement rénovée. Le cachet ancien.
   - **Chambres** : 3
   - **Salles de bain + Salles d’eau** : 2 + 1
   - **Aire habitable (s-sol exclu)** : 1 948 pi²
   - **Taille du terrain** : 104 092 pi²
   - **Lien** : [Détails](https://duproprio.com/fr/quebec-rive-sud/st-nicolas/maison-a-vendre/hab-2100-chemin-filteau-1083305)

4. **Condo à vendre**
   - **Prix** : 314 500 $
   - **Localisation** : Sherbrooke (Jacques-Cartier), 1136, rue Victor-Dupuis
   - **Description** : Une opportunité de vivre dans le calme et la lumière.
   - **Chambres** : 3
   - **Salles de bain + Salles d’eau** : 1
   - **Aire habitable (s-sol exclu)** : 1 200 pi²
   - **Taille du terrain** : 21 527 pi²
   - **Lien** : [Détails](https://duproprio.com/fr/estrie/sherbrooke-jacques-cartier/condo-a-vendre/hab-1136-rue-victor-dupuis-1084377)

5. **Bungalow à vendre**
   - **Prix** : 839 900 $
   - **Localisation** : Mirabel (Domaine-Vert Nord), 17580, 17582 rue Notre-Dame
   - **Description** : Une grande propriété avec une belle véranda 4 saisons, incluant un garage.
   - **Chambres** : 3
   - **Salles de bain + Salles d’eau** : 2
   - **Aire habitable (s-sol exclu)** : 2 247 pi²
   - **Taille du terrain** : 6 020 pi²
   - **Lien** : [Détails](https://duproprio.com/fr/laurentides/mirabel-domaine-vert-nord/bungalow-a-vendre/hab-17580-17582-rue-notre-dame-1084424)

6. **Condo à vendre**
   - **Prix** : 289 900 $
   - **Localisation** : Pointe-Aux-Trembles / Montréal-Est, 125, 31e avenue
   - **Description** : Magnifique condo, situé à proximité de tous les services.
   - **Chambres** : 2
   - **Salles de bain + Salles d’eau** : 1
   - **Aire habitable (s-sol exclu)** : 871 pi²
   - **Lien** : [Détails](https://duproprio.com/fr/montreal/pointe-aux-trembles-montreal-est

Block 9 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations extraites concernant les propriétés récemment mises en vente à partir du contenu de la page 9 :

1. **Bungalow à vendre**
   - **Prix**: 469 000 $
   - **Localisation**: Waterville, 123, boulevard Champêtre
   - **Chambres**: 4
   - **Salles de bain + Salles d’eau**: 3
   - **Aire habitable (s-sol exclu)**: 1 420 pi²
   - **Taille du terrain**: 13 125 pi²

2. **Jumelé à vendre**
   - **Prix**: 343 000 $
   - **Localisation**: Trois-Rivières, 6927, rue Marie-Drouet
   - **Chambres**: 4
   - **Salles de bain + Salles d’eau**: 2 + 1
   - **Aire habitable (s-sol exclu)**: 1 429 pi²
   - **Taille du terrain**: 4 129 pi²
   - **Caractéristique**: Sans voisins arrière, Visite 3D

3. **Maison à vendre**
   - **Prix**: 499 000 $
   - **Localisation**: Rawdon, 4741, route 125
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 2 + 1
   - **Aire habitable (s-sol exclu)**: 1 350 pi²
   - **Taille du terrain**: 60 000 pi²
   - **Caractéristique**: Sans voisins arrière, Visite 3D

4. **Chalet à vendre**
   - **Prix**: 859 900 $
   - **Localisation**: Val-Des-Bois, 103, chemin de la Rivière
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 3
   - **Aire habitable (s-sol exclu)**: 1 400 pi²
   - **Taille du terrain**: 65 904 pi²
   - **Caractéristique**: Magnifique chalet au bord de l'eau, Visite 3D

5. **Terrain commercial à vendre**
   - **Prix**: 559 000 $
   - **Localisation**: Huntingdon, route 202
   - **Taille du terrain**: 37 500 pi²
   - **Caractéristique**: Terrain commercial prêt à construire

6. **Condo à vendre**
   - **Prix**: 335 000 $
   - **Localisation**: Chomedey, 1012-2555, avenue du Havre des Îles
   - **Chambres**: 2
   - **Salles de bain + Salles d’eau**: 1
   - **Aire habitable (s-sol exclu)**: 837 pi²
   - **Taille du terrain**: 782 pi²
   - **Caractéristique**: Avec garage, Visite 3D

7. **Jumelé à vendre**
   - **Prix**: 349 000 $
   - **Localisation**: Ste-Brigitte-De-Laval, 13, rue Dawson
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 2 + 1
   - **Taille du terrain**: 3 547 pi²

8. **Duplex à vendre**
   - **Prix**: 529 000 $
   - **Localisation**: Sherbrooke (Brompton), 20-22, rue du Couvent
   - **Chambres**: 4
   - **Salles de bain + Salles d’eau**: 2 + 1
   - **Taille du terrain**: 5 547 pi²
   - **Caractéristique**: Construction 2023, Visite 3D

9. **Condo à vendre**
   - **Prix**: 519 000 $
   - **Localisation**: Ville-Marie (Centre-Ville et Vieux-Montréal), 2809, rue Hochelaga
   - **Chambres**: 3
   - **Salles de bain + Salles d’eau**: 1 + 1
   - **Aire habitable (s-sol exclu)**: 1 839 pi²
   - **Taille du terrain**: 1 614 pi²

10. **Terrain résidentiel

Block 10 (Model: gpt-4o-mini, Max Tokens: 1000):

Output: Voici les informations des propriétés récemment mises en vente extraites du contenu de la page 10 :

1. **Mandeville**
   - **Type**: Terrain résidentiel
   - **Prix**: 84 999 $
   - **Adresse**: 705, 3e rang de Peterborough Sud
   - **Caractéristiques**: Bord de l'eau, taille du terrain 43 097 pi²
   - **Lien**: [Détails](https://duproprio.com/fr/lanaudiere/mandeville/terrain-a-vendre/hab-705-3e-rang-de-peterborough-su-1084972)

2. **St-Jean-Baptiste**
   - **Type**: Bungalow
   - **Prix**: 1 200 000 $
   - **Adresse**: 3030, rue Noiseux
   - **Caractéristiques**: Avec garage, 4 chambres, 2 salles de bain + salles d’eau, aire habitable 1 800 pi², taille du terrain 60 000 pi²
   - **Lien**: [Détails](https://duproprio.com/fr/monteregie-rive-sud-montreal/st-jean-baptiste/bungalow-a-vendre/hab-3030-rue-noiseux-912548)

3. **St-Eustache**
   - **Type**: Maison 2 étages
   - **Prix**: 759 000 $
   - **Adresse**: 318, boulevard Louis-Joseph-Rodrigue
   - **Caractéristiques**: Prise de possession rapide possible, 4 chambres, 2 salles de bain + 1 salle d’eau, aire habitable 1 800 pi², taille du terrain 4 585 pi²
   - **Lien**: [Détails](https://duproprio.com/fr/laurentides/st-eustache/maison-a-vendre/hab-318-boulevard-louis-joseph-rod-1083706)

4. **Drummondville**
   - **Type**: Triplex
   - **Prix**: 560 000 $
   - **Adresse**: 930, 107e Avenue
   - **Caractéristiques**: Vendu au prix de l'évaluation, 3 chambres, 1 salle de bain + salles d’eau, taille du terrain 5 000 pi²
   - **Lien**: [Détails](https://duproprio.com/fr/centre-du-quebec/drummondville-drummondville/triplex-a-vendre/hab-930-107e-avenue-1083142)

5. **Lévis**
   - **Type**: Condo
   - **Prix**: 244 000 $
   - **Adresse**: 1479, rue du Quotidien
   - **Caractéristiques**: Visite 3D, 2 chambres, 1 salle de bain + salle d’eau, aire habitable 1 032 pi²
   - **Lien**: [Détails](https://duproprio.com/fr/quebec-rive-sud/levis/condo-a-vendre/hab-1479-rue-du-quotidien-1084185)

6. **Ville-Marie (Centre-Ville et Vieux-Montréal)**
   - **Type**: Condo
   - **Prix**: 342 000 $
   - **Adresse**: 1084, rue Saint-Timothée
   - **Caractéristiques**: Entièrement rénové, 1 chambre, 1 salle de bain + salle d’eau, aire habitable 630 pi², taille du terrain 263 pi²
   - **Lien**: [Détails](https://duproprio.com/fr/montreal/ville-marie-centre-ville-et-vieux-montreal/condo-a-vendre/hab-1084-rue-saint-timothee-1024819)

7. **Contrecoeur**
   - **Type**: Maison 2 étages
   - **Prix**: 549 000 $
   - **Adresse**: 1291, rue Laurent-Hubert
   - **Caractéristiques**: Visite 3D, 3 chambres, 1 salle de bain + 1 salle d’eau, aire habitable 1 312 pi², taille du terrain 4 068 pi²
   - **Lien**: [Détails](https://duproprio.com/fr/monteregie-rive-sud-montreal/contrecoeur/maison-a-vendre/hab-1291-rue-laurent-hubert-1083682)

8. **Boisch

2024-09-18 10:58:49,735 - INFO - External data for Step 2, Block 1: ...
2024-09-18 10:58:49,736 - INFO - Processing Step 2, Block 1
2024-09-18 10:58:49,736 - INFO - Prompt: Voici les informations extraites des propriétés récemment mises en vente :

1. **Propriété à Drummon...
Step 2 Results:
Block 1 (Model: gpt-4o-mini, Max Tokens: 4000):

Output: Voici un tableau récapitulatif des propriétés récemment mises en vente :

| **Localisation**                      | **Type**                             | **Prix**      | **Adresse**                                   | **Chambres** | **Salles de bain + Salles d’eau** | **Aire habitable (s-sol exclu)** | **Taille du terrain**     | **Visite 3D** | **Lien**                                                                 |
|--------------------------------------|-------------------------------------|---------------|-----------------------------------------------|--------------|-----------------------------------|----------------------------------|----------------------------|----------------|-------------------------------------------------------------------------|
| Drummondville                        | Maison 2 étages                    | 820 000 $     | 150, rue Joly                                | 5            | 2 + 1                             | 2 108 pi²                        | 8 607 pi²                | Oui            |                                                                         |
| St-Elzéar-de-Beauce                 | Jumelé                             | 295 000 $     | 735, rue des Rosiers                         | 3            | 2 + 1                             | 832 pi²                          | 5 202 pi²                | Oui            |                                                                         |
| Terrebonne                           | Maison mobile                      | 180 000 $     | 8, rue de la Châtelaine                     | 2            | 1                                 | 840 pi²                          | 3 575 pi²                | Oui            |                                                                         |
| Gatineau                             | Maison 2 étages                    | 889 000 $     | 318, boulevard des Trembles                  | 3            | 3 + 1                             | 2 277 pi²                        | 5 304 pi²                | Oui            |                                                                         |
| St-Lin-Laurentides                  | Bungalow                           | 474 900 $     | 86, rue Xavier                               | 4            | 1 + 1                             | 1 200 pi²                        | 16 500 pi²               | Oui            |                                                                         |
| Val-Des-Monts                        | Bungalow Surélevé                  | 445 000 $     | 185, Chemin des Trois Lacs                   | 4            | 1 + 1                             | 1 000 pi²                        | 96 410 pi²               | Oui            |                                                                         |
| St-Alphonse-Rodriguez               | Bungalow                           | 140 000 $     | 98, JOSÉE                                    | 1            | 1                                 | 629 pi²                          | 7 500 pi²                | Oui            |                                                                         |
| Le Plateau-Mont-Royal                | Condo                              | 599 000 $     | 4454, avenue de Lorimier                     | 2            | 1                                 | 1 150 pi²                        | -                          | Oui            |                                                                         |
| St-Nicolas                           | Jumelé                             | 485 000 $     | 1113, rue de Grenoble                        | 3            | 2 + 1                             | 1 560 pi²                        | 4 726 pi²                | -              |                                                                         |
| Brossard                             | Condo                              | 850 000 $     | 1715-5905, boulevard du Quartier             | 3            | 3                                 | 1 395 pi²                        | -                          | -              |                                                                         |
| Brossard                             | Maison                             | 885 000 $     | 1756, croissant Turgeon                      | 4            | 1 + 2                             | 1 251 pi²                        | 10 168 pi²               | -              |                                                                         |
| Auteuil                              | Maison                             | 939 000 $     | 85, Corriveau                                | 3            | 2                                 | 1 805 pi²                        | 25 510 pi²               | -              |                                                                         |
| St-Lin-Laurentides                  | Maison modulaire                   | 410 000 $     | 739, rue Auger                               | 2            | 1                                 | 1 472 pi²                        | 11 600 pi²               | -              |                                                                         |
| St-Pie                               | Bungalow                           | 499 000 $     | 86, Rue Ernest-Despars                      | 3            | 2 + 1                             | 1 064 pi²                        | 7 567 pi²                | -              |                                                                         |
| La Malbaie                           | Maison                             | 422 000 $     | 785, boulevard Malcolm-Fraser                | 6            | 2 + 1                             | 3 100 pi²                        | 16 600 pi²               | -              |                                                                         |
| Dunham                               | Bungalow                           | 749 900 $     | 198, rue Guy                                 | 2            | 1                                 | 1 810 pi²                        | 26 046 pi²               | -              |                                                                         |
| Mercier / Hochelaga / Maisonneuve   | Triplex                            | 1 380 000 $   | 4489, rue Dickson                            | 9            | 4                                 | -                                | 2 196 pi²                | -              |                                                                         |
| St-Rose-De-Watford                  | Terrain résidentiel                | 130 000 $     | 159, chemin du Lac Algonquin                | -            | -                                 | -                                | 77 000 pi²               | -              |                                                                         |
| St-Bruno-De-Montarville             | Bungalow                           | 764 500 $     | 1050, rue de la Madeleine                   | 4            | 1 + 1                             | 1 142 pi²                        | 7 480 pi²                | -              |                                                                         |
| St-Bernard                           | Jumelé                             | 280 000 $     | 333, RUE LEMAY                              | 3            | 2 + 1                             | 768 pi²                          | 4 340 pi²                | -              |                                                                         |
| Bromont                              | Terrain résidentiel                | 239 000 $     | 77, carré des Pionnières                    | -            | -                                 | -                                | 6 134 pi²                | -              |                                                                         |
| St-Michel-Des-Saints                | Terrain résidentiel                | 150 000 $     | 41, chemin Lamarche                         | -            | -                                 | -                                | 70 493 pi²               | -              |                                                                         |
| Otter Lake                           | Bungalow                           | 389 000 $     | 24, Rue 2                                   | 2            | 1                                 | 1 024 pi²                        | 33 637 pi²               | -              |                                                                         |
| Lac Frontière                       | Bungalow                           | 92 500 $      | 9, rue du Lac Nord                          | 2            | 1                                 | 841 pi²                          | 7 199 pi²                | -              |                                                                         |
| Beauport                             | Jumelé                             | 395 000 $     | 207, rue Laurelou                           | 3            | 1 + 1                             | 1 431 pi²                        | 4 858 pi²                | -              |                                                                         |
| Mirabel (St-Janvier)                | Bungalow                           | 569 900 $     | 13530-13532, rue du Blizzard                | 2            | 1                                 | 1 000 pi²                        | -                          | -              |                                                                         |
| Le Plateau-Mont-Royal                | Condo                              | 599 000 $     | 4423, rue Messier                           | 2            | 1                                 | 1 011 pi²                        | 1 210 pi²                | Oui            | [Lien](https://duproprio.com/fr/montreal/le-plateau-mont-royal/condo-a-vendre/hab-4423-rue-messier-1079137) |
| St-Lin-Laurentides                  | Bungalow                           | 519 500 $     | 1031, rue Rivest                            | 2            | 1 + 1                             | 784 pi²                          | 16 184 pi²               | Oui            | [Lien](https://duproprio.com/fr/lanaudiere/st-lin-laurentides/bungalow-a-vendre/hab-1031-rue-rivest-1084708) |
| Gatineau (Hull)                     | Bungalow                           | 644 500 $     | 22, rue du Frimas                           | 2            | 2                                 | 1 087 pi²                        | 5 043 pi²                | Oui            | [Lien](https://duproprio.com/fr/outaouais/gatineau-hull/bungalow-a-vendre/hab-22-rue-du-frimas-1084751) |
| La Baie                              | Maison                             | 549 000 $     | 1215, RUE P.-O.-GAGNON                     | 6            | 3                                 | 1 615 pi²                        | 8 623 pi²                | Oui            | [Lien](https://duproprio.com/fr/saguenay-lac-saint-jean/la-baie/maison-a-vendre/hab-1215-rue-p-o-gagnon-1083238) |
| St-Ferréol-les-Neiges               | Chalet                             | 399 500 $     | 18, rue du Refuge                           | 2            | 1                                 | 768 pi²                          | 8 322 pi²                | Oui            | [Lien](https://duproprio.com/fr/quebec-rive-nord/st-ferreol-les-neiges/chalet-a-vendre/hab-18-rue-du-refuge-1062693) |
| ND-Des-Prairies                     | Condo                              | 410 000 $     | 3-12, avenue des Champs-Elysées            | 3            | 1 + 1                             | 1 139 pi²                        | 13 165 pi²               | Oui            | [Lien](https://duproprio.com/fr/lanaudiere/nd-des-prairies/condo-a-vendre/hab-3-12-avenue-des-champs-elysees-1084998) |
| Sherbrooke (Jacques-Cartier)       | Condo                              | 314 500 $     | 1136, rue Victor-Dupuis                    | 3            | 1                                 | 1 200 pi²                        | 21 527 pi²               | Oui            | [Lien](https://duproprio.com/fr/estrie/sherbrooke-jacques-cartier/condo-a-vendre/hab-1136-rue-victor-dupuis-1084377) |
| Mirabel (Domaine-Vert Nord)         | Bungalow                           | 839 900 $     | 17580, 17582 rue Notre-Dame                 | 3            | 2                                 | 2 247 pi²                        | 6 020 pi²                | Oui            | [Lien](https://duproprio.com/fr/laurentides/mirabel-domaine-vert-nord/bungalow-a-vendre/hab-17580-17582-rue-notre-dame-1084424) |
| Mandeville                           | Terrain résidentiel                | 84 999 $      | 705, 3e rang de Peterborough Sud            | -            | -                                 | -                                | 43 097 pi²               | -              | [Lien](https://duproprio.com/fr/lanaudiere/mandeville/terrain-a-vendre/hab-705-3e-rang-de-peterborough-su-1084972) |
| St-Jean-Baptiste                    | Bungalow                           | 1 200 000 $   | 3030, rue Noiseux                           | 4            | 2 + 1                             | 1 800 pi²                        | 60 000 pi²               | -              | [Lien](https://duproprio.com/fr/monteregie-rive-sud-montreal/st-jean-baptiste/bungalow-a-vendre/hab-3030-rue-noiseux-912548) |
| St-Eustache                          | Maison 2 étages                    | 759 000 $     | 318, boulevard Louis-Joseph-Rodrigue       | 4            | 2 + 1                             | 1 800 pi²                        | 4 585 pi²                | -              | [Lien](https://duproprio.com/fr/laurentides/st-eustache/maison-a-vendre/hab-318-boulevard-louis-joseph-rod-1083706) |
| Drummondville                        | Triplex                            | 560 000 $     | 930, 107e Avenue                            | 3            | 1 + 1                             | -                                | 5 000 pi²                | -              | [Lien](https://duproprio.com/fr/centre-du-quebec/drummondville-drummondville/triplex-a-vendre/hab-930-107e-avenue-1083142) |
| Lévis                                | Condo                              | 244 000 $     | 1479, rue du Quotidien                     | 2            | 1 + 1                             | 1 032 pi²                        | -                          | Oui            | [Lien](https://duproprio.com/fr/quebec-rive-sud/levis/condo-a-vendre/hab-1479-rue-du-quotidien-1084185) |
| Ville-Marie (Centre-Ville et Vieux-Montréal) | Condo         | 342 000 $     | 1084, rue Saint-Timothée                   | 1            | 1 + 1                             | 630 pi²                          | 263 pi²                  | -              | [Lien](https://duproprio.com/fr/montreal/ville-marie-centre-ville-et-vieux-montreal/condo-a-vendre/hab-1084-rue-saint-timothee-1024819) |
| Contrecoeur                          | Maison 2 étages                    | 549 000 $     | 1291, rue Laurent-Hubert                    | 3            | 1 + 1                             | 1 312 pi²                        | 4 068 pi²                | Oui            | [Lien](https://duproprio.com/fr/monteregie-rive-sud-montreal/contrecoeur/maison-a-vendre/hab-1291-rue-laurent-hubert-1083682) |

Ce tableau résume toutes les informations des propriétés mentionnées, incluant le type, le prix, l'adresse, le nombre de chambres, le nombre de salles de bain, l'aire habitable, la taille du terrain, la présence d'une visite 3D, et les liens pertinents lorsque disponibles.

2024-09-18 10:59:24,276 - INFO - External data for Step 3, Block 1: ...
2024-09-18 10:59:24,276 - INFO - Processing Step 3, Block 1
2024-09-18 10:59:24,276 - INFO - Prompt: Voici un tableau récapitulatif des propriétés récemment mises en vente :

| **Localisation**        ...
2024-09-18 10:59:24,277 - INFO - External data for Step 3, Block 2: ...
2024-09-18 10:59:24,277 - INFO - Processing Step 3, Block 2
2024-09-18 10:59:24,278 - INFO - Prompt: Voici un tableau récapitulatif des propriétés récemment mises en vente :

| **Localisation**        ...
2024-09-18 10:59:24,278 - INFO - External data for Step 3, Block 3: ...
2024-09-18 10:59:24,278 - INFO - Processing Step 3, Block 3
2024-09-18 10:59:24,279 - INFO - Prompt: Voici un tableau récapitulatif des propriétés récemment mises en vente :

| **Localisation**        ...
2024-09-18 10:59:24,279 - INFO - External data for Step 3, Block 4: ...
2024-09-18 10:59:24,279 - INFO - Processing Step 3, Block 4
2024-09-18 10:59:24,280 - INFO - Prompt: Voici un tableau récapitulatif des propriétés récemment mises en vente :

| **Localisation**        ...
Step 3 Results:
Block 1 (Model: gpt-4o-mini, Max Tokens: 4000):

Output: Pour calculer le prix moyen des propriétés listées dans le tableau, nous allons d'abord additionner tous les prix et ensuite diviser par le nombre total de propriétés.

Voici les prix des propriétés :

- 820 000
- 295 000
- 180 000
- 889 000
- 474 900
- 445 000
- 140 000
- 599 000
- 485 000
- 850 000
- 885 000
- 939 000
- 410 000
- 499 000
- 422 000
- 749 900
- 1 380 000
- 130 000
- 764 500
- 280 000
- 239 000
- 150 000
- 389 000
- 92 500
- 395 000
- 569 900
- 599 000
- 410 000
- 314 500
- 839 900
- 84 999
- 1 200 000
- 759 000
- 560 000
- 244 000
- 342 000
- 549 000

Additionnons tous ces prix :

\[
820\,000 + 295\,000 + 180\,000 + 889\,000 + 474\,900 + 445\,000 + 140\,000 + 599\,000 + 485\,000 + 850\,000 + 885\,000 + 939\,000 + 410\,000 + 499\,000 + 422\,000 + 749\,900 + 1\,380\,000 + 130\,000 + 764\,500 + 280\,000 + 239\,000 + 150\,000 + 389\,000 + 92\,500 + 395\,000 + 569\,900 + 599\,000 + 410\,000 + 314\,500 + 839\,900 + 84\,999 + 1\,200\,000 + 759\,000 + 560\,000 + 244\,000 + 342\,000 + 549\,000 =  13\,637\,799
\]

Il y a 36 propriétés dans le tableau. 

Pour trouver le prix moyen :

\[
\text{Prix moyen} = \frac{\text{Total des prix}}{\text{Nombre de propriétés}} = \frac{13\,637\,799}{36} \approx 379\,382.75
\]

Donc, le prix moyen des propriétés est d'environ **379 382,75 $**.

Block 2 (Model: gpt-4o-mini, Max Tokens: 4000):

Output: Pour calculer le prix moyen des propriétés de type condo dans le tableau, nous allons d'abord extraire les prix des condos, puis effectuer la moyenne.

Voici les prix des condos :

1. 599 000 $
2. 850 000 $
3. 599 000 $
4. 410 000 $
5. 314 500 $
6. 244 000 $
7. 342 000 $

Maintenant, additionnons ces prix :

\[
599000 + 850000 + 599000 + 410000 + 314500 + 244000 + 342000 = 3,598,500
\]

Ensuite, nous divisons cette somme par le nombre de condos :

\[
\text{Prix moyen} = \frac{3,598,500}{7} \approx 514,071.43
\]

Le prix moyen pour toutes les propriétés de type condo est d'environ **514,071.43 $**.

Block 3 (Model: gpt-4o-mini, Max Tokens: 4000):

Output: Pour calculer le prix moyen des propriétés de type "bungalow", nous allons d'abord extraire les prix des bungalows mentionnés dans le tableau :

1. **St-Lin-Laurentides** : 474 900 $
2. **Val-Des-Monts** : 445 000 $
3. **St-Alphonse-Rodriguez** : 140 000 $
4. **St-Lin-Laurentides** : 519 500 $
5. **St-Pie** : 499 000 $
6. **Dunham** : 749 900 $
7. **Otter Lake** : 389 000 $
8. **Lac Frontière** : 92 500 $
9. **Mirabel (St-Janvier)** : 569 900 $
10. **Gatineau (Hull)** : 644 500 $
11. **La Baie** : 549 000 $
12. **St-Ferréol-les-Neiges** : 399 500 $
13. **Saint-Jean-Baptiste** : 1 200 000 $
14. **St-Eustache** : 759 000 $
15. **Drummondville** : 560 000 $

Additionnons ces prix :

\[
474\,900 + 445\,000 + 140\,000 + 519\,500 + 499\,000 + 749\,900 + 389\,000 + 92\,500 + 569\,900 + 644\,500 + 549\,000 + 399\,500 + 1\,200\,000 + 759\,000 + 560\,000 = 7\,625\,700
\]

Il y a 15 bungalows au total. 

Pour obtenir le prix moyen, nous divisons la somme par le nombre de bungalows :

\[
\text{Prix moyen} = \frac{7\,625\,700}{15} \approx 508\,380
\]

Le prix moyen des propriétés de type bungalow est donc d'environ **508 380 $**.

Block 4 (Model: gpt-4o-mini, Max Tokens: 4000):

Output: Pour calculer le prix moyen des propriétés de type "maison 2 étages", nous allons d'abord identifier les propriétés correspondantes dans le tableau et ensuite calculer la moyenne.

Les maisons 2 étages dans le tableau sont :

1. Drummondville - 820 000 $
2. Gatineau - 889 000 $
3. St-Eustache - 759 000 $
4. Contrecoeur - 549 000 $

Total des prix :
820 000 + 889 000 + 759 000 + 549 000 = 3 017 000 $

Nombre de maisons 2 étages : 4

Prix moyen = Total des prix / Nombre de maisons
Prix moyen = 3 017 000 $ / 4 = 754 250 $

Le prix moyen pour les propriétés de type maison 2 étages est **754 250 $**.