|
import pandas as pd |
|
import streamlit as st |
|
import re |
|
import logging |
|
from docx import Document |
|
from langdetect import detect |
|
from transformers import pipeline |
|
from dotenv import load_dotenv |
|
from langchain_groq import ChatGroq |
|
from langchain_core.output_parsers import StrOutputParser |
|
from langchain_core.prompts import ChatPromptTemplate |
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") |
|
|
|
|
|
llm = ChatGroq(temperature=0.5, groq_api_key="GROQ_API_KEY", model_name="llama3-8b-8192") |
|
|
|
|
|
nltk.download("punkt") |
|
|
|
|
|
frame_categories = { |
|
"Human Rights & Justice": ["rights", "law", "justice", "legal", "humanitarian"], |
|
"Political & State Accountability": ["government", "policy", "state", "corruption", "accountability"], |
|
"Gender & Patriarchy": ["gender", "women", "violence", "patriarchy", "equality"], |
|
"Religious Freedom & Persecution": ["religion", "persecution", "minorities", "intolerance", "faith"], |
|
"Grassroots Mobilization": ["activism", "community", "movement", "local", "mobilization"], |
|
"Environmental Crisis & Activism": ["climate", "deforestation", "water", "pollution", "sustainability"], |
|
"Anti-Extremism & Anti-Violence": ["extremism", "violence", "hate speech", "radicalism", "mob attack"], |
|
"Social Inequality & Economic Disparities": ["class privilege", "labor rights", "economic", "discrimination"], |
|
"Activism & Advocacy": ["justice", "rights", "demand", "protest", "march", "campaign", "freedom of speech"], |
|
"Systemic Oppression": ["discrimination", "oppression", "minorities", "marginalized", "exclusion"], |
|
"Intersectionality": ["intersecting", "women", "minorities", "struggles", "multiple oppression"], |
|
"Call to Action": ["join us", "sign petition", "take action", "mobilize", "support movement"], |
|
"Empowerment & Resistance": ["empower", "resist", "challenge", "fight for", "stand up"], |
|
"Climate Justice": ["environment", "climate change", "sustainability", "biodiversity", "pollution"], |
|
"Human Rights Advocacy": ["human rights", "violations", "honor killing", "workplace discrimination", "law reform"] |
|
} |
|
|
|
|
|
def detect_language(text): |
|
try: |
|
return detect(text) |
|
except Exception as e: |
|
logging.error(f"Error detecting language: {e}") |
|
return "unknown" |
|
|
|
|
|
def extract_tone(text): |
|
try: |
|
response = llm.chat([{"role": "system", "content": "Analyze the tone of the following text and provide descriptive tone labels."}, |
|
{"role": "user", "content": text}]) |
|
return response["choices"][0]["message"]["content"].split(", ") |
|
except Exception as e: |
|
logging.error(f"Groq API error: {e}") |
|
return extract_tone_fallback(text) |
|
|
|
|
|
def extract_tone_fallback(text): |
|
detected_tones = set() |
|
text_lower = text.lower() |
|
for category, keywords in tone_categories.items(): |
|
if any(word in text_lower for word in keywords): |
|
detected_tones.add(category) |
|
return list(detected_tones) if detected_tones else ["Neutral"] |
|
|
|
|
|
def extract_frames(text): |
|
try: |
|
response = llm.chat([{"role": "system", "content": "Classify the following text into relevant activism frames and assign Major, Significant, or Minor focus."}, |
|
{"role": "user", "content": text}]) |
|
return response["choices"][0]["message"]["content"] |
|
except Exception as e: |
|
logging.error(f"Groq API error: {e}") |
|
return extract_frames_fallback(text) |
|
|
|
|
|
def extract_frames_fallback(text): |
|
detected_frames = set() |
|
text_lower = text.lower() |
|
for category, keywords in frame_categories.items(): |
|
if any(word in text_lower for word in keywords): |
|
detected_frames.add(f"{category}: Major Focus") |
|
return list(detected_frames) if detected_frames else ["No Focus"] |
|
|
|
|
|
def extract_captions_from_docx(docx_file): |
|
doc = Document(docx_file) |
|
captions = {} |
|
current_post = None |
|
for para in doc.paragraphs: |
|
text = para.text.strip() |
|
if re.match(r"Post \d+", text, re.IGNORECASE): |
|
current_post = text |
|
captions[current_post] = [] |
|
elif current_post: |
|
captions[current_post].append(text) |
|
return {post: " ".join(lines) for post, lines in captions.items() if lines} |
|
|
|
|
|
def extract_metadata_from_excel(excel_file): |
|
try: |
|
df = pd.read_excel(excel_file) |
|
metadata = df.set_index("Post Number").to_dict(orient="index") |
|
return metadata |
|
except Exception as e: |
|
logging.error(f"Error reading Excel file: {e}") |
|
return {} |
|
|
|
|
|
def merge_metadata_with_generated_data(generated_data, excel_metadata): |
|
for post, metadata in excel_metadata.items(): |
|
if post in generated_data: |
|
generated_data[post].update(metadata) |
|
return generated_data |
|
|
|
|
|
def create_structured_output_without_table(merged_data, output_path): |
|
doc = Document() |
|
doc.add_heading('Extracted Social Media Data', 0) |
|
|
|
|
|
for sr_no, (post, data) in enumerate(merged_data.items(), 1): |
|
doc.add_heading(f'Post {sr_no}', level=1) |
|
|
|
|
|
doc.add_paragraph(f"Date of Post: {data.get('Date of Post', 'N/A')}") |
|
doc.add_paragraph(f"Media Type: {data.get('Media Type', 'N/A')}") |
|
doc.add_paragraph(f"No of Pictures: {data.get('No of Pictures', 0)}") |
|
doc.add_paragraph(f"No of Videos: {data.get('No of Videos', 0)}") |
|
doc.add_paragraph(f"No of Audios: {data.get('No of Audios', 0)}") |
|
doc.add_paragraph(f"Likes: {data.get('Likes', 'N/A')}") |
|
doc.add_paragraph(f"Comments: {data.get('Comments', 'N/A')}") |
|
doc.add_paragraph(f"Tagged Audience: {data.get('Tagged Audience', 'No')}") |
|
doc.add_paragraph(f"Caption: {data.get('Full Caption', 'N/A')}") |
|
doc.add_paragraph(f"Language of Caption: {data.get('Language', 'N/A')}") |
|
doc.add_paragraph(f"Total No of Hashtags: {len(data.get('Hashtags', []))}") |
|
|
|
if data.get('Hashtags'): |
|
doc.add_paragraph(f"Hashtags: {', '.join(data['Hashtags'])}") |
|
else: |
|
doc.add_paragraph("Hashtags: N/A") |
|
|
|
|
|
doc.add_heading("Frames", level=2) |
|
if data.get("Frames"): |
|
for frame in data['Frames']: |
|
doc.add_paragraph(f"- {frame}") |
|
else: |
|
doc.add_paragraph("No Frames available") |
|
|
|
doc.add_paragraph("\n") |
|
|
|
|
|
doc.save(output_path) |
|
|
|
|
|
st.title("AI-Powered Activism Message Analyzer") |
|
|
|
st.write("Enter text or upload a DOCX/Excel file for analysis:") |
|
|
|
|
|
input_text = st.text_area("Input Text", height=200) |
|
|
|
|
|
uploaded_docx = st.file_uploader("Upload a DOCX file", type=["docx"]) |
|
|
|
|
|
uploaded_excel = st.file_uploader("Upload an Excel file", type=["xlsx"]) |
|
|
|
|
|
output_data = {} |
|
|
|
|
|
if uploaded_docx: |
|
output_data = extract_captions_from_docx(uploaded_docx) |
|
if uploaded_excel: |
|
metadata = extract_metadata_from_excel(uploaded_excel) |
|
output_data = merge_metadata_with_generated_data(output_data, metadata) |
|
|
|
|
|
if output_data: |
|
|
|
for post, data in output_data.items(): |
|
|
|
frames = extract_frames(data) |
|
data['Frames'] = frames |
|
|
|
|
|
create_structured_output_without_table(output_data, "final_output.docx") |
|
st.write("The DOCX file has been created and saved!") |
|
st.download_button("Download DOCX", data=open("final_output.docx", "rb"), file_name="final_output.docx") |
|
|
|
|
|
|