Error in Viewing Exchange File created from 3d View in Revit

Error in Viewing Exchange File created from 3d View in Revit

hardik_malik9ZCEX
Participant Participant
182 Views
0 Replies
Message 1 of 1

Error in Viewing Exchange File created from 3d View in Revit

hardik_malik9ZCEX
Participant
Participant

Hello,

I am creating a web application using the Autodesk APIs, that creates an exchange file from the 3D view, and then we can check that model, according to the parameters specified by us. But, I am facing an issue where, after I have created the exchange file from the 3D view in Revit, I am unable to view it. For reference to how I have created the exchange file, I have shared the code snippet below, or you can see the process through https://forums.autodesk.com/t5/data-exchange-forum/create-exchange-file-from-3d-view-in-revit-error/... .

 

i) The result that I am getting after clicking create exchange is:

{'success': True, 'data': {'data': {'createExchange': {'exchange': {'id': 'ZXhjfjBhNUl4THIzSnNlY1FuSnlZa3pwYldfTDJDfjcwODc5N2E0LWQ2N2UtMzZlZS05OGE3LTJkN2QxZjIzMjg0NA', 'name': '5TH STOREY_Exchange', 'alternativeIdentifiers': {'fileUrn': 'urn:adsk.wipprod:dm.lineage:KDkTkAZ0TbSbcu4zVFmFvQ', 'fileVersionUrn': 'urn:adsk.wipprod:fs.file:vf.KDkTkAZ0TbSbcu4zVFmFvQ?version=1'}}}}}, 'exchange_id': 'ZXhjfjBhNUl4THIzSnNlY1FuSnlZa3pwYldfTDJDfjcwODc5N2E0LWQ2N2UtMzZlZS05OGE3LTJkN2QxZjIzMjg0NA', 'exchange_name': '5TH STOREY_Exchange', 'urn': 'dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLktEa1RrQVowVGJTYmN1NHpWRm1GdlE_dmVyc2lvbj0x', 'raw_urn': 'urn:adsk.wipprod:fs.file:vf.KDkTkAZ0TbSbcu4zVFmFvQ?version=1'}
================================================================================
[EXCHANGE CREATION RESULT]
Exchange ID: ZXhjfjBhNUl4THIzSnNlY1FuSnlZa3pwYldfTDJDfjcwODc5N2E0LWQ2N2UtMzZlZS05OGE3LTJkN2QxZjIzMjg0NA
Raw URN: urn:adsk.wipprod:fs.file:vf.KDkTkAZ0TbSbcu4zVFmFvQ?version=1
URL-safe Base64-encoded URN: dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLktEa1RrQVowVGJTYmN1NHpWRm1GdlE_dmVyc2lvbj0x
================================================================================
127.0.0.1 - - [01/Dec/2025 11:09:04] "POST /api/create_exchange HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 11:09:04] "OPTIONS /api/FolderContent?id=Zm9sZH5iLjNlYTAyZWQxLWQwMzAtNGE0Ni05NjNiLTgwMTVmMTEzYTEwY35iLjk5YjVlMDA1LWQyZWItNDk4YS1iZjU1LTAxZWQ5MDkxMTRhZn51cm46YWRzay53aXBwcm9kOmZzLmZvbGRlcjpjby5JR0g3RVlreFFJUzBJY3VWbUNtUzdR HTTP/1.1" 200 -
Using token: eyJhbGciOiJSUzI1NiIsImtpZCI6IlZiakZvUzhQU3lYODQyMV... for folder: Zm9sZH5iLjNlYTAyZWQxLWQwMzAtNGE0Ni05NjNiLTgwMTVmMTEzYTEwY35iLjk5YjVlMDA1LWQyZWItNDk4YS1iZjU1LTAxZWQ5MDkxMTRhZn51cm46YWRzay53aXBwcm9kOmZzLmZvbGRlcjpjby5JR0g3RVlreFFJUzBJY3VWbUNtUzdR
Sending request to https://developer.api.autodesk.com/dataexchange/2023-05/graphql for folder Zm9sZH5iLjNlYTAyZWQxLWQwMzAtNGE0Ni05NjNiLTgwMTVmMTEzYTEwY35iLjk5YjVlMDA1LWQyZWItNDk4YS1iZjU1LTAxZWQ5MDkxMTRhZn51cm46YWRzay53aXBwcm9kOmZzLmZvbGRlcjpjby5JR0g3RVlreFFJUzBJY3VWbUNtUzdR
Response status: 200
Processed content: {
"folders": [],
"exchanges": [
{
"id": "ZXhjfjBhNUl4THIzSnNlY1FuSnlZa3pwYldfTDJDfjcwODc5N2E0LWQ2N2UtMzZlZS05OGE3LTJkN2QxZjIzMjg0NA",
"name": "5TH STOREY_Exchange",
"alternativeIdentifiers": {
"fileUrn": "urn:adsk.wipprod:dm.lineage:KDkTkAZ0TbSbcu4zVFmFvQ",
"fileVersionUrn": "urn:adsk.wipprod:fs.file:vf.KDkTkAZ0TbSbcu4zVFmFvQ?version=1"
},
"__typename": "Exchange"
}

 

ii) Result after clicking on the created exchange, in order to view it:

127.0.0.1 - - [01/Dec/2025 11:09:07] "GET /api/FolderContent?id=Zm9sZH5iLjNlYTAyZWQxLWQwMzAtNGE0Ni05NjNiLTgwMTVmMTEzYTEwY35iLjk5YjVlMDA1LWQyZWItNDk4YS1iZjU1LTAxZWQ5MDkxMTRhZn51cm46YWRzay53aXBwcm9kOmZzLmZvbGRlcjpjby5JR0g3RVlreFFJUzBJY3VWbUNtUzdR HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 11:34:02] "GET /api/config HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 11:34:02] "OPTIONS /api/get_exchange_urn HTTP/1.1" 200 -
[GET EXCHANGE URN] Request received for Exchange ID: ZXhjfjBhNUl4THIzSnNlY1FuSnlZa3pwYldfTDJDfjcwODc5N2E0LWQ2N2UtMzZlZS05OGE3LTJkN2QxZjIzMjg0NA
================================================================================
[EXCHANGE URN QUERY] Exchange ID: ZXhjfjBhNUl4THIzSnNlY1FuSnlZa3pwYldfTDJDfjcwODc5N2E0LWQ2N2UtMzZlZS05OGE3LTJkN2QxZjIzMjg0NA
data from the response ********** {'data': {'exchange': {'alternativeIdentifiers': {'fileUrn': 'urn:adsk.wipprod:dm.lineage:KDkTkAZ0TbSbcu4zVFmFvQ', 'fileVersionUrn': 'urn:adsk.wipprod:fs.file:vf.KDkTkAZ0TbSbcu4zVFmFvQ?version=1'}}}}
fileVersionUrn ********** urn:adsk.wipprod:fs.file:vf.KDkTkAZ0TbSbcu4zVFmFvQ?version=1
fileUrn ********** urn:adsk.wipprod:dm.lineage:KDkTkAZ0TbSbcu4zVFmFvQ
[URN INFO] Raw URN: urn:adsk.wipprod:dm.lineage:KDkTkAZ0TbSbcu4zVFmFvQ
[URN INFO] URL-safe Base64-encoded URN: dXJuOmFkc2sud2lwcHJvZDpkbS5saW5lYWdlOktEa1RrQVowVGJTYmN1NHpWRm1GdlE
================================================================================
[GET EXCHANGE URN] Successfully retrieved URN for Exchange ID: ZXhjfjBhNUl4THIzSnNlY1FuSnlZa3pwYldfTDJDfjcwODc5N2E0LWQ2N2UtMzZlZS05OGE3LTJkN2QxZjIzMjg0NA
[GET EXCHANGE URN] URN: dXJuOmFkc2sud2lwcHJvZDpkbS5saW5lYWdlOktEa1RrQVowVGJTYmN1NHpWRm1GdlE
127.0.0.1 - - [01/Dec/2025 11:34:06] "POST /api/get_exchange_urn HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 11:34:06] "OPTIONS /api/conversation/start HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 11:34:08] "POST /api/conversation/start HTTP/1.1" 200 -

 

