File size: 6,160 Bytes
b2e8432
984add3
2096cd3
 
984add3
 
 
2096cd3
476fbdb
 
 
 
 
 
b2e8432
476fbdb
2096cd3
 
 
984add3
2096cd3
 
 
 
 
 
 
 
984add3
 
 
 
ec922d3
2096cd3
984add3
 
 
ec922d3
2096cd3
984add3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209a467
ec922d3
209a467
984add3
 
 
 
 
 
 
 
 
ec922d3
984add3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec922d3
984add3
 
 
ec922d3
 
 
 
984add3
 
 
 
 
ec922d3
2096cd3
 
 
 
48ba2af
d0bc8ee
2096cd3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
984add3
2096cd3
984add3
2096cd3
 
 
 
 
 
 
 
 
 
ec922d3
 
 
8e6312c
2096cd3
984add3
2096cd3
 
984add3
 
 
2096cd3
 
 
 
 
 
ec922d3
2096cd3
 
476fbdb
2096cd3
476fbdb
 
984add3
 
 
476fbdb
 
 
489f421
89a3bfc
476fbdb
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import os
import json
import gradio as gr
import pandas as pd
from python_request import process_wod_document

from dummy import output_test

# --- Authentication Function ---
def authenticate_user(username, password):
    """
    Simple authentication function.
    In production, you should use more secure methods like hashed passwords.
    """
    return username == "demo" and password == os.environ["PASSWORD"]

# --- Core Application Logic ---
def analyze_wod(file_obj, wod_type):
    """
    This function analyzes a Work Order Document using the remote API.

    Args:
        file_obj: The uploaded file object from Gradio.
        wod_type: The selected type of Work Order Document.

    Returns:
        A pandas DataFrame with the analysis results.
    """
    # Check if user has selected a valid WOD type
    if wod_type == "-- WOD type --" or wod_type is None:
        # Show warning dialog and return empty DataFrame
        gr.Warning("Please select a WOD type first!")
        return "", pd.DataFrame()
    
    # Check if file is uploaded
    if file_obj is None:
        gr.Warning("Please upload a PDF file first!")
        return "", pd.DataFrame()
    
    print(f"Analyzing '{file_obj.name}' (Type: {wod_type})...")
    
    try:
        # In modern Gradio versions, file_obj is already a path string
        # We can use it directly or get the path from it
        if hasattr(file_obj, 'name') and os.path.isfile(file_obj.name):
            # file_obj has a .name attribute pointing to the temporary file
            temp_file_path = file_obj.name
            cleanup_needed = False
        else:
            # Fallback: assume file_obj is a path string
            temp_file_path = str(file_obj)
            cleanup_needed = False
        
        # Process the document using the API
        api_response = process_wod_document(temp_file_path, wod_type)

        # api_response = json.loads(output_test) 
        
        # Clean up temporary file if we created one
        if cleanup_needed:
            os.unlink(temp_file_path)
        
        # Check if API call was successful
        if api_response.get("status") != "success":
            error_msg = api_response.get("message", "Unknown error occurred")
            gr.Error(f"API Error: {error_msg}")
            return "", pd.DataFrame()
        
        # Parse the API response
        results = api_response.get("results", {})
        summary = results.get("summary", {})
        
        # Convert API response to DataFrame format
        requirements = []
        reasons = []
        statuses = []
        
        for requirement_name, details in summary.items():
            requirements.append(requirement_name)
            reasons.append(details.get("reasoning", ""))
            # Convert true/false to PASS/FAIL
            status_bool = details.get("status", "false")
            if isinstance(status_bool, str):
                status = "PASS" if status_bool.lower() == "true" else "FAIL"
            else:
                status = "PASS" if status_bool else "FAIL"
            statuses.append(status)
        
        # Create DataFrame
        df = pd.DataFrame({
            "Requirement": requirements,
            "Reason": reasons,
            "Status": statuses
        })
        
        # Get prediction for display
        prediction = results.get("prediction", "Unknown")
        gr.Info(f"Analysis completed! Overall prediction: {prediction}")
        
        # Format prediction as centered H1 for display
        prediction_display = f"<h1 style='text-align: center; color: #1f77b4;'>{prediction}</h1>" if prediction != "Unknown" else ""
        
        return prediction_display, df
        
    except Exception as e:
        error_msg = f"Error processing document: {str(e)}"
        print(error_msg)
        gr.Error(error_msg)
        return "", pd.DataFrame()

# --- Gradio User Interface Definition ---
# Using gr.Blocks() for a custom layout that matches the elegant design.
with gr.Blocks(
    #theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), 
    theme=gr.themes.Default(primary_hue="blue", secondary_hue="sky"), 
    css=".gradio-container {max-width: 960px !important; margin: auto !important;}"
) as demo:
    
    # Main Title and Description
    gr.Markdown(
        """
        # WOD Analyzer
        Upload a Work Order Document to automatically check for requirements.
        """
    )

    # Input Section
    with gr.Row():
        # File Upload Component
        file_input = gr.File(label="Upload WOD PDF")
        
        # Dropdown for WOD Type
        type_input = gr.Dropdown(
            ["-- WOD type --", "REPLACEMENT", "THERMAL", "VISIT", "PREVENTIVE_MAINTENANCE", "INSTALLATION", "WITHDRAWAL"],
            label="Type",
            value="-- WOD type --",
            info="Select the type of work order."
        )

    # Action Button
    analyze_btn = gr.Button("Analyze Document", variant="primary")

    # Results Section
    gr.Markdown("---")
    gr.Markdown("## Results")
    
    # Prediction display (centered H1)
    prediction_output = gr.Markdown(value="", visible=True)
    
    # DataFrame to display the output, with styling for the 'Status' column
    results_output = gr.DataFrame(
        headers=["Requirement", "Reason", "Status"],
        datatype=["str", "str", "str"],
        interactive=False,
        max_height=1250,
        column_widths=[30, 60, 10],
        wrap=True
    )

    # Define the interaction: clicking the button calls the function
    analyze_btn.click(
        fn=analyze_wod,
        inputs=[file_input, type_input],
        outputs=[prediction_output, results_output]
    )

# --- Launch the Application with Authentication ---
if __name__ == "__main__":
    # The launch() command creates a web server with authentication enabled
    # Users must provide the correct username and password to access the app

    # demo.launch(debug=True)

    demo.launch(
        auth=authenticate_user,  # Enable authentication
        auth_message="Please enter your credentials to access the WOD Analyzer",
        share=True,
        ssr_mode=False,
    )