Skip to content

Commit 8daacf3

Browse files
Merge pull request #65 from seanpedrick-case/dev
Rollback to Gradio 6.0.2 as some features degraded. Improved LLM dedu…
2 parents 5d39fde + c0280e8 commit 8daacf3

18 files changed

+1856
-355
lines changed

Dockerfile

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
# This Dockerfile is optimised for AWS ECS using Python 3.11, and assumes CPU inference with OpenBLAS for local models.
1+
# This Dockerfile is optimised for AWS ECS using Python 3.12, and assumes CUDA 12.6 for local models. The Dockerfile will need to be modified to install all linux CUDA / GPU dependencies.
2+
23
# Stage 1: Build dependencies and download models
3-
FROM public.ecr.aws/docker/library/python:3.11.13-slim-trixie AS builder
4+
FROM public.ecr.aws/docker/library/python:3.12.12-slim-trixie AS builder
45

56
# Install system dependencies.
67
RUN apt-get update && apt-get install -y \
@@ -19,22 +20,20 @@ WORKDIR /src
1920

2021
COPY requirements_lightweight.txt .
2122

22-
# Set environment variables for OpenBLAS - not necessary if not building from source
23-
# ENV OPENBLAS_VERBOSE=1
24-
# ENV CMAKE_ARGS="-DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS"
25-
2623
ARG INSTALL_TORCH=False
2724
ENV INSTALL_TORCH=${INSTALL_TORCH}
2825

26+
# Local torch install requires CUDA 12.6
2927
RUN if [ "$INSTALL_TORCH" = "True" ]; then \
30-
pip install --no-cache-dir --target=/install torch==2.9.1+cpu --extra-index-url https://download.pytorch.org/whl/cpu; \
28+
pip install --no-cache-dir --target=/install torch==2.9.1 --extra-index-url https://download.pytorch.org/whl/cu126; \
3129
fi
3230

3331
ARG INSTALL_LLAMA_CPP_PYTHON=False
3432
ENV INSTALL_LLAMA_CPP_PYTHON=${INSTALL_LLAMA_CPP_PYTHON}
3533

34+
# Llama CPP Python install requires CUDA 12.4
3635
RUN if [ "$INSTALL_LLAMA_CPP_PYTHON" = "True" ]; then \
37-
pip install --no-cache-dir --target=/install https://github.com/seanpedrick-case/llama-cpp-python-whl-builder/releases/download/v0.1.0/llama_cpp_python-0.3.16-cp311-cp311-linux_x86_64.whl; \
36+
pip install --no-cache-dir --target=/install https://github.com/abetlen/llama-cpp-python/releases/download/v0.3.16-cu124/llama_cpp_python-0.3.16-cp312-cp312-linux_x86_64.whl; \
3837
fi
3938

4039
RUN pip install --no-cache-dir --target=/install -r requirements_lightweight.txt
@@ -44,7 +43,7 @@ RUN rm requirements_lightweight.txt
4443
# ===================================================================
4544
# Stage 2: A common 'base' for both Lambda and Gradio
4645
# ===================================================================
47-
FROM public.ecr.aws/docker/library/python:3.11.13-slim-trixie AS base
46+
FROM public.ecr.aws/docker/library/python:3.12.12-slim-trixie AS base
4847

4948
# Set build-time and runtime environment variable for whether to run in Gradio mode or Lambda mode
5049
ARG APP_MODE=gradio

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ emoji: 📚
44
colorFrom: purple
55
colorTo: yellow
66
sdk: gradio
7-
sdk_version: 6.2.0
7+
sdk_version: 6.0.2
88
app_file: app.py
99
pinned: true
1010
license: agpl-3.0
@@ -13,7 +13,7 @@ short_description: Create thematic summaries for open text data with LLMs
1313

1414
# Large language model topic modelling
1515

16-
Version: 0.8.0
16+
Version: 0.9.0
1717