iii) The exchange screen shows:

hardik_malik9ZCEX_0-1764569829381.png

 

iv) The code that I am using for these are:

1) Exchange creation from file (model_derivative.py):

def create_exchange_from_file(endpoint_url, project_id, item_id, folder_id, view_name, exchange_name, aps_token):
    """
    Create an exchange from a Revit file using GraphQL IDs (not URNs):
    1. Get folder data using getFolderById to ensure we have the correct GraphQL folder ID
    2. Verify the source file item exists in the folder (item_id should be GraphQL ID from folder.items.results[].id)
    3. Use folder GraphQL ID and item GraphQL ID in createExchange mutation
    
    According to Autodesk documentation:
    - sourceFileId: The GraphQL item ID from folder.items.results[].id (NOT a URN)
    - targetFolderId: The GraphQL folder ID from folder.id (NOT a URN)
    """
    try:
        # Step 1: Get folder data to extract and verify GraphQL IDs
        print(f"[EXCHANGE] Getting folder data for folder_id: {folder_id}")
        folder_result = get_folder_by_id_graphql(endpoint_url, folder_id, aps_token)
        
        if not folder_result.get("success"):
            error_type = folder_result.get("error", "UNKNOWN_ERROR")
            error_message = folder_result.get("message", "Failed to get folder information")
            
            # Provide user-friendly messages for folder errors
            if error_type == "NO_FOLDER_DATA":
                user_message = "The folder could not be found. Please select a valid folder and try again."
            elif error_type == "GRAPHQL_ERROR":
                user_message = "Unable to access folder information. Please check your permissions and try again."
            else:
                user_message = error_message
            
            return {
                "error": error_type,
                "message": error_message,
                "user_message": user_message,
                "details": folder_result.get("details")
            }
        
        # Extract GraphQL folder ID (this is the targetFolderId)
        graphql_folder_id = folder_result["folder_id"]
        print(f"[SUCCESS] GraphQL Folder ID: {graphql_folder_id}")
        
        # Step 2: Verify the source file item exists in the folder
        # The item_id passed should be a GraphQL ID from folder.items.results[].id
        items = folder_result.get("items", [])
        print(f"[INFO] Found {len(items)} items in folder")
        
        # Check if item_id matches any item in the folder
        source_file_graphql_id = None
        for item in items:
            if item.get("id") == item_id:
                source_file_graphql_id = item["id"]
                print(f"[SUCCESS] Found source file in folder: {item.get('name')} (ID: {source_file_graphql_id})")
                break
        
        if not source_file_graphql_id:
            # If not found, but item_id doesn't start with "urn:", assume it's a GraphQL ID
            # (might be from a different folder or parent folder)
            if item_id and not item_id.startswith("urn:"):
                source_file_graphql_id = item_id
                print(f"[INFO] Using item_id directly as GraphQL ID: {source_file_graphql_id}")
                print(f"[WARNING] Item not found in folder items list, but using provided ID")
            else:
                return {
                    "error": "ITEM_NOT_FOUND",
                    "message": "Source file item not found in folder",
                    "user_message": "The source file could not be found in the selected folder. Please ensure:\n1. The file exists in the target folder\n2. You're using the correct file from the folder"
                }
        
        print(f"[SUCCESS] Using Source File GraphQL ID: {source_file_graphql_id}")

        # Step 3: Prepare GraphQL mutation with GraphQL IDs (not URNs)
        mutation = """
        mutation createExchangeFromRevit($source_file_id: String!, $folder_id: String!, $view_name: String!, $target_name: String!) {
          createExchange(
            input: {
              viewName: $view_name
              source: { fileId: $source_file_id }
              target: { name: $target_name, folderId: $folder_id }
            }
          ) {
            exchange {
                    id
                    name
                    alternativeIdentifiers {
                        fileUrn
                        fileVersionUrn
                    }
            }
        }
    }
    """
    
        variables = {
            "source_file_id": source_file_graphql_id,  # GraphQL item ID, not URN
            "folder_id": graphql_folder_id,  # GraphQL folder ID, not URN
            "view_name": view_name,
            "target_name": exchange_name
        }

        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {aps_token}"
        }

        print("[PAYLOAD] FINAL PAYLOAD (Using GraphQL IDs):")
        print(f"  viewName: {view_name}")
        print(f"  sourceFileId (GraphQL ID): {source_file_graphql_id}")
        print(f"  targetExchangeName: {exchange_name}")
        print(f"  targetFolderId (GraphQL ID): {graphql_folder_id}")

        # Step 4: Call Data Exchange GraphQL endpoint
        response = requests.post(endpoint_url, json={"query": mutation, "variables": variables}, headers=headers)
        print(f"[STATUS] Response Status: {response.status_code}")
        data = response.json()
        print("response", data)
        
        if response.status_code != 200:
            return {"error": "API_ERROR", "message": f"{response.status_code} - {response.text}"}

        if "errors" in data:
            print(f"[ERROR] GraphQL Errors: {data['errors']}")
            # Parse GraphQL errors to provide specific error messages
            graphql_errors = data["errors"]
            error_info = parse_graphql_errors(graphql_errors)
            return {
                "error": error_info.get("error_type", "GRAPHQL_ERROR"),
                "message": error_info.get("message", "Failed to create exchange"),
                "details": graphql_errors,
                "user_message": error_info.get("user_message", error_info.get("message"))
            }

        print(f"[SUCCESS] Exchange created successfully: {data}")
        exchange_data = data.get("data", {}).get("createExchange", {}).get("exchange", {})
        
        # Extract exchange ID
        exchange_id = exchange_data.get("id")
        print(f"{'='*80}")
        print(f"[EXCHANGE INFO] Exchange ID: {exchange_id}")
        print(f"{'='*80}")
        
        # Extract alternative identifiers for URN
        alt_ids = exchange_data.get("alternativeIdentifiers", {})
        file_version_urn = alt_ids.get("fileVersionUrn","")
        file_urn = alt_ids.get("fileUrn","")
        raw_urn = file_version_urn or file_urn
        
        # Log the raw URN for debugging
        if raw_urn:
            print(f"[URN INFO] Raw URN: {raw_urn}")
            # Encode the URN for viewer use
            import base64
            encoded_urn = base64.urlsafe_b64encode(raw_urn.encode("utf-8")).decode("utf-8").rstrip("=")
            print(f"[URN INFO] URL-safe Base64-encoded URN: {encoded_urn}")
        else:
            print(f"[WARNING] No URN found in alternativeIdentifiers - may need to query separately")
            encoded_urn = None
        
        print(f"{'='*80}\n")
        
        return {
            "success": True,
            "data": data,
            "exchange_id": exchange_id,
            "exchange_name": exchange_data.get("name"),
            "urn": encoded_urn,  # Include the encoded URN if available
            "raw_urn": raw_urn  # Include raw URN for reference
        }

    except Exception as e:
        return {"error": "EXCEPTION", "message": str(e)}

 

