Skip to content

Commit 08f8d44

Browse files
committed
refactor: optimize LLM extraction with pixtral-large, remove OCR hybrid
1 parent 46de410 commit 08f8d44

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

chart2csv/core/llm_extraction.py

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def encode_image_base64(image: np.ndarray) -> str:
2929

3030
def extract_chart_llm(
3131
image_path: str,
32-
model: str = "pixtral-12b-2409"
32+
model: str = "mistral-ocr-latest"
3333
) -> Tuple[Dict[str, Any], float]:
3434
"""
3535
Extract chart data using LLM vision in a single API call.
@@ -64,36 +64,43 @@ def extract_chart_llm(
6464
# Create Mistral client
6565
client = Mistral(api_key=api_key)
6666

67-
# Craft extraction prompt
68-
prompt = """Analyze this chart image and extract ALL data points.
67+
# Craft extraction prompt - chain of thought for precision
68+
prompt = """You are extracting data from a chart. Be EXTREMELY precise.
6969
70-
IMPORTANT INSTRUCTIONS:
71-
1. Read the axis labels and scale carefully
72-
2. For each visible data point (dot, bar, or line vertex), estimate its X and Y values
73-
3. Use the actual axis values, not pixel positions
74-
4. Be precise - read tick marks and interpolate between them
70+
TASK: Extract the X,Y coordinates of EVERY data point marker in this chart.
7571
76-
Return ONLY valid JSON in this exact format:
72+
STEP 1 - ANALYZE AXES:
73+
First, identify the axis ranges by reading the tick labels.
74+
75+
STEP 2 - LOCATE MARKERS:
76+
For line charts: find every dot/marker on the line (not the line itself, the markers).
77+
For scatter plots: find every dot.
78+
For bar charts: measure the height of each bar.
79+
80+
STEP 3 - READ VALUES:
81+
For EACH marker, look at its position and read:
82+
- X: What X gridline or tick is it at or between?
83+
- Y: What Y gridline is the marker at? If between gridlines, estimate precisely.
84+
85+
CRITICAL: Do NOT interpolate or assume patterns. Each point may have a UNIQUE value.
86+
Many charts have irregular data - do not assume smooth curves.
87+
88+
Return JSON only:
7789
{
78-
"chart_type": "line" or "bar" or "scatter",
79-
"x_label": "label from X axis or empty string",
80-
"y_label": "label from Y axis or empty string",
81-
"x_min": minimum X axis value,
82-
"x_max": maximum X axis value,
83-
"y_min": minimum Y axis value,
84-
"y_max": maximum Y axis value,
85-
"data": [
86-
{"x": 0, "y": 10},
87-
{"x": 1, "y": 20},
88-
...
89-
]
90+
"chart_type": "line" or "scatter" or "bar",
91+
"x_label": "axis label",
92+
"y_label": "axis label",
93+
"data": [{"x": val, "y": val}, ...]
9094
}
9195
92-
Extract ALL visible data points. Do not skip any."""
96+
Example for irregular data:
97+
{"data": [{"x": 0, "y": 5}, {"x": 1, "y": 8}, {"x": 2, "y": 12}, {"x": 3, "y": 15}]}
98+
Note: each Y is different and not following a pattern."""
9399

94100
try:
101+
# Direct extraction with pixtral (OCR doesn't work for charts)
95102
response = client.chat.complete(
96-
model=model,
103+
model="pixtral-large-latest",
97104
messages=[
98105
{
99106
"role": "user",
@@ -104,7 +111,7 @@ def extract_chart_llm(
104111
}
105112
],
106113
max_tokens=4096,
107-
temperature=0.1 # Low temperature for precision
114+
temperature=0.0
108115
)
109116

110117
content = response.choices[0].message.content.strip()

0 commit comments

Comments
 (0)