코딩캠프/AI 웹개발 취업캠프

[AI 웹개발 취업캠프] 75Day - 프로젝트 26일차

고랑E 2023. 11. 6. 20:46
728x90

아마.. 이제 남은 기능이 2개다?

 

  1. ipynb 파일 업로드??
  2. 모델 테스트 이미지 업로드

 

ipynb 파일 업로드??

일단 프로젝트 폴더에 업로드 파일이 저장되게 해보자

 

main.py

 

@app.post("/models/{modelId}/ipynb")
async def update_file_ipynb(modelId: int, file: UploadFile, db: Session = Depends(get_db)):
    file_path = Path.cwd()/file.filename
    content = await file.read()
    with open(file_path, 'wb') as fs:
        fs.write(content)
    return JSONResponse(content={"message": "업로드가 완료되었습니다."}, status_code=200)

 

 

 

주피터 노트북을 마크다운으로 변환하는 패키지를 설치한다.

 

https://github.com/jupyter/nbconvert

 

GitHub - jupyter/nbconvert: Jupyter Notebook Conversion

Jupyter Notebook Conversion. Contribute to jupyter/nbconvert development by creating an account on GitHub.

github.com

 

 

nbconvert 패키지 설치

 

pip install nbconvert

 

아까전에 프로젝트 폴더로 업로드된 test.ipynb을 nbconvert 패키지를 이용해서 마크다운으로 변환해보자

 

명령어

 

jupyter nbconvert --to <파일 포멧> <주피터노트북>

 

처럼 변환할 파일 포멧 과 주피터 노트북을 정해주면 변환해준다

 

마크다운으로 아까 업로드한 test.ipynb 를 변환할거니까.

 

jupyter nbconvert --to markdown .\test.ipynb

 

을 입력해주면

 

 

처럼 잘 변환해준다.. 이걸 코드로 작성해보자 파이썬 코드 안에서 명령어를 입력해주는 걸 검색해봤더니

3.x 부터 subprocess 라는게 추가되었다

 

https://docs.python.org/ko/3/library/subprocess.html

 

subprocess — Subprocess management

Source code: Lib/subprocess.py The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace seve...

docs.python.org

 

subprocess 모듈의 run() 함수를 사용해서 nbconvert 명령어를 실행 시켜보자

 

subprocess.run(["jupyter", "nbconvert", "--to", "markdown", file.filename])

 

를 추가 해서 테스트를 해보면

 

 

잘 만들어졌다.

 

근데 문제가 발생했다..

 

마크다운으로 변환시 이미지 파일이 따로 출력된다

 

 

알아 보던중 

 

--ExtractOutputPreprocessor.enabled=False

 

를 추가하면 된다고 양키형들이 말해준다.

https://discourse.jupyter.org/t/convert-notebook-to-a-standalone-markdown/5363

 

Convert notebook to a standalone markdown

Hi. Can I use nbconvert --to markdown to write all the generated images in the notebook as their data URIs instead of writing them to disk? I want to be able to share the notebook on discourse forums.

discourse.jupyter.org

 

subprocess.run(["jupyter", "nbconvert", "--to", "markdown", "--ExtractOutputPreprocessor.enabled=False", file.filename])

 

로 바꾸고 테스트 해보면!!

 

 

 

잘 바꿔준다!! 헤헤헿

 

이제 DB에 저장하는걸 해야겠다!!

 

with_suffix(".md") 으로 변환한 파일을 가져온다.

 

    md_file_path = file_path.with_suffix(".md")
    with open(md_file_path, 'r') as f:
        md_content = f.read()

    return JSONResponse(content={"message": "업로드가 완료되었습니다.", "md": md_content}, status_code=200)

 

로 변경해서 response 에 마크다운으로 변환된걸 잘 가져오는지 보자

 

 

잘 가져온다

 

이제 상단에 crud.py 사용할 model_ipynb 를 상단에 적어주고

 

# 상단에 model_ipynb 추가
from BE.crud import create_user, get_user, verify_password, get_user_info, update_user_info, get_models, get_my_models, create_model, get_model, user_image, email_code, check_email_code, user_image, user_model, model_ipynb
@app.post("/models/{modelId}/ipynb")
async def update_file_ipynb(modelId: int, file: UploadFile, db: Session = Depends(get_db)):
    file_path = Path.cwd()/file.filename
    content = await file.read()
    with open(file_path, 'wb') as fs:
        fs.write(content)

    subprocess.run(["jupyter", "nbconvert", "--to", "markdown", "--ExtractOutputPreprocessor.enabled=False", file.filename])

    md_file_path = file_path.with_suffix(".md")
    with open(md_file_path, 'r') as f:
        md_content = f.read()

    model_ipynb(db, model_id = modelId, ipynb = md_content)

    return JSONResponse(content={"message": "업로드가 완료되었습니다."}, status_code=200)

 

