sadew12's picture
initial commit
8fb729a verified
Raw
History Blame Contribute Delete
7.85 kB
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from docx import Document
import pandas as pd
import io
import zipfile
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Manual Input සඳහා ආකෘතිය
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
NDA_TEMPLATE_PATH = os.path.join(BASE_DIR, "NDA_template.docx")
OFFER_LETTER_TEMPLATE_PATH = os.path.join(BASE_DIR, "Offer_Letter_template.docx")
class InternData(BaseModel):
name_with_initials: str
full_name: str
home_address: str
welcome_name: str
start_date: str
end_date: str
nic: str
department: str
telephone_number: str
supervisor_name: str
supervisor_designation: str
line_address: str
def format_standard_date(date_val):
if pd.isna(date_val) or not str(date_val).strip():
return ""
try:
dt = pd.to_datetime(date_val)
return f"{dt.day} {dt.strftime('%B')} {dt.year}"
except Exception:
return str(date_val).strip().split(" ")[0]
def format_ordinal_date(date_val):
if pd.isna(date_val) or not str(date_val).strip():
return ""
try:
dt = pd.to_datetime(date_val)
day = dt.day
if 11 <= day <= 13:
suffix = "th"
else:
suffix = {1: "st", 2: "nd", 3: "rd"}.get(day % 10, "th")
day_str = f"{day}{suffix}"
month_str = dt.strftime("%B")
year_str = dt.strftime("%Y")
return f"{day_str} day of {month_str} {year_str}"
except Exception:
return str(date_val).strip()
def normalize_data(raw_data):
def get_val(keys):
for k in keys:
if k in raw_data:
val = raw_data[k]
return clean_string_val(val)
for rk in raw_data.keys():
rk_clean = str(rk).strip().lower().replace("_", "").replace(" ", "").replace("-", "")
k_clean = str(k).strip().lower().replace("_", "").replace(" ", "").replace("-", "")
if rk_clean == k_clean:
val = raw_data[rk]
return clean_string_val(val)
return ""
def clean_string_val(val):
if pd.isna(val):
return ""
if isinstance(val, float) and val.is_integer():
return str(int(val))
return str(val).strip()
return {
"name_with_initials": get_val(["Name with initials", "Name_with_initials", "name_with_initials", "NameWithInitials", "name"]),
"full_name": get_val(["Full Name", "Full_Name", "full_name", "FullName"]),
"home_address": get_val(["Home Adress", "Home Address", "home_address", "Home_Adress", "address"]),
"welcome_name": get_val(["welcome name", "welcome_name", "welcomeName"]),
"start_date": get_val(["Start date", "Start_Date", "start_date", "StartDate"]),
"end_date": get_val(["End date", "End_Date", "end_date", "EndDate"]),
"nic": get_val(["NIC", "nic", "NIC Number", "nic_number"]),
"department": get_val(["Department", "department"]),
"telephone_number": get_val(["Telephone number", "Telephone_number", "telephone_number", "TelephoneNumber", "tel"]),
"supervisor_name": get_val(["Supervisor name", "Supervisor_name", "supervisor_name", "SupervisorName"]),
"supervisor_designation": get_val(["supervisor designation", "supervisor_designation", "supervisorDesignation", "Supervisor_Designation"]),
"line_address": get_val(["line adress", "line address", "line_address", "Line_Adress", "Line_Address"])
}
def fill_document(template_path, data):
doc = Document(template_path)
placeholders = {
"NAME_WITH_INITIALS": data["name_with_initials"],
"FULL_NAME": data["full_name"],
"HOME_ADDRESS": data["home_address"],
"WELCOME_NAME": data["welcome_name"],
"START_DATE": format_standard_date(data["start_date"]),
"START_DATE_ORDINAL": format_ordinal_date(data["start_date"]),
"END_DATE": format_standard_date(data["end_date"]),
"NIC": data["nic"],
"DEPARTMENT": data["department"],
"TELEPHONE": data["telephone_number"],
"SUPERVISOR_NAME": data["supervisor_name"],
"SUPERVISOR_DESIGNATION": data["supervisor_designation"],
"LINE_ADDRESS": data["line_address"]
}
for p in doc.paragraphs:
for run in p.runs:
if run.text:
for k, v in placeholders.items():
tag = f"{{{{{k}}}}}"
if tag in run.text:
run.text = run.text.replace(tag, str(v))
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for p in cell.paragraphs:
for run in p.runs:
if run.text:
for k, v in placeholders.items():
tag = f"{{{{{k}}}}}"
if tag in run.text:
run.text = run.text.replace(tag, str(v))
file_stream = io.BytesIO()
doc.save(file_stream)
file_stream.seek(0)
return file_stream.getvalue()
def create_zip_archive(data_list):
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
for raw_data in data_list:
data = normalize_data(raw_data)
if not data['full_name'] or data['full_name'] == 'nan':
continue
safe_name = data['full_name'].replace(" ", "_")
ol_file = fill_document(OFFER_LETTER_TEMPLATE_PATH, data)
nda_file = fill_document(NDA_TEMPLATE_PATH, data)
zip_file.writestr(f"Offer_Letters/{safe_name}_Offer_Letter.docx", ol_file)
zip_file.writestr(f"NDAs/{safe_name}_NDA.docx", nda_file)
zip_buffer.seek(0)
return zip_buffer
@app.post("/generate")
async def generate_single(data: InternData):
try:
zip_buffer = create_zip_archive([data.dict()])
safe_name = data.full_name.replace(' ', '_')
return StreamingResponse(
zip_buffer,
media_type="application/x-zip-compressed",
headers={
"Content-Disposition": f"attachment; filename=Intern_Docs_{safe_name}.zip"}
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/generate-bulk")
async def generate_bulk(file: UploadFile = File(...)):
if not file.filename.endswith(('.xlsx', '.xls')):
raise HTTPException(
status_code=400, detail="කරුණාකර Excel (.xlsx) ෆයිල් එකක් පමණක් Upload කරන්න.")
try:
contents = await file.read()
df = pd.read_excel(io.BytesIO(contents))
data_list = df.to_dict(orient='records')
zip_buffer = create_zip_archive(data_list)
return StreamingResponse(
zip_buffer,
media_type="application/x-zip-compressed",
headers={
"Content-Disposition": "attachment; filename=Bulk_Intern_Docs.zip"}
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8080)