@@ -99,23 +99,47 @@ def _call_llm(
9999 if return_token_usage :
100100 # Extract token usage from response metadata
101101 token_usage = 0
102- if hasattr (response , 'response_metadata' ):
103- usage_metadata = response .response_metadata .get ('usage' , {})
104- # OpenAI/Gemini format
102+
103+ logger .info (f"=== TOKEN DEBUG START ===" )
104+ logger .info (f"Response type: { type (response )} " )
105+ logger .info (f"Has usage_metadata: { hasattr (response , 'usage_metadata' )} " )
106+ logger .info (f"Has response_metadata: { hasattr (response , 'response_metadata' )} " )
107+
108+ # Try response.usage_metadata first (Gemini pool format)
109+ if hasattr (response , 'usage_metadata' ) and response .usage_metadata :
110+ usage = response .usage_metadata
111+ logger .info (f"usage_metadata type: { type (usage )} " )
112+ logger .info (f"usage_metadata value: { usage } " )
113+
114+ if isinstance (usage , dict ):
115+ token_usage = usage .get ('total_tokens' , 0 )
116+ if not token_usage :
117+ token_usage = usage .get ('input_tokens' , 0 ) + usage .get ('output_tokens' , 0 )
118+ else :
119+ token_usage = getattr (usage , 'total_tokens' , 0 )
120+ if not token_usage :
121+ token_usage = getattr (usage , 'input_tokens' , 0 ) + getattr (usage , 'output_tokens' , 0 )
122+
123+ logger .info (f"Extracted token_usage from usage_metadata: { token_usage } " )
124+
125+ # Fallback: response.response_metadata (OpenAI format)
126+ if not token_usage and hasattr (response , 'response_metadata' ):
127+ metadata = response .response_metadata
128+ logger .info (f"response_metadata: { metadata } " )
129+ usage_metadata = metadata .get ('usage' , {})
130+ logger .info (f"usage from response_metadata: { usage_metadata } " )
131+
105132 token_usage = usage_metadata .get ('total_tokens' , 0 )
106- # Fallback: prompt_tokens + completion_tokens
107133 if not token_usage :
108134 token_usage = usage_metadata .get ('prompt_tokens' , 0 ) + usage_metadata .get ('completion_tokens' , 0 )
109- # Fallback: input_tokens + output_tokens
110135 if not token_usage :
111136 token_usage = usage_metadata .get ('input_tokens' , 0 ) + usage_metadata .get ('output_tokens' , 0 )
112- # Alternative: usage_metadata attribute (dict or object)
113- if not token_usage and hasattr (response , 'usage_metadata' ) and response .usage_metadata :
114- usage = response .usage_metadata
115- if isinstance (usage , dict ):
116- token_usage = usage .get ('total_tokens' , 0 ) or (usage .get ('input_tokens' , 0 ) + usage .get ('output_tokens' , 0 ))
117- else :
118- token_usage = getattr (usage , 'total_tokens' , 0 ) or (getattr (usage , 'input_tokens' , 0 ) + getattr (usage , 'output_tokens' , 0 ))
137+
138+ logger .info (f"Extracted token_usage from response_metadata: { token_usage } " )
139+
140+ logger .info (f"Final token_usage: { token_usage } " )
141+ logger .info (f"=== TOKEN DEBUG END ===" )
142+
119143 return response_content , token_usage
120144
121145 return response_content
@@ -641,7 +665,11 @@ def _node(state: TableState) -> TableState:
641665 errors .append (f"QA prompt missing placeholder: { e } " )
642666 return {** state , "errors" : errors }
643667
644- response_text = _call_llm (llm , prompt )
668+ response_text , token_usage = _call_llm (llm , prompt , return_token_usage = True )
669+
670+ # Debug log for token usage
671+ logger .info (f"QA generation token usage: { token_usage } " )
672+
645673 response_json = robust_json_parse (response_text )
646674
647675 qa_results = []
@@ -650,7 +678,8 @@ def _node(state: TableState) -> TableState:
650678 else :
651679 logger .warning ("QA generation did not return valid JSON or 'qa_pairs' key." )
652680
653- return {** state , "qa_results" : qa_results }
681+ logger .info (f"Returning token_usage: { token_usage } " )
682+ return {** state , "qa_results" : qa_results , "token_usage" : token_usage }
654683
655684 return _node
656685
@@ -685,6 +714,10 @@ def _node(state: TableState) -> TableState:
685714 prompt = prompt_template
686715
687716 response_text , token_usage = _call_llm (llm , prompt , image_urls = image_data_urls , return_token_usage = True )
717+
718+ # Debug log for token usage
719+ logger .info (f"QA generation token usage: { token_usage } " )
720+
688721 response_json = robust_json_parse (response_text )
689722
690723 qa_results = []
@@ -693,6 +726,7 @@ def _node(state: TableState) -> TableState:
693726 else :
694727 logger .warning ("QA generation from image did not return valid JSON or 'qa_pairs' key." )
695728
729+ logger .info (f"Returning token_usage: { token_usage } " )
696730 return {** state , "qa_results" : qa_results , "token_usage" : token_usage }
697731
698732 return _node
@@ -877,6 +911,8 @@ def run_synthetic_table_flow(
877911 temperature : float = 0.2 ,
878912 base_url : str | None = None ,
879913 config_path : str | None = None ,
914+ azure_deployment : str | None = None ,
915+ azure_endpoint : str | None = None ,
880916 qa_only : bool = False ,
881917 image_paths : List [str ] | None = None ,
882918 domain : str | None = None ,
@@ -891,11 +927,13 @@ def run_synthetic_table_flow(
891927
892928 Args:
893929 image_path: Path to the input image or HTML file
894- provider: LLM provider (openai, gemini, gemini_pool, claude, vllm)
930+ provider: LLM provider (openai, azure, gemini, gemini_pool, claude, vllm)
895931 model: Model name
896932 temperature: Sampling temperature
897933 base_url: Custom base URL for vLLM
898934 config_path: Config path for gemini_pool
935+ azure_deployment: Azure OpenAI deployment name
936+ azure_endpoint: Azure OpenAI endpoint URL
899937 qa_only: If True, skip synthetic data generation and only generate QA from image
900938 image_paths: Optional list of image paths for multi-image processing
901939 domain: Optional domain for prompt customization (e.g. 'public')
0 commit comments