File size: 4,137 Bytes
eb520b9
 
 
 
 
 
 
 
8a58692
 
 
 
 
 
 
 
 
 
 
 
 
 
eb520b9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8a58692
ef74289
eb520b9
8a58692
eb520b9
 
 
 
 
 
 
 
 
8a58692
625f024
 
8a58692
 
625f024
eb520b9
 
 
 
 
 
 
 
 
 
8a58692
eb520b9
 
 
 
 
 
 
 
 
8a58692
 
 
eb520b9
ef74289
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import gradio as gr
import pandas as pd
import PIL.Image
import io
import re
import os
from google import genai

# --- 1. The JS Hack to Force the Rear Native Camera ---
js_code = """
function() {
    // Continuously check for the upload button and force the camera intent
    setInterval(function() {
        let file_inputs = document.querySelectorAll('input[type="file"]:not([capture])');
        file_inputs.forEach(function(input) {
            input.setAttribute('capture', 'environment');
            input.setAttribute('accept', 'image/*');
        });
    }, 500);
}
"""

theme = gr.themes.Soft(
    primary_hue="indigo",
    secondary_hue="slate",
    neutral_hue="slate",
    font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"],
)

css = """
footer {display: none !important;}
.gradio-container {border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);}
"""

def extract_tables(image, api_key_input, progress=gr.Progress()):
    progress(0.1, desc="Initializing Gemini Vision...")
    
    api_key = api_key_input or os.environ.get("GEMINI_API_KEY")
    
    if not api_key:
        raise gr.Error("⚠️ Please enter your Gemini API Key in the box.")
    if image is None:
        raise gr.Error("⚠️ Please capture or upload a log sheet first.")

    try:
        progress(0.4, desc="Analyzing log sheet image...")
        client = genai.Client(api_key=api_key)
        
        prompt = """
        Carefully extract all the data tables from this dashboard image. 
        Format the output strictly as CSV (Comma Separated Values).
        For each table you find, provide the title of the table, and then enclose the CSV data inside ```csv ``` code blocks.
        Ensure column headers are included in the CSV.
        """
        
        response = client.models.generate_content(
            model="gemini-3-flash-preview", 
            contents=[prompt, image],
        )
        
        progress(0.8, desc="Parsing extracted tables...")
        csv_blocks = re.findall(r'```csv\n(.*?)\n```', response.text, re.DOTALL)
        
        if not csv_blocks:
            raise gr.Error(f"⚠️ Could not detect any tables. Raw Output:\n{response.text}")
            
        extracted_dfs = []
        for csv_data in csv_blocks:
            df = pd.read_csv(io.StringIO(csv_data))
            extracted_dfs.append(df)
            
        progress(1.0, desc="Done!")
        return extracted_dfs, gr.update(value="✅ **Extraction Complete!**", visible=True)
        
    except Exception as e:
        raise gr.Error(f"❌ An error occurred: {str(e)}")

# --- Build the UI ---
with gr.Blocks(title="Industrial Data Extractor") as demo:
    gr.HTML("<h2 style='text-align: center; color: #4338ca; margin-bottom: 0px;'>🏭 Industrial Data Extractor</h2>")
    gr.HTML("<p style='text-align: center; color: #64748b; margin-top: 5px;'>Capture log sheets to digitize tabular data.</p>")
    
    table_state = gr.State([])
    
    api_key_ui = gr.Textbox(
        label="Authentication", 
        type="password", 
        placeholder="Enter Gemini API Key here to begin..."
    )
    
    # We use "upload" only. The JS will hijack it and turn it into a camera button.
    image_input = gr.Image(
        type="pil", 
        label="Tap here to open Rear Camera", 
        sources=["upload"]
    )
    
    extract_btn = gr.Button("Extract Tables", variant="primary", size="lg")
    status_ui = gr.Markdown("", visible=False)
    
    gr.Markdown("---")
    gr.Markdown("### 📥 Extracted Data")
    
    @gr.render(inputs=table_state)
    def show_tables(dfs):
        if not dfs:
            gr.HTML("<div style='text-align: center; color: #94a3b8;'><i>Data will appear here.</i></div>")
        for i, df in enumerate(dfs):
            gr.Markdown(f"**Table {i+1}**")
            gr.Dataframe(value=df, interactive=False, wrap=True)

    extract_btn.click(
        fn=extract_tables, 
        inputs=[image_input, api_key_ui], 
        outputs=[table_state, status_ui]
    )
    
    # Inject the JS hack into the app
    demo.load(js=js_code)

demo.launch(theme=theme, css=css)