1818
Extract topics and summarise outputs using Large Language Models (LLMs), either local, Gemini, Azure, or AWS Bedrock models (e.g. Claude, Nova models). The app will query the LLM with batches of responses to produce summary tables, which are then compared iteratively to output a table with the general topics, subtopics, topic sentiment, and a topic summary. Instructions on use can be found in the README.md file. You can try out examples by clicking on one of the example datasets on the main app page, which will show you example outputs from a local model run. API keys for AWS, Azure, and Gemini services can be entered on the settings page (note that Gemini has a free public API).
1919

app.py

Lines changed: 14 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from tools.auth import authenticate_user
88
from tools.aws_functions import (
9-
download_file_from_s3,
9+
download_cost_codes_with_error_handling,
1010
export_outputs_to_s3,
1111
upload_file_to_s3,
1212
)
@@ -83,6 +83,7 @@
8383
LOG_FILE_NAME,
8484
MAX_FILE_SIZE,
8585
MAX_QUEUE_SIZE,
86+
MAXIMUM_ALLOWED_TOPICS,
8687
MPLCONFIGDIR,
8788
OUTPUT_COST_CODES_PATH,
8889
OUTPUT_DEBUG_FILES,
@@ -119,7 +120,6 @@
119120
from tools.custom_csvlogger import CSVLogger_custom
120121
from tools.dedup_summaries import (
121122
deduplicate_topics,
122-
deduplicate_topics_llm,
123123
overall_summary,
124124
wrapper_summarise_output_topics_per_group,
125125
)
@@ -135,7 +135,6 @@
135135
empty_output_vars_extract_topics,
136136
empty_output_vars_summarise,
137137
enforce_cost_codes,
138-
ensure_model_in_map,
139138
get_connection_params,
140139
join_cols_onto_reference_df,
141140
load_in_data_file,
@@ -151,6 +150,7 @@
151150
)
152151
from tools.llm_api_call import (
153152
all_in_one_pipeline,
153+
deduplicate_topics_llm_wrapper,
154154
modify_existing_output_tables,
155155
validate_topics_wrapper,
156156
wrapper_extract_topics_per_column_value,
@@ -923,6 +923,7 @@ def show_info_box_on_click(
923923

924924
with gr.Accordion("Response sentiment analysis", open=False):
925925
sentiment_checkbox = gr.Radio(
926+
label="Should the model assess the sentiment of responses?",
926927
value="Negative or Positive",
927928
choices=[
928929
"Negative or Positive",
@@ -1268,7 +1269,15 @@ def show_info_box_on_click(
12681269
precision=1,
12691270
step=0.1,
12701271
)
1272+
with gr.Row(equal_height=True):
12711273
batch_size_number.render()
1274+
max_topics_number = gr.Number(
1275+
value=MAXIMUM_ALLOWED_TOPICS,
1276+
label="Maximum number of topics allowed. If exceeded, the LLM will make efforts to deduplicate topics after every batch until the total number of topics is below this number (not foolproof).",
1277+
precision=0,
1278+
minimum=1,
1279+
maximum=1000,
1280+
)
12721281
random_seed = gr.Number(
12731282
value=LLM_SEED, label="Random seed for LLM generation", visible="hidden"
12741283
)
@@ -1533,6 +1542,7 @@ def show_info_box_on_click(
15331542
additional_validation_issues_textbox,
15341543
show_previous_table_radio,
15351544
api_url_textbox,
1545+
max_topics_number,
15361546
],
15371547
outputs=[
15381548
display_topic_table_markdown,
@@ -1676,6 +1686,7 @@ def show_info_box_on_click(
16761686
aws_secret_key_textbox,
16771687
aws_region_textbox,
16781688
api_url_textbox,
1689+
max_topics_number,
16791690
],
16801691
outputs=[
16811692
display_topic_table_markdown,
@@ -1835,63 +1846,6 @@ def show_info_box_on_click(
18351846
api_name="deduplicate_topics",
18361847
)
18371848

1838-
# When LLM deduplication button pressed, deduplicate data using LLM
1839-
def deduplicate_topics_llm_wrapper(
1840-
reference_df,
1841-
topic_summary_df,
1842-
reference_table_file_name,
1843-
unique_topics_table_file_name,
1844-
model_choice,
1845-
in_api_key,
1846-
temperature,
1847-
in_excel_sheets,
1848-
merge_sentiment,
1849-
merge_general_topics,
1850-
in_data_files,
1851-
chosen_cols,
1852-
output_folder,
1853-
candidate_topics=None,
1854-
azure_endpoint="",
1855-
api_url=None,
1856-
aws_access_key_textbox="",
1857-
aws_secret_key_textbox="",
1858-
aws_region_textbox="",
1859-
azure_api_key_textbox="",
1860-
sentiment_checkbox="Negative or Positive",
1861-
):
1862-
# Ensure custom model_choice is registered in model_name_map
1863-
ensure_model_in_map(model_choice)
1864-
model_source = model_name_map[model_choice]["source"]
1865-
return deduplicate_topics_llm(
1866-
reference_df,
1867-
topic_summary_df,
1868-
reference_table_file_name,
1869-
unique_topics_table_file_name,
1870-
model_choice,
1871-
in_api_key,
1872-
temperature,
1873-
model_source,
1874-
None,
1875-
None,
1876-
None,
1877-
None,
1878-
in_excel_sheets,
1879-
merge_sentiment,
1880-
merge_general_topics,
1881-
in_data_files,
1882-
chosen_cols,
1883-
output_folder,
1884-
candidate_topics,
1885-
azure_endpoint,
1886-
OUTPUT_DEBUG_FILES,
1887-
api_url,
1888-
aws_access_key_textbox,
1889-
aws_secret_key_textbox,
1890-
aws_region_textbox,
1891-
azure_api_key_textbox,
1892-
sentiment_checkbox=sentiment_checkbox,
1893-
)
1894-
18951849
deduplicate_llm_previous_data_btn.click(
18961850
load_in_previous_data_files,
18971851
inputs=[deduplication_input_files],
@@ -2511,16 +2465,6 @@ def deduplicate_topics_llm_wrapper(
25112465
f"Attempting to download from bucket: {S3_LOG_BUCKET}, key: {S3_COST_CODES_PATH}"
25122466
)
25132467

2514-
# Create a wrapper function with error handling
2515-
def download_cost_codes_with_error_handling(bucket, key, local_path):
2516-
try:
2517-
download_file_from_s3(bucket, key, local_path)
2518-
return True
2519-
except Exception as e:
2520-
print(f"Error downloading cost codes from S3: {e}")
2521-
print(f"Failed to download s3://{bucket}/{key}")
2522-
return False
2523-
25242468
app.load(
25252469
download_cost_codes_with_error_handling,
25262470
inputs=[

cli_topics.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
LLM_SEED,
3838
LLM_TEMPERATURE,
3939
MAX_TIME_FOR_LOOP,
40-
MAXIMUM_ZERO_SHOT_TOPICS,
40+
MAXIMUM_ALLOWED_TOPICS,
4141
OUTPUT_DEBUG_FILES,
4242
OUTPUT_FOLDER,
4343
RUN_AWS_FUNCTIONS,
@@ -833,10 +833,10 @@ def main(direct_mode_args={}):
833833
help=f"Enable deduplication after each batch during topic extraction (True/False). Default: {ENABLE_BATCH_DEDUPLICATION}",
834834
)
835835
extract_group.add_argument(
836-
"--maximum_zero_shot_topics",
836+
"--maximum_allowed_topics",
837837
type=int,
838-
default=MAXIMUM_ZERO_SHOT_TOPICS,
839-
help=f"Maximum number of topics before triggering LLM-based deduplication. Default: {MAXIMUM_ZERO_SHOT_TOPICS}",
838+
default=MAXIMUM_ALLOWED_TOPICS,
839+
help=f"Maximum number of topics before triggering LLM-based deduplication. Default: {MAXIMUM_ALLOWED_TOPICS}",
840840
)
841841

842842
# --- Validation Arguments ---
@@ -1061,8 +1061,8 @@ def main(direct_mode_args={}):
10611061

10621062
if hasattr(args, "enable_batch_deduplication"):
10631063
config_module.ENABLE_BATCH_DEDUPLICATION = args.enable_batch_deduplication
1064-
if hasattr(args, "maximum_zero_shot_topics"):
1065-
config_module.MAXIMUM_ZERO_SHOT_TOPICS = args.maximum_zero_shot_topics
1064+
if hasattr(args, "maximum_allowed_topics"):
1065+
config_module.MAXIMUM_ALLOWED_TOPICS = args.maximum_allowed_topics
10661066

10671067
# Get username and folders
10681068
(

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "llm_topic_modelling"
7-
version = "0.8.0"
7+
version = "0.9.0"
88
description = "Generate thematic summaries from open text in tabular data files with a large language model."
99
requires-python = ">=3.10"
1010
readme = "README.md"
@@ -51,7 +51,7 @@ classifiers = [
5151
]
5252

5353
dependencies = [
54-
"gradio==6.2.0",
54+
"gradio==6.0.2",
5555
"transformers==4.57.2",
5656
"spaces==0.42.1",
5757
"boto3==1.42.1",

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Note that this requirements file is optimised for Hugging Face spaces / Python 3.10. Please use requirements_no_local.txt for installation without local model inference (simplest approach to get going). Please use requirements_cpu.txt for CPU instances and requirements_gpu.txt for GPU instances using Python 3.11
2-
gradio==6.2.0
2+
gradio==6.0.2
33
transformers==4.57.2
44
spaces==0.42.1
55
boto3>=1.42.1

requirements_cpu.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
gradio==6.2.0
1+
gradio==6.0.2
22
transformers==4.57.2
33
spaces==0.42.1
44
pandas>=2.3.3

requirements_gpu.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
gradio==6.2.0
1+
gradio==6.0.2
22
transformers==4.57.2
33
spaces==0.42.1
44
boto3>=1.42.1

requirements_lightweight.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This requirements file is optimised for AWS ECS using Python 3.11 alongside the Dockerfile, without local torch and llama-cpp-python. For AWS ECS, torch and llama-cpp-python are optionally installed in the main Dockerfile
2-
gradio==6.2.0
2+
gradio==6.0.2
33
transformers==4.57.2
44
spaces==0.42.1
55
boto3>=1.42.1

test/mock_inference_server.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ def _generate_mock_response(self, prompt: str, system_prompt: str) -> str:
3232
"""
3333
# Generate a simple markdown table that satisfies the validation
3434
# This mimics a topic extraction table response
35-
mock_table = """| Reference | General Topic | Sub-topic | Sentiment |
36-
|-----------|---------------|-----------|-----------|
37-
| 1 | Test Topic | Test Subtopic | Positive |
38-
| 2 | Another Topic | Another Subtopic | Neutral |
39-
| 3 | Third Topic | Third Subtopic | Negative |
35+
mock_table = """| General topic | Subtopic | Sentiment | Response References | Summary |
36+
|-----------|---------------|-----------|-----------|-----------|
37+
| Test Topic | Test Subtopic | Positive | 1 | Test summary |
38+
| Another Topic | Another Subtopic | Neutral | 2,3 | Another summary |
39+
| Third Topic | Third Subtopic | Negative | 1, 2, 3 | Third summary |
4040
4141
This is a mock response from the test inference server. The actual content would be generated by a real LLM model, but for testing purposes, this dummy response allows us to verify that the CLI commands work correctly without incurring API costs."""
4242

0 commit comments

Comments
 (0)