File size: 7,737 Bytes
c0b438e
 
8983cc5
7c1803b
b502585
c0b438e
7c1803b
 
 
 
c0b438e
 
7c1803b
c0b438e
75b3e3c
 
 
c0b438e
7c1803b
75b3e3c
c0b438e
75b3e3c
7c1803b
9160e30
50a9b3d
 
 
 
f2483b7
 
7c1803b
75b3e3c
 
7c1803b
75b3e3c
c0b438e
 
 
75b3e3c
c0b438e
 
 
 
e29ad92
 
c111e1f
e29ad92
 
 
 
 
 
 
c0b438e
75b3e3c
 
c0b438e
75b3e3c
 
c0b438e
 
 
 
75b3e3c
c0b438e
 
 
 
 
7abf484
 
 
 
 
 
 
75b3e3c
 
c0b438e
7c1803b
75b3e3c
 
c0b438e
 
 
192d806
b502585
75b3e3c
 
c0b438e
e29ad92
94c3657
da61819
75b3e3c
c111e1f
 
75b3e3c
e29ad92
c111e1f
e29ad92
c111e1f
5e6a7ba
 
 
 
 
 
c111e1f
5e6a7ba
c111e1f
 
 
5e6a7ba
 
c111e1f
 
e29ad92
22752e7
c0b438e
75b3e3c
 
 
 
 
c0b438e
75b3e3c
7abf484
9160e30
75b3e3c
 
 
9160e30
7abf484
75b3e3c
 
 
c0b438e
e29ad92
75b3e3c
7c1803b
e29ad92
c0b438e
 
 
e29ad92
9160e30
 
7c1803b
75b3e3c
 
 
e29ad92
7c1803b
e29ad92
7abf484
75b3e3c
 
9160e30
75b3e3c
 
7abf484
c111e1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import gradio as gr
import uuid
import os
import matplotlib.pyplot as plt
from openai import OpenAI
from app_utils import (
    LANG_CODES, save_to_db, fetch_user_sessions,
    parse_scores_from_feedback, generate_progress_summary,
    build_score_comparison_data, render_score_chart,
    build_trend_data, render_trend_chart
)

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def generate_written_feedback(text, language, goal="general improvement", focus_areas=None, previous_text=None):
    focus_str = ", ".join(focus_areas) if focus_areas else "Clarity, Structure, Grammar, Style, Tone, Creativity"
    history_section = f"\n\nCompare this to their previous writing:\n{previous_text}" if previous_text else ""

    prompt = f"""
You are a writing coach helping a student improve their writing for the following goal: **{goal}**.

First, return a JSON object with scores (0–10) for each of these:
{focus_str}

For each area:
- Repeat the score (0–10)
- Detailed explaination of why the user got that score
Then add
- A detailed summary of strengths and improvements
- One motivational line, without using the actual motivation keyword

Current text:
{text}
{history_section}
"""
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": f"You are a helpful writing tutor responding in {language}."},
            {"role": "user", "content": prompt}
        ],
        temperature=0.7
    )
    feedback = response.choices[0].message.content

    # Strip JSON before returning
    try:
        split_idx = feedback.index('}') + 1
        feedback_clean = feedback[split_idx:].strip()
    except:
        feedback_clean = feedback

    return feedback, feedback_clean

def improve_written_text(text, language):
    prompt = f"""Improve this writing by refining structure, grammar, and clarity β€” without changing its meaning.

Text:
{text}
"""
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": f"Reply in {language}. Provide only the improved version."},
            {"role": "user", "content": prompt}
        ]
    )
    return response.choices[0].message.content

def render_empty_chart(title):
    fig, ax = plt.subplots()
    ax.set_title(title)
    ax.text(0.5, 0.5, "No data yet", ha='center', va='center', fontsize=12)
    ax.axis('off')
    return fig

