File size: 3,300 Bytes
f02d09b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15b63bb
 
 
 
f02d09b
15b63bb
 
f02d09b
15b63bb
 
 
 
 
 
f02d09b
15b63bb
f02d09b
15b63bb
 
 
 
 
f02d09b
15b63bb
 
 
f02d09b
87edaf4
15b63bb
f02d09b
15b63bb
 
 
 
 
f02d09b
 
 
 
 
 
 
 
 
15b63bb
 
f02d09b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15b63bb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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()