Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -5,9 +5,8 @@ import pandas as pd
|
|
| 5 |
from docx import Document
|
| 6 |
import time
|
| 7 |
|
| 8 |
-
#==== import completed
|
| 9 |
-
|
| 10 |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
|
|
|
| 11 |
#=====
|
| 12 |
#Payment type
|
| 13 |
manual_payment_type="""
|
|
@@ -72,155 +71,114 @@ PQC_rules="""
|
|
| 72 |
15. PQC should balance inclusion of capable vendors and exclusion of incapable ones."""
|
| 73 |
|
| 74 |
#============starting extract_docx_text
|
|
|
|
| 75 |
def extract_docx_text(file_path):
|
| 76 |
-
# Load the DOCX file
|
| 77 |
doc = Document(file_path)
|
| 78 |
-
|
| 79 |
-
# Extract all content in a structured way
|
| 80 |
final_data = []
|
| 81 |
-
|
| 82 |
-
# Process all tables in the document
|
| 83 |
for table_idx, table in enumerate(doc.tables):
|
| 84 |
for row in table.rows:
|
| 85 |
cells = [cell.text.strip() for cell in row.cells]
|
| 86 |
-
|
| 87 |
-
# If it's a 2-column layout (Key: Value format)
|
| 88 |
if len(cells) == 2:
|
| 89 |
key = cells[0].replace(':', '').strip()
|
| 90 |
value = cells[1].strip()
|
| 91 |
if key and value:
|
| 92 |
final_data.append({'Field': key, 'Value': value, 'Source': f'Table_{table_idx+1}'})
|
| 93 |
else:
|
| 94 |
-
# Multi-column or single column data
|
| 95 |
combined = ' | '.join([c for c in cells if c])
|
| 96 |
if combined:
|
| 97 |
final_data.append({'Field': 'Multi-Column Data', 'Value': combined, 'Source': f'Table_{table_idx+1}'})
|
|
|
|
| 98 |
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
#doc = Document(file_path)
|
| 102 |
-
#text = "\n".join([para.text for para in doc.paragraphs])
|
| 103 |
-
return df
|
| 104 |
-
|
| 105 |
-
#====generate response function started
|
| 106 |
-
def generate_response(manual,proposal):
|
| 107 |
-
prompt = """
|
| 108 |
You are a strict compliance checker for Govt. procurement policies.
|
| 109 |
|
| 110 |
-
|
| 111 |
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
Fix: <clear corrective action>
|
| 117 |
|
| 118 |
-
|
| 119 |
|
| 120 |
MANUAL: {manual}
|
| 121 |
|
| 122 |
proposal: {proposal}
|
| 123 |
-
|
| 124 |
"""
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
return response.
|
| 132 |
-
|
| 133 |
-
#
|
| 134 |
-
|
| 135 |
-
Value_of_proposal=""
|
| 136 |
-
|
| 137 |
-
Tender_Type_of_proposal=""
|
| 138 |
-
Name_of_proposal=""
|
| 139 |
-
manual_rules=""
|
| 140 |
-
proposal_details=""
|
| 141 |
for index, row in df.iterrows():
|
| 142 |
key = str(row['Field'])
|
| 143 |
value = str(row['Value'])
|
| 144 |
-
i=0
|
| 145 |
-
proposal_details=""
|
| 146 |
-
manual_rules=""
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
continue
|
| 150 |
-
if key == "PR No.":
|
| 151 |
-
#print(f"The proposal PR No. is: {value}")
|
| 152 |
continue
|
|
|
|
| 153 |
if key == "Value (Rs)":
|
| 154 |
-
|
| 155 |
-
Value_of_proposal=f"The proposal Value is {value}. \n"
|
| 156 |
continue
|
| 157 |
if key == "Category":
|
| 158 |
-
|
| 159 |
-
Category_of_proposal=f"The proposal Category is {value}. \n"
|
| 160 |
continue
|
| 161 |
if key == "Tender Type":
|
| 162 |
-
|
| 163 |
-
Tender_Type_of_proposal=f"The proposal Tender Type is {value}. \n"
|
| 164 |
-
continue
|
| 165 |
-
if key == "Name of proposal":
|
| 166 |
-
#print(f"The proposal Name of proposal is: {value}. \n")
|
| 167 |
-
continue
|
| 168 |
-
if key == "Justification/Reason for Procurement":
|
| 169 |
-
#print(f"The reason for Procurement of the items is as under: {value}. \n")
|
| 170 |
continue
|
|
|
|
| 171 |
if key == "PQC for Open tenders":
|
| 172 |
manual_rules = PQC_rules
|
| 173 |
-
proposal_details= f"The Pre Qualifying Criteria (PQC) of the proposal is under: {value}. {Value_of_proposal}"
|
| 174 |
-
i=1
|
| 175 |
-
|
| 176 |
-
manual_rules=manual_basis_of_estimate
|
| 177 |
-
proposal_details= f"The basis of estimate of the proposal is under: {value}.
|
| 178 |
-
i=1
|
| 179 |
-
|
| 180 |
-
manual_rules=manual_payment_type
|
| 181 |
-
proposal_details=f"The Payment Terms of the proposal is {value}.
|
| 182 |
-
i=1
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
print(f"Error: {e} - skipping row")
|
| 196 |
-
continue
|
| 197 |
-
#======loop function completed
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
def check_compliance(file):
|
| 202 |
if file.name.endswith(".docx"):
|
| 203 |
df1 = extract_docx_text(file.name)
|
| 204 |
-
loop_function(df1)
|
| 205 |
else:
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
#=====gradio coding
|
| 210 |
|
|
|
|
| 211 |
with gr.Blocks() as demo:
|
| 212 |
with gr.Row():
|
| 213 |
-
inp=gr.File(
|
| 214 |
label="Upload Proposal",
|
| 215 |
file_types=[".docx"]
|
| 216 |
)
|
| 217 |
|
| 218 |
out = gr.Textbox(lines=15, label="Compliance Result")
|
| 219 |
-
|
| 220 |
run_btn = gr.Button("Check compliance")
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
run_btn.click(check_compliance, inputs=inp, outputs=out)
|
| 224 |
|
| 225 |
demo.queue().launch()
|
| 226 |
-
|
|
|
|
| 5 |
from docx import Document
|
| 6 |
import time
|
| 7 |
|
|
|
|
|
|
|
| 8 |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
| 9 |
+
|
| 10 |
#=====
|
| 11 |
#Payment type
|
| 12 |
manual_payment_type="""
|
|
|
|
| 71 |
15. PQC should balance inclusion of capable vendors and exclusion of incapable ones."""
|
| 72 |
|
| 73 |
#============starting extract_docx_text
|
| 74 |
+
|
| 75 |
def extract_docx_text(file_path):
|
|
|
|
| 76 |
doc = Document(file_path)
|
|
|
|
|
|
|
| 77 |
final_data = []
|
|
|
|
|
|
|
| 78 |
for table_idx, table in enumerate(doc.tables):
|
| 79 |
for row in table.rows:
|
| 80 |
cells = [cell.text.strip() for cell in row.cells]
|
|
|
|
|
|
|
| 81 |
if len(cells) == 2:
|
| 82 |
key = cells[0].replace(':', '').strip()
|
| 83 |
value = cells[1].strip()
|
| 84 |
if key and value:
|
| 85 |
final_data.append({'Field': key, 'Value': value, 'Source': f'Table_{table_idx+1}'})
|
| 86 |
else:
|
|
|
|
| 87 |
combined = ' | '.join([c for c in cells if c])
|
| 88 |
if combined:
|
| 89 |
final_data.append({'Field': 'Multi-Column Data', 'Value': combined, 'Source': f'Table_{table_idx+1}'})
|
| 90 |
+
return pd.DataFrame(final_data)
|
| 91 |
|
| 92 |
+
def generate_response(manual, proposal):
|
| 93 |
+
prompt = f"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
You are a strict compliance checker for Govt. procurement policies.
|
| 95 |
|
| 96 |
+
Check whether the proposal complies with MANUAL requirements. Respond in EXACT format:
|
| 97 |
|
| 98 |
+
Status: COMPLIANT or NON-COMPLIANT
|
| 99 |
+
Severity: HIGH or MEDIUM or LOW
|
| 100 |
+
Deviations: <short bullet-style description or 'None'>
|
| 101 |
+
Fix: <clear corrective action>
|
|
|
|
| 102 |
|
| 103 |
+
COMPLIANCE ANALYSIS: <2–4 sentences explaining reasoning>
|
| 104 |
|
| 105 |
MANUAL: {manual}
|
| 106 |
|
| 107 |
proposal: {proposal}
|
|
|
|
| 108 |
"""
|
| 109 |
+
|
| 110 |
+
response = client.chat.completions.create( # FIXED: correct method
|
| 111 |
+
model="gpt-4o-mini", # FIXED: use existing model (gpt-5-mini may not exist)
|
| 112 |
+
messages=[{"role": "user", "content": prompt}],
|
| 113 |
+
temperature=0.1
|
| 114 |
+
)
|
| 115 |
+
return response.choices[0].message.content # FIXED: correct path
|
| 116 |
+
|
| 117 |
+
def loop_function(df): # now properly yields
|
| 118 |
+
text = "" # FIXED: initialize
|
| 119 |
+
Value_of_proposal = ""
|
| 120 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
for index, row in df.iterrows():
|
| 122 |
key = str(row['Field'])
|
| 123 |
value = str(row['Value'])
|
| 124 |
+
i = 0
|
| 125 |
+
proposal_details = ""
|
| 126 |
+
manual_rules = ""
|
| 127 |
+
|
| 128 |
+
if key == "File No." or key == "PR No." or key == "Name of proposal" or key == "Justification/Reason for Procurement":
|
|
|
|
|
|
|
|
|
|
| 129 |
continue
|
| 130 |
+
|
| 131 |
if key == "Value (Rs)":
|
| 132 |
+
Value_of_proposal = f"The proposal Value is {value}. \n"
|
|
|
|
| 133 |
continue
|
| 134 |
if key == "Category":
|
| 135 |
+
Category_of_proposal = f"The proposal Category is {value}. \n"
|
|
|
|
| 136 |
continue
|
| 137 |
if key == "Tender Type":
|
| 138 |
+
Tender_Type_of_proposal = f"The proposal Tender Type is {value}. \n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
continue
|
| 140 |
+
|
| 141 |
if key == "PQC for Open tenders":
|
| 142 |
manual_rules = PQC_rules
|
| 143 |
+
proposal_details = f"The Pre Qualifying Criteria (PQC) of the proposal is under: {value}. {Value_of_proposal}"
|
| 144 |
+
i = 1
|
| 145 |
+
elif key == "Basis of estimate": # FIXED: elif
|
| 146 |
+
manual_rules = manual_basis_of_estimate
|
| 147 |
+
proposal_details = f"The basis of estimate of the proposal is under: {value}."
|
| 148 |
+
i = 1
|
| 149 |
+
elif key == "Payment Terms":
|
| 150 |
+
manual_rules = manual_payment_type
|
| 151 |
+
proposal_details = f"The Payment Terms of the proposal is {value}."
|
| 152 |
+
i = 1
|
| 153 |
+
|
| 154 |
+
if i == 1:
|
| 155 |
+
try:
|
| 156 |
+
rr = generate_response(manual_rules, proposal_details)
|
| 157 |
+
text += rr + "\n\n" # FIXED: accumulate
|
| 158 |
+
yield text
|
| 159 |
+
time.sleep(3)
|
| 160 |
+
except Exception as e:
|
| 161 |
+
print(f"Error: {e} - skipping row")
|
| 162 |
+
continue
|
| 163 |
+
|
| 164 |
+
def check_compliance(file): # FIXED: now streams
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
if file.name.endswith(".docx"):
|
| 166 |
df1 = extract_docx_text(file.name)
|
| 167 |
+
yield from loop_function(df1) # FIXED: delegate yields
|
| 168 |
else:
|
| 169 |
+
yield "Unsupported file format"
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
+
# Gradio (FIXED input name)
|
| 172 |
with gr.Blocks() as demo:
|
| 173 |
with gr.Row():
|
| 174 |
+
inp = gr.File( # consistent name
|
| 175 |
label="Upload Proposal",
|
| 176 |
file_types=[".docx"]
|
| 177 |
)
|
| 178 |
|
| 179 |
out = gr.Textbox(lines=15, label="Compliance Result")
|
|
|
|
| 180 |
run_btn = gr.Button("Check compliance")
|
| 181 |
+
|
| 182 |
+
run_btn.click(check_compliance, inputs=inp, outputs=out) # FIXED: inputs=inp
|
|
|
|
| 183 |
|
| 184 |
demo.queue().launch()
|
|
|