def written_dashboard(nickname_input):
    with gr.Column() as written_panel:
        gr.Markdown("""
        <div id="header" style="text-align: center;">
            <h2>✍️ Written Communication with <strong>Chatter the Owl</strong></h2>
            <p>Paste or upload your writing. Select your goal and focus, and receive personalized feedback with progress tracking.</p>
        </div>
        """)

        with gr.Row():
            language_dropdown = gr.Dropdown(label="🌍 Language", choices=list(LANG_CODES.keys()), value="English")
            goal_dropdown = gr.Dropdown(label="🎯 Writing Goal", choices=["Essay for school", "Job application", "Blog post", "Creative writing", "General improvement"], value="General improvement")
            focus_checkboxes = gr.CheckboxGroup(label="🧠 Focus Areas", choices=["Clarity", "Organization", "Grammar", "Vocabulary", "Tone", "Creativity"], value=["Clarity", "Organization", "Grammar", "Vocabulary", "Tone", "Creativity"])

        input_text = gr.Textbox(label="πŸ“ Your Writing", lines=10, elem_id="input_text", elem_classes=["text_area"], interactive=True)
        submit_button = gr.Button("πŸš€ Submit", variant="primary", size="sm")

        file_input = gr.File(label="πŸ“„ Upload Text File", file_types=[".txt", ".md"])
        feedback_box = gr.Textbox(label="πŸ’‘ Feedback", interactive=False)
        improved_box = gr.Textbox(label="🎯 Improved Version", interactive=False)
        history_table = gr.Dataframe(headers=["πŸ•’ Timestamp", "🌐 Language", "✍️ Text", "πŸ“‹ Feedback"])

        # === Chart Area ===
        with gr.Row():
            with gr.Column(scale=1):
                gr.Dropdown(
                    choices=[""],
                    label="πŸ“Š Score Comparison",
                    interactive=False,
                    show_label=True
                )
                score_chart = gr.Plot()
        
            with gr.Column(scale=1):
                trend_category_dropdown = gr.Dropdown(
                    label="πŸ“ˆ Track Progress In",
                    choices=["Clarity", "Structure", "Fluency", "Tone", "Content Relevance"],
                    value="Tone"
                )
                trend_chart = gr.Plot(label="Progress Over Time")

        milestone_box = gr.Markdown(visible=False)

        def extract_text(file):
            if file is None:
                return ""
            with open(file.name, 'r', encoding='utf-8') as f:
                return f.read()

        file_input.change(fn=extract_text, inputs=file_input, outputs=input_text)

        def tutor_written(text, language, goal, focus_areas, trend_category, nickname):
            if hasattr(nickname, "value"):
                nickname = nickname.value
            if not text.strip():
                return "", "", [], render_empty_chart("πŸ“Š Score Comparison"), render_empty_chart("πŸ“ˆ Progress Over Time"), gr.update(visible=False)

            sessions = fetch_user_sessions(nickname)
            previous_text = sessions[-1].transcript if sessions else None
            previous_feedback = sessions[-1].feedback if sessions else None

            full_feedback, feedback_clean = generate_written_feedback(text, language, goal, focus_areas, previous_text)
            improved = improve_written_text(text, language)

            save_to_db(nickname, text, full_feedback, language)
            sessions = fetch_user_sessions(nickname)
            session_table = [[s.timestamp, s.language, s.transcript[:40], s.feedback[:40]] for s in sessions]

            score_plot = render_score_chart(build_score_comparison_data(full_feedback, previous_feedback)) if previous_feedback else render_empty_chart("πŸ“Š Score Comparison")
            dates, trend_scores = build_trend_data(sessions, trend_category)
            trend_plot = render_trend_chart(dates, trend_scores, trend_category) if trend_scores else render_empty_chart(f"πŸ“ˆ {trend_category} Progress")

            milestone_msg = ""
            if len(sessions) in [3, 5, 10]:
                milestone_msg = f"πŸŽ‰ You’ve completed **{len(sessions)} writing sessions**!"
                feedback_clean += f"\n\n{milestone_msg}"

            return feedback_clean, improved, session_table, score_plot, trend_plot, gr.update(visible=bool(milestone_msg), value=milestone_msg)

        submit_button.click(
            fn=tutor_written,
            inputs=[input_text, language_dropdown, goal_dropdown, focus_checkboxes, trend_category_dropdown, nickname_input],
            outputs=[feedback_box, improved_box, history_table, score_chart, trend_chart, milestone_box]
        )

        def update_trend_chart(trend_category, nickname):
            if hasattr(nickname, "value"):
                nickname = nickname.value
            sessions = fetch_user_sessions(nickname)
            dates, trend_scores = build_trend_data(sessions, trend_category)
            if trend_scores:
                return render_trend_chart(dates, trend_scores, trend_category)
            return render_empty_chart(f"πŸ“ˆ {trend_category} Progress")

        trend_category_dropdown.change(
            fn=update_trend_chart,
            inputs=[trend_category_dropdown, nickname_input],
            outputs=[trend_chart]
        )

    return written_panel