diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000000..ffe3d41e69 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,8 @@ +secrets.json +test.ipynb +documents +__pycache__ +document.csv +.python-version +.env +.venv \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000000..689ff953e7 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,17 @@ +FROM ubuntu:22.04 + +RUN apt-get update && apt-get upgrade -y + +# install python 3.10 +RUN apt-get install -y software-properties-common +RUN add-apt-repository ppa:deadsnakes/ppa -y +RUN apt install python3.10 +RUN apt install -y python3-pip + +COPY . . + +RUN pip3 install -r requirements.txt + +WORKDIR /app + +EXPOSE 8000 \ No newline at end of file diff --git a/backend/README.md b/backend/README.md index ed97599ab9..b102301688 100644 --- a/backend/README.md +++ b/backend/README.md @@ -13,15 +13,72 @@ - Default region name : ap-northeast-2 입력 - Default output format : json 입력 -### requirments 설치하기 +### How to install (without Docker) - - pip install -r requirements.txt +- repository clone -### 서버 실행하기 +```shell +git clone https://github.com/kookmin-sw/capstone-2024-05.git +``` - - main함수 실행하면 됨. - - app폴더로 이동 후 - - uvicorn main:app --reload +- Backend 디렉토리로 이동 + +```shell +cd backend +``` + +- Python 가상 환경 설정 + +```shell +python -m venv .venv +source venv/bin/activate + +``` + +- 필요한 package 설치 + +```shell +pip install -r requirements.txt +``` + +- AWS CLI Configure 설정 + +- 실행 + +```shell +cd app +uvicorn main:app --host=0.0.0.0 --port=8000 +``` + +### How to install (with Docker) + +- repository clone + +```shell +git clone https://github.com/kookmin-sw/capstone-2024-05.git +``` + +- Backend 디렉토리로 이동 + +```shell +cd backend +``` + +- Docker 빌드 후 내부 컨테이너 진입 + +```shell +docker build . -t [image name] +docker run -it -p [host port]:8000 --env-file .env [image name] +``` + +- AWS CLI Configure 설정 + +- 실행 + +```shell +cd app +uvicorn main:app --host=0.0.0.0 --port=8000 +``` ### ENV @@ -40,39 +97,34 @@ OPENAI_APIKEY ### 서버 디렉토리 구조 - /app - - /api : API 코드가 모여있는 폴더입니다. - - /routes : domain별로 구분하여 개발 중입니다. + - /api : Functional APIs + - /routes + - hashtag.py - templates.py - users.pu - - main.py - - /db : 데이터베이스 관련 코드가 모여있는 폴더입니다. - - database.py : 현재 운영중인 DB를 연결하는 코드입니다. - - DB의존성 주입을 위한 get_db 메서드가 있습니다. - - 세션 생성, 운영, 종료를 처리해주는 함수입니다. - - DB사용 시에는 이 메서드 사용해주시면 됩니다. - - api 메서드 파라미터에 db: Session = Depends(get_db) 작성해주시고 db 객체 사용해주시면 됩니다. + - router.py + - /db : Database Management + - database.py - models.py - - /retrieval + - /retrieval : RAG Implementation - init_vector_db.py - markdown_splitter.py - rag_prototype.py - rag.py - settings.py - - /static + - /static : Static Files - /examples - example-error.json - example-valid.json - - style.css - - /templates - - item.html + - tmp.json + - /templates : HTML Templates - main.html - - template-validation-fail.html - - template-validation-success.html - - /utils + - /utils : Utility Modules + - auth.py - gpt.py - setup.py - main.py - .env - : 데이터베이스 URL을 저장해야합니다. 연락주시면(현승) 별도로 전달드리겠습니다. (DB_URL) - README.md - requirements.txt + - Dockerfile diff --git a/backend/app/api/routes/hashtag.py b/backend/app/api/routes/hashtag.py index 5d58940876..3215c67b03 100644 --- a/backend/app/api/routes/hashtag.py +++ b/backend/app/api/routes/hashtag.py @@ -78,5 +78,4 @@ def store_default_to_db(request: Request, db: Session = Depends(get_db)): db.refresh(isntance) hashtag = db.query(HashTag).all() - print(hashtag) return hashtag diff --git a/backend/app/api/routes/templates.py b/backend/app/api/routes/templates.py index 0ef2f72a96..fb2bd190b9 100644 --- a/backend/app/api/routes/templates.py +++ b/backend/app/api/routes/templates.py @@ -21,6 +21,24 @@ router = APIRouter() +def find_all_type_values(dict_obj): + results = [] + def _extract(dict_obj): + if isinstance(dict_obj, dict): + for k, v in dict_obj.items(): + if k == "Type": + if v.startswith("AWS::"): + results.append(v.split("::")[1]) + if isinstance(v, (dict, list)): + _extract(v) + elif isinstance(dict_obj, list): + for item in dict_obj: + _extract(item) + try: + _extract(dict_obj) + except: + return results + return results # function to get values of dict def recursive_value_collect(dict_obj): @@ -37,31 +55,9 @@ def recursive_value_collect(dict_obj): yield value -def parse_prompt_result(result): - template_file, description = [], [] - state = False - - for l in result.split("\n"): - if "```" in l: - state = not state - continue - if state: - template_file.append(l + "\n") - else: - description.append(l + "\n") - - description = "".join(description) - description = description.strip() - - template_file = "".join(template_file) - template_file = json.loads(template_file) - - return template_file, description - - # 해시태그 추가함수 def add_hashtag(template): - hashtags = template.hashtags + hashtags = template.hashtag hashtags = list(map(lambda x: x.tag, hashtags)) if hashtags: # dictionary로 변환 @@ -199,6 +195,9 @@ async def create_template( filtered_keywords = [ k for k in keywords if k not in ["AWS", "Amazon"] and len(k) > 2 ] + type_res = find_all_type_values(template_file) + filtered_keywords += type_res + filtered_keywords = list(set(filtered_keywords)) if not filtered_keywords: # 사전 정의된 키워드 기반이라 키워드가 없는 경우가 존재함 @@ -277,9 +276,7 @@ def upload_template( def validate(params: Template): try: is_valid, error_message = validate_template(params.template) - message = ( - "유효한 template 입니다." if is_valid else error_message - ) + message = "유효한 template 입니다." if is_valid else error_message return { "isValid": is_valid, "message": message, diff --git a/backend/app/db/models.py b/backend/app/db/models.py index e94a38c7ad..c56e1cc326 100644 --- a/backend/app/db/models.py +++ b/backend/app/db/models.py @@ -54,9 +54,7 @@ class PromptAns(Base): user = relationship("User", back_populates="promptAnses") # 다대다 관계 설정 - hashtags = relationship( - "HashTag", secondary=PromptAns_HashTag, backref="prompt_ans" - ) + hashtag = relationship("HashTag", secondary=PromptAns_HashTag, backref="prompt_ans") class HashTag(Base): diff --git a/backend/app/templates/main.html b/backend/app/templates/main.html index 325a7a7bb6..a39fe98c67 100644 --- a/backend/app/templates/main.html +++ b/backend/app/templates/main.html @@ -19,7 +19,7 @@

