File size: 6,065 Bytes
1e6bf18
 
 
 
 
 
afbad91
 
8c8ef2f
1e6bf18
 
817c4af
1e6bf18
 
 
 
afbad91
1e6bf18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
afbad91
 
 
 
 
 
 
 
 
 
072fcab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
afbad91
 
 
 
8c8ef2f
afbad91
8c8ef2f
 
 
 
afbad91
8c8ef2f
afbad91
1e6bf18
afbad91
8c8ef2f
afbad91
8c8ef2f
 
afbad91
 
1e6bf18
8c8ef2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1e6bf18
 
8c8ef2f
 
 
 
 
 
 
 
 
1e6bf18
8c8ef2f
 
 
 
 
 
 
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
from sqlmodel import SQLModel, Field, create_engine, Session, select
from datetime import datetime
from typing import Optional
import os
import uuid
import subprocess
import re
import json
import matplotlib.pyplot as plt
from faster_whisper import WhisperModel
from openai import OpenAI

# === Setup ===
db_path = "/tmp/chatter_sessions.db"
engine = create_engine(f"sqlite:///{db_path}")
SQLModel.metadata.create_all(engine)

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

# === Language Map ===
LANG_CODES = {
    "English": "en", "Spanish": "es", "Hindi": "hi", "French": "fr", "German": "de",
    "Arabic": "ar", "Chinese": "zh", "Portuguese": "pt", "Japanese": "ja", "Korean": "ko"
}

# === Session Table (shared for spoken + written) ===
class SessionEntry(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    user: str
    timestamp: str
    transcript: str
    feedback: str
    language: str

# === Session Utilities ===
def save_to_db(user, transcript, feedback, language):
    session = Session(engine)
    entry = SessionEntry(
        user=user,
        timestamp=datetime.now().strftime("%Y-%m-%d %H:%M"),
        transcript=transcript,
        feedback=feedback,
        language=language
    )
    session.add(entry)
    session.commit()
    session.close()

def fetch_user_sessions(user):
    session = Session(engine)
    statement = select(SessionEntry).where(SessionEntry.user == user)
    results = session.exec(statement).all()
    session.close()
    return results

# === Whisper Audio Utilities (Spoken Only) ===
model = WhisperModel("base", compute_type="int8")

def convert_to_wav(input_file):
    output_wav = f"/tmp/{uuid.uuid4()}.wav"
    command = ["ffmpeg", "-y", "-i", input_file, "-ar", "16000", "-ac", "1", output_wav]
    subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    return output_wav

def transcribe_audio(audio_path):
    segments, _ = model.transcribe(audio_path)
    return " ".join([segment.text for segment in segments])

# === Score Extraction & Comparison Utilities ===
def parse_scores_from_feedback(feedback_text):
    try:
        json_match = re.search(r"\{.*?\}", feedback_text, re.DOTALL)
        if json_match:
            score_block = json.loads(json_match.group(0))
            return {k.strip(): int(v) for k, v in score_block.items() if str(v).isdigit()}
    except Exception as e:
        print("Score parsing failed:", e)
    return {}

def generate_feedback(transcript, language, goal="general improvement", focus_areas=None, previous_transcript=None):
    focus_str = ", ".join(focus_areas) if focus_areas else "Clarity, Structure, Fluency, Content Relevance, and Tone"
    history_section = f"\n\nFor reference, their previous transcript was:\n{previous_transcript}" if previous_transcript else ""

    prompt = f"""
You are a supportive communication coach helping a learner whose goal is: **{goal}**.

Evaluate the user's current speech based on the following areas:
{focus_str}

Give a score out of 10 and a short explanation for each area.

Then provide:
- A summary of strengths and improvement areas.
- One motivational line to end with.

Transcript:
{transcript}
{history_section}
""".strip()

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": f"You are a warm and constructive communication coach responding in {language}."},
            {"role": "user", "content": prompt}
        ],
        temperature=0.7
    )
    return response.choices[0].message.content


def generate_progress_summary(current_feedback, previous_feedback):
    current_scores = parse_scores_from_feedback(current_feedback)
    previous_scores = parse_scores_from_feedback(previous_feedback)
    if not current_scores or not previous_scores:
        return ""

    lines = []
    for cat in current_scores:
        if cat in previous_scores:
            diff = current_scores[cat] - previous_scores[cat]
            if diff > 0:
                lines.append(f"βœ… **{cat}** improved by **+{diff}**")
            elif diff < 0:
                lines.append(f"⚠️ **{cat}** dropped by **{abs(diff)}**")
            else:
                lines.append(f"βž– **{cat}** stayed the same")

    if lines:
        return "\n\n**πŸ“ˆ Progress Tracker**\n" + "\n".join(lines)
    return ""

# === Score Charting (Current vs. Previous) ===
def build_score_comparison_data(current_feedback, previous_feedback):
    current = parse_scores_from_feedback(current_feedback)
    previous = parse_scores_from_feedback(previous_feedback)
    categories = list(set(current.keys()).union(set(previous.keys())))
    return {
        "Category": categories,
        "Current Score": [current.get(cat, 0) for cat in categories],
        "Previous Score": [previous.get(cat, 0) for cat in categories]
    }

def render_score_chart(data):
    fig, ax = plt.subplots()
    x = range(len(data["Category"]))
    ax.bar([i - 0.2 for i in x], data["Previous Score"], width=0.4, label='Previous')
    ax.bar([i + 0.2 for i in x], data["Current Score"], width=0.4, label='Current')
    ax.set_xticks(list(x))
    ax.set_xticklabels(data["Category"])
    ax.set_ylim(0, 10)
    ax.legend()
    ax.set_ylabel("Score")
    ax.set_title("🎯 Score Comparison")
    return fig

# === Trend Charting (Category Over Time) ===
def build_trend_data(sessions, category="Clarity"):
    points = []
    timestamps = []
    for s in sessions:
        score = parse_scores_from_feedback(s.feedback).get(category)
        if score is not None:
            points.append(score)
            timestamps.append(s.timestamp.split()[0])
    return timestamps, points

def render_trend_chart(timestamps, points, category="Clarity"):
    fig, ax = plt.subplots()
    ax.plot(timestamps, points, marker="o", linestyle="-", color="blue")
    ax.set_title(f"πŸ“ˆ {category} Progress Over Time")
    ax.set_ylim(0, 10)
    ax.set_ylabel("Score")
    ax.set_xlabel("Date")
    return fig