Skip to content

Commit e7db965

Browse files
authored
Merge branch 'code-differently:main' into main
2 parents 1f746b1 + 6eb1d9c commit e7db965

36 files changed

+7476
-1
lines changed

lesson_05/jaydenellis/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Real Time Translation App
2+
3+
## Overview
4+
I wanted to base my user stories around an app that would make translating languages in real time easier for conversations and studying (this probably already exists).
5+
6+
7+
## User Story #1
8+
1. As a traveler, I want to be able to record a conversation of someone speaking in a different language and translate it in real time, so I can communicate with people who might need help.
9+
10+
## Acceptance Criteria
11+
- Audio Recording Functionality: The app must provide a clear record button that captures audio input with visual feedback during recording.
12+
- Real-Time Translation: Translation processing should begin within a few seconds and display accurate text in the target language.
13+
- Audio Playback: The app should convert translated text to speech and play it aloud in the target language.
14+
- Multiple recordings in sequence: Users should be able to record multiple conversations back-to-back for ongoing dialogue.
15+
16+
17+
## User Story #2
18+
2. As a foreigner, I want to take a picture of a language and have it translated in real time so that I can avoid dealing with language barriers.
19+
20+
## Acceptance Criteria
21+
- Camera Integration: The app must provide a camera button that allows users to capture photos of text with proper focus and lighting guidance.
22+
- Text Recognition: The app should detect and extract text from images using OCR technology within a few seconds of capture.
23+
- Visual Translation Display: Translated text should appear overlaid on the original image or in a clear display format below the photo.
24+
- Multiple Text Languages: The app should support translation of common languages found on signs, menus, and documents while traveling.
25+
26+
27+
28+
29+
## User Story #3
30+
3. As a student, I want to store the previous translations that I've done on the app so that I can look back at them at a later date and study them.
31+
32+
## Acceptance Criteria
33+
- Translation History Storage: The app must automatically save all completed translations with timestamps and source/target language pairs.
34+
- Easy Access to Saved Translations: Users should be able to access their translation history through a clearly labeled menu or tab within the app.
35+
- Search and Filter Functionality: The app should allow users to search through their saved translations by date, language, or keywords from the original text.
36+
- Study Mode Features: Saved translations should display both original and translated text side-by-side for effective language learning and review.
37+
38+
39+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import csv from 'csv-parser';
2+
import fs from 'fs';
3+
import { Credit, MediaItem, MediaType } from '../models/index.js';
4+
import { Loader } from './loader.js';
5+
6+
export class BrooklynHardenLoader implements Loader {
7+
getLoaderName(): string {
8+
return 'brooklynharden';
9+
}
10+
11+
async loadData(): Promise<MediaItem[]> {
12+
const credits = await this.loadCredits();
13+
const mediaItems = await this.loadMediaItems();
14+
credits.forEach(credit => {
15+
const media_item = mediaItems.find(media_item => media_item.getId() === credit.getMediaItemId());
16+
if(media_item) {
17+
media_item.addCredit(credit);
18+
}
19+
})
20+
21+
22+
console.log(
23+
`Loaded ${credits.length} credits and ${mediaItems.length} media items`,
24+
);
25+
26+
return [...mediaItems.values()];
27+
}
28+
29+
async loadMediaItems(): Promise<MediaItem[]> {
30+
const results = [];
31+
const read = fs
32+
.createReadStream('data/media_items.csv', 'utf-8')
33+
.pipe(csv());
34+
for await (const row of read) {
35+
const { id, type, title, year } = row;
36+
const mediaType = type as MediaType;
37+
results.push(new MediaItem(id, title, mediaType, parseInt(year), []));
38+
}
39+
return results;
40+
}
41+
42+
async loadCredits(): Promise<Credit[]> {
43+
const credits = [];
44+
const readable = fs
45+
.createReadStream('data/credits.csv', 'utf-8')
46+
.pipe(csv());
47+
for await (const row of readable) {
48+
const { media_item_id, role, name } = row;
49+
credits.push(new Credit(media_item_id, name, role));
50+
}
51+
return credits;
52+
}
53+
}
54+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import csv from 'csv-parser';
2+
import fs from 'fs';
3+
import { Credit, MediaItem, MediaType } from '../models/index.js';
4+
import { Loader } from './loader.js';
5+
6+
export class JaizelcespedesLoader implements Loader {
7+
getLoaderName(): string {
8+
return 'jaizelcespedes';
9+
}
10+
11+
async loadData(): Promise<MediaItem[]> {
12+
const credits = await this.loadCredits();
13+
const mediaItems = await this.loadMediaItems();
14+
15+
console.log(
16+
`Loaded ${credits.length} credits and ${mediaItems.length} media items`,
17+
);
18+
19+
return [...mediaItems.values()];
20+
}
21+
22+
async loadMediaItems(): Promise<MediaItem[]> {
23+
const mediaItems: MediaItem[] = [];
24+
const readable = fs
25+
.createReadStream('data/media_items.csv', 'utf-8')
26+
.pipe(csv());
27+
28+
for await (const row of readable) {
29+
const { id, type, title, year } = row;
30+
31+
// Convert the string type to MediaType enum
32+
let mediaType: MediaType;
33+
switch (type) {
34+
case 'movie':
35+
mediaType = MediaType.Movie;
36+
break;
37+
case 'tv_show':
38+
mediaType = MediaType.TVShow;
39+
break;
40+
case 'documentary':
41+
mediaType = MediaType.Documentary;
42+
break;
43+
default:
44+
console.warn(`Unknown media type: ${type}. Defaulting to Movie.`);
45+
mediaType = MediaType.Movie;
46+
}
47+
48+
// Create MediaItem with empty credits array for now
49+
// Credits will be associated separately in loadData method
50+
const mediaItem = new MediaItem(
51+
id,
52+
title,
53+
mediaType,
54+
parseInt(year, 10),
55+
[]
56+
);
57+
58+
mediaItems.push(mediaItem);
59+
}
60+
61+
return mediaItems;
62+
}
63+
64+
async loadCredits(): Promise<Credit[]> {
65+
const credits = [];
66+
const readable = fs
67+
.createReadStream('data/credits.csv', 'utf-8')
68+
.pipe(csv());
69+
for await (const row of readable) {
70+
const { media_item_id, role, name } = row;
71+
credits.push(new Credit(media_item_id, name, role));
72+
}
73+
return credits;
74+
}
75+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import csv from 'csv-parser';
2+
import fs from 'fs';
3+
import { Credit, MediaItem, MediaType, Role } from '../models/index.js';
4+
import { Loader } from './loader.js';
5+
6+
export class JaredEdgeLoader implements Loader {
7+
getLoaderName(): string {
8+
return 'jarededge';
9+
}
10+
11+
async loadData(): Promise<MediaItem[]> {
12+
const [items, credits] = await Promise.all([
13+
this.loadMediaItems(),
14+
this.loadCredits(),
15+
]);
16+
17+
const byId = new Map(items.map((i) => [i.getId(), i]));
18+
19+
for (const credit of credits) {
20+
const mediaItemId = this.creditToMediaItemId(credit);
21+
const item = byId.get(mediaItemId);
22+
if (item) item.addCredit(credit);
23+
}
24+
25+
return [...byId.values()];
26+
}
27+
28+
async loadMediaItems(): Promise<MediaItem[]> {
29+
const items: MediaItem[] = [];
30+
const readable = fs
31+
.createReadStream('data/media_items.csv', 'utf-8')
32+
.pipe(csv());
33+
34+
for await (const row of readable) {
35+
const id = String(row.id).trim();
36+
const title = String(row.title).trim();
37+
const releaseYear = Number.parseInt(String(row.year), 10);
38+
const mediaType = this.toMediaType(String(row.type));
39+
40+
if (Number.isNaN(releaseYear)) {
41+
throw new Error(`Invalid year "${row.year}" for id=${id} (${title})`);
42+
}
43+
44+
items.push(new MediaItem(id, title, mediaType, releaseYear, []));
45+
}
46+
47+
return items;
48+
}
49+
50+
private toMediaType(raw: string): MediaType {
51+
const v = raw.trim().toLowerCase();
52+
if (v === 'movie') return MediaType.Movie;
53+
if (v === 'tv_show') return MediaType.TVShow;
54+
if (v === 'documentary') return MediaType.Documentary;
55+
throw new Error(`Unknown media type: ${raw}`);
56+
}
57+
58+
async loadCredits(): Promise<Credit[]> {
59+
const credits: Credit[] = [];
60+
const readable = fs
61+
.createReadStream('data/credits.csv', 'utf-8')
62+
.pipe(csv());
63+
for await (const row of readable) {
64+
const mediaItemId = String(row.media_item_id).trim();
65+
const name = String(row.name).trim();
66+
const role = this.toRole(String(row.role));
67+
credits.push(new Credit(mediaItemId, name, role));
68+
}
69+
return credits;
70+
}
71+
72+
private toRole(raw: string): Role {
73+
const normalized = raw.trim();
74+
const values = Object.values(Role) as string[];
75+
76+
const match = values.find(
77+
(v) => v === normalized || v.toLowerCase() === normalized.toLowerCase(),
78+
);
79+
if (match) return match as Role;
80+
81+
const map = Role as unknown as Record<string, Role>;
82+
const key = Object.keys(map).find(
83+
(k) => k.toLowerCase() === normalized.toLowerCase(),
84+
);
85+
if (key) return map[key];
86+
87+
throw new Error(`Unknown role: ${raw}`);
88+
}
89+
90+
private creditToMediaItemId(c: Credit): string {
91+
return c.getMediaItemId();
92+
}
93+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import csv from 'csv-parser';
2+
import fs from 'fs';
3+
import { Credit, MediaItem } from '../models/index.js';
4+
import { Loader } from './loader.js';
5+
6+
export class JoneemckellarLoader implements Loader {
7+
getLoaderName(): string {
8+
return 'joneemckellar';
9+
}
10+
11+
async loadData(): Promise<MediaItem[]> {
12+
const credits = await this.loadCredits();
13+
const mediaItems = await this.loadMediaItems(credits);
14+
15+
console.log(
16+
`Loaded ${credits.length} credits and ${mediaItems.length} media items`,
17+
);
18+
19+
return mediaItems;
20+
}
21+
22+
// Pass all credits to associate with each media item
23+
async loadMediaItems(credits: Credit[]): Promise<MediaItem[]> {
24+
const mediaItems: MediaItem[] = []; // Declare the array
25+
const readable = fs
26+
.createReadStream('data/media_items.csv', 'utf-8')
27+
.pipe(csv());
28+
29+
for await (const row of readable) {
30+
const { id, title, type, release_year } = row;
31+
32+
// Filter credits for this specific media item
33+
const itemCredits = credits.filter((c) => c.getMediaItemId() === id);
34+
35+
// Handle missing or empty release_year values
36+
const parsedReleaseYear =
37+
release_year && release_year.trim() !== ''
38+
? parseInt(release_year, 10)
39+
: 0;
40+
41+
mediaItems.push(
42+
new MediaItem(id, title, type, parsedReleaseYear, itemCredits),
43+
);
44+
}
45+
46+
return mediaItems;
47+
}
48+
49+
async loadCredits(): Promise<Credit[]> {
50+
const credits: Credit[] = [];
51+
const readable = fs
52+
.createReadStream('data/credits.csv', 'utf-8')
53+
.pipe(csv());
54+
55+
for await (const row of readable) {
56+
const { media_item_id, role, name } = row;
57+
credits.push(new Credit(media_item_id, name, role));
58+
}
59+
60+
return credits;
61+
}
62+
}

0 commit comments

Comments
 (0)