from fastapi import APIRouter, HTTPException from pydantic import BaseModel, validator from app.services.speckle_service import SpeckleService from specklepy.objects import Base from datetime import datetime from typing import Any, List import json class GenericPayload(BaseModel): payload: str @validator("payload") def validate_payload(cls, value): # Parse the JSON string to ensure it's valid try: parsed = json.loads(value) # You can add additional validation here if needed except json.JSONDecodeError: raise ValueError("payload must be a valid JSON string") return value def get_data(self): return json.loads(self.payload) def extract_value(obj: Any, key: str) -> Any: """Recursively search for the value of a given key in nested objects""" print(f"Extracting value for key: {key} from object: {obj}") if isinstance(obj, dict): for k, v in obj.items(): print(f"Checking key: {k}, value: {v}") if k == key: print(f"Found key: {k}, returning value: {v}") return v elif isinstance(v, (dict, list)): result = extract_value(v, key) if result is not None: return result elif isinstance(obj, list): for item in obj: result = extract_value(item, key) if result is not None: return result return None router = APIRouter() @router.post("/mergeForDashboard") async def merge_for_dashboard(payload: GenericPayload): try: data = payload.get_data() # Log the received data print(f"Received data: {data}") # Extract necessary fields from the payload try: speckle_input_resultBranch1 = extract_value(data, 'speckleInput_resultBranch1') speckle_output_dashboard = extract_value(data, 'speckleOutput_Dashboard') token = extract_value(data, 'token') # Check if any of the extracted values are None if None in [speckle_input_resultBranch1, speckle_output_dashboard, token]: raise ValueError("One or more keys not found in payload.") # Extract the URLs from the nested branches structure branch_urls = [branch['speckleInput_resultBranch1_url'] for branch in speckle_input_resultBranch1['branches']] except ValueError as e: print(f"Error extracting values: {str(e)}") raise HTTPException(status_code=400, detail=f"Key not found in payload: {str(e)}") # Log extracted values print(f"Extracted values: speckle_input_resultBranch1={branch_urls}, speckle_output_dashboard={speckle_output_dashboard}, token={token}") # Step 1: Create the client print("Creating Speckle client...") client = SpeckleService.create_client(base_url="https://speckle.xyz", token=token) print("Client created successfully.") # Step 2: Parse the Speckle URLs to get the components input_data = [] input_commit_ids = [] for url in branch_urls: print(f"Parsing URL: {url}") speckle_url_info = SpeckleService.parse_speckle_url(url) stream_id = speckle_url_info["streamID"] branch_name = speckle_url_info["branchName"] print(f"Fetching Speckle stream for streamID: {stream_id}, branchName: {branch_name}") data, commit_id = SpeckleService.get_speckle_stream(stream_id, branch_name, client) input_data.append(data) input_commit_ids.append(commit_id) print(f"Data fetched for streamID: {stream_id}, commitID: {commit_id}") output_speckle_url_info = SpeckleService.parse_speckle_url(speckle_output_dashboard) output_stream_id = output_speckle_url_info["streamID"] output_branch_name = output_speckle_url_info["branchName"] print(f"Output streamID: {output_stream_id}, branchName: {output_branch_name}") # Step 3: Generate metadata metadata = SpeckleService.generate_metadata(branch_urls, token) print("Metadata generated.") # Step 4: Create a dummy Speckle object dummy_object = Base() dummy_object["IWasCreatedBy"] = "mergeForDashboard" dummy_object["MetaData"] = metadata dummy_object["MergedData"] = input_data print("Dummy Speckle object created.") # Step 5: Update the Speckle stream new_commit_id = SpeckleService.update_speckle_stream(output_stream_id, output_branch_name, client, dummy_object) print(f"Speckle stream updated with new commitID: {new_commit_id}") # Step 6: Create the report using metadata current_time = datetime.utcnow().isoformat() sources = [ { "streamID": SpeckleService.parse_speckle_url(url)["streamID"], "branchName": SpeckleService.parse_speckle_url(url)["branchName"], "commitID": commit_id, "time": current_time } for url, commit_id in zip(branch_urls, input_commit_ids) ] targets = [ { "streamID": output_stream_id, "branchName": output_branch_name, "commitID": new_commit_id, "time": current_time } ] report = { "method": "mergeForDashboard", "sources": sources, "targets": targets } print("Report created successfully.") return report except Exception as e: print(f"Error occurred: {str(e)}") raise HTTPException(status_code=500, detail=str(e))