안녕하세요. 과제를 잘 못 이해한건가 싶기도 하지만 아래와 같은 조건하에 구현을 해 봤습니다. 수업 과정에서 Front-end는 고정인 상황이기 때문에 기존 API는 변경이 없다는 가정하에 변경 해 봤습니다. 시간대1개와 요일n개의 설정이 하나의 row로 묶여있는 상태로는 요일별 시간대 변동에 대응하기 까다로운 것 같아 요일별 개별 row로 저장하도록 일부 수정 하였습니다. API endpoint 모델 변경을 피하기 위해서 내부적으로 여러개의 요일별 row로 나누어 저장하도록 했습니다. 고민중에 작가님께서 올려 놓으신 레퍼런스 코드를 봤는데, 책에서 언급하신 것 처럼 postgres 경우와 sqlite 경우로 코드가 분기 되는 것을 보았고, 지금은 교육 과정이기 때문이라고 생각 하지만 배포 코드와 개발 환경 코드가 다른것은 여러모로 좋지 않은 것 같아 현재는 sqlite 기준으로 개별 DB구현에서만 지원하는 것은 배제하는 방향으로 구현 했습니다. 1과 같이 변경 함으로써, 기 등록된 정보의 수정에서는 개별 날짜 별 시간대 설정 면에서 자유도가 생겼다고 생각 됩니다. 타임슬롯의 변경과 삭제에 관해서는 내부적으로는 time-slot으로 관리하지만, 외부공개 id는 아니므로, 키 로서 start-time, end-time, weekday (API형태로서는 리스트)조합으로 정의 해서 동작 하도록 구현했습니다. 특히 삭제의 경우는 부득이 delete method의 경우는 payload가 포함되는것이 받아들여지지 않는 경우도 있는것을 고려해서, 새 등록 값 두가지(new_start_time과, new_end_time) 값이 모두 제공되고 같은 경우를 특정하여 삭제 동작으로 정의하여 동작하도록 구현했습니다. class TimeSlotUpdateByGroupIn(SQLModel): start_time: time end_time: time weekdays: Weekdays new_start_time: time | None = None new_end_time: time | None = None new_weekdays: Weekdays | None = None @model_validator(mode="after") def check_update_fields(self): update_fields = { "new_start_time": self.new_start_time, "new_end_time": self.new_end_time, "new_weekdays": self.new_weekdays, } if not any(value is not None for value in update_fields.values()): raise ValueError("최소 하나의 수정 필드는 반드시 제공되어야 합니다.") return self @router.post("/time-slots", status_code=status.HTTP_201_CREATED, response_model=TimeSlotOut) async def create_time_slot( user: CurrentUserDep, session: DbSessionDep, payload: TimeSlotCreateIn, ) -> TimeSlotOut: if not user.is_host: raise GuestPermissionError() weekdays = sorted(set(payload.weekdays)) # dup. check with already exist one stmt = select(TimeSlot).where( and_( TimeSlot.calendar_id == user.calendar.id, TimeSlot.weekday.in_(weekdays), TimeSlot.start_time < payload.end_time, TimeSlot.end_time > payload.start_time, ) ) result = await session.execute(stmt) existing_time_slot = result.scalars().first() if existing_time_slot: raise TimeSlotOverlapError() time_slots = [ TimeSlot( calendar_id=user.calendar.id, start_time=payload.start_time, end_time=payload.end_time, weekday=weekday, ) for weekday in weekdays ] session.add_all(time_slots) await session.commit() if not time_slots: raise TimeSlotOverlapError() return TimeSlotOut( start_time=time_slots[0].start_time, end_time=time_slots[0].end_time, weekdays=weekdays, created_at=time_slots[0].created_at, updated_at=time_slots[0].updated_at, ) @router.get( "/time-slots/{host_username}", status_code=status.HTTP_200_OK, response_model=list[TimeSlotOut], ) async def get_host_timeslots( host_username: str, session: DbSessionDep, ) -> list[TimeSlotOut]: stmt = ( select(User) .where(User.username == host_username) .where(User.is_host.is_(true())) ) result = await session.execute(stmt) host = result.scalar_one_or_none() if host is None or host.calendar is None: raise HostNotFoundError() stmt = select(TimeSlot).where(TimeSlot.calendar_id == host.calendar.id) result = await session.execute(stmt) time_slots = result.scalars().all() grouped: dict[tuple[time, time], TimeSlotOut] = {} for time_slot in time_slots: key = (time_slot.start_time, time_slot.end_time) if key not in grouped: grouped[key] = TimeSlotOut( start_time=time_slot.start_time, end_time=time_slot.end_time, weekdays=[time_slot.weekday], created_at=time_slot.created_at, updated_at=time_slot.updated_at, ) continue grouped[key].weekdays.append(time_slot.weekday) if time_slot.created_at < grouped[key].created_at: grouped[key].created_at = time_slot.created_at if time_slot.updated_at > grouped[key].updated_at: grouped[key].updated_at = time_slot.updated_at if not grouped: raise TimeSlotNotFoundError() for time_slot in grouped.values(): time_slot.weekdays = sorted(set(time_slot.weekdays)) return list(grouped.values()) @router.patch( "/time-slots", status_code=status.HTTP_200_OK, response_model=TimeSlotOut | None, ) async def update_time_slot( user: CurrentUserDep, session: DbSessionDep, payload: TimeSlotUpdateByGroupIn, ) -> TimeSlotOut | None: if not user.is_host: raise GuestPermissionError() current_weekdays = sorted(set(payload.weekdays)) stmt = select(TimeSlot).where( and_( TimeSlot.calendar_id == user.calendar.id, TimeSlot.start_time == payload.start_time, TimeSlot.end_time == payload.end_time, ) ) result = await session.execute(stmt) current_slots = result.scalars().all() if not current_slots: raise TimeSlotNotFoundError() existing_weekdays = sorted({slot.weekday for slot in current_slots}) if existing_weekdays != current_weekdays: raise TimeSlotNotFoundError() delete_only = ( payload.new_start_time is not None and payload.new_end_time is not None and payload.new_start_time == payload.new_end_time ) if delete_only: current_ids = [slot.id for slot in current_slots] await session.execute(delete(TimeSlot).where(TimeSlot.id.in_(current_ids))) await session.commit() return None new_start_time = payload.new_start_time or payload.start_time new_end_time = payload.new_end_time or payload.end_time new_weekdays = sorted(set(payload.new_weekdays or payload.weekdays)) if new_start_time >= new_end_time: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail="시작 시간은 종료 시간보다 빨라야 합니다.", ) current_ids = [slot.id for slot in current_slots] stmt = select(TimeSlot).where( and_( TimeSlot.calendar_id == user.calendar.id, TimeSlot.weekday.in_(new_weekdays), TimeSlot.start_time < new_end_time, TimeSlot.end_time > new_start_time, TimeSlot.id.not_in(current_ids), ) ) result = await session.execute(stmt) existing_time_slot = result.scalars().first() if existing_time_slot: raise TimeSlotOverlapError() await session.execute(delete(TimeSlot).where(TimeSlot.id.in_(current_ids))) new_time_slots = [ TimeSlot( calendar_id=user.calendar.id, start_time=new_start_time, end_time=new_end_time, weekday=weekday, ) for weekday in new_weekdays ] session.add_all(new_time_slots) await session.commit() return TimeSlotOut( start_time=new_start_time, end_time=new_end_time, weekdays=new_weekdays, created_at=new_time_slots[0].created_at, updated_at=new_time_slots[0].updated_at, )
소득세법 제55조(세율) 및 제47조(근로소득공제)에 따르면, 거주자 기준으로 연봉 5천만원(근로소득)의 소득세는 다음과 같이 계산됩니다. 근로소득공제 적용 총급여액 5천만원 기준 공제액: 1,475만원 (5천만원 × 15% + 75만원, 단 최고 한도 2천만원 미만) 과세표준 산정 5천만원 - 1,475만원 = 3,525만원 종합소득세율 적용 3,525만원 구간: 1,400만원 이하 6% + 초과분 15% 산출세액: 84만원(1,400만원 × 6%) + (3,525만원 - 1,400만원) × 15% = 474.75만원 최종 납부세액 474.75만원에서 근로소득세액공제 (산출세액의 55% 한도) 등 추가 공제 적용 가능 ※ 정확한 세액은 의료비·교육비·보험료 등 추가 공제항목에 따라 달라질 수 있습니다. (추가 설명: "거주자"는 직장·자영업 등 소득 유형과 무관하게 국적에 관계없이 국내 주소를 둔 개인을 의미하며, 직장인은 그 하위 범주에 포함됩니다.) 답변이 전혀 다르고 이상하게 근거없는 숫자도 나오는데 왜그런걸까유 fewshot하는것까지 작성했습니다.
안녕하세요. 좋은 강의 감사합니다. 강의를 듣다 몇가지 의문이 있어 글을 작성합니다. 애드몹 광고는 비공개 테스트시에도 적용을 해야하나요. 비공개 테스트시에도 애드몹광고를 추가한 상태에서 진행해야하나요? 비공개 테스트가 완료된 상태에서 애드몹광고를 추가하고 출시가 가능한가요? 비공개 테스트시에는 애드몸광고를 넣지않고 앱을 개시할때 추가해도되나요 애드몹 공고로 등록한 모바일 폰은 비공개 테스트 시 12개중한개의 모바일폰에 포함되나요.
저는 강사님의 refer & earn 주소로 runpod.io 사이트 열고, 영상에 나온 팝업창 누르고 구글 계정으로가입하고 10달러 결제까진 순조롭게 되었습니다....만 5달러는 안들어왔고 딱 결제한만큼 10달러만 있네요! 다른 분들은 어떻게... 추가로 5달러 받으셨는지 궁금합니다.
강의 수강 방법에 대해서 질문이 있습니다. 저는 Blind75를 순서대로 풀고 있는데 강의 순서랑은 Blind75 순서랑 조금 다르더라구요 자료구조 알고리즘을 모르는 상태로 강의를 시작해도 되는지 1번과 연계되는 질문으로 일단 문제 풀이를 시도하되 한 문제당 어느정도의 시간을 두고 풀면 되는지 보통 10분 정도 고민해보고 정말 모르겠다면 문제풀이 강의를 바로 들어보는 편입니다. Blind75 순서대로 문제를 풀면서 풀지 못한 문제에 대해서만 강의를 시청하면 되는지 좋은 강의 만들어주셔서 감사합니다.
new_question 이 ''연봉 5천만원인 거주자의 소득세는 얼마인가요?'' 이라는 질문만 내놓고, 답은 내놓지 않습니다 %pip install python-dotenv langchain langchain-upstage langchain-community langchain-text-splitters langchain-pinecone docx2txt from langchain_community.document_loaders import Docx2txtLoader from langchain_text_splitters import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=1500, chunk_overlap=200, ) loader = Docx2txtLoader('./tax.docx') document_list = loader.load_and_split(text_splitter=text_splitter) from dotenv import load_dotenv from langchain_upstage import UpstageEmbeddings # 환경변수를 불러옴 load_dotenv() # OpenAI에서 제공하는 Embedding Model을 활용해서 `chunk`를 vector화 embedding = UpstageEmbeddings(model="embedding-query") from langchain_pinecone import PineconeVectorStore # 데이터를 처음 저장할 때 index_name = 'tax-upstage-index' database = PineconeVectorStore.from_documents(document_list, embeddin g, index_name=index_name) query = '연봉 5천만원인 직장인의 소득세는 얼마인가요?' # `k` 값을 조절해서 얼마나 많은 데이터를 불러올지 결정 retrieved_docs = database.similarity_search(query, k=3) retrieved_docs from langchain_upstage import ChatUpstage llm = ChatUpstage() from langchain_core.prompts import PromptTemplate prompt_with_template = '아래 질문에 답변해주세요:\n\n {query}' prompt_template = PromptTemplate(template=prompt_with_template, input_variables={"query"}) from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate dictionary = ["사람을 나타내는 표현 -> 거주자"] prompt = ChatPromptTemplate.from_template(f""" 사용자의 질문을 보고, 우리의 사전을 참고해서 사용자의 질문을 변경해주세요. 만약 변경할 필요가 없다고 판단된다면, 사용자의 질문을 변경하지 않아도 됩니다. 그런 경우에는 질문만 리턴해주세요 사전: {dictionary} 질문: {{question}} """) dictionary_chain = prompt | llm | StrOutputParser() tax_chain = {"query": dictionary_chain} | prompt_template new_question = dictionary_chain.invoke({"question": query}) new_question RetrievalQA 가 사라져서 PromptTemplate 랑 Pinecorn으로 어떻게든 대체하려고 했는데 엉망이 된거 같습니다. ㅠㅠ 어떻게 하면 답까지 내놓게 할 수 있을까요?
강의 내용 중에 "pip install pykrx" 이 부분에 대한 설명을 해 주신다고 했지만 나중에 VS CODE만 설명하시면서 실제로는 강의에서 빠져 있어서 기존 문의드린 오류가 난 게 아닌가 합니다. 느낌으로는 conda promp 상에서 실행하면 될 것 같은데 안되네요. "pip install pykrx" 를 어디에 설치해야 하나요? 아래 2곳에서는 안됩니다.
안녕하세요, 일단 책 출간하는 점 축하드립니다. 그리고 여쭤볼 사항이 있습니다. 제이쓴님의 "AI Agent 실무 적용 완전 정복 로드맵" 강의를 전부 구매했고, 현재 한시간으로 끝내는 LangChain 기본기만 전부 들은 상태입니다. 지금까지 나온 강의는 다 듣고 복습하는 느낌으로 책을 읽는 게 좋을까요? 1) AI Agent 실무 적용 완전 정복 로드맵 -> 책 -> 신규강의 2) 책 -> AI Agent 실무 적용 완전 정복 로드맵 + 추후 신규강의
graphRAG - Neo4J로 구현하는 지식 그래프 기반 RAG 시스템 (feat. LangChain)
지식그래프(KG) 검색 - 전문 검색에서 fulltext index 생성이 안됩니다. 여러번 실행해도 동일합니다. 아래 3개 중 movie_title_tagline_fulltext만 생성되고 movie_title_fulltext와 person_name_fulltext는 실행해도 반응이 없습니다. SHOW FULLTEXT INDEXES를 실행하면 movie_title_tagline_fulltext만 표시됩니다. Neo4j 버전: 버전 2.1.1(2.1.1) Neo4j는 Desktop 버전으로 실행했습니다. [참고] 실행 파일: KG_P1_03_neo4j_movie_03_full-text_search.ipynb [스크립트] CREATE FULLTEXT INDEX movie_title_fulltext IF NOT EXISTS FOR (m:Movie) ON EACH [m.title] CREATE FULLTEXT INDEX movie_title_tagline_fulltext IF NOT EXISTS FOR (m:Movie) ON EACH [m.title, m.tagline] CREATE FULLTEXT INDEX person_name_fulltext IF NOT EXISTS FOR (p:Person) ON EACH [ p.name ]
[ 질문 배경 ] Deque에 대한 자료를 보면 포인터를 사용한다고 나와있습니다. 따라서 popleft()시 맨 좌측부터 포인터가 가르키며 삭제하게 되는데, 이는 논리적으로 "삭제"라는 개념보다는 포인터가 가르키는 곳을 다음으로 이동시킨다는 의미를 가진다고 gpt를 통해 알게 되었습니다. [ 질문 ] 그렇다면, popleft()시 포인터가 다음으로 이동할 시 메모리에 적재되어 있던 이전 값은 그대로 남아있게 될텐데, 그렇다면 이것은 메모리 낭비로 이어질 수 있지 않나요? 자바의 경우 가비지 컬렉터가 알아서 메모리를 관리하죠. GPT에게 물어보니 메모리 슬롯은 유지하며 재사용할 수 있도록 대기상태에 들어간다고 합니다. 그렇다면 이 재사용을 할지 말지에 대한 것은 누가 결정하며 어떻게 처리되나요? 궁금합니다. C의 경우 malloc 으로 메모리 빌림 , 메모리 반납을 거치게 되는데, 이 경우도 궁금합니다.
안녕하세요. 현재 회사 사무실에서 강의듣고 있는데, 일부 폐쇄망입니다. 그래서 Colab에서 실습 시 업로드 할 경우 아래 에러가 발생합니다. colab말고 다른방법은 없겟죠? A network error occurred and the request could not be completed. GapiError: A network error occurred and the request could not be completed.