import re import pandas as pd import gradio as gr def parse_transcript(text: str, user_marker: str, assistant_marker: str) -> pd.DataFrame: pattern = re.compile( rf"({re.escape(user_marker)}|{re.escape(assistant_marker)})\s*", re.IGNORECASE ) parts = pattern.split(text) rows = [] turn = 0 for i in range(1, len(parts), 2): marker = parts[i].strip().lower() content = parts[i + 1].strip() if not content: continue speaker = "user" if marker == user_marker.lower() else "gpt" turn += 1 chars = len(content) words = len(content.split()) tokens_est = int(round(words * 1.33)) rows.append({ "turn": turn, "speaker": speaker, "chars": chars, "words": words, "tokens_est": tokens_est }) return pd.DataFrame(rows) def convert(file_path, user_marker, assistant_marker, preview_rows): try: if not file_path: return None, None, "Upload a .md or .txt transcript." with open(file_path, "r", encoding="utf-8", errors="replace") as f: text = f.read() if user_marker.lower() not in text.lower() and assistant_marker.lower() not in text.lower(): return None, None, ( "No markers found in the file.\n" "Update the marker strings to match your transcript format " f"(e.g., '{user_marker}' / '{assistant_marker}')." ) df = parse_transcript(text, user_marker=user_marker, assistant_marker=assistant_marker) if df.empty: return None, None, ( "Parsed 0 turns. Markers may not match the transcript format, " "or content blocks may be empty." ) pr = int(preview_rows) pr = max(5, min(pr, 100)) preview = df.head(pr) out_path = "converted_turns.csv" df.to_csv(out_path, index=False) msg = f"Parsed {len(df)} turns. Download the CSV below." return preview, out_path, msg except Exception as e: return None, None, f"Conversion failed: {type(e).__name__}: {e}" with gr.Blocks(title="Markdown → CSV Converter") as demo: gr.Markdown( "### Markdown → CSV Converter\n" "Upload a transcript (.md/.txt) and convert it into a canonical turn-level CSV.\n\n" "**Privacy:** Files are processed in-session and not stored." ) # IMPORTANT: type="filepath" makes this stable on HF/Gradio file = gr.File(label="Upload transcript", file_types=[".md", ".txt"], type="filepath") with gr.Row(): user_marker = gr.Textbox(value="You said:", label="User marker") assistant_marker = gr.Textbox(value="ChatGPT said:", label="Assistant marker") preview_rows = gr.Slider(5, 100, value=20, step=1, label="Preview rows") btn = gr.Button("Convert") preview = gr.Dataframe(label="Preview", interactive=False, wrap=True) out_file = gr.File(label="Download CSV") status = gr.Textbox(label="Status", interactive=False) btn.click( fn=convert, inputs=[file, user_marker, assistant_marker, preview_rows], outputs=[preview, out_file, status], ) demo.launch()