2) Getting exchange ID, and URN (app.py):

@app.route('/api/create_exchange', methods=['POST'])
def create_exchange():
    try:
        data = request.get_json()
        file_id = data.get('fileId')
        project_id = data.get('projectId')
        folder_id = data.get('folderId')
        view_name = data.get('viewName') 
    
        exchange_name = view_name+"_Exchange"
        
        # Get token from config
        aps_token = config.get('aps_token')
        if not aps_token:
            return jsonify({"error": "No authorization token available"}), 401
        
        print(f"[EXCHANGE] Exchange creation request:")
        print(f"[INFO] File ID: {file_id}")
        print(f"[INFO] Project ID: {project_id}")
        print(f"[INFO] Folder ID: {folder_id}")
        print(f"[INFO] View Name: {view_name}")
        print(f"[INFO] Exchange Name: {exchange_name}")

        # The file_id and folder_id from frontend should already be GraphQL IDs
        # from the getFolderById query response
        # file_id comes from items.results[].id (GraphQL item ID)
        # folder_id comes from folder.id (GraphQL folder ID)
        
        # Use the GraphQL IDs directly - no decoding needed
        result = create_exchange_from_file(
            ENDPOINT_URL, 
            project_id,  # Keep project_id for reference, but not used for GraphQL IDs
            file_id,  # This should be the GraphQL item ID from folder.items.results[].id
            folder_id,  # This should be the GraphQL folder ID from folder.id
            view_name, 
            exchange_name, 
            aps_token,
        )

        # result = create_revit_exchange(aps_token)
        print("589 result", result)
        if not result:
            return jsonify({"error": "Failed to create exchange"}), 500

        if result.get("success"):
            exchange_id = result.get("exchange_id")
            encoded_urn = result.get("urn")
            raw_urn = result.get("raw_urn")
            
            # Print exchange ID and URN for verification
            print(f"{'='*80}")
            print(f"[EXCHANGE CREATION RESULT]")
            print(f"Exchange ID: {exchange_id}")
            if raw_urn:
                print(f"Raw URN: {raw_urn}")
            if encoded_urn:
                print(f"URL-safe Base64-encoded URN: {encoded_urn}")
            print(f"{'='*80}")
            
            response_data = {
                "success": True,
                "exchangeId": exchange_id,
                "exchangeName": result.get("exchange_name"),
                "elementsCount": result.get("elements_count", 0),
                "message": "Exchange created successfully"
            }
            # Include URN if available from exchange creation
            if encoded_urn:
                response_data["urn"] = encoded_urn
            return jsonify(response_data)
        else:
            # Use user_message if available, otherwise fall back to message
            error_message = result.get("user_message") or result.get("message", "Failed to create exchange")
            return jsonify({
                "success": False,
                "error": result.get("error"),
                "error_type": result.get("error"),  # Include error type for frontend handling
                "message": error_message,
                "details": result.get("details")
            }), 500

    except Exception as e:
        print(f"Error creating exchange: {e}")
        return jsonify({
            "success": False,
            "error": str(e),
            "message": "Error creating exchange"
        }), 500