- StackOrderFlow Logo + StackOrderFlow Logo

Back-end Server

-> See API Documnets

diff --git a/backend/app/utils/gpt.py b/backend/app/utils/gpt.py index bee93c7e1b..3251fb2ed2 100644 --- a/backend/app/utils/gpt.py +++ b/backend/app/utils/gpt.py @@ -29,8 +29,6 @@ def validate_template(template: dict): # 254 명령이 성공적으로 구문 분석되고 지정된 서비스에 요청이 전송되었지만, 서비스에서 오류가 반환되었습니다. 일반적으로 이는 잘못된 API 사용 또는 기타 서비스 특정 문제를 나타냅니다. # 255 일반적인 캐치올 오류입니다. 명령은 구문 분석이 올바르게 되었을 수 있지만, 명령을 실행하는 동안 명시되지 않은 런타임 오류가 발생했습니다. 이는 일반적인 오류 코드이기 때문에 오류가 255에서 더 구체적인 반환 코드로 변경될 수 있습니다. 255의 반환 코드는 특정한 오류 사례를 결정하기 위해 의존되어서는 안 됩니다. - print(f"{result.returncode=}") - print(f"{result.stderr=}") is_valid = result.returncode == 0 error_message = "" if is_valid else result.stderr @@ -95,7 +93,6 @@ def gpt_genereate(instruction: str, retrieved_doc: List[dict]): response = completion.choices[0].message.content template, description = parse_prompt_result(response) is_valid, error_message = validate_template(template) - print(f"execution_cnt=1, {completion.usage.total_tokens=}") if is_valid: doc_title_list = list(set([doc["title"] for doc in retrieved_doc])) return template, description, doc_title_list, 1 @@ -164,7 +161,6 @@ def gpt_generate_retry(instruction, retrieved_doc, error_message, wrong_template response = completion.choices[0].message.content template, description = parse_prompt_result(response) is_valid, error_message = validate_template(template) - print(f"{execution_cnt=}, {completion.usage.total_tokens=}") if is_valid: doc_title_list = list(set([doc["title"] for doc in retrieved_doc])) return template, description, doc_title_list, execution_cnt diff --git a/frontend/app/globals.css b/frontend/app/globals.css index ca48d9562c..51fb8aceb9 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -27,9 +27,9 @@ @media (prefers-color-scheme: dark) { :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; } } diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 69296ab46b..7f68763300 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -43,7 +43,7 @@ export default function RootLayout({ > - +
{children} diff --git a/frontend/components/TemplateHub/index.tsx b/frontend/components/TemplateHub/index.tsx index 84765d9e47..763ead8aeb 100644 --- a/frontend/components/TemplateHub/index.tsx +++ b/frontend/components/TemplateHub/index.tsx @@ -23,7 +23,7 @@ import Link from 'next/link'; import classes from './TemplateHub.module.css'; import { IconSearch } from '@tabler/icons-react'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import HubItems from './HubItems'; interface IHub { @@ -36,13 +36,18 @@ export default function TemplateHub({ templates }: IHub) { const [searchResults, setSearchResults] = useState([]); const [filteredTemplates, setFilteredTemplates] = useState([]); + useEffect(() => { + filterTemplates(); + }, [searchResults || []]); + const filterTemplates = () => { - const results = templates.filter((template) => - searchResults.every((tag) => template.hashtag.includes(tag)), + const results = templates.filter(template => + searchResults.every(tag => template.hashtag && template.hashtag.includes(tag)) ); setFilteredTemplates(results); }; + const handleIconClick = () => { if (value.length > 0) { setShowResults(true); diff --git a/frontend/components/UsePage/UserInput/Index.tsx b/frontend/components/UsePage/UserInput/Index.tsx index 2d8cf6a487..efd8652518 100644 --- a/frontend/components/UsePage/UserInput/Index.tsx +++ b/frontend/components/UsePage/UserInput/Index.tsx @@ -38,7 +38,7 @@ export default function UserInput({ {`여러분이 원하는 템플릿의 기능과 구성 요소에 대해 가능한 한 구체적으로 - 설명해 주세요. {
}예를 들어, "EC2 인스턴스를 생성하고 싶어요" + 설명해 주세요. 예를 들어, "EC2 인스턴스를 생성하고 싶어요" 보다는 "t2.micro 타입의 EC2 인스턴스를 2개 생성하고, 각 인스턴스에 10GB의 EBS 볼륨을 연결하고 싶어요"가 더 도움이 됩니다.`}