최종 코드로 이렇게 수정해준다..

 

그리고 crud.py

 

def model_ipynb(db: Session, model_id: int, ipynb: str):
    db_model = db.query(Model).filter(Model.id == model_id).first()
    db_model.description = ipynb
    db.commit()
    return db_model

 

으로 해서 변환한 마크다운 내용물을 description 컬럼에 넣는다.

 

테스트를 해보면!!

 

 

잘 들어가는걸 볼 수 있다!!

 

근데 여기서 아무것도 안해주면 업로드한 ipynb 와 md 파일들이 쌓이게 된다. 이걸 db에 저장이 되면 삭제해주자

 

os.remove() 로 삭제!!

 

    os.remove(file_path)
    os.remove(md_file_path)

 

 

테스트!!

 

 

끝!!

 

는.. 항상 끝났다고 생각했을때 문제가 있더라.. 파일이름이 한글일때 문제 발생

 

 

이것처럼 업로드 되는 파일이 한글이 들어갈 경우 오류가 발생함..

 

 

md_content = f.read() 에서 발행하는 오류이니 인코딩을 utf8 로 바꾸면 해결!!

 

 

성공!!!

 


 

모델 테스트 이미지 업로드

그냥 단순하게 body로 userId를 받아 오고 파일도 받아오려고 계속 시도하다가 공식문서를 읽게되었다.

 

fastapi 문서를 읽던 도중에 

 

https://fastapi.tiangolo.com/tutorial/request-forms-and-files/#recap

 

Request Forms and Files - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

 

마지막 부분에 이게 있었다??

대충 해석해 보면

다중 file 및 form 매개변수를 선언할수있는데 json 대신 form-data를 사용해서 json으로 전달 될 body 필드를 선언할 수 없다??

라는 뜻이고 마지막 줄에

이건 fastapi 가 아닌 http 프로토콜 부분이다! 라고 자기탓 아니라고 말해준다.. 흠..

 

에시 코드에 나와있는것처럼 userId를 form 으로 받으면 되겠다

 

 

여기서 코드를!!

 

@app.post("/models/{modelId}/img")
async def update_file_img(modelId: int, file: UploadFile, userId: int = Form(...), db: Session = Depends(get_db)):
    return JSONResponse(content={"message": "업로드가 완료되었습니다. 분석 후 결과값이 출력됩니다."}, status_code=200)

 

파일 쪽은 그대로 쓰고 userId를 Form() 으로 받고

 

상단에 Form을 가져온다

 

# 상단에 File 추가
from fastapi import FastAPI, Depends, Form, HTTPException, File, UploadFile

 

 

print 를 찍어서 테스트를 해보면

 

 

잘 받아와 진다!!!

 

기존 업로드 코드에서 달라진 점은 저장되는 폴더와 db에 저장되는 테이블이 달라진다.

 

main.py에 나머지 코드를 작성해주고

 

# 상단에 model_img 를 추가
from BE.crud import create_user, get_user, verify_password, get_user_info, update_user_info, get_models, get_my_models, create_model, get_model, user_image, email_code, check_email_code, user_image, user_model, model_ipynb, model_img
@app.post("/models/{modelId}/img")
async def update_file_img(modelId: int, file: UploadFile, userId: int = Form(...), db: Session = Depends(get_db)):
    file_path = await file.read()

    s3_file_name = 'models_img/' + file.filename
    s3_url = upload_to_s3(file_path, s3_file_name)
    file.filename = s3_url

    model_img(db, model_id = modelId, img= file.filename, user_id = userId)
    return JSONResponse(content={"message": "업로드가 완료되었습니다. 분석 후 결과값이 출력됩니다."}, status_code=200)

 

 

crud.py 에 디비에 넣어줄 코드를 작성한다.

 

# 상단에 ModelImages 추가
from BE.models import User, Model, EmailAuth, ModelImages
def model_img(db: Session, model_id: int, img: str, user_id: int):
    model_images = ModelImages(model_id= model_id, user_id= user_id, img_test= img)
    db.add(model_images)
    db.commit()
    db.refresh(model_images)
    return model_images

 

 

이렇게 작성해주고 테스트!!

 

 

잘된다!!

 

또 한주 시작되서.. k-mooc 강의 들어야되네.. 들으러 갑니다.

 

 

 

본 후기는 정보통신산업진흥원(NIPA)에서 주관하는 <AI 서비스완성! AI+웹개발 취업캠프 - 프론트엔드&백엔드> 과정 학습/프로젝트/과제 기록으로 작성되었습니다.