@app.route('/api/get_exchange_urn', methods=['POST'])
def get_exchange_urn():
    data = request.get_json() or {}
    exchange_id = data.get('exchangeId')
    auth_token = data.get('authToken')
    if not exchange_id:
        return jsonify({"error": "Please provide exchangeId"}), 400
        
    # If no auth token provided, try to use the one from config
    if not auth_token:
        auth_token = AUTH_TOKEN
        if not auth_token:
            return jsonify({"error": "No auth token provided"}), 400

    print(f"[GET EXCHANGE URN] Request received for Exchange ID: {exchange_id}")
    urn = exchange_urn_from_id(
        endpoint_url=ENDPOINT_URL,
        exchange_id=exchange_id,
        auth_token=auth_token
    )
    if urn:
        print(f"[GET EXCHANGE URN] Successfully retrieved URN for Exchange ID: {exchange_id}")
        print(f"[GET EXCHANGE URN] URN: {urn}")
    else:
        print(f"[GET EXCHANGE URN] Failed to retrieve URN for Exchange ID: {exchange_id}")
    # Fetch metadata synchronously
    properties_data = fetch_exchange_properties(endpoint_url=ENDPOINT_URL, exchange_id=exchange_id, auth_token=auth_token)
    # print("Fetched properties:", properties_data)
    # Store results in app config
    if properties_data:
        # Store both property names and their units
        app.config['EXCHANGE_PROPERTIES'] = properties_data['property_names']
        app.config['PROPERTY_UNITS'] = properties_data['property_units']  # Store unit information
        app.config['EXCHANGE_PROPERTIES'].append("category")  # Ensure "category" is always included
        # Remove duplicates and sort properties case-insensitively
        app.config['EXCHANGE_PROPERTIES'] = sorted(list(set(app.config['EXCHANGE_PROPERTIES'])), key=lambda x: str(x).lower())
    
    if urn:
        return jsonify({
            "urn": urn,
            "categories": app.config['EXCHANGE_CATEGORIES'],
            "properties": app.config['EXCHANGE_PROPERTIES']
        })
    return jsonify({"error": "Failed to fetch URN"}), 500

 

