ajurasovic/MENA
0
1import streamlit as st2import json3import ast4 5# Number of topics to display initially per section6INITIAL_VISIBLE_COUNT = 5 # Topics initially visible7TOPIC_INCREMENT = 5 # Number of additional topics shown per "Show More" click8KEYWORD_LIMIT = 10 # Maximum keywords shown initially9 10@st.cache_data11def load_topics_file():12 """Load topics data from topics.txt."""13 with open("topics.txt", "r", encoding="utf-8") as f:14 return f.read()15 16def safe_parse_keywords(keyword_str):17 """18 Safely parses a list of keywords from a given string.19 Handles various formatting issues like mismatched quotes.20 """21 keyword_str = keyword_str.strip()22 23 # Try parsing as a valid JSON array24 try:25 return json.loads(keyword_str)26 except json.JSONDecodeError:27 pass28 29 # Try parsing as a Python literal (handles improperly formatted JSON-like lists)30 try:31 parsed_keywords = ast.literal_eval(keyword_str)32 if isinstance(parsed_keywords, list):33 return parsed_keywords34 except (SyntaxError, ValueError):35 pass36 37 # If parsing fails, return an empty list and log an error38 st.error(f"Error parsing keywords: {keyword_str}")39 return []40 41def parse_topics_from_text(text):42 """43 Parses topics from the structured text section and organizes them into competitive and opportunity topics.44 """45 lines = text.split("\n")46 current_section = None47 competitive_topics = []48 opportunity_topics = []49 current_topic = None50 51 # Ignore the JSON section (everything before '=== Topic Analysis Summary ===')52 start_parsing = False53 54 for line in lines:55 line = line.strip()56 if not line:57 continue58 59 # Detect the start of the relevant section60 if "=== Topic Analysis Summary ===" in line:61 start_parsing = True62 continue63 64 if not start_parsing:65 continue # Skip everything before this section66 67 # Detect section headers68 if "Competitive Topics" in line:69 if current_topic and current_section == "competitive":70 competitive_topics.append(current_topic)71 current_topic = None72 current_section = "competitive"73 continue74 elif "Opportunity Topics" in line:75 if current_topic:76 if current_section == "competitive":77 competitive_topics.append(current_topic)78 elif current_section == "opportunity":79 opportunity_topics.append(current_topic)80 current_topic = None81 current_section = "opportunity"82 continue83 84 # Parse topic details85 if line.startswith("Topic:"):86 if current_topic:87 if current_section == "competitive":88 competitive_topics.append(current_topic)89 elif current_section == "opportunity":90 opportunity_topics.append(current_topic)91 current_topic = {}92 current_topic["title"] = line.replace("Topic:", "").strip()93 elif line.startswith("Total Volume:"):94 current_topic["totalVolume"] = float(line.replace("Total Volume:", "").strip())95 elif line.startswith("Average KD:"):96 current_topic["avgKD"] = float(line.replace("Average KD:", "").strip())97 elif line.startswith("Keyword Count:"):98 current_topic["keywordCount"] = int(line.replace("Keyword Count:", "").strip())99 elif line.startswith("Keywords:"):100 keyword_str = line.replace("Keywords:", "").strip()101 current_topic["keywords"] = safe_parse_keywords(keyword_str)102 103 # Append the last topic if exists104 if current_topic:105 if current_section == "competitive":106 competitive_topics.append(current_topic)107 elif current_section == "opportunity":108 opportunity_topics.append(current_topic)109 110 return competitive_topics, opportunity_topics111 112def display_topics(section_title, topics, key_prefix):113 """Displays topics in a paginated manner with keyword expansion options."""114 st.subheader(section_title)115 116 # Track how many topics to show117 if f"{key_prefix}_visible_count" not in st.session_state:118 st.session_state[f"{key_prefix}_visible_count"] = INITIAL_VISIBLE_COUNT119 120 visible_count = st.session_state[f"{key_prefix}_visible_count"]121 122 for idx, topic in enumerate(topics[:visible_count]):123 st.markdown(f"**{topic['title']}**")124 st.write(f"Total Volume: {topic['totalVolume']}")125 st.write(f"Avg KD: {topic['avgKD']}")126 127 # Keywords: Show up to 10 initially, with a "Show All" button128 keyword_key = f"{key_prefix}_keywords_{idx}"129 if keyword_key not in st.session_state:130 st.session_state[keyword_key] = False # Default to collapsed keywords131 132 if len(topic["keywords"]) > KEYWORD_LIMIT:133 if not st.session_state[keyword_key]: # Show only first 10 keywords134 st.write(f"Keywords: {', '.join(topic['keywords'][:KEYWORD_LIMIT])} ...")135 if st.button("Show All", key=f"show_{keyword_key}"):136 st.session_state[keyword_key] = True137 st.rerun()138 else: # Show full list of keywords139 st.write(f"Keywords: {', '.join(topic['keywords'])}")140 else:141 st.write(f"Keywords: {', '.join(topic['keywords'])}")142 143 st.markdown("---")144 145 # "Show More" Button for paginated topic loading146 if visible_count < len(topics):147 if st.button("Show More", key=f"show_more_{key_prefix}"):148 st.session_state[f"{key_prefix}_visible_count"] += TOPIC_INCREMENT149 st.rerun()150 151def main():152 st.title("JNS Topics")153 154 # Load and parse the topics file155 text = load_topics_file()156 competitive_topics, opportunity_topics = parse_topics_from_text(text)157 158 # Create two columns for competitive and opportunity topics159 col1, col2 = st.columns(2)160 161 with col1:162 display_topics("Competitive Topics", competitive_topics, "competitive")163 164 with col2:165 display_topics("Opportunity Topics", opportunity_topics, "opportunity")166 167if __name__ == "__main__":168 main()169 