| |
| """Fill and correct the URAAS IBR Proposal Presentation.pptx using verified facts |
| from the codebase and the IBR application document.""" |
| import copy |
| from pptx import Presentation |
| from pptx.util import Emu, Pt |
| from pptx.dml.color import RGBColor |
| from pptx.enum.text import PP_ALIGN |
| from pptx.oxml.ns import qn |
|
|
| SRC = r"c:\Users\hp\Downloads\crawler-unilag-apa\URAAS IBR Proposal Presentation.pptx" |
| OUT = r"c:\Users\hp\Downloads\crawler-unilag-apa\URAAS IBR Proposal Presentation - Filled.pptx" |
|
|
| BLUE = RGBColor(0x00, 0x70, 0xC0) |
| GOLD = RGBColor(0xD4, 0xA8, 0x43) |
| DARKGOLD = RGBColor(0x9C, 0x77, 0x15) |
| BLACK = RGBColor(0x22, 0x22, 0x22) |
|
|
| prs = Presentation(SRC) |
|
|
| TITLE_LEFT = Emu(1524634) |
| TITLE_TOP = Emu(1136655) |
| TITLE_WIDTH = Emu(15773400) |
| TITLE_HEIGHT = Emu(1988345) |
| CONTENT_TOP = Emu(3200000) |
| CONTENT_HEIGHT = Emu(6700000) |
|
|
|
|
| def shape_by_id(slide, sid): |
| for s in slide.shapes: |
| if s.shape_id == sid: |
| return s |
| raise KeyError(sid) |
|
|
|
|
| def set_run_text_replace(slide, sid, old, new): |
| shp = shape_by_id(slide, sid) |
| for para in shp.text_frame.paragraphs: |
| for run in para.runs: |
| if old in run.text: |
| run.text = run.text.replace(old, new) |
|
|
|
|
| def fill_content_placeholder(slide, items, left=TITLE_LEFT, top=CONTENT_TOP, |
| width=TITLE_WIDTH, height=CONTENT_HEIGHT): |
| """items: list of (level, text, bold, color, size_pt)""" |
| ph = None |
| for shp in slide.placeholders: |
| if shp.placeholder_format.idx == 1: |
| ph = shp |
| break |
| ph.left, ph.top, ph.width, ph.height = left, top, width, height |
| tf = ph.text_frame |
| tf.word_wrap = True |
| |
| tf.clear() |
| first = True |
| for level, text, bold, color, size in items: |
| if first: |
| p = tf.paragraphs[0] |
| first = False |
| else: |
| p = tf.add_paragraph() |
| p.level = level |
| run = p.add_run() |
| run.text = text |
| run.font.bold = bold |
| run.font.size = Pt(size) |
| run.font.name = "Georgia" |
| if color: |
| run.font.color.rgb = color |
| p.space_after = Pt(8 if level == 0 else 4) |
| return ph |
|
|
|
|
| def new_content_slide(title_text): |
| layout = [l for l in prs.slide_layouts if l.name == "Title and Content"][0] |
| slide = prs.slides.add_slide(layout) |
| title_ph = slide.shapes.title |
| title_ph.left, title_ph.top, title_ph.width, title_ph.height = ( |
| TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, TITLE_HEIGHT) |
| title_ph.text_frame.clear() |
| p = title_ph.text_frame.paragraphs[0] |
| run = p.add_run() |
| run.text = title_text |
| run.font.bold = True |
| run.font.name = "Times New Roman" |
| run.font.color.rgb = BLUE |
| run.font.size = Pt(40) |
| return slide |
|
|
|
|
| def clone_shape(slide, sid, dx, dy, new_text=None): |
| src = shape_by_id(slide, sid) |
| new_el = copy.deepcopy(src._element) |
| |
| max_id = max(s.shape_id for s in slide.shapes) |
| cNvPr = new_el.find(qn('p:nvSpPr') + '/' + qn('p:cNvPr')) |
| if cNvPr is None: |
| cNvPr = new_el.find(qn('p:nvSpPr')) |
| cNvPr = cNvPr.find(qn('p:cNvPr')) |
| cNvPr.set('id', str(max_id + 1)) |
| slide.shapes._spTree.append(new_el) |
| new_shape = slide.shapes[-1] |
| new_shape.left = Emu(src.left + dx) |
| new_shape.top = Emu(src.top + dy) |
| if new_text is not None and new_shape.has_text_frame: |
| paras = new_shape.text_frame.paragraphs |
| if paras and paras[0].runs: |
| paras[0].runs[0].text = new_text |
| return new_shape |
|
|
|
|
| |
| |
| |
| slide = prs.slides[1] |
| items = [ |
| (0, "Indigenous Knowledge is a foundational African intellectual asset", True, BLUE, 22), |
| (1, "Oral traditions, ecological practice, medicine and cultural heritage accumulated across generations (Berkes, 2009; Battiste, 2002)", False, BLACK, 18), |
| (0, "That knowledge is disappearing faster than it can be documented", True, BLUE, 22), |
| (1, "Globalization, urban migration and the loss of elder custodians erode oral-only transmission systems (UNESCO, 2017; Ngulube, 2002)", False, BLACK, 18), |
| (0, "Nigerian scholarly and cultural output is scattered and unindexed", True, BLUE, 22), |
| (1, "Departmental drives, personal pages and print-only archives β undiscoverable, duplicated, at risk of permanent loss", False, BLACK, 18), |
| (0, "Conventional repositories were not built for African epistemologies", True, BLUE, 22), |
| (1, "DSpace-style tools reflect linear, Western archival norms; Mukurtu CMS was built for Pacific Indigenous communities β neither natively supports Yoruba, Igbo, Hausa, oral-source attribution or community-ownership flags", False, BLACK, 18), |
| (0, "Directly aligned to TETFund NRF 2026 priorities", True, GOLD, 22), |
| (1, "Thematic area: ICT in Education & Library and Information Science β identified by the UNILAG Research Management Office as a strategic digital-preservation gap", False, BLACK, 18), |
| (0, "Our response: URAAS", True, DARKGOLD, 24), |
| (1, "A self-archiving, analytics-driven digital repository purpose-built to harvest, classify, preserve and analyse African research, indigenous knowledge and cultural heritage", False, BLACK, 18), |
| ] |
| fill_content_placeholder(slide, items) |
|
|
| |
| |
| |
| slide = prs.slides[3] |
| items = [ |
| (0, "Aim", True, BLUE, 22), |
| (1, "Design and deploy a self-archiving, analytics-driven digital asset management system to curate, preserve and evaluate the impact of Indigenous Knowledge, cultural heritage and African innovation.", False, BLACK, 18), |
| (0, "Specific Objectives", True, BLUE, 22), |
| (1, "1. Deploy URAAS as an enterprise-level, automated web crawler to centralize scattered institutional research assets", False, BLACK, 18), |
| (1, "2. Safeguard institutional scholarly output against data loss through robust digital preservation architecture", False, BLACK, 18), |
| (1, "3. Enable large-scale processing of discovery logs and metadata to reveal actionable patterns for university administrators and library leadership", False, BLACK, 18), |
| (1, "4. Undertake analytics to review trends and produce data-guided reports for institutional decision-making and impact", False, BLACK, 18), |
| (0, "Guiding Research Questions", True, GOLD, 22), |
| (1, "Does automated archival improve preservation speed & coverage vs. manual workflows?", False, BLACK, 17), |
| (1, "Can automated metadata extraction reduce fragmentation and raise the visibility of Nigerian IK output?", False, BLACK, 17), |
| (1, "Does curation and archival meaningfully facilitate preservation of IK for posterity?", False, BLACK, 17), |
| (1, "How should cultural sensitivity, IP and data sovereignty be encoded into a digital preservation system?", False, BLACK, 17), |
| ] |
| fill_content_placeholder(slide, items) |
|
|
| |
| |
| |
| slide = prs.slides[4] |
| for shp in slide.shapes: |
| if shp.has_text_frame and "RIVIEW" in shp.text_frame.text: |
| for para in shp.text_frame.paragraphs: |
| for run in para.runs: |
| run.text = run.text.replace("LITERATURE RIVIEW", "LITERATURE REVIEW") |
|
|
| items = [ |
| (0, "Analytics-driven institutional decision-making", True, BLUE, 21), |
| (1, "Predictive analytics and scenario simulation replace reactive, anecdotal library planning (Davenport & Harris, 2007; Witten et al., 2011)", False, BLACK, 17), |
| (0, "NLP-enabled metadata enrichment", True, BLUE, 21), |
| (1, "Automated extraction reduces fragmentation and improves discoverability of dispersed IK sources (Bird et al., 2009; Grishman, 1997)", False, BLACK, 17), |
| (0, "Curation as active cultural continuity, not passive storage", True, BLUE, 21), |
| (1, "Community-participatory archival frameworks preserve authenticity and IP sovereignty (Smith, 2012; Christen, 2012)", False, BLACK, 17), |
| (0, "The gap this project fills", True, GOLD, 21), |
| (1, "No enterprise-grade system exists for Nigerian multilingual, orally-transmitted, non-linear knowledge β existing tools (DSpace, Mukurtu) were not designed for this context", False, BLACK, 17), |
| (0, "Theoretical Framework", True, DARKGOLD, 21), |
| (1, "Data-Driven Decision-Making (DDDM) & Intelligence-Driven Leadership β centralized, evidence-based systems improve strategic outputs and institutional rankings", False, BLACK, 17), |
| (1, "Knowledge Management Theory (Nonaka & Takeuchi, 1995) β converting tacit indigenous knowledge into explicit, archivable form", False, BLACK, 17), |
| (1, "Digital Heritage Theory (UNESCO, 2017) β authenticity, accessibility and sustainability of digital cultural artefacts", False, BLACK, 17), |
| ] |
| fill_content_placeholder(slide, items) |
|
|
| |
| |
| |
| slide = prs.slides[5] |
| items = [ |
| (0, "Modular microservices architecture", True, BLUE, 21), |
| (1, "Django REST Framework Β· Elasticsearch 8.x Β· PostgreSQL Β· React.js PWA Β· Celery task queue", False, BLACK, 17), |
| (0, "Six delivery phases", True, BLUE, 21), |
| (1, "1. Framework Development β architecture & environment setup", False, BLACK, 16), |
| (1, "2. Identification, Classification & Coding β URAAS Taxonomy & Metadata Standard (UTMS): MARC 21 + Dublin Core + IK-specific fields", False, BLACK, 16), |
| (1, "3. Crawling & Curating β automated ingestion, NLP enrichment, MinHash duplicate detection", False, BLACK, 16), |
| (1, "4. Validation β technical (SHA-256, PRONOM, ClamAV/PII) and cultural-compliance auditing", False, BLACK, 16), |
| (1, "5. Preservation β three-site distributed storage, 25-year sustainability horizon", False, BLACK, 16), |
| (1, "6. Analytics for Impact β Apache Superset dashboard over Elasticsearch + PostgreSQL", False, BLACK, 16), |
| (0, "Already in build β not just on paper", True, GOLD, 21), |
| (1, "14 live harvesting spiders already running (OpenAlex, Crossref, DOAJ, AJOL, OAI-PMH, PubMed, DataCite, ISNI and more)", False, BLACK, 17), |
| (1, "3-gate attribution filter (ROR + staff fuzzy-match + affiliation regex) already validating live UNILAG output", False, BLACK, 17), |
| (1, "DocID + ARK persistent identifiers minted per record; direct DSpace 9.1 institutional-repository deposit pipeline", False, BLACK, 17), |
| (1, "Working analytics engine β TK Vitality Score, Linguistic Diversity Index, Intra-African Collaboration, SDG alignment", False, BLACK, 17), |
| (1, "See System Architecture & Live Demo, next β", False, DARKGOLD, 17), |
| ] |
| fill_content_placeholder(slide, items) |
|
|
| |
| |
| |
| s6 = prs.slides[6] |
| set_run_text_replace(s6, 7, "11", "14") |
| set_run_text_replace(s6, 12, "133", "346") |
| set_run_text_replace(s6, 22, "IR, with ", "IR β ") |
| set_run_text_replace(s6, 22, "approval workflow", "direct deposit (no manual gate)") |
|
|
| s7 = prs.slides[7] |
| set_run_text_replace(s7, 6, "11", "14") |
| set_run_text_replace(s7, 7, "+ 5 more", "+ 8 more") |
|
|
| s8 = prs.slides[8] |
| set_run_text_replace( |
| s8, 14, |
| "Institution-specific lists, 400+ researchers each.", |
| "UNILAG staff registry: 500 named researchers (3,107 detailed records).", |
| ) |
|
|
| s9 = prs.slides[9] |
| set_run_text_replace(s9, 3, "Eleven sources", "Fourteen sources") |
| _seed_shape = shape_by_id(s9, 30) |
| _seed_runs = _seed_shape.text_frame.paragraphs[0].runs |
| _seed_runs[0].text = "20 seed phrases " |
| _seed_runs[1].text = "across 8 Special Collections categories, injected as oversampling queries." |
| |
| |
| col3_dx = 7140972 - 1047750 |
| row5_dy = 5616873 - 4854873 |
| |
| clone_shape(s9, 22, col3_dx, 0) |
| clone_shape(s9, 23, col3_dx, 0, new_text="arXiv") |
| |
| clone_shape(s9, 22, 0, row5_dy) |
| clone_shape(s9, 23, 0, row5_dy, new_text="DataCite") |
| |
| clone_shape(s9, 24, 0, row5_dy) |
| clone_shape(s9, 25, 0, row5_dy, new_text="ISNI") |
|
|
| s10 = prs.slides[10] |
| set_run_text_replace(s10, 12, "6.2% global baseline", "8.4% global baseline") |
| set_run_text_replace(s10, 14, "Citations Velocity", "Citation Velocity") |
| set_run_text_replace(s10, 15, "Lag between use of citations records", "Time lag between publication and first citation, tracked per record") |
|
|
| |
| |
| |
|
|
| |
| slide = new_content_slide("EXPECTED OUTCOMES & INNOVATION") |
| items = [ |
| (0, "Six outcomes, mapped to the six methodology phases", True, BLUE, 20), |
| (1, "URAAS Indigenous Knowledge Taxonomy & Metadata Standard (UTMS) β openly published, reusable across Nigerian universities", False, BLACK, 16), |
| (1, "Fully functional, deployable URAAS platform β self-archiving portal, role-based access, multilingual interface, documented API", False, BLACK, 16), |
| (1, "Populated repository β minimum 5,000 indexed records (faculty outputs + community-sourced IK assets: audio, video, text, image)", False, BLACK, 16), |
| (1, "Validation & Audit Report β integrity, cultural compliance, IP sovereignty; replicable Community Validation Protocol", False, BLACK, 16), |
| (1, "Digital Preservation Policy β three-site redundancy, signed post-grant maintenance MoU, 25-year survival horizon", False, BLACK, 16), |
| (1, "Quarterly Data-Guided Reports + final Impact Assessment Report, feeding UNILAG strategic planning", False, BLACK, 16), |
| (0, "Innovation", True, GOLD, 20), |
| (1, "First enterprise-grade digital asset management system purpose-built for African epistemologies (vs. Mukurtu, standard DSpace)", False, BLACK, 16), |
| (1, "Single pipeline unifying crawling, curation and analytics β not three separate tools bolted together", False, BLACK, 16), |
| (1, "100% open-source stack β zero recurring licence cost, sustainable by any Nigerian university with basic cloud infrastructure", False, BLACK, 16), |
| ] |
| fill_content_placeholder(slide, items) |
|
|
| |
| slide = new_content_slide("BUDGET & TIMELINE (9 MONTHS)") |
| items = [ |
| (0, "Total requested: β¦4,889,529.50", True, BLUE, 22), |
| (1, "Personnel 12.5% | Equipment 27.6% | Data Collection & Analysis 31.0%", False, BLACK, 17), |
| (1, "Dissemination 10.8% | Consumables 8.2% | Travel 5.1% | Miscellaneous 4.9%", False, BLACK, 17), |
| (0, "9-month delivery timeline", True, BLUE, 22), |
| (1, "M1β2 Framework & technical architecture setup", False, BLACK, 17), |
| (1, "M2β3 Indigenous Knowledge Taxonomy & Metadata Standard (UTMS)", False, BLACK, 17), |
| (1, "M3β6 Crawling, ingestion & NLP enrichment (target: 5,000+ records)", False, BLACK, 17), |
| (1, "M5β7 Technical & cultural-compliance validation", False, BLACK, 17), |
| (1, "M6β8 Three-site preservation infrastructure", False, BLACK, 17), |
| (1, "M6β9 Analytics dashboard build & community engagement", False, BLACK, 17), |
| (1, "M9 Final Impact Assessment Report", False, BLACK, 17), |
| ] |
| fill_content_placeholder(slide, items) |
|
|
| |
| slide = new_content_slide("TEAM & INSTITUTIONAL CAPACITY") |
| items = [ |
| (0, "A cross-functional team already operating the working prototype", True, BLUE, 20), |
| (1, "Dr Titilayo Adedokun β Principal Investigator, Senior Librarian, Ph.D Library Science", False, BLACK, 17), |
| (1, "Prof. Olatokunbo Okiki β Ph.D Library Science", False, BLACK, 17), |
| (1, "Prof. Luqman Adams β Ph.D, University Ranking Data Provider", False, BLACK, 17), |
| (1, "Olufemi Agunbiade β B.Sc, Data Analytics", False, BLACK, 17), |
| (1, "Giyath Lawal β Undergraduate Software Engineer, lead builder of the working URAAS prototype", False, BLACK, 17), |
| (0, "Sustainability", True, GOLD, 20), |
| (1, "Zero-markup, open-source stack (Scrapy, Django, Elasticsearch, PostgreSQL, Superset) β no recurring vendor dependency", False, BLACK, 17), |
| (1, "Signed MoU secures post-grant institutional maintenance for a minimum of 25 years", False, BLACK, 17), |
| (1, "Crawler already configured for 43 institutions beyond UNILAG β a foundation for pan-Nigerian scale-up", False, BLACK, 17), |
| ] |
| fill_content_placeholder(slide, items) |
|
|
| |
| layout = [l for l in prs.slide_layouts if l.name == "Title and Content"][0] |
| slide = prs.slides.add_slide(layout) |
| ph = None |
| for shp in slide.placeholders: |
| if shp.placeholder_format.idx == 1: |
| ph = shp |
| ph.left, ph.top, ph.width, ph.height = Emu(1257300), Emu(2500000), Emu(15773400), Emu(5500000) |
| tf = ph.text_frame |
| tf.word_wrap = True |
| tf.clear() |
| p = tf.paragraphs[0] |
| p.alignment = PP_ALIGN.CENTER |
| run = p.add_run() |
| run.text = "Thank You" |
| run.font.bold = True |
| run.font.name = "Times New Roman" |
| run.font.color.rgb = BLUE |
| run.font.size = Pt(54) |
|
|
| p2 = tf.add_paragraph() |
| p2.alignment = PP_ALIGN.CENTER |
| r2 = p2.add_run() |
| r2.text = "Questions & Discussion" |
| r2.font.name = "Georgia" |
| r2.font.color.rgb = GOLD |
| r2.font.size = Pt(28) |
| r2.font.bold = True |
|
|
| p3 = tf.add_paragraph() |
| p3.alignment = PP_ALIGN.CENTER |
| r3 = p3.add_run() |
| r3.text = "Requesting β¦4,889,529.50 over 9 months to take URAAS from working prototype to a validated, deployed institutional asset." |
| r3.font.name = "Georgia" |
| r3.font.size = Pt(20) |
|
|
| prs.save(OUT) |
| print("Saved:", OUT) |
|
|