3) Creating/Retrieving URN (graphql_queries.py):

def exchange_urn_from_id(endpoint_url, exchange_id, auth_token=None):
    """
    Returns the Base64-encoded URN for a given exchange ID.

    Args:
        endpoint_url: The URL of the GraphQL API.
        exchange_id: The ID of the exchange.
        auth_token: (Optional) The authentication token.

    Returns:
        The Base64-encoded URN string (without padding) or None if failed.
    """
    graphql_query = """
    query Exchange($exchangeId: ID!) {
        exchange(exchangeId: $exchangeId) {
            alternativeIdentifiers {
                fileUrn
                fileVersionUrn
            }
        }
    }
    """
    variables = {"exchangeId": exchange_id}
    headers = {"Content-Type": "application/json"}
    if auth_token:
        headers["Authorization"] = f"Bearer {auth_token}"

    try:
        print(f"{'='*80}")
        print(f"[EXCHANGE URN QUERY] Exchange ID: {exchange_id}")
        
        response = requests.post(
            endpoint_url,
            headers=headers,
            json={"query": graphql_query, "variables": variables}
        )
        data = response.json()
        print("data from the response **********", data)
        ids = data["data"]["exchange"]["alternativeIdentifiers"]
        fileVersionUrn = ids.get("fileVersionUrn","")
        fileUrn = ids.get("fileUrn","")
        print("fileVersionUrn **********", fileVersionUrn)
        print("fileUrn **********", fileUrn)

        # raw_urn = ids.get("fileVersionUrn","") or ids.get("fileUrn","")
        if not fileUrn:
            print("No fileUrn found for exchange ID: {exchange_id}")
            return None
        else :
            raw_urn = fileUrn

        # raw_urn =  fileVersionUrn or fileUrn
        # if not raw_urn:
        #     print(f"[WARNING] No URN found for exchange ID: {exchange_id}")
        #     print(f"{'='*80}")
        #     return None
        
        print(f"[URN INFO] Raw URN: {raw_urn}")
        #TODO : check this encoding and decoding happening same place ? 
        b64 = base64.urlsafe_b64encode(raw_urn.encode("utf-8")).decode("utf-8")
        encoded_urn = b64.rstrip("=")
        print(f"[URN INFO] URL-safe Base64-encoded URN: {encoded_urn}")
        print(f"{'='*80}")
        return encoded_urn
    except Exception as e:
        print(f"[ERROR] Failed to get URN for exchange ID {exchange_id}: {e}")
        print(f"{'='*80}")
        return None

 

