GitHub Actions Bot commited on
Commit
ae9c02f
·
0 Parent(s):

Sync from GitHub kumarsrinivasbobba/case_study_1@cf796927435e8a4b0e2e91e4f713110439fbbea2

Browse files
Files changed (6) hide show
  1. .gitignore +81 -0
  2. README.md +45 -0
  3. app.py +592 -0
  4. pytest.ini +11 -0
  5. requirements.txt +5 -0
  6. test_app.py +272 -0
.gitignore ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ *.manifest
29
+ *.spec
30
+
31
+ # Installer logs
32
+ pip-log.txt
33
+ pip-delete-this-directory.txt
34
+
35
+ # Unit test / coverage reports
36
+ htmlcov/
37
+ .tox/
38
+ .nox/
39
+ .coverage
40
+ .coverage.*
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+ *.cover
45
+ *.py,cover
46
+ .hypothesis/
47
+ .pytest_cache/
48
+
49
+ # Translations
50
+ *.mo
51
+ *.pot
52
+
53
+ # Environments
54
+ .env
55
+ .venv
56
+ env/
57
+ venv/
58
+ ENV/
59
+ env.bak/
60
+ venv.bak/
61
+
62
+ # IDE
63
+ .idea/
64
+ .vscode/
65
+ *.swp
66
+ *.swo
67
+ *~
68
+
69
+ # Jupyter Notebook
70
+ .ipynb_checkpoints
71
+
72
+ # Model cache (can be large)
73
+ *.bin
74
+ *.safetensors
75
+
76
+ # OS
77
+ .DS_Store
78
+ Thumbs.db
79
+
80
+ # Gradio
81
+ flagged/
README.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: DreamWeaver AI - Local Transformers
3
+ emoji: 🌙
4
+ colorFrom: indigo
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 4.44.0
8
+ python_version: "3.10"
9
+ app_file: app.py
10
+ pinned: false
11
+ license: mit
12
+ short_description: Dream journal & interpreter (local Transformers)
13
+ ---
14
+
15
+ # 🌙 DreamWeaver AI - Dream Journal & Interpreter
16
+
17
+ An innovative AI-powered dream analysis tool that interprets your dreams, identifies emotional themes, and generates creative dream-inspired stories.
18
+
19
+ ## Features
20
+
21
+ - 🎭 **Emotional Analysis**: Detect the emotional undertones of your dreams
22
+ - 🔮 **Symbol Detection**: Identify and interpret common dream symbols
23
+ - 📖 **AI Interpretation**: Get personalized dream interpretations
24
+ - ✨ **Story Generation**: Transform dreams into creative stories
25
+ - 🎨 **Visual Prompts**: Generate prompts for AI image generators
26
+ - 📔 **Dream Journal**: Save and format your dream entries
27
+
28
+ ## Architecture
29
+
30
+ This is the **Local Transformers Version** which uses:
31
+ - `transformers` pipelines for model inference (models are downloaded to the Space)
32
+ - Gradio for the user interface
33
+ - Hosted on Hugging Face Spaces
34
+
35
+ ## Models Used
36
+
37
+ - `j-hartmann/emotion-english-distilroberta-base` - Emotion classification
38
+ - `distilgpt2` - Lightweight text generation for interpretations and stories
39
+
40
+ ## Citations
41
+
42
+ - Hugging Face Transformers Documentation
43
+ - Gradio Documentation
44
+ - Dream symbolism inspired by Jungian psychology
45
+ - GitHub Copilot for code assistance
app.py ADDED
@@ -0,0 +1,592 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 🌙 DreamWeaver AI - Dream Journal & Interpreter (Local Transformers Version)
3
+ ====================================================================
4
+ An innovative AI-powered dream analysis tool that interprets your dreams,
5
+ identifies emotional themes, and generates creative dream-inspired stories.
6
+
7
+ This version uses local Transformers pipelines (downloaded at runtime) for model execution.
8
+
9
+ Citations:
10
+ - Hugging Face Transformers Documentation
11
+ - Gradio Documentation (gradio.app)
12
+ - GitHub Copilot for code assistance
13
+ - Dream symbolism inspired by Jungian psychology concepts
14
+ """
15
+
16
+ import gradio as gr
17
+ import time
18
+ import random
19
+ import os
20
+ from datetime import datetime
21
+
22
+
23
+ class _LabelScore:
24
+ def __init__(self, label: str, score: float):
25
+ self.label = label
26
+ self.score = score
27
+
28
+
29
+ class LocalTransformersClient:
30
+ """A tiny wrapper around local `transformers` pipelines.
31
+
32
+ Keeps the same `client.text_classification()` and `client.text_generation()`
33
+ interface used by the app and tests, but runs models locally.
34
+ """
35
+
36
+ def __init__(self):
37
+ self._emotion_model_id: str | None = None
38
+ self._emotion_pipe = None
39
+ self._generation_model_id: str | None = None
40
+ self._generation_pipe = None
41
+
42
+ def _get_emotion_pipe(self, model: str):
43
+ if self._emotion_pipe is not None and self._emotion_model_id == model:
44
+ return self._emotion_pipe
45
+
46
+ from transformers import pipeline
47
+
48
+ self._emotion_model_id = model
49
+ self._emotion_pipe = pipeline(
50
+ task="text-classification",
51
+ model=model,
52
+ device=-1,
53
+ top_k=None,
54
+ )
55
+ return self._emotion_pipe
56
+
57
+ def _get_generation_pipe(self, model: str):
58
+ if self._generation_pipe is not None and self._generation_model_id == model:
59
+ return self._generation_pipe
60
+
61
+ from transformers import pipeline
62
+
63
+ self._generation_model_id = model
64
+ self._generation_pipe = pipeline(
65
+ task="text-generation",
66
+ model=model,
67
+ device=-1,
68
+ )
69
+ return self._generation_pipe
70
+
71
+ def text_classification(self, text: str, model: str):
72
+ pipe = self._get_emotion_pipe(model)
73
+ raw = pipe(text)
74
+
75
+ # transformers can return `[[{label,score},...]]` when running on a list of inputs.
76
+ if isinstance(raw, list) and raw and isinstance(raw[0], list):
77
+ raw = raw[0]
78
+
79
+ if not isinstance(raw, list):
80
+ raise RuntimeError(f"Unexpected text_classification response: {raw!r}")
81
+
82
+ results: list[_LabelScore] = []
83
+ for item in raw:
84
+ if isinstance(item, dict) and "label" in item and "score" in item:
85
+ results.append(_LabelScore(str(item["label"]), float(item["score"])))
86
+
87
+ results.sort(key=lambda x: x.score, reverse=True)
88
+ if not results:
89
+ raise RuntimeError(f"Empty/invalid text_classification response: {raw!r}")
90
+ return results
91
+
92
+ def text_generation(
93
+ self,
94
+ prompt: str,
95
+ model: str,
96
+ max_new_tokens: int = 200,
97
+ temperature: float = 0.7,
98
+ do_sample: bool = True,
99
+ ) -> str:
100
+ pipe = self._get_generation_pipe(model)
101
+ try:
102
+ out = pipe(
103
+ prompt,
104
+ max_new_tokens=int(max_new_tokens),
105
+ temperature=float(temperature),
106
+ do_sample=bool(do_sample),
107
+ return_full_text=False,
108
+ )
109
+ except TypeError:
110
+ out = pipe(
111
+ prompt,
112
+ max_new_tokens=int(max_new_tokens),
113
+ temperature=float(temperature),
114
+ do_sample=bool(do_sample),
115
+ )
116
+
117
+ if not isinstance(out, list) or not out or not isinstance(out[0], dict) or "generated_text" not in out[0]:
118
+ raise RuntimeError(f"Unexpected text_generation response: {out!r}")
119
+
120
+ generated = str(out[0]["generated_text"])
121
+ if generated.startswith(prompt):
122
+ generated = generated[len(prompt):].lstrip()
123
+ return generated
124
+
125
+
126
+ client = LocalTransformersClient()
127
+
128
+ # Dream symbol database for enhanced interpretations
129
+ DREAM_SYMBOLS = {
130
+ "water": "💧 Emotions, unconscious mind, purification",
131
+ "flying": "🦋 Freedom, ambition, escaping limitations",
132
+ "falling": "⬇️ Loss of control, anxiety, letting go",
133
+ "teeth": "🦷 Confidence, self-image, communication",
134
+ "chase": "🏃 Avoidance, pressure, unresolved issues",
135
+ "house": "🏠 Self, psyche, different aspects of personality",
136
+ "snake": "🐍 Transformation, hidden fears, healing",
137
+ "death": "💀 Endings, transformation, new beginnings",
138
+ "baby": "👶 New beginnings, innocence, vulnerability",
139
+ "car": "🚗 Life direction, control, personal drive",
140
+ "fire": "🔥 Passion, anger, transformation, energy",
141
+ "ocean": "🌊 Vast emotions, the unknown, life's depth",
142
+ "forest": "🌲 Unconscious, mystery, personal growth",
143
+ "mirror": "🪞 Self-reflection, truth, identity",
144
+ "stairs": "🪜 Progress, transition, spiritual journey",
145
+ "door": "🚪 Opportunities, transitions, new paths",
146
+ "rain": "🌧️ Cleansing, sadness, renewal",
147
+ "sun": "☀️ Clarity, vitality, consciousness",
148
+ "moon": "🌙 Intuition, feminine energy, cycles",
149
+ "bird": "🐦 Freedom, perspective, spiritual messages"
150
+ }
151
+
152
+ # Mood colors for visualization
153
+ MOOD_COLORS = {
154
+ "joy": "#FFD700",
155
+ "fear": "#4B0082",
156
+ "sadness": "#4169E1",
157
+ "anger": "#DC143C",
158
+ "surprise": "#FF69B4",
159
+ "peace": "#90EE90",
160
+ "confusion": "#DDA0DD",
161
+ "excitement": "#FF4500"
162
+ }
163
+
164
+
165
+ def analyze_dream_sentiment(dream_text: str) -> tuple:
166
+ """
167
+ Analyze the emotional content of a dream using sentiment analysis.
168
+ """
169
+ if not dream_text.strip():
170
+ return "Please describe your dream first.", "N/A", ""
171
+
172
+ start_time = time.time()
173
+
174
+ try:
175
+ # Multi-label emotion classification
176
+ emotions = client.text_classification(
177
+ dream_text,
178
+ model="j-hartmann/emotion-english-distilroberta-base"
179
+ )
180
+
181
+ end_time = time.time()
182
+ response_time = f"{(end_time - start_time):.3f}s"
183
+
184
+ # Format emotional analysis
185
+ result = "## 🎭 Emotional Landscape of Your Dream\n\n"
186
+
187
+ emotion_bars = ""
188
+ for emotion in emotions[:5]: # Top 5 emotions
189
+ label = emotion.label.capitalize()
190
+ score = emotion.score
191
+ bar_length = int(score * 20)
192
+ color = MOOD_COLORS.get(label.lower(), "#888888")
193
+ emoji = {"joy": "😊", "fear": "😨", "sadness": "😢", "anger": "😠",
194
+ "surprise": "😲", "disgust": "🤢", "neutral": "😐"}.get(label.lower(), "🔮")
195
+
196
+ result += f"{emoji} **{label}**: {'█' * bar_length}{'░' * (20-bar_length)} {score:.1%}\n"
197
+
198
+ # Dominant mood
199
+ dominant = emotions[0].label if emotions else "Unknown"
200
+ result += f"\n### 🎯 Dominant Mood: **{dominant.upper()}**"
201
+
202
+ return result, response_time, dominant.lower()
203
+
204
+ except Exception as e:
205
+ return f"❌ Error analyzing emotions: {str(e)}", "N/A", ""
206
+
207
+
208
+ def generate_text(prompt: str, max_tokens: int, temperature: float) -> tuple:
209
+ """Basic text generation helper (used by unit tests)."""
210
+ if not prompt.strip():
211
+ return "Please enter some text to generate.", "N/A"
212
+
213
+ start_time = time.time()
214
+ try:
215
+ result = client.text_generation(
216
+ prompt,
217
+ model="distilgpt2",
218
+ max_new_tokens=max_tokens,
219
+ temperature=temperature,
220
+ do_sample=True,
221
+ )
222
+ end_time = time.time()
223
+ response_time = f"{(end_time - start_time):.3f}s"
224
+ return result, response_time
225
+ except Exception as e:
226
+ return f"❌ Error generating text: {str(e)}", "N/A"
227
+
228
+
229
+ def find_dream_symbols(dream_text: str) -> str:
230
+ """
231
+ Identify and interpret common dream symbols in the text.
232
+ """
233
+ dream_lower = dream_text.lower()
234
+ found_symbols = []
235
+
236
+ for symbol, meaning in DREAM_SYMBOLS.items():
237
+ if symbol in dream_lower:
238
+ found_symbols.append(f"- **{symbol.capitalize()}**: {meaning}")
239
+
240
+ if found_symbols:
241
+ return "## 🔮 Dream Symbols Detected\n\n" + "\n".join(found_symbols)
242
+ else:
243
+ return "## 🔮 Dream Symbols\n\n*No common symbols detected. Your dream may contain unique personal symbolism.*"
244
+
245
+
246
+ def generate_dream_interpretation(dream_text: str, mood: str) -> tuple:
247
+ """
248
+ Generate an AI interpretation of the dream using text generation.
249
+ """
250
+ if not dream_text.strip():
251
+ return "Please describe your dream first.", "N/A"
252
+
253
+ start_time = time.time()
254
+
255
+ try:
256
+ # Create a prompt for dream interpretation
257
+ prompt = f"""As a dream analyst, provide a thoughtful interpretation of this dream:
258
+
259
+ Dream: {dream_text}
260
+
261
+ The dreamer's dominant emotion was: {mood}
262
+
263
+ Interpretation:"""
264
+
265
+ result = client.text_generation(
266
+ prompt,
267
+ model="distilgpt2",
268
+ max_new_tokens=200,
269
+ temperature=0.7,
270
+ do_sample=True
271
+ )
272
+
273
+ end_time = time.time()
274
+ response_time = f"{(end_time - start_time):.3f}s"
275
+
276
+ interpretation = f"## 📖 Dream Interpretation\n\n{result}"
277
+ return interpretation, response_time
278
+
279
+ except Exception as e:
280
+ return f"❌ Error generating interpretation: {str(e)}", "N/A"
281
+
282
+
283
+ def generate_dream_story(dream_text: str, genre: str, length: int) -> tuple:
284
+ """
285
+ Transform the dream into a creative short story.
286
+ """
287
+ if not dream_text.strip():
288
+ return "Please describe your dream first.", "N/A"
289
+
290
+ start_time = time.time()
291
+
292
+ try:
293
+ genre_prompts = {
294
+ "Fantasy": "Write a magical fantasy story",
295
+ "Sci-Fi": "Write a futuristic science fiction story",
296
+ "Mystery": "Write a mysterious thriller story",
297
+ "Romance": "Write a romantic story",
298
+ "Horror": "Write a suspenseful horror story",
299
+ "Adventure": "Write an exciting adventure story"
300
+ }
301
+
302
+ prompt = f"""{genre_prompts.get(genre, "Write a creative story")} inspired by this dream:
303
+
304
+ Dream elements: {dream_text}
305
+
306
+ Story:"""
307
+
308
+ result = client.text_generation(
309
+ prompt,
310
+ model="distilgpt2",
311
+ max_new_tokens=length,
312
+ temperature=0.8,
313
+ do_sample=True
314
+ )
315
+
316
+ end_time = time.time()
317
+ response_time = f"{(end_time - start_time):.3f}s"
318
+
319
+ story = f"## ✨ Dream-Inspired {genre} Story\n\n{result}"
320
+ return story, response_time
321
+
322
+ except Exception as e:
323
+ return f"❌ Error generating story: {str(e)}", "N/A"
324
+
325
+
326
+ def generate_dream_image_prompt(dream_text: str) -> str:
327
+ """
328
+ Generate an image prompt based on the dream for use with image generators.
329
+ """
330
+ # Extract key visual elements
331
+ visual_keywords = []
332
+
333
+ for symbol in DREAM_SYMBOLS.keys():
334
+ if symbol in dream_text.lower():
335
+ visual_keywords.append(symbol)
336
+
337
+ # Add atmospheric descriptors based on common dream themes
338
+ atmosphere = random.choice([
339
+ "surreal", "ethereal", "mystical", "dreamlike",
340
+ "fantastical", "otherworldly", "atmospheric"
341
+ ])
342
+
343
+ style = random.choice([
344
+ "digital art", "oil painting style", "watercolor",
345
+ "concept art", "impressionist", "fantasy illustration"
346
+ ])
347
+
348
+ if visual_keywords:
349
+ elements = ", ".join(visual_keywords[:5])
350
+ prompt = f"A {atmosphere} scene featuring {elements}, {style}, dreamy lighting, vivid colors, detailed"
351
+ else:
352
+ prompt = f"A {atmosphere} dreamscape, {style}, surreal environment, dreamy lighting, mysterious atmosphere"
353
+
354
+ return f"## 🎨 Image Generation Prompt\n\n*Use this prompt with DALL-E, Midjourney, or Stable Diffusion:*\n\n```\n{prompt}\n```"
355
+
356
+
357
+ def save_to_journal(dream_text: str, interpretation: str) -> str:
358
+ """
359
+ Format dream entry for saving to a journal.
360
+ """
361
+ timestamp = datetime.now().strftime("%B %d, %Y at %I:%M %p")
362
+
363
+ journal_entry = f"""
364
+ # 📔 Dream Journal Entry
365
+ ## {timestamp}
366
+
367
+ ### 💭 The Dream
368
+ {dream_text}
369
+
370
+ ### 🔮 Interpretation
371
+ {interpretation}
372
+
373
+ ---
374
+ *Recorded with DreamWeaver AI*
375
+ """
376
+ return journal_entry
377
+
378
+
379
+ # Create the main Gradio interface
380
+ with gr.Blocks(
381
+ title="🌙 DreamWeaver AI",
382
+ theme=gr.themes.Soft(
383
+ primary_hue="indigo",
384
+ secondary_hue="purple",
385
+ neutral_hue="slate"
386
+ ),
387
+ css="""
388
+ .gradio-container {
389
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
390
+ }
391
+ .main-title {
392
+ text-align: center;
393
+ color: #e2e2e2;
394
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
395
+ }
396
+ """
397
+ ) as demo:
398
+
399
+ gr.Markdown("""
400
+ # 🌙 DreamWeaver AI - Dream Journal & Interpreter
401
+ ### *Unlock the secrets of your subconscious mind*
402
+
403
+ Welcome to DreamWeaver AI! This innovative tool uses advanced AI to analyze your dreams,
404
+ identify emotional patterns, discover symbolic meanings, and even transform your dreams
405
+ into creative stories.
406
+
407
+ **✨ Local Transformers Version** - Models are downloaded and run on this Space
408
+
409
+ ---
410
+ """)
411
+
412
+ with gr.Row():
413
+ with gr.Column(scale=2):
414
+ dream_input = gr.Textbox(
415
+ label="🌙 Describe Your Dream",
416
+ placeholder="Last night I dreamed I was flying over a vast ocean. The water was crystal clear and I could see colorful fish below. Suddenly, I noticed a mysterious door floating in the sky...",
417
+ lines=8,
418
+ max_lines=15
419
+ )
420
+
421
+ with gr.Row():
422
+ analyze_btn = gr.Button("🔍 Analyze Dream", variant="primary", size="lg")
423
+ clear_btn = gr.Button("🗑️ Clear", variant="secondary")
424
+
425
+ with gr.Tabs():
426
+ # Tab 1: Emotional Analysis
427
+ with gr.TabItem("🎭 Emotional Analysis"):
428
+ with gr.Row():
429
+ with gr.Column():
430
+ emotion_output = gr.Markdown(label="Emotional Landscape")
431
+ with gr.Column():
432
+ emotion_time = gr.Textbox(label="⏱️ Analysis Time", interactive=False)
433
+
434
+ mood_state = gr.State("")
435
+
436
+ # Tab 2: Symbol Interpretation
437
+ with gr.TabItem("🔮 Dream Symbols"):
438
+ symbols_output = gr.Markdown(label="Detected Symbols")
439
+
440
+ # Tab 3: AI Interpretation
441
+ with gr.TabItem("📖 AI Interpretation"):
442
+ with gr.Row():
443
+ interpret_btn = gr.Button("🧠 Generate Interpretation", variant="primary")
444
+ interpretation_output = gr.Markdown(label="Dream Interpretation")
445
+ interpretation_time = gr.Textbox(label="⏱️ Generation Time", interactive=False)
446
+
447
+ # Tab 4: Dream Story Generator
448
+ with gr.TabItem("✨ Story Generator"):
449
+ gr.Markdown("### Transform your dream into a creative story!")
450
+
451
+ with gr.Row():
452
+ genre_dropdown = gr.Dropdown(
453
+ choices=["Fantasy", "Sci-Fi", "Mystery", "Romance", "Horror", "Adventure"],
454
+ value="Fantasy",
455
+ label="📚 Select Genre"
456
+ )
457
+ length_slider = gr.Slider(
458
+ minimum=100,
459
+ maximum=500,
460
+ value=250,
461
+ step=50,
462
+ label="📏 Story Length (tokens)"
463
+ )
464
+
465
+ story_btn = gr.Button("✍️ Generate Story", variant="primary")
466
+ story_output = gr.Markdown(label="Your Dream Story")
467
+ story_time = gr.Textbox(label="⏱️ Generation Time", interactive=False)
468
+
469
+ # Tab 5: Image Prompt
470
+ with gr.TabItem("🎨 Visualize"):
471
+ gr.Markdown("### Create visual art from your dream!")
472
+ image_prompt_btn = gr.Button("🖼️ Generate Image Prompt", variant="primary")
473
+ image_prompt_output = gr.Markdown(label="Image Prompt")
474
+
475
+ # Tab 6: Dream Journal
476
+ with gr.TabItem("📔 Journal"):
477
+ gr.Markdown("### Save your dream to your journal")
478
+ save_btn = gr.Button("💾 Format for Journal", variant="primary")
479
+ journal_output = gr.Textbox(
480
+ label="Journal Entry (Copy this)",
481
+ lines=15,
482
+ show_copy_button=True
483
+ )
484
+
485
+ # Tab 7: About
486
+ with gr.TabItem("ℹ️ About"):
487
+ gr.Markdown("""
488
+ ## About DreamWeaver AI
489
+
490
+ ### 🌟 Features
491
+ - **Emotional Analysis**: Detect the emotional undertones of your dreams
492
+ - **Symbol Detection**: Identify and interpret common dream symbols
493
+ - **AI Interpretation**: Get personalized dream interpretations
494
+ - **Story Generation**: Transform dreams into creative stories
495
+ - **Visual Prompts**: Generate prompts for AI image generators
496
+
497
+ ### 🔧 Technical Architecture
498
+
499
+ | Component | Technology |
500
+ |-----------|------------|
501
+ | Frontend | Gradio 4.x |
502
+ | Emotion Model | distilroberta-base |
503
+ | Text Generation | distilgpt2 |
504
+ | Hosting | Hugging Face Spaces |
505
+ | Inference | Local Transformers |
506
+
507
+ ### ⚡ Local Model Approach Trade-offs
508
+
509
+ | ✅ Advantages | ⚠️ Considerations |
510
+ |--------------|-------------------|
511
+ | No external API dependency | First-run model download time |
512
+ | No network latency | More RAM/disk usage |
513
+ | Works offline (after download) | Smaller models on CPU |
514
+
515
+ ### 📚 Citations
516
+ - Hugging Face Transformers
517
+ - Gradio Documentation
518
+ - Dream symbolism: Jungian psychology concepts
519
+ - GitHub Copilot assistance
520
+
521
+ ### 👥 Team
522
+ *Add your team members here*
523
+ """)
524
+
525
+ # Example dreams
526
+ gr.Examples(
527
+ examples=[
528
+ ["I was flying over a beautiful forest at sunset. The trees below were golden and I felt completely free. Suddenly I noticed I was being chased by a dark shadow."],
529
+ ["I found myself in my childhood home, but all the rooms were different. There was a mysterious door that I had never seen before. When I opened it, I saw an endless staircase."],
530
+ ["I was swimming in a crystal-clear ocean with colorful fish. The water was warm and I could breathe underwater. I discovered an ancient underwater city with golden buildings."],
531
+ ["I was taking an important exam but realized I couldn't read any of the questions. My teeth started falling out and everyone was staring at me."],
532
+ ],
533
+ inputs=dream_input,
534
+ label="💭 Example Dreams"
535
+ )
536
+
537
+ # Event handlers
538
+ def full_analysis(dream_text):
539
+ emotions, time, mood = analyze_dream_sentiment(dream_text)
540
+ symbols = find_dream_symbols(dream_text)
541
+ return emotions, time, mood, symbols
542
+
543
+ analyze_btn.click(
544
+ fn=full_analysis,
545
+ inputs=[dream_input],
546
+ outputs=[emotion_output, emotion_time, mood_state, symbols_output]
547
+ )
548
+
549
+ interpret_btn.click(
550
+ fn=generate_dream_interpretation,
551
+ inputs=[dream_input, mood_state],
552
+ outputs=[interpretation_output, interpretation_time]
553
+ )
554
+
555
+ story_btn.click(
556
+ fn=generate_dream_story,
557
+ inputs=[dream_input, genre_dropdown, length_slider],
558
+ outputs=[story_output, story_time]
559
+ )
560
+
561
+ image_prompt_btn.click(
562
+ fn=generate_dream_image_prompt,
563
+ inputs=[dream_input],
564
+ outputs=[image_prompt_output]
565
+ )
566
+
567
+ save_btn.click(
568
+ fn=lambda d, i: save_to_journal(d, i),
569
+ inputs=[dream_input, interpretation_output],
570
+ outputs=[journal_output]
571
+ )
572
+
573
+ clear_btn.click(
574
+ fn=lambda: ("", "", "", "", "", "", "", ""),
575
+ outputs=[dream_input, emotion_output, emotion_time, symbols_output,
576
+ interpretation_output, story_output, image_prompt_output, journal_output]
577
+ )
578
+
579
+ gr.Markdown("""
580
+ ---
581
+ <center>
582
+
583
+ *🌙 DreamWeaver AI - Powered by Transformers*
584
+
585
+ *Made with ❤️ for MLOps Case Study*
586
+
587
+ </center>
588
+ """)
589
+
590
+
591
+ if __name__ == "__main__":
592
+ demo.launch()
pytest.ini ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Pytest configuration file
2
+
3
+ [pytest]
4
+ testpaths = .
5
+ python_files = test_*.py
6
+ python_functions = test_*
7
+ python_classes = Test*
8
+ addopts = -v --tb=short
9
+ filterwarnings =
10
+ ignore::DeprecationWarning
11
+ ignore::UserWarning
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ huggingface_hub<0.24
3
+ transformers>=4.35.0
4
+ torch>=2.0.0
5
+ accelerate>=0.24.0
test_app.py ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Unit Tests for DreamWeaver AI - API-Based Version
3
+ ==================================================
4
+ These tests verify the functionality of the dream analysis components.
5
+ Note: Some tests mock API calls to avoid rate limits during CI/CD.
6
+
7
+ Run with: pytest test_app.py -v
8
+ """
9
+
10
+ import pytest
11
+ import sys
12
+ import os
13
+ from unittest.mock import Mock, patch, MagicMock
14
+
15
+ # Add parent directory to path for imports
16
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
17
+
18
+
19
+ class TestDreamSymbols:
20
+ """Test suite for dream symbol detection (no API calls needed)."""
21
+
22
+ def test_import_app(self):
23
+ """Test that app module can be imported."""
24
+ import app
25
+ assert app is not None
26
+
27
+ def test_dream_symbols_exist(self):
28
+ """Test that dream symbols dictionary exists."""
29
+ import app
30
+ assert hasattr(app, 'DREAM_SYMBOLS')
31
+ assert len(app.DREAM_SYMBOLS) > 0
32
+
33
+ def test_find_dream_symbols_basic(self):
34
+ """Test basic symbol detection."""
35
+ import app
36
+ dream = "I was flying over the ocean and saw a beautiful house."
37
+ result = app.find_dream_symbols(dream)
38
+ assert "flying" in result.lower() or "ocean" in result.lower() or "house" in result.lower()
39
+
40
+ def test_find_dream_symbols_no_match(self):
41
+ """Test when no symbols are found."""
42
+ import app
43
+ dream = "I had a conversation with someone."
44
+ result = app.find_dream_symbols(dream)
45
+ assert "No common symbols" in result or "unique personal symbolism" in result
46
+
47
+ def test_find_dream_symbols_multiple(self):
48
+ """Test detection of multiple symbols."""
49
+ import app
50
+ dream = "I saw water, fire, and a snake near a door in the moonlight."
51
+ result = app.find_dream_symbols(dream)
52
+ # At least some symbols should be detected
53
+ assert "🔮" in result # The header emoji
54
+
55
+
56
+ class TestMoodColors:
57
+ """Test suite for mood color mappings."""
58
+
59
+ def test_mood_colors_exist(self):
60
+ """Test that mood colors dictionary exists."""
61
+ import app
62
+ assert hasattr(app, 'MOOD_COLORS')
63
+ assert len(app.MOOD_COLORS) > 0
64
+
65
+ def test_mood_colors_have_hex(self):
66
+ """Test that mood colors have hex values."""
67
+ import app
68
+ for mood, color in app.MOOD_COLORS.items():
69
+ assert color.startswith('#')
70
+
71
+
72
+ class TestImagePromptGeneration:
73
+ """Test suite for image prompt generation (no API calls)."""
74
+
75
+ def test_generate_image_prompt_basic(self):
76
+ """Test image prompt generation."""
77
+ import app
78
+ dream = "I was flying through a forest with the moon above."
79
+ result = app.generate_dream_image_prompt(dream)
80
+ assert "Image Generation Prompt" in result
81
+ assert "```" in result # Code block for the prompt
82
+
83
+ def test_generate_image_prompt_empty(self):
84
+ """Test image prompt with minimal input."""
85
+ import app
86
+ dream = "A simple dream."
87
+ result = app.generate_dream_image_prompt(dream)
88
+ assert "dreamscape" in result.lower() or "scene" in result.lower()
89
+
90
+
91
+ class TestJournalSaving:
92
+ """Test suite for journal entry formatting."""
93
+
94
+ def test_save_to_journal_format(self):
95
+ """Test journal entry formatting."""
96
+ import app
97
+ dream = "I had a wonderful dream about flying."
98
+ interpretation = "This dream represents freedom."
99
+ result = app.save_to_journal(dream, interpretation)
100
+
101
+ assert "Dream Journal Entry" in result
102
+ assert dream in result
103
+ assert interpretation in result
104
+ assert "DreamWeaver AI" in result
105
+
106
+
107
+ class TestSentimentAnalysisMocked:
108
+ """Test suite for sentiment analysis with mocked API."""
109
+
110
+ @patch('app.client')
111
+ def test_analyze_sentiment_success(self, mock_client):
112
+ """Test sentiment analysis with mocked successful response."""
113
+ import app
114
+
115
+ # Mock the API response
116
+ mock_result = [
117
+ Mock(label="joy", score=0.8),
118
+ Mock(label="surprise", score=0.1),
119
+ Mock(label="neutral", score=0.1)
120
+ ]
121
+ mock_client.text_classification.return_value = mock_result
122
+
123
+ result, time, mood = app.analyze_dream_sentiment("I was so happy in my dream!")
124
+
125
+ assert "Emotional Landscape" in result
126
+ assert mood == "joy"
127
+ assert "s" in time # time should contain seconds
128
+
129
+ @patch('app.client')
130
+ def test_analyze_sentiment_empty_input(self, mock_client):
131
+ """Test sentiment analysis with empty input."""
132
+ import app
133
+
134
+ result, time, mood = app.analyze_dream_sentiment("")
135
+
136
+ assert "Please enter some text" in result or "Please describe your dream" in result
137
+ mock_client.text_classification.assert_not_called()
138
+
139
+
140
+ class TestTextGenerationMocked:
141
+ """Test suite for text generation with mocked API."""
142
+
143
+ @patch('app.client')
144
+ def test_generate_text_success(self, mock_client):
145
+ """Test text generation with mocked response."""
146
+ import app
147
+
148
+ mock_client.text_generation.return_value = "Once upon a time, in a magical land..."
149
+
150
+ result, time = app.generate_text("Once upon a time", 50, 0.7)
151
+
152
+ assert isinstance(result, str)
153
+ assert "s" in time
154
+
155
+ @patch('app.client')
156
+ def test_generate_text_empty_input(self, mock_client):
157
+ """Test text generation with empty input."""
158
+ import app
159
+
160
+ result, time = app.generate_text("", 50, 0.7)
161
+
162
+ assert "Please enter" in result
163
+ mock_client.text_generation.assert_not_called()
164
+
165
+
166
+ class TestDreamInterpretationMocked:
167
+ """Test suite for dream interpretation with mocked API."""
168
+
169
+ @patch('app.client')
170
+ def test_generate_interpretation_success(self, mock_client):
171
+ """Test interpretation generation with mocked response."""
172
+ import app
173
+
174
+ mock_client.text_generation.return_value = "This dream symbolizes your desire for freedom..."
175
+
176
+ result, time = app.generate_dream_interpretation(
177
+ "I was flying over mountains",
178
+ "joy"
179
+ )
180
+
181
+ assert "Dream Interpretation" in result
182
+ assert "s" in time
183
+
184
+
185
+ class TestDreamStoryMocked:
186
+ """Test suite for story generation with mocked API."""
187
+
188
+ @patch('app.client')
189
+ def test_generate_story_fantasy(self, mock_client):
190
+ """Test fantasy story generation."""
191
+ import app
192
+
193
+ mock_client.text_generation.return_value = "The hero discovered a magical realm..."
194
+
195
+ result, time = app.generate_dream_story(
196
+ "I found a magical sword",
197
+ "Fantasy",
198
+ 250
199
+ )
200
+
201
+ assert "Fantasy" in result
202
+ assert "Story" in result
203
+
204
+ @patch('app.client')
205
+ def test_generate_story_scifi(self, mock_client):
206
+ """Test sci-fi story generation."""
207
+ import app
208
+
209
+ mock_client.text_generation.return_value = "In the year 3000..."
210
+
211
+ result, time = app.generate_dream_story(
212
+ "I was on a spaceship",
213
+ "Sci-Fi",
214
+ 250
215
+ )
216
+
217
+ assert "Sci-Fi" in result
218
+
219
+
220
+ class TestErrorHandling:
221
+ """Test suite for error handling."""
222
+
223
+ @patch('app.client')
224
+ def test_api_error_handling(self, mock_client):
225
+ """Test that API errors are handled gracefully."""
226
+ import app
227
+
228
+ mock_client.text_classification.side_effect = Exception("API rate limit exceeded")
229
+
230
+ result, time, mood = app.analyze_dream_sentiment("Test dream")
231
+
232
+ assert "Error" in result
233
+ assert "rate limit" in result.lower() or "error" in result.lower()
234
+
235
+
236
+ class TestGradioInterface:
237
+ """Test suite for Gradio interface components."""
238
+
239
+ def test_demo_exists(self):
240
+ """Test that the Gradio demo object exists."""
241
+ import app
242
+ assert hasattr(app, 'demo')
243
+
244
+ def test_demo_is_blocks(self):
245
+ """Test that demo is a Gradio Blocks instance."""
246
+ import app
247
+ import gradio as gr
248
+ assert isinstance(app.demo, gr.Blocks)
249
+
250
+
251
+ # Integration test (only runs if HF_TOKEN is available)
252
+ class TestIntegrationWithAPI:
253
+ """Integration tests that actually call the API (skipped in CI without token)."""
254
+
255
+ @pytest.mark.skipif(
256
+ os.getenv('SKIP_API_TESTS', 'true').lower() == 'true',
257
+ reason="Skipping API tests to avoid rate limits"
258
+ )
259
+ def test_real_sentiment_analysis(self):
260
+ """Test real API call for sentiment analysis."""
261
+ import app
262
+
263
+ result, time, mood = app.analyze_dream_sentiment(
264
+ "I was extremely happy flying through beautiful clouds."
265
+ )
266
+
267
+ assert "Emotional Landscape" in result
268
+ assert mood != ""
269
+
270
+
271
+ if __name__ == "__main__":
272
+ pytest.main([__file__, "-v", "--tb=short"])