Skip to content

Commit 9e63ff2

Browse files
committed
feat(api): add api call for solving equations based on image data
Adds API interaction infrastructure and a single call to solve image data. Also configures commitizen and transmits image data from the PhotoCaptureComponent to the HomePageComponent.
1 parent 99a45de commit 9e63ff2

13 files changed

+824
-46
lines changed

package-lock.json

+712
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.0.0",
44
"scripts": {
55
"ng": "ng",
6-
"start": "ng serve",
6+
"start": "ng serve --proxy-config proxy.conf.json",
77
"build": "ng build",
88
"test": "ng test",
99
"lint": "ng lint",
@@ -29,10 +29,11 @@
2929
"@angular-devkit/build-angular": "~0.1001.0",
3030
"@angular/cli": "~10.1.0",
3131
"@angular/compiler-cli": "~10.1.0",
32-
"@types/node": "^12.11.1",
3332
"@types/jasmine": "~3.5.0",
3433
"@types/jasminewd2": "~2.0.3",
34+
"@types/node": "^12.11.1",
3535
"codelyzer": "^6.0.0",
36+
"cz-conventional-changelog": "^3.3.0",
3637
"jasmine-core": "~3.6.0",
3738
"jasmine-spec-reporter": "~5.0.0",
3839
"karma": "~5.0.0",
@@ -44,5 +45,10 @@
4445
"ts-node": "~8.3.0",
4546
"tslint": "~6.1.0",
4647
"typescript": "~4.0.2"
48+
},
49+
"config": {
50+
"commitizen": {
51+
"path": "./node_modules/cz-conventional-changelog"
52+
}
4753
}
4854
}

proxy.conf.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"/": {
3+
"target": "http://159.89.90.18:5000",
4+
"secure": false,
5+
"changeOrigin": true
6+
}
7+
}

src/app/app.module.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { NgModule } from '@angular/core';
44
import { AppRoutingModule } from './app-routing.module';
55
import { AppComponent } from './app.component';
66
import { SiteHomeModule } from '../lib/site-home/site-home.module';
7+
import { HttpClientModule } from '@angular/common/http';
78

89
@NgModule({
910
declarations: [
@@ -12,7 +13,8 @@ import { SiteHomeModule } from '../lib/site-home/site-home.module';
1213
imports: [
1314
BrowserModule,
1415
AppRoutingModule,
15-
SiteHomeModule
16+
SiteHomeModule,
17+
HttpClientModule
1618
],
1719
providers: [],
1820
bootstrap: [AppComponent]
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
<div *ngIf="homePageState|async as State">
2-
<div *ngIf="!State.takingPhoto">
3-
James is best teacher.
4-
<Button (click)="startTakingPhoto()"> </Button>
5-
6-
</div>
7-
1+
<div *ngIf="homePageState|async as state">
2+
<div *ngIf="!state.takingPhoto">
3+
<h2>MLM</h2>
4+
<h1 class="home-page__title">Math Learning Machine</h1>
5+
<p class="home-page__description">A tool that harnesses the power of Machine Learning and Optical Character
6+
recognition to solve hand written
7+
math problems, both simple and complex. Just write it out and snap a picture!</p>
88

9-
10-
<app-photo-capture *ngIf="State.takingPhoto"></app-photo-capture>
9+
<button class="home-page__capture-button" (click)="startTakingPhoto()">Capture</button>
10+
<p>Created by Grant Williams, James Mann, Raj Kapadia, Spencer Brown, and Steven Kemp *in order of the alphabet,
11+
not of importance*</p>
12+
</div>
13+
<app-photo-capture *ngIf="state.takingPhoto" (imageDataUpdated)="sendImage($event)"></app-photo-capture>
1114
</div>
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
import { Component, OnInit } from '@angular/core';
2-
import { HomePageService} from '../../services/home-page.service';
2+
import { HomePageService } from '../../services/home-page/home-page.service';
3+
import { MathLearningMachineApiService } from '../../services/math-learning-machine-api/math-learning-machine-api.service';
34

45
@Component({
56
selector: 'app-home-page',
67
templateUrl: './home-page.component.html',
78
styleUrls: ['./home-page.component.scss']
89
})
910
export class HomePageComponent implements OnInit {
10-
homePageState = this.homepageservice.getState();
11+
homePageState = this.homePageService.getState();
1112

12-
constructor(private homepageservice:HomePageService) { }
13+
constructor(private homePageService: HomePageService, private mathLearningMachineApiService: MathLearningMachineApiService) { }
1314

1415
ngOnInit(): void {
1516
}
1617

17-
startTakingPhoto(){
18-
this.homepageservice.updateState({takingPhoto:true});
18+
startTakingPhoto() {
19+
this.homePageService.setTakingPhoto(true);
1920
}
2021

22+
sendImage(imageData) {
23+
this.mathLearningMachineApiService.solveImage(imageData).subscribe({
24+
next: (res) => {
25+
console.log(res);
26+
this.homePageService.setTakingPhoto(false);
27+
},
28+
error: (e) => {
29+
console.log(e);
30+
this.homePageService.setTakingPhoto(false);
31+
}
32+
});
33+
this.homePageService.setTakingPhoto(false);
34+
}
2135
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
<div class="container vh-100">
2-
<div class="d-flex flex-column align-items-center">
3-
<div class="p-1">
4-
<video #video class="app-photo-capture__video-feed" autoplay></video>
5-
</div>
6-
<div class="pb-2">
7-
<button mat-fab theme="" color="primary" class="app-photo-capture__capture-button"
8-
(click)="capture()"></button>
9-
</div>
10-
</div>
11-
<div class="p-1">
12-
<canvas #canvas class="app-photo-capture__video-feed"></canvas>
1+
<div class="app-photo-capture">
2+
<video #video [class]="!(photoCaptured | async)? 'app-photo-capture__video-feed' : 'app-photo-capture__hidden'"
3+
autoplay></video>
4+
<button mat-fab theme="" color="primary"
5+
[class]="!(photoCaptured | async)? 'app-photo-capture__capture-button' : 'app-photo-capture__hidden'"
6+
(click)="capture()">
7+
</button>
8+
<canvas #canvas
9+
[class]="(photoCaptured | async)? 'app-photo-capture__photo' : 'app-photo-capture__hidden'"></canvas>
10+
<div *ngIf="photoCaptured | async">
11+
<button mat-button color="primary" (click)="retake()">Retake</button>
12+
<button mat-button color="primary" (click)="acceptImage()">Accept</button>
1313
</div>
1414
</div>
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
.app-photo-capture{
2+
height: 100vh;
3+
width: 100vw;
4+
background: black;
5+
display: flex;
6+
flex-direction: column;
7+
align-items: center;
8+
justify-content: center;
9+
210
&__video-feed {
311
height: 100%;
412
width: 100%;
513
}
614

15+
&__photo {
16+
width: 100%;
17+
}
18+
719
&__capture-button {
820
position: absolute;
9-
bottom: 2rem;
21+
bottom: 1rem;
1022
left: calc(50% - 52px);
1123
}
24+
25+
&__hidden{
26+
display: none;
27+
}
1228
}

src/lib/site-home/components/photo-capture/photo-capture.component.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { Component, OnInit, ViewChild, ElementRef, Renderer2, Output, EventEmitter } from '@angular/core';
1+
import { Component, OnInit, ViewChild, ElementRef, Renderer2, Output, EventEmitter, AfterViewInit } from '@angular/core';
22
import { BehaviorSubject } from 'rxjs';
33

44
@Component({
55
selector: 'app-photo-capture',
66
templateUrl: './photo-capture.component.html',
77
styleUrls: ['./photo-capture.component.scss']
88
})
9-
export class PhotoCaptureComponent implements OnInit {
10-
@ViewChild('video', { static: true }) videoElement: ElementRef;
11-
@ViewChild('canvas', { static: true }) canvas: ElementRef;
12-
@Output() imageData = new EventEmitter<string>();
9+
export class PhotoCaptureComponent implements AfterViewInit {
10+
@ViewChild('video', { static: false }) videoElement: ElementRef;
11+
@ViewChild('canvas', { static: false }) canvas: ElementRef;
12+
@Output() imageDataUpdated = new EventEmitter<string>();
1313

1414
constraints: object = {
1515
video: {
@@ -22,11 +22,11 @@ export class PhotoCaptureComponent implements OnInit {
2222
videoHeight: number = 0;
2323
videoWidth: number = 0;
2424

25-
photoCaptureState = new BehaviorSubject<boolean>(false);
25+
photoCaptured = new BehaviorSubject<boolean>(false);
2626

2727
constructor(private renderer: Renderer2) { }
2828

29-
ngOnInit(): void {
29+
ngAfterViewInit() {
3030
this.startCamera();
3131
}
3232

@@ -35,7 +35,7 @@ export class PhotoCaptureComponent implements OnInit {
3535
if ((navigator.mediaDevices && navigator.mediaDevices.getUserMedia)) {
3636
navigator.mediaDevices.getUserMedia(this.constraints).then(this.attachVideo.bind(this)).catch(this.handleError.bind(this));
3737
}
38-
else {
38+
else {
3939
alert('Sorry, camera not available.');
4040
}
4141
}
@@ -59,11 +59,15 @@ export class PhotoCaptureComponent implements OnInit {
5959
this.renderer.setProperty(this.canvas.nativeElement, 'width', this.videoWidth);
6060
this.renderer.setProperty(this.canvas.nativeElement, 'height', this.videoHeight);
6161
this.canvas.nativeElement.getContext('2d').drawImage(this.videoElement.nativeElement, 0, 0);
62-
this.photoCaptureState.next(true);
62+
this.photoCaptured.next(true);
63+
}
64+
65+
retake() {
66+
this.photoCaptured.next(false);
6367
}
6468

6569
acceptImage() {
6670
const canvasElement = this.canvas.nativeElement as HTMLCanvasElement;
67-
this.imageData.emit(canvasElement.toDataURL());
71+
this.imageDataUpdated.emit(canvasElement.toDataURL());
6872
}
6973
}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
import { Injectable } from '@angular/core';
22
import { BehaviorSubject } from 'rxjs';
3-
import { iHomePageState } from '../interfaces/home-page.interface';
3+
import { iHomePageState } from '../../interfaces/home-page.interface';
44

55
@Injectable({
66
providedIn: 'root'
77
})
88
export class HomePageService {
99
defaultStateStatus = {
10-
takingPhoto:false
10+
takingPhoto: false
1111
}
1212
homePageState = new BehaviorSubject<iHomePageState>(this.defaultStateStatus);
1313

14-
getState(){
14+
getState() {
1515
return this.homePageState.asObservable();
1616
}
17-
updateState(newState){
17+
18+
updateState(newState) {
1819
const currState = this.homePageState.getValue();
19-
this.homePageState.next({...currState,...newState})
20+
this.homePageState.next({ ...currState, ...newState })
21+
}
22+
23+
setTakingPhoto(value: boolean) {
24+
this.updateState({ takingPhoto: value })
2025
}
2126
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { Injectable } from '@angular/core';
2+
import { HttpClient } from '@angular/common/http';
3+
import { Observable } from 'rxjs';
24

35
@Injectable({
46
providedIn: 'root'
57
})
68
export class MathLearningMachineApiService {
9+
constructor(private httpClient: HttpClient) { }
710

8-
constructor() { }
11+
solveImage(imageData: string): Observable<any> {
12+
return this.httpClient.post('/solve-image', { b64_img: imageData.substring(22) });
13+
}
914
}

src/styles.scss

+4
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
/* You can add global styles to this file, and also import other style files */
2+
html,body{
3+
margin: 0;
4+
padding: 0;
5+
}

0 commit comments

Comments
 (0)