4) Manifest file creation (model_derivative.py):

def get_model_manifest(base64_urn, access_token):
    """Call Model Derivative API manifest endpoint and return the full response."""
    url = f"https://developer.api.autodesk.com/modelderivative/v2/designdata/{base64_urn}/manifest"
    headers = {"Authorization": f"Bearer {access_token}"}
    
    print(f"[EXTRACT] Getting manifest for URN: {base64_urn}")
    try:
        resp = requests.get(url, headers=headers)
        print(f"[STATUS] Response Status: {resp.status_code}")

        result = {
            "status_code": resp.status_code,
            "url": url,
            "response_data": None,
            "error": None
        }

        # Handle different response types
        if resp.headers.get('content-type', '').startswith('application/json'):
            try:
                result["response_data"] = resp.json()
            except ValueError as e:
                result["error"] = f"Invalid JSON response: {str(e)}"
                result["response_data"] = resp.text
                print(f"[ERROR] JSON parsing failed: {str(e)}")
        else:
            result["response_data"] = resp.text

        if resp.status_code == 200:
            print("[SUCCESS] Manifest retrieved successfully")
        elif resp.status_code == 202:
            result["error"] = "Translation still in progress"
            print("[PROGRESS] Translation is still in progress")
        elif resp.status_code == 404:
            result["error"] = "Manifest not found - translation may not have started"
            print("[ERROR] Manifest not found (likely not translated yet)")
        else:
            result["error"] = f"API returned status {resp.status_code}"
            print(f"[WARNING] API Error: {resp.status_code} - {resp.text}")

        return result
        
    except requests.exceptions.RequestException as e:
        print(f"[ERROR] Request Error: {e}")
        return {
            "status_code": None,
            "url": url,
            "response_data": None,
            "error": str(e)
        }

 

