ArijitMishra commited on
Commit
49aeb61
·
verified ·
1 Parent(s): 10c889d

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +200 -0
app.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import whisper
3
+ import torch
4
+ from transformers import pipeline
5
+ import warnings
6
+ warnings.filterwarnings("ignore")
7
+
8
+
9
+ print("Loading Whisper (transcription)...")
10
+ whisper_model = whisper.load_model("base")
11
+
12
+ model_name = "Qwen/Qwen2.5-0.5B-Instruct"
13
+ print(f"Loading {model_name} (reflection)...")
14
+ generator = pipeline(
15
+ "text-generation",
16
+ model=model_name,
17
+ device_map="auto",
18
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
19
+ )
20
+
21
+ print("Models ready.")
22
+
23
+ def transcribe(audio_path: str) -> str:
24
+ """Transcribe audio file to text using Whisper."""
25
+ if audio_path is None:
26
+ return ""
27
+ result = whisper_model.transcribe(audio_path)
28
+ return result["text"].strip()
29
+
30
+
31
+ def reflect(transcript: str) -> str:
32
+ """Generate a journaling reflection using Qwen."""
33
+ if not transcript:
34
+ return "No transcript found — try recording again."
35
+
36
+ prompt = f"""You are a warm, thoughtful journaling companion. Your tone is human and gentle, never clinical or robotic.
37
+
38
+ The user just shared this voice journal entry:
39
+
40
+ "{transcript}"
41
+
42
+ Respond with exactly three parts, clearly separated:
43
+
44
+ **Mood check:** A 2-sentence summary of the emotional tone you picked up.
45
+
46
+ **What I noticed:** One pattern, theme, or detail that stood out in what they shared.
47
+
48
+ **Something to sit with:** One gentle, open question for them to reflect on later.
49
+
50
+ Keep the full response under 160 words. Be kind, specific, and real."""
51
+
52
+ messages = [
53
+ {"role": "system", "content": "You are a warm journaling companion. Be human, brief, and specific."},
54
+ {"role": "user", "content": prompt},
55
+ ]
56
+
57
+ output = generator(
58
+ messages,
59
+ max_new_tokens=220,
60
+ do_sample=True,
61
+ temperature=0.7,
62
+ pad_token_id=generator.tokenizer.eos_token_id,
63
+ )
64
+
65
+ # Extract the assistant's reply from the chat template output
66
+ generated = output[0]["generated_text"]
67
+ if isinstance(generated, list):
68
+ # Chat format: last message is the assistant reply
69
+ reply = generated[-1]["content"]
70
+ else:
71
+ # Fallback: strip the prompt
72
+ reply = generated[len(prompt):]
73
+
74
+ return reply.strip()
75
+
76
+
77
+ def process_entry(audio_path):
78
+ """Pipeline: audio → transcript → reflection."""
79
+ if audio_path is None:
80
+ return (
81
+ "",
82
+ "Please record something first, then click Reflect.",
83
+ )
84
+
85
+ transcript = transcribe(audio_path)
86
+ if not transcript:
87
+ return (
88
+ "",
89
+ "Couldn't make out any speech. Try speaking a bit louder or closer to the mic.",
90
+ )
91
+
92
+ reflection = reflect(transcript)
93
+ return transcript, reflection
94
+
95
+
96
+
97
+ DESCRIPTION = """
98
+ ## Voice Journal
99
+ *Speak your day. Get it reflected back.*
100
+
101
+ Record a voice note about anything — how your day went, what's on your mind,
102
+ something that happened. A small AI model will listen and gently reflect it back to you.
103
+
104
+ Everything runs locally. Nothing leaves your machine.
105
+ """
106
+
107
+ FOOTER = """
108
+ ---
109
+ *Built for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon) ·
110
+ Whisper (140M) + Qwen2.5-7B · No cloud APIs · Runs on your laptop*
111
+ """
112
+
113
+ custom_css = """
114
+ body { font-family: 'Georgia', serif; }
115
+
116
+ #title-block { text-align: center; padding: 1.5rem 0 0.5rem; }
117
+
118
+ #record-col { display: flex; flex-direction: column; gap: 0.75rem; }
119
+
120
+ #reflect-btn {
121
+ background: #2d4a3e !important;
122
+ color: #f0ebe0 !important;
123
+ border: none !important;
124
+ border-radius: 8px !important;
125
+ font-size: 1rem !important;
126
+ padding: 0.75rem !important;
127
+ cursor: pointer;
128
+ }
129
+
130
+ #reflect-btn:hover { background: #1f3429 !important; }
131
+
132
+ #transcript-box textarea, #reflection-box textarea {
133
+ font-family: 'Georgia', serif !important;
134
+ font-size: 0.95rem !important;
135
+ line-height: 1.65 !important;
136
+ background: #faf8f3 !important;
137
+ border: 1px solid #d8d0c0 !important;
138
+ border-radius: 8px !important;
139
+ }
140
+
141
+ #reflection-box textarea {
142
+ background: #f0ede4 !important;
143
+ color: #2a2a2a !important;
144
+ }
145
+
146
+ footer { display: none !important; }
147
+ """
148
+
149
+ with gr.Blocks(
150
+ title="Voice Journal",
151
+ theme=gr.themes.Soft(
152
+ primary_hue="emerald",
153
+ neutral_hue="stone",
154
+ font=gr.themes.GoogleFont("Lora"),
155
+ ),
156
+ css=custom_css,
157
+ ) as app:
158
+
159
+ with gr.Column(elem_id="title-block"):
160
+ gr.Markdown(DESCRIPTION)
161
+
162
+ with gr.Row(equal_height=False):
163
+ # Left column — input
164
+ with gr.Column(scale=1, elem_id="record-col"):
165
+ audio_input = gr.Audio(
166
+ sources=["microphone"],
167
+ type="filepath",
168
+ label="Record your entry",
169
+ show_download_button=False,
170
+ )
171
+ reflect_btn = gr.Button("Reflect →", elem_id="reflect-btn", variant="primary")
172
+
173
+ # Right column — output
174
+ with gr.Column(scale=1):
175
+ transcript_box = gr.Textbox(
176
+ label="What you said",
177
+ lines=5,
178
+ interactive=False,
179
+ placeholder="Your words will appear here after you click Reflect…",
180
+ elem_id="transcript-box",
181
+ )
182
+ reflection_box = gr.Textbox(
183
+ label="Reflection",
184
+ lines=8,
185
+ interactive=False,
186
+ placeholder="Your reflection will appear here…",
187
+ elem_id="reflection-box",
188
+ )
189
+
190
+ reflect_btn.click(
191
+ fn=process_entry,
192
+ inputs=audio_input,
193
+ outputs=[transcript_box, reflection_box],
194
+ api_name="reflect",
195
+ )
196
+
197
+ gr.Markdown(FOOTER)
198
+
199
+ if __name__ == "__main__":
200
+ app.launch(share=False)