This document provides detailed technical documentation for all modules in the TCDOC_EXTRACT toolkit.
- document_extract2.py - Document text extraction
- predefined_categories6.py - Action categorization
- evaluate_multi_col.py - Performance evaluation
- subclus_calc_weight.py - TF-IDF keyword analysis
- rule_based_class.py - Sub-category classification
- rag_extract_simple12.py - RAG document extraction
- rag_alignment_workflow_unpaired8.py - Action alignment workflow
- enumerate_resources.py - Resource enumeration
- create_graphical_summary_multi_institution.py - Graphical visualization
- create_comprehensive_summary_multi_institution.py - Text-based summary tables
Extracts action items from Technician Commitment documents stored in Google Drive using AI-powered text analysis.
Handles OAuth2 authentication for Google Drive API access.
Returns:
Credentials: Valid Google OAuth2 credentials
Files Used:
credentials.json- OAuth2 client credentialstoken.json- Stored authentication token
Retrieves list of files from a specified Google Drive folder.
Parameters:
service: Google Drive API service instancefolder_id(str): Google Drive folder ID
Returns:
list: List of file metadata dictionaries
Extracts text content from Google Docs or PDF files.
Parameters:
service: Google Drive API service instancefile_id(str): Google Drive file IDmime_type(str): MIME type of the file
Returns:
str: Extracted text content
Supported Formats:
- Google Docs (
application/vnd.google-apps.document) - PDF files (
application/pdf)
Uses Google Gemini AI to extract discrete action items from document text.
Parameters:
text(str): Full document text
Returns:
list: List of extracted action strings
Configuration:
- Model:
gemini-2.5-pro - Temperature: 0.0 (deterministic output)
- Location:
us-central1
SCOPES = ['https://www.googleapis.com/auth/drive.readonly']
CREDENTIALS_FILE = 'credentials.json'
TOKEN_FILE = 'token.json'
LOCATION = 'us-central1'
OUTPUT_CSV_FILE = 'actions_output2.csv'
PROJECT_ID = 'tcdocext'
MODEL_ID = 'gemini-2.5-pro'CSV file with columns:
Document Name: Source document filenameExtracted Action: Individual action item text
Categorizes extracted actions into predefined thematic categories using weighted keyword matching and NLP preprocessing.
Tokenizes and normalizes text using NLTK.
Parameters:
text(str): Input text to preprocessmode(str): Processing mode ('lemmatization' or basic tokenization)
Returns:
list: List of preprocessed tokens
Processing Steps:
- Tokenization
- Lowercase conversion
- Stopword removal (with custom exceptions)
- POS tagging
- Lemmatization
Converts Penn Treebank POS tags to WordNet tags.
Parameters:
treebank_tag(str): Penn Treebank POS tag
Returns:
- WordNet POS constant
Loads and preprocesses keyword dictionary from JSON.
Parameters:
filename(str): Path to keyword JSON filemode(str): Preprocessing mode
Returns:
dict: Category -> [(token_tuple, weight), ...] mapping
categorize_action_with_scoring(action_text, category_keywords, mode='lemmatization', use_ratio_threshold=False, ratio=0.3, min_score=0.1)
Scores action against all categories using weighted keyword matching.
Parameters:
action_text(str): Action text to categorizecategory_keywords(dict): Preprocessed keyword dictionarymode(str): Processing modeuse_ratio_threshold(bool): Whether to use relative thresholdratio(float): Relative score threshold (0.0-1.0)min_score(float): Minimum absolute score threshold
Returns:
dict: Category -> score mapping
PROCESSING_MODE = "lemmatization"
INPUT_CSV_PATH = 'All_RAG.csv'
KEYWORD_JSON_PATH = 'keyword_categories_4.json'
OUTPUT_CSV_PATH = 'categorized_actions_output_RAG.csv'
MIN_WORD_COUNT = 3
ACTION_COLUMN_NAME = 'Action'Custom stopwords retained for domain-specific meaning:
of,on,for,with,against,upongoing,regular,provide
CSV with one-hot encoded category columns:
- Original action columns preserved
- Binary column per category (1 = assigned, 0 = not assigned)
Uncategorisedcolumn for unmatched actions
Evaluates categorization performance against ground truth using confusion matrix metrics.
Normalizes text for comparison.
Parameters:
s(str): Text to normalize
Returns:
str: Normalized text (lowercase, collapsed whitespace)
Calculates sensitivity and specificity for each category.
Parameters:
df_merged(DataFrame): Merged predictions and ground truthcategory_cols(list): List of category column names
Returns:
DataFrame: Performance metrics per category
Metrics Calculated:
- Sensitivity (Recall): TP / (TP + FN)
- Specificity: TN / (TN + FP)
- True Positives, False Positives, True Negatives, False Negatives
- Support (actual positive count)
PREDICTIONS_FILE = 'categorized_actions_output_multicol_weighted2.csv'
GROUND_TRUTH_FILE = 'ground_truth2.csv'
OUTPUT_REPORT_FILE = 'sensitivity_specificity_report_weighted2.csv'
PREDICTION_ACTION_COL = 'Extracted Action'
GROUND_TRUTH_ACTION_COL = 'Extracted Action'
GROUND_TRUTH_CATEGORY_COL = 'Ground Truth'CSV with columns:
Category: Category nameSensitivity (Recall): 0.0-1.0Specificity: 0.0-1.0True Positives,False Positives,True Negatives,False NegativesSupport (Actual Positives)
Identifies salient keywords within each category using TF-IDF analysis to inform sub-category creation.
Iterates through each category and:
- Filters actions for category
- Applies TF-IDF vectorization
- Sums scores across documents
- Extracts top 15 keywords
- Writes to output file
TfidfVectorizer(
stop_words='english',
max_features=1000,
smooth_idf=True,
sublinear_tf=True
)Input:
Actions_FinalData - All_Data.csvwith columns:Categories: Category nameExtracted Action: Action text
Output:
initial_keyword_analysis.txt: Top 15 keywords per category
Assigns actions to sub-categories within their main category using predefined keyword rules.
Dictionary mapping:
{
'Category Name': {
'Sub-Category Name': ['keyword1', 'keyword2', ...],
...
},
...
}Coverage:
- 17 main categories
- 3 sub-categories per main category
- Manually curated keyword lists
Assigns statement to best-matching sub-category.
Parameters:
statement(str): Action textsubcluster_definitions(dict): Sub-category -> keyword list mapping
Returns:
str: Assigned sub-category name or 'Unassigned'
Algorithm:
- Convert statement to lowercase
- For each sub-category, count whole-word keyword matches
- Assign to sub-category with highest count
- Return 'Unassigned' if all scores are 0
Input:
Actions_FinalData - All_Data.csv
Output:
named_subcluster_analysis.csvwith added column:predefined_subcluster: Sub-category assignment
Extracts actions with RAG (Red/Amber/Green) status indicators from assessment documents.
Same OAuth2 authentication as document_extract2.py.
Extracts institution, year, document type, and RAG flag from filename.
Parameters:
filename(str): Document filename
Returns:
dict: Metadata with keysinstitution,year,doc_type,is_rag
Supported Patterns:
YYYY-Institution-DocTypeInstitution-YYYY-DocTypeInstitutionActionPlanYYYYInstitutionRAGYYYY
Lines 223-517 implement intelligent table parsing:
- Header Detection: Scans rows 0-1 for "action" and "RAG" columns
- Column Selection: Prioritizes exact "action" match, then most content
- Continuation Tables: Tracks columns across headerless continuation tables
- Multi-Row Merging: Combines split actions using capitalization heuristics
- RAG Extraction: Identifies R/A/G markers and normalizes to single-letter format
Lines 520-574 use Gemini AI for documents without tables:
Model: gemini-2.0-flash-001
Prompt Instructions:
- Identify discrete actions as complete sentences
- Remove RAG indicators from action text
- Preserve sentence completeness
- Clean formatting artifacts
Input Limit: First 50,000 characters per document
SCOPES = ["https://www.googleapis.com/auth/drive.readonly"]
CREDENTIALS_FILE = "credentials.json"
TOKEN_FILE = "token.json"
LOCATION = "us-central1"
OUTPUT_CSV_FILE = "rag_actions_extraction.csv"
PROJECT_ID = "tcdocprog"
MODEL_ID = "gemini-2.0-flash"CSV with columns:
LineID: Sequential identifierInstitution: Organization nameDocument Type: AP1, AP2, AP3, RAG_AP1, RAG_AP2, RAG_AP3Action: Full action textRAG value: R, A, or G (empty for Action Plans)Category: Populated by categorization step
Comprehensive workflow for matching actions across documents and time periods, with checkpoint-based resumability.
Applies same categorization as predefined_categories6.py to all extracted actions.
Function: Tier 1 matching (lines 117-289)
Algorithm:
- Filter actions to same period (e.g., AP1 vs RAG_AP1)
- Compute TF-IDF vectors
- Calculate cosine similarity
- Classify matches:
Identical: similarity ≥ 0.95Match: similarity ≥ 0.85Similar: similarity ≥ 0.70
Bidirectional: AP→RAG_AP and RAG_AP→AP
Function: Tier 2 matching (lines 289-383)
Algorithm:
- Compare RAG_AP(n) actions against AP(n+1) actions
- Batch up to 10 comparisons per API call
- Include category metadata in prompt
- Request relationship classification:
Identical: UnchangedExtended: More ambitiousNarrowed: More focusedRelated: Connected but differentUnrelated: No connection
- Return JSON with relationship and confidence score (0.0-1.0)
- Filter to score ≥ 0.5, keep top 5 matches
Implementation:
- Sliding window deque tracking request timestamps
- 15 requests per minute limit
- Automatic sleep when approaching limit
- 4-second pause between batches
Features:
- Saves after each major task completion
- Saves after each institution-period transition
- Stores dataframe to
checkpoints/checkpoint_name.csv - Stores metadata to
checkpoints/workflow_state.json - Auto-detects and offers resume on restart
Metadata Tracked:
- Last completed institution
- Last completed period transition
- Progress metrics
- Timestamp
Codes:
C(Continued): Same focus (Identical/Extended)R(Related): Different focus (Related/Narrowed)S(Stopped): No successorN(New): No predecessorU(Unknown): Insufficient data
Seven quantitative metrics per category:
- Growth Rate: (Period 3 count - Period 1 count) / Period 1 × 100%
- Continuation Rate: (Continued + Related) / (Continued + Related + Stopped) × 100%
- Trajectory Diversity: Shannon entropy of trajectory distribution (0-100%)
- Splitting Ratio: Avg successors per source action
- Merging Ratio: Avg predecessors per target action
- Longevity Score: % of Period 1 actions traceable to Period 3
- Category Coherence: 1 - std dev of trajectory types
PROJECT_ID = "tcdocprog"
LOCATION = "us-central1"
EMBEDDING_MODEL = "text-embedding-004"
INPUT_CSV = "rag_actions_extraction.csv"
OUTPUT_CSV = "rag_actions_extraction_MATCHED.csv"
KEYWORD_JSON = "keyword_categories_4.json"
CHECKPOINT_DIR = "checkpoints"Enriched CSV with:
- All original extraction columns
- Within-period match columns (bidirectional)
- Cross-period match columns with relationships
- Trajectory codes
- Derived metrics
Searches action plans for mentions of external resources, professional bodies, and support structures.
Loads resource names from JSON dictionary.
Parameters:
filename(str): Path to resources JSON
Returns:
list: Flat list of resource names/phrases
Searches for whole-word phrase matches with context display.
Parameters:
actions_df(DataFrame): Actions datasetkey_phrases(list): Resource names to search for
Returns:
DataFrame: Phrase counts
Features:
- Whole-word boundary matching (
\b...\b) - Case-insensitive search
- Context display (10 words before/after)
- Terminal highlighting with ANSI colors
- Multiple matches per action counted
ACTIONS_CSV_PATH = 'actions_output2_all.csv'
KEYPHRASES_JSON_PATH = 'external_resources.json'
ACTION_COLUMN_NAME = 'Extracted Action'
OUTPUT_CSV_PATH = 'exact_phrase_counts_whole_word.csv'
CONTEXT_WORD_COUNT = 10Colored context display:
Found: [phrase] in row 42 >> ...context before PHRASE context after...
CSV with columns:
Key Phrase: Resource nameCount: Number of whole-word matches
Sorted by count (descending)
Generates publication-quality visualizations of category-level action evolution across assessment periods.
Represents 5 data dimensions simultaneously:
- Temporal period: Horizontal axis
- Category membership: Vertical axis
- Action volume: Node size
- Trajectory type: Edge color
- Performance metrics: Heatmap overlay
COLOURS = {
"Continued": "#27ae60", # Green
"Extended": "#27ae60", # Green
"Related": "#f39c12", # Orange
"Narrowed": "#f39c12", # Orange
"Stopped": "#e74c3c", # Red
"New": "#3498db", # Blue
"Unknown": "#95a5a6", # Grey
}- One PNG per institution
- Filename:
{institution}_category_summary.png - High-resolution suitable for publication
Generates text-based summary tables for all institutions in a single output file.
Parses Gemini match results.
Parameters:
match_text(str): Fuzzy match column value
Returns:
list: [(lineid, relationship, score), ...]
Format: "LineID (Relationship, Score); LineID (Relationship, Score); ..."
- Forward-looking transitions: Where actions go in next period
- Backward-looking origins: Where actions came from
- Derived metrics: All 7 quantitative metrics
Single text file with sections per institution, formatted as readable tables.
Google Drive Documents
↓
document_extract2.py → actions_output2.csv
↓
predefined_categories6.py → categorized_actions.csv
↓
evaluate_multi_col.py → performance_report.csv
subclus_calc_weight.py → keyword_analysis.txt
↓
rule_based_class.py → subclustered_actions.csv
Google Drive RAG Docs
↓
rag_extract_simple12.py → rag_actions_extraction.csv
↓
rag_alignment_workflow_unpaired8.py → rag_actions_extraction_MATCHED.csv
↓
├─→ create_graphical_summary_multi_institution.py → PNG files
└─→ create_comprehensive_summary_multi_institution.py → text tables
enumerate_resources.py → resource_counts.csv
- Cause: Missing or invalid
credentials.json - Solution: Download OAuth2 credentials from Google Cloud Console
- Cause: Missing NLTK corpora
- Solution: Run
python -m nltk.downloader punkt averaged_perceptron_tagger wordnet stopwords
- Cause: Free tier API limits reached
- Solution: Workflow automatically falls back to TF-IDF; or upgrade GCP account
- Cause: Input CSV from previous step missing
- Solution: Run pipeline steps in sequence
- Batch Processing:
rag_alignment_workflow_unpaired8.pybatches 10 comparisons per API call - Checkpointing: Use resume functionality for large datasets
- Rate Limiting: Conservative 15 req/min prevents quota exhaustion
- TF-IDF Caching: Within-period matching is fast and cached
- Multiprocessing: Not currently implemented but possible for independent institutions
- document_extract2.py: ~10 sec per document
- predefined_categories6.py: ~1 sec per 1000 actions
- rag_alignment_workflow_unpaired8.py: ~2-3 hours for full dataset (with checkpoints)
- Visualization scripts: ~30 sec per institution
- v1.0 (August 2025): Initial release for Technician Commitment analysis
- Associated paper: "Synergies and Gaps in Technical Skills Development in UK Universities"
- Author: Dr. Samuel J Jackson
For issues or questions:
- Check configuration variables match your file paths
- Verify all dependencies installed (
pip install -r requirements.txt) - Review error messages for specific file/column names
- Consult Methods.txt for methodological details