Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -993,7 +993,6 @@ def process_excel_to_word(excel_file_path):
|
|
| 993 |
|
| 994 |
# ======================== GRADIO INTERFACE ========================
|
| 995 |
def create_interface():
|
| 996 |
-
# ... (Your entire Gradio interface layout remains here, unchanged)
|
| 997 |
generator = BlogGenerator()
|
| 998 |
with gr.Blocks(title="π― Digiworks Unified Blog Generator", theme=gr.themes.Soft()) as interface:
|
| 999 |
gr.HTML("""<div style='text-align: center; padding: 25px; background: linear-gradient(135deg, #1a365d 0%, #2d3748 100%); color: white; margin-bottom: 25px; border-radius: 15px;'><h1 style='margin: 0; font-size: 2.5em; font-weight: 900;'>π― Digiworks Unified Blog Generator</h1><p style='margin: 15px 0 0 0; font-size: 1.2em;'>Idea Generation β Blog Post Creation β Word Document Formatting</p></div>""")
|
|
@@ -1047,134 +1046,134 @@ def create_interface():
|
|
| 1047 |
with gr.Row():
|
| 1048 |
download_word_btn = gr.File(label="π₯ Download Formatted Word Document", visible=False)
|
| 1049 |
gr.HTML("""<div style='background: #065f46; color: white; padding: 15px; border-radius: 8px; text-align: center; margin-left: 15px; border: 1px solid #10b981;'><strong style='color: #6ee7b7;'>π‘ WordPress Tip:</strong><span style='color: white;'>Copy sections directly from Word to WordPress editor!</span></div>""")
|
| 1050 |
-
|
| 1051 |
-
|
| 1052 |
-
|
| 1053 |
-
|
| 1054 |
-
|
| 1055 |
-
|
| 1056 |
-
|
| 1057 |
-
|
| 1058 |
-
|
| 1059 |
-
|
| 1060 |
-
|
| 1061 |
-
|
| 1062 |
-
|
| 1063 |
-
|
| 1064 |
-
|
| 1065 |
-
|
| 1066 |
-
|
| 1067 |
-
|
| 1068 |
-
|
| 1069 |
-
|
| 1070 |
-
|
| 1071 |
-
|
| 1072 |
-
|
| 1073 |
-
|
| 1074 |
-
|
| 1075 |
-
|
| 1076 |
-
|
| 1077 |
-
|
| 1078 |
-
|
| 1079 |
-
|
| 1080 |
-
|
| 1081 |
-
|
| 1082 |
-
|
| 1083 |
-
|
| 1084 |
-
|
| 1085 |
-
|
| 1086 |
-
|
| 1087 |
-
|
| 1088 |
-
|
| 1089 |
-
|
| 1090 |
-
|
| 1091 |
-
|
| 1092 |
-
|
| 1093 |
-
|
| 1094 |
-
|
| 1095 |
-
|
| 1096 |
-
|
| 1097 |
-
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
-
|
| 1101 |
-
|
| 1102 |
-
|
| 1103 |
-
|
| 1104 |
-
|
| 1105 |
-
|
| 1106 |
-
|
| 1107 |
-
|
| 1108 |
-
|
| 1109 |
-
|
| 1110 |
-
|
| 1111 |
-
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
|
| 1115 |
-
|
| 1116 |
-
|
| 1117 |
-
|
| 1118 |
-
|
| 1119 |
-
|
| 1120 |
-
|
| 1121 |
-
|
| 1122 |
-
|
| 1123 |
-
|
| 1124 |
-
|
| 1125 |
-
|
| 1126 |
-
|
| 1127 |
-
|
| 1128 |
-
|
| 1129 |
-
|
| 1130 |
-
|
| 1131 |
-
|
| 1132 |
-
|
| 1133 |
-
|
| 1134 |
-
|
| 1135 |
-
|
| 1136 |
-
|
| 1137 |
-
|
| 1138 |
-
|
| 1139 |
-
|
| 1140 |
-
|
| 1141 |
-
|
| 1142 |
-
|
| 1143 |
-
|
| 1144 |
-
|
| 1145 |
-
|
| 1146 |
-
|
| 1147 |
-
|
| 1148 |
-
|
| 1149 |
-
|
| 1150 |
-
|
| 1151 |
-
|
| 1152 |
-
|
| 1153 |
-
|
| 1154 |
-
|
| 1155 |
-
|
| 1156 |
-
|
| 1157 |
-
|
| 1158 |
-
|
| 1159 |
-
|
| 1160 |
-
|
| 1161 |
-
|
| 1162 |
-
|
| 1163 |
-
|
| 1164 |
-
|
| 1165 |
-
|
| 1166 |
-
|
| 1167 |
-
|
| 1168 |
-
|
| 1169 |
-
|
| 1170 |
-
|
| 1171 |
-
|
| 1172 |
-
|
| 1173 |
-
|
| 1174 |
-
|
| 1175 |
-
|
| 1176 |
-
|
| 1177 |
-
|
| 1178 |
return interface
|
| 1179 |
|
| 1180 |
|
|
|
|
| 993 |
|
| 994 |
# ======================== GRADIO INTERFACE ========================
|
| 995 |
def create_interface():
|
|
|
|
| 996 |
generator = BlogGenerator()
|
| 997 |
with gr.Blocks(title="π― Digiworks Unified Blog Generator", theme=gr.themes.Soft()) as interface:
|
| 998 |
gr.HTML("""<div style='text-align: center; padding: 25px; background: linear-gradient(135deg, #1a365d 0%, #2d3748 100%); color: white; margin-bottom: 25px; border-radius: 15px;'><h1 style='margin: 0; font-size: 2.5em; font-weight: 900;'>π― Digiworks Unified Blog Generator</h1><p style='margin: 15px 0 0 0; font-size: 1.2em;'>Idea Generation β Blog Post Creation β Word Document Formatting</p></div>""")
|
|
|
|
| 1046 |
with gr.Row():
|
| 1047 |
download_word_btn = gr.File(label="π₯ Download Formatted Word Document", visible=False)
|
| 1048 |
gr.HTML("""<div style='background: #065f46; color: white; padding: 15px; border-radius: 8px; text-align: center; margin-left: 15px; border: 1px solid #10b981;'><strong style='color: #6ee7b7;'>π‘ WordPress Tip:</strong><span style='color: white;'>Copy sections directly from Word to WordPress editor!</span></div>""")
|
| 1049 |
+
gr.HTML("""<div style='text-align: center; padding: 20px; margin-top: 25px; border-top: 1px solid #e0e0e0;'><p style='color: #666; margin: 0;'>π― <strong>Digiworks Unified Blog Generator</strong> | Idea Generation β Blog Post Creation β Word Document Formatting<br><small>Perfect for content teams and marketers</small></p></div>""")
|
| 1050 |
+
|
| 1051 |
+
# --- HANDLER FUNCTIONS (MODIFIED for Incremental Save) ---
|
| 1052 |
+
def toggle_content_type(mode): return gr.update(visible=(mode == "Single Type"))
|
| 1053 |
+
def handle_idea_generation(mode, content_type_val, num_topics_val):
|
| 1054 |
+
try:
|
| 1055 |
+
if mode == "Single Type": result, df, status = generate_blog_topics(content_type_val, num_topics_val)
|
| 1056 |
+
else: result, df, status = generate_all_types(num_topics_val)
|
| 1057 |
+
download_file, download_visible = None, False
|
| 1058 |
+
if not df.empty:
|
| 1059 |
+
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
| 1060 |
+
filename = f"digiworks_blog_ideas_{timestamp}.xlsx"
|
| 1061 |
+
temp_path = os.path.join(tempfile.gettempdir(), filename)
|
| 1062 |
+
with pd.ExcelWriter(temp_path, engine='openpyxl') as writer: df.to_excel(writer, sheet_name='Blog Ideas', index=False)
|
| 1063 |
+
download_file, download_visible = temp_path, True
|
| 1064 |
+
return status, result, df, gr.update(value=download_file, visible=download_visible)
|
| 1065 |
+
except Exception as e: return f"β Error: {str(e)}", f"β Generation failed: {str(e)}", pd.DataFrame(), gr.update(visible=False)
|
| 1066 |
+
def load_excel_and_create_checklist(file_path):
|
| 1067 |
+
if not file_path: return gr.update(choices=[], value=[]), pd.DataFrame(), "Please upload an Excel file"
|
| 1068 |
+
try:
|
| 1069 |
+
df = pd.read_excel(file_path)
|
| 1070 |
+
required_cols = ['Content Type', 'Headline']
|
| 1071 |
+
if missing_cols := [col for col in required_cols if col not in df.columns]: return gr.update(choices=[], value=[]), pd.DataFrame(), f"Missing columns: {', '.join(missing_cols)}"
|
| 1072 |
+
choices = []
|
| 1073 |
+
for i, row in df.iterrows():
|
| 1074 |
+
content_type = row.get('Content Type', '').replace(' π', '').replace(' π', '').replace(' βοΈ', '').replace(' π', '').replace(' π', '').replace(' π‘', '')
|
| 1075 |
+
headline = row.get('Headline', '')[:60]; keywords = row.get('Keywords', '')[:50]
|
| 1076 |
+
choices.append(f"#{i+1} [{content_type}] {headline}... | Keywords: {keywords}...")
|
| 1077 |
+
return gr.update(choices=choices, value=choices), df, f"β
Loaded {len(df)} topics. Select topics to generate blog posts."
|
| 1078 |
+
except Exception as e: return gr.update(choices=[], value=[]), pd.DataFrame(), f"β Error: {str(e)}"
|
| 1079 |
+
def reset_topic_counter():
|
| 1080 |
+
generator.reset_counter()
|
| 1081 |
+
return "π Topic counter reset to 0. Next generation will start from Topic #1."
|
| 1082 |
+
|
| 1083 |
+
def generate_selected_posts(file_path, selected_choices, df):
|
| 1084 |
+
if not file_path or not selected_choices:
|
| 1085 |
+
yield "Please upload an Excel file and select at least one topic to generate.", pd.DataFrame(), gr.update(visible=False)
|
| 1086 |
+
return
|
| 1087 |
+
all_sections_data, status_log = [], ["π Starting blog post generation..."]
|
| 1088 |
+
latest_file_path = None
|
| 1089 |
+
yield "\n".join(status_log), pd.DataFrame(), gr.update(value=None, visible=False)
|
| 1090 |
+
try:
|
| 1091 |
+
for topic_counter, choice in enumerate(selected_choices, 1):
|
| 1092 |
+
choice_index = int(choice.split('#')[1].split(' ')[0]) - 1
|
| 1093 |
+
if choice_index < len(df):
|
| 1094 |
+
topic_data = df.iloc[choice_index].to_dict()
|
| 1095 |
+
generation_iterator = generator.generate_blog_from_topic_data(topic_data, topic_index=topic_counter)
|
| 1096 |
+
|
| 1097 |
+
topic_sections = []
|
| 1098 |
+
for update_type, update_value, *rest in generation_iterator:
|
| 1099 |
+
if update_type == 'status':
|
| 1100 |
+
message = update_value
|
| 1101 |
+
status_log.append(message)
|
| 1102 |
+
yield "\n".join(status_log), pd.DataFrame(all_sections_data), gr.update(value=latest_file_path, visible=bool(latest_file_path))
|
| 1103 |
+
elif update_type == 'result':
|
| 1104 |
+
sections, msg = update_value, rest[0]
|
| 1105 |
+
if sections:
|
| 1106 |
+
topic_sections.extend(sections)
|
| 1107 |
+
status_log.append(msg)
|
| 1108 |
+
|
| 1109 |
+
if topic_sections:
|
| 1110 |
+
all_sections_data.extend(topic_sections)
|
| 1111 |
+
intermediate_df = pd.DataFrame(all_sections_data)
|
| 1112 |
+
intermediate_file = create_excel_export(all_sections_data)
|
| 1113 |
+
latest_file_path = intermediate_file
|
| 1114 |
+
status_log.append(f"π¦ Intermediate file for Topic #{topic_counter} ready.")
|
| 1115 |
+
yield "\n".join(status_log), intermediate_df, gr.update(value=latest_file_path, visible=True)
|
| 1116 |
+
|
| 1117 |
+
if all_sections_data:
|
| 1118 |
+
final_df = pd.DataFrame(all_sections_data)
|
| 1119 |
+
total_topics, total_sections = len(selected_choices), len(all_sections_data)
|
| 1120 |
+
successful_sections = len([s for s in all_sections_data if s['Word Count'] > 0])
|
| 1121 |
+
total_words = sum(s['Word Count'] for s in all_sections_data if s['Word Count'] > 0)
|
| 1122 |
+
final_status = f"""π ALL TOPICS COMPLETE!\n--------------------\nπ Generated {total_sections} sections across {total_topics} topics\nβ
Successful sections: {successful_sections}/{total_sections}\nπ Total words generated: {total_words:,}\nπ’ Topics indexed: 1-{total_topics}\n\nFull Log:\n""" + "\n".join(status_log)
|
| 1123 |
+
yield final_status, final_df, gr.update(value=latest_file_path, visible=True)
|
| 1124 |
+
else:
|
| 1125 |
+
yield "β No sections were generated.", pd.DataFrame(), gr.update(visible=False)
|
| 1126 |
+
except Exception as e:
|
| 1127 |
+
import traceback
|
| 1128 |
+
tb_str = traceback.format_exc()
|
| 1129 |
+
yield f"β An unexpected error occurred: {str(e)}\n\nTraceback:\n{tb_str}", pd.DataFrame(), gr.update(visible=False)
|
| 1130 |
+
|
| 1131 |
+
def process_excel_file(excel_file):
|
| 1132 |
+
if not excel_file: return "Please upload an Excel file", "", gr.update(visible=False)
|
| 1133 |
+
try:
|
| 1134 |
+
df = pd.read_excel(excel_file); preview = "No content preview available"
|
| 1135 |
+
if not df.empty and 'Section Content' in df.columns:
|
| 1136 |
+
cleaned_sample = clean_blog_content(df.iloc[0]['Section Content'])
|
| 1137 |
+
preview = cleaned_sample[:500] + "..." if len(cleaned_sample) > 500 else cleaned_sample
|
| 1138 |
+
status = f"β
Excel loaded: {len(df)} sections found\nπ Topics: {df['Topic Number'].nunique() if 'Topic Number' in df.columns else 'Unknown'}\nπ Ready to generate Word document"
|
| 1139 |
+
return status, preview, gr.update(visible=False)
|
| 1140 |
+
except Exception as e: return f"β Error reading Excel: {str(e)}", "", gr.update(visible=False)
|
| 1141 |
+
|
| 1142 |
+
def generate_word_document(excel_file):
|
| 1143 |
+
if not excel_file:
|
| 1144 |
+
yield "Please upload an Excel file.", "", gr.update(visible=False)
|
| 1145 |
+
return
|
| 1146 |
+
status_log = ["π Starting Word document generation..."]
|
| 1147 |
+
yield "\n".join(status_log), "", gr.update(visible=False)
|
| 1148 |
+
try:
|
| 1149 |
+
processing_generator = process_excel_to_word(excel_file)
|
| 1150 |
+
for type, val1, *val2 in processing_generator:
|
| 1151 |
+
if type == 'status':
|
| 1152 |
+
status_log.append(val1)
|
| 1153 |
+
yield "\n".join(status_log), "", gr.update(visible=False)
|
| 1154 |
+
elif type == 'complete':
|
| 1155 |
+
word_file_path, result_message = val1, val2[0]
|
| 1156 |
+
df = pd.read_excel(excel_file)
|
| 1157 |
+
preview = "Document generated successfully"
|
| 1158 |
+
if not df.empty and 'Section Content' in df.columns:
|
| 1159 |
+
cleaned_sample = clean_blog_content(df.iloc[0]['Section Content'])
|
| 1160 |
+
preview = cleaned_sample[:500] + "..." if len(cleaned_sample) > 500 else cleaned_sample
|
| 1161 |
+
yield result_message, preview, gr.update(value=word_file_path, visible=True)
|
| 1162 |
+
elif type == 'error':
|
| 1163 |
+
yield val1, "", gr.update(visible=False)
|
| 1164 |
+
except Exception as e:
|
| 1165 |
+
import traceback
|
| 1166 |
+
yield f"β An unexpected error occurred: {str(e)}\n{traceback.format_exc()}", "", gr.update(visible=False)
|
| 1167 |
+
|
| 1168 |
+
# --- EVENT LISTENERS ---
|
| 1169 |
+
mode_choice.change(fn=toggle_content_type, inputs=[mode_choice], outputs=[content_type])
|
| 1170 |
+
generate_ideas_btn.click(fn=handle_idea_generation, inputs=[mode_choice, content_type, num_topics], outputs=[ideas_status, ideas_results, ideas_df, download_ideas_btn])
|
| 1171 |
+
excel_upload.change(fn=load_excel_and_create_checklist, inputs=[excel_upload], outputs=[topics_checklist, loaded_data, posts_status])
|
| 1172 |
+
reset_counter_btn.click(fn=reset_topic_counter, inputs=[], outputs=[posts_status])
|
| 1173 |
+
generate_posts_btn.click(fn=generate_selected_posts, inputs=[excel_upload, topics_checklist, loaded_data], outputs=[posts_status, posts_dataframe, download_posts_btn])
|
| 1174 |
+
word_excel_input.change(fn=process_excel_file, inputs=[word_excel_input], outputs=[word_status, word_preview, download_word_btn])
|
| 1175 |
+
generate_word_btn.click(fn=generate_word_document, inputs=[word_excel_input], outputs=[word_status, word_preview, download_word_btn])
|
| 1176 |
+
|
| 1177 |
return interface
|
| 1178 |
|
| 1179 |
|