5) Extracting manifest file:

def extract_views_from_manifest(manifest):
    """Extract 3D views from manifest recursively."""
    
    print("[EXTRACT] Extracting views from manifest...")
    print(f"[INFO] Manifest keys: {list(manifest.keys()) if isinstance(manifest, dict) else 'Not a dict'}")
    
    # Get the actual response data from the manifest wrapper
    response_data = manifest.get("response_data", {})
    if not response_data:
        print("[ERROR] No response_data in manifest")
        return {"status": "error", "message": "No response data", "views": []}
    
    print(f"[INFO] Response data keys: {list(response_data.keys()) if isinstance(response_data, dict) else 'Not a dict'}")
    print(f"[INFO] Manifest status: {response_data.get('status')}")
    print(f"[INFO] Progress: {response_data.get('progress')}")
    
    # Check for processing errors
    if 'messages' in response_data:
        messages = response_data.get('messages', [])
        print(f"[INFO] Processing messages: {messages}")
        for msg in messages:
            if msg.get('type') == 'error':
                print(f"[ERROR] Processing error: {msg.get('message', 'Unknown error')}")
    
    # Check for failed derivatives and provide detailed error information
    derivatives = response_data.get("derivatives", [])
    failed_derivatives = []
    timeout_derivatives = []
    
    for i, derivative in enumerate(derivatives):
        status = derivative.get('status', 'unknown')
        if status == 'failed':
            error_msg = derivative.get('messages', 'No error details')
            print(f"[ERROR] Derivative {i} failed: {error_msg}")
            failed_derivatives.append({
                "index": i,
                "name": derivative.get('name', 'Unnamed'),
                "outputType": derivative.get('outputType', 'unknown'),
                "error": error_msg
            })
        elif status == 'timeout':
            print(f"[TIMEOUT] Derivative {i} timed out during processing")
            timeout_derivatives.append({
                "index": i,
                "name": derivative.get('name', 'Unnamed'),
                "outputType": derivative.get('outputType', 'unknown')
            })
    
    # If all derivatives failed, return error
    if len(failed_derivatives) == len(derivatives) and len(derivatives) > 0:
        return {
            "status": "all_derivatives_failed",
            "message": "All derivatives failed to process",
            "failed_derivatives": failed_derivatives,
            "views": []
        }
    
    # If some derivatives timed out, warn but continue
    if timeout_derivatives:
        print(f"[WARNING] {len(timeout_derivatives)} derivatives timed out, but continuing with available ones")
    
    # Handle translation status response
    if response_data.get("status") == "inprogress":
        return {
            "status": "translation_in_progress",
            "message": "File is being translated",
            "views": []
        }
    
    if response_data.get("status") == "failed":
        return {
            "status": "translation_failed",
            "message": "Translation failed",
            "views": []
        }
    
    views = []

 

6) Viewing Exchange File (urn_viewer.js):

window.loadModelFromBackend = async function(exchangeId, retryCount = 0) {
  try {
    console.log(`🔄 Loading exchange ${exchangeId} (attempt ${retryCount + 1})`);
    
    // Update the EXCHANGE_ID
    EXCHANGE_ID = exchangeId;
    localStorage.setItem('exchange_id', exchangeId);

    // First get the config to ensure we have the token
    const configResponse = await fetch('http://localhost:4000/api/config');
    if (!configResponse.ok) {
      throw new Error('Failed to fetch config');
    }
    const config = await configResponse.json();
    APS_TOKEN = config.aps_token;

    if (!APS_TOKEN) {
      throw new Error('No authentication token available');
    }

    // Then fetch the URN with retry logic
    const response = await fetch('http://localhost:4000/api/get_exchange_urn', {
      method: 'POST',
      headers: { 
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${APS_TOKEN}`
      },
      body: JSON.stringify({ 
        exchangeId: exchangeId,
        authToken: APS_TOKEN
      })
    });

    if (!response.ok) {
      // If it's a newly created exchange, it might not be ready yet
      if (response.status === 404 && retryCount < 3) {
        console.log(`⏳ Exchange not ready yet, retrying in 10 seconds... (${retryCount + 1}/3)`);
        await new Promise(resolve => setTimeout(resolve, 10000));
        return window.loadModelFromBackend(exchangeId, retryCount + 1);
      }
      throw new Error(`Failed to fetch URN: ${response.status}`);
    }

    const data = await response.json();
    if (data.error) {
      // If it's a newly created exchange, it might not be ready yet
      if (data.error.includes('not found') && retryCount < 3) {
        console.log(`⏳ Exchange not ready yet, retrying in 10 seconds... (${retryCount + 1}/3)`);
        await new Promise(resolve => setTimeout(resolve, 10000));
        return window.loadModelFromBackend(exchangeId, retryCount + 1);
      }
      throw new Error(data.error);
    }

    if (!data.urn) {
      if (retryCount < 3) {
        console.log(`⏳ URN not ready yet, retrying in 10 seconds... (${retryCount + 1}/3)`);
        await new Promise(resolve => setTimeout(resolve, 10000));
        return window.loadModelFromBackend(exchangeId, retryCount + 1);
      }
      throw new Error('No URN returned from server');
    }

    console.log(`✅ Got URN: ${data.urn}`);

    // Save metadata if available
    if (data.categories) {
      window.EXCHANGE_CATEGORIES = data.categories;
    }

    // Initialize chat only after exchange is selected and loaded
    if (window.initializeChat && typeof window.initializeChat === 'function') {
      window.initializeChat();
    }

    if (data.properties) {
      window.EXCHANGE_PROPERTIES = data.properties;
    }
    await loadModel(data.urn);

    // Let other components know the model has been loaded
    window.postMessage({ 
      type: 'modelLoaded', 
      payload: { 
        urn: data.urn,
        exchangeId: exchangeId,
        token: APS_TOKEN
      }
    }, '*');

    return data.urn;
    window.postMessage({ 
      type: 'modelLoaded', 
      payload: { 
        urn: data.urn,
        exchangeId: exchangeId
      }
    }, '*');

  } catch (err) {
    alert('Failed to load model: ' + err.message);
    throw err;
  }
}

 

API Documentation Reference:
- APS Data Exchange GraphQL API: createExchange mutation
- Using APS Data Management API to get file/item information

0 Likes
183 Views
0 Replies
Replies (0)