Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api 업로드 및 쇼츠 추출화면 구현 #88

Merged
merged 8 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Deploy to Amazon S3

on:
push:
branches: ['week11']
branches: ['Master']

env:
AWS_REGION: ap-northeast-2
Expand Down
25 changes: 11 additions & 14 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TALKAK</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>

</html>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/Logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TALKAK</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Binary file added public/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/apis/instance/Instance.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const baseURL = isMSWEnvironment ? 'http://localhost:5173' : `${BASE_URL}`;

export const createInstance = (config: AxiosRequestConfig): AxiosInstance => {
const instance = axios.create({
timeout: 5000,
timeout: 10000,
...config,
baseURL,
headers: {
Expand Down
55 changes: 3 additions & 52 deletions src/apis/instance/InstanceFast.api.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import axios from 'axios';
import type {
AxiosInstance,
AxiosRequestConfig,
InternalAxiosRequestConfig,
AxiosRequestConfig, // InternalAxiosRequestConfig,
} from 'axios';

import { postReissue } from '@/apis/auth';

// import { postReissue } from '@/apis/auth';
import { BASE_FAST_URL } from '@/constants/URI';

const isMSWEnvironment = import.meta.env.VITE_RUN_MSW === 'true';
Expand All @@ -19,7 +17,7 @@ export const createFastInstance = (
config: AxiosRequestConfig
): AxiosInstance => {
const instance = axios.create({
timeout: 5000,
timeout: 15000,
withCredentials: true,
...config,
baseURL: fastBaseURL,
Expand All @@ -30,53 +28,6 @@ export const createFastInstance = (
},
});

instance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
const accessToken = localStorage.getItem('accessToken');
const isReissueRequest = config.url?.includes('/api/reissue');

if (accessToken && !isReissueRequest) {
config.headers['Authorization'] = `Bearer ${accessToken}`;
}

return config;
},
(error: unknown) => Promise.reject(error)
);

// console.log(instance.interceptors.response);

instance.interceptors.response.use(
(response) => response,
async (error) => {
const { config, response } = error;
if (response.status === 401) {
const refreshToken = localStorage.getItem('refreshToken');
// console.log('Refresh token:', refreshToken);
if (refreshToken) {
try {
const data = await postReissue({ refreshToken });
console.log('Reissue success:', data);

localStorage.setItem('accessToken', data.access_token);
localStorage.setItem('refreshToken', data.refresh_token);

config.headers['Authorization'] = `Bearer ${data.access_token}`;
return axios(config);
} catch (reissueError) {
// console.log('Reissue failed:', reissueError);
return Promise.reject(reissueError);
}
} else {
console.error('No refresh token found');
return Promise.reject(error);
}
}

return Promise.reject(error);
}
);

return instance;
};

Expand Down
21 changes: 12 additions & 9 deletions src/pages/auto/apis/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
export { postValidateUrl } from './postValidateUrl.api';
export type { ValidateUrlProps, UrlOnlyProps } from './postValidateUrl.api';
export { postConvertForm } from './postConvertForm.api';
export { useFetchTaskStatus } from './fetchTaskStatus';
export { fetchSelectHighlight } from './fetchSelectHighLight.api';
export type { fetchSelectHighlightResponseProps } from './fetchSelectHighLight.api';
export { postHighlightSelection } from './postHighlightSelection.api';
export { postValidateUrl } from './form/postValidateUrl.api';
export type {
ValidateUrlProps,
UrlOnlyProps,
} from './form/postValidateUrl.api';
export { postConvertForm } from './form/postConvertForm.api';
export { useFetchTaskStatus } from './progress/fetchTaskStatus';
export { fetchSelectHighlight } from './select/fetchSelectHighLight.api';
export type { fetchSelectHighlightResponseProps } from './select/fetchSelectHighLight.api';
export { postHighlightSelection } from './select/postHighlightSelection.api';
export type {
hightlightSelectionRequestProps,
hightlightSelectionResponseProps,
} from './postHighlightSelection.api';
export { fetchVideoExtract } from './fetchVideoExtract.api';
} from './select/postHighlightSelection.api';
export { fetchVideoExtract } from './select/fetchVideoExtract.api';
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { fetchFastInstance } from '@/apis/instance';
import { fetchInstance } from '@/apis/instance';

const fetchVideoExtractPath = (videoId: number) =>
`/api/videos/${videoId}/extract`;

export const fetchVideoExtract = async (videoId: number) => {
const response = await fetchFastInstance.get(fetchVideoExtractPath(videoId));
const response = await fetchInstance.get(fetchVideoExtractPath(videoId));
return response.data;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,23 @@ import { fetchFastInstance } from '@/apis';

export type hightlightSelectionRequestProps = {
index: number;
fileName: string;
title: string;
memberId: number;
categoryId: number;
task_id: string;
};

// export type PythonDTO = {
// url: string;
// email: string;
// title: string;
// memberId: number;
// categoryId: number;
// };

export type hightlightSelectionResponseProps = {
videoId: number;
thumbnail: string;
title: string;
memberId: number;
createdAt: Date;
message: string;
video_id: number;
};

const postHighlightSelectionPath = () => '/select-highlight';

export const postHighlightSelection = async ({
index,
fileName,
title,
memberId,
categoryId,
task_id,
}: hightlightSelectionRequestProps): Promise<hightlightSelectionResponseProps> => {
const response = await fetchFastInstance.post(postHighlightSelectionPath(), {
index,
fileName,
title,
memberId,
categoryId,
task_id,
});

return response.data;
Expand Down
78 changes: 37 additions & 41 deletions src/pages/auto/components/final/FinalView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,21 @@ import { useState } from 'react';

import styled from 'styled-components';

import { Button } from '@/components';
import { Button, Spinner } from '@/components';

import { fetchVideoExtract, postHighlightSelection } from '@/pages/auto/apis';
import { InitBtn } from '@/pages/auto/components';
import { useProcessContext } from '@/pages/auto/provider';

import ConvertShorts from './ConvertShorts';

const FinalView = () => {
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const { setProcessState } = useProcessContext();

const [categoryId, setCategoryId] = useState<number | null>(null);
const [titles, setTitle] = useState<string | null>(null);

const handleSelectVideo = (
index: number,

title: string,
category_id: number
) => {
const handleSelectVideo = (index: number) => {
setSelectedIndex(index);
setCategoryId(category_id);
setTitle(title);
};

const handleUpload = async () => {
Expand All @@ -32,44 +25,47 @@ const FinalView = () => {
return;
}

const memberId = parseInt(sessionStorage.getItem('member_id') ?? '0', 10);
const title = titles ?? '';

// const pythonDto = {
// url: sessionStorage.getItem('initialUrl') ?? '',
// email,
// title,
// memberId,
// categoryId: categoryId ?? 0,
// };

setIsLoading(true);
try {
// console.log({ index: selectedIndex, s3Url: selectedUrl, pythonDto });
const response = await postHighlightSelection({
index: selectedIndex,
fileName: sessionStorage.getItem('task_id') ?? '',
title,
memberId,
categoryId: categoryId ?? 0,
task_id: sessionStorage.getItem('task_id') ?? '',
});

const videoId = response.videoId;
console.log('Video ID:', videoId);

// videoId로 다운로드 URL 받기
const extractResponse = await fetchVideoExtract(videoId); // videoId를 string으로 변환하여 전달
alert('비디오 업로드 중입니다. 잠시만 기다려주세요.');

// URL을 통해 비디오 다운로드 (예시)
const link = document.createElement('a');
link.href = extractResponse;
link.download = 'video.mp4';
link.click();
const videoId = response.video_id;
console.log('Video ID:', videoId);

alert('비디오 업로드 성공');
console.log('Response:', response);
// // Presigned URL을 통해 다운로드 링크 가져오기
const downloadUrl = await fetchVideoExtract(videoId);
if (!downloadUrl) {
throw new Error('Failed to fetch video download URL');
}

console.log('Download URL:', downloadUrl);
// 새로운 창에서 다운로드
const downloadWindow = window.open('', '_blank');
if (!downloadWindow) {
alert('팝업 차단이 되어 있는 것 같습니다. 팝업 차단을 해제해주세요.');
return;
}

// 새로운 창에서 다운로드를 위한 <a> 태그 생성
const anchor = downloadWindow.document.createElement('a');
anchor.href = downloadUrl;
anchor.target = '_self'; // 새 창 내에서 동작하도록 설정
anchor.download = 'video.mp4'; // 다운로드 파일명 설정
anchor.click();

alert('비디오 업로드 성공, 초기화면으로 이동합니다.');
setProcessState('initial');
window.location.href = '/';
} catch (error) {
console.error('Error uploading video:', error);
alert('업로드 중 오류가 발생했습니다.');
} finally {
setIsLoading(false); // 로딩 완료
}
};

Expand All @@ -78,7 +74,7 @@ const FinalView = () => {
<ConvertShorts onSelectVideo={handleSelectVideo} />
<ButtonWrapper>
<Button variant='default' type='button' onClick={handleUpload}>
추출하기 및 업로드
{isLoading ? <Spinner /> : '추출하기 및 업로드'}
</Button>
<InitBtn />
</ButtonWrapper>
Expand Down
8 changes: 8 additions & 0 deletions src/pages/auto/components/loading/ProgressView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ const ProgressView = ({
sessionStorage.setItem('status', 'completed');
setProcessState('final');
clearInterval(pollingInterval);
} else if (refetchedData?.status === 'failed') {
sessionStorage.setItem('status', 'failed');
alert('데이터 추출에 실패했습니다. 다시 시도해주세요.');
setProcessState('initial');
clearInterval(pollingInterval);
} else {
sessionStorage.setItem('status', refetchedData?.status ?? '');
updateProgressBar(refetchedData?.status ?? '');
Expand Down Expand Up @@ -65,6 +70,9 @@ const ProgressView = ({
case 'completed':
setProgress(100);
break;
case 'failed':
setProgress(0);
break;
default:
break;
}
Expand Down
Empty file removed src/styles/.gitkeep
Empty file.
Empty file removed src/types/.gitkeep
Empty file.