1. 랭체인 이미지 인식 후 처리 마무리

2. fastAPI로 프로젝트 구조 실습

1. 랭체인 이미지 인식 후 처리 마무리
2. fastAPI로 프로젝트 구조 실습
This commit is contained in:
2026-06-15 18:08:35 +09:00
parent d6be22857b
commit ccfdac1286
59 changed files with 3144 additions and 133 deletions
+10
View File
@@ -0,0 +1,10 @@
# 디폴트 무시된 파일
/shelf/
/workspace.xml
# 에디터 기반 HTTP 클라이언트 요청
/httpRequests/
# 쿼리 파일을 포함한 무시된 디폴트 폴더
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="~/Source/project/.venv" project-jdk-type="Python SDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/project.iml" filepath="$PROJECT_DIR$/.idea/project.iml" />
</modules>
</component>
</project>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/rag_app/.venv" />
</content>
<orderEntry type="jdk" jdkName="~/Source/project/.venv" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PyToolsState">
<option name="tools">
<map>
<entry key="pyrefly">
<value>
<ToolEntry />
</value>
</entry>
<entry key="pyright">
<value>
<ToolEntry />
</value>
</entry>
<entry key="ruff">
<value>
<ToolEntry />
</value>
</entry>
<entry key="ty">
<value>
<ToolEntry />
</value>
</entry>
</map>
</option>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
+16
View File
@@ -0,0 +1,16 @@
# 샘플 Python 스크립트입니다.
# Shift+F10을(를) 눌러 실행하거나 내 코드로 바꿉니다.
# 클래스, 파일, 도구 창, 액션 및 설정을 어디서나 검색하려면 Shift 두 번을(를) 누릅니다.
def print_hi(name):
# 스크립트를 디버그하려면 하단 코드 줄의 중단점을 사용합니다.
print(f'Hi, {name}') # 중단점을 전환하려면 Ctrl+F8을(를) 누릅니다.
# 스크립트를 실행하려면 여백의 녹색 버튼을 누릅니다.
if __name__ == '__main__':
print_hi('PyCharm')
# https://www.jetbrains.com/help/pycharm/에서 PyCharm 도움말 참조
+5
View File
@@ -0,0 +1,5 @@
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
+10
View File
@@ -0,0 +1,10 @@
# 디폴트 무시된 파일
/shelf/
/workspace.xml
# 에디터 기반 HTTP 클라이언트 요청
/httpRequests/
# 쿼리 파일을 포함한 무시된 디폴트 폴더
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PortForwardingSettings">
<ports>
<entry key="8000">
<ForwardedPortInfo>
<option name="hostPort" value="8000" />
<option name="readOnly" value="false" />
</ForwardedPortInfo>
</entry>
</ports>
</component>
</project>
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="~/Source/project/rag_app/.venv" project-jdk-type="Python SDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/rag_app.iml" filepath="$PROJECT_DIR$/.idea/rag_app.iml" />
</modules>
</component>
</project>
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PyToolsState">
<option name="tools">
<map>
<entry key="black">
<value>
<ToolEntry />
</value>
</entry>
<entry key="pyrefly">
<value>
<ToolEntry />
</value>
</entry>
<entry key="pyright">
<value>
<ToolEntry />
</value>
</entry>
<entry key="ruff">
<value>
<ToolEntry />
</value>
</entry>
<entry key="ty">
<value>
<ToolEntry />
</value>
</entry>
</map>
</option>
</component>
</project>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="~/Source/project/rag_app/.venv" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>
+9
View File
@@ -0,0 +1,9 @@
from langchain_ibm import WatsonxEmbeddings
from backend.config.settings import settings
watson_embedding = WatsonxEmbeddings(
model_id="ibm/granite-embedding-278m-multilingual",
url=f"{settings.watsonx_url}",
api_key=f"{settings.watsonx_api_key}",
project_id=f"{settings.watsonx_project_id}",
)
+13
View File
@@ -0,0 +1,13 @@
from langchain_ibm import ChatWatsonx
from backend.config.settings import settings
watson_llm = ChatWatsonx(
model_id="ibm/granite-4-h-small",
url=f"{settings.watsonx_url}",
api_key=f"{settings.watsonx_api_key}",
project_id=f"{settings.watsonx_project_id}",
max_tokens=2000,
params={
"temperature": 0
}
)
@@ -0,0 +1,11 @@
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file="backend/.env", extra="ignore")
# 사용할 모델
watsonx_api_key: str = Field(alias="WATSONX_API_KEY")
watsonx_project_id: str = Field(alias="WATSONX_PROJECT_ID")
watsonx_url: str = Field(alias="WATSONX_URL")
settings = Settings()
+16
View File
@@ -0,0 +1,16 @@
from fastapi import FastAPI
from starlette.staticfiles import StaticFiles
from backend.routers.page_router import router as page_router
from backend.routers.api_router import router as api_router
app = FastAPI()
app.include_router(page_router)
app.include_router(api_router)
# static 폴더 지정
app.mount("/static", StaticFiles(directory="backend/static"), name="static")
# http://127.0.0.1:8000/item/1 + GET
# @app.get("/item/{item_id}")
# async def read_item(item_id):
# return {"item_id" : item_id}
@@ -0,0 +1,25 @@
from fastapi import APIRouter, Request, UploadFile
from backend.services.llm_service import question_and_answer
from backend.schemas.basic_schema import QuestionRequest
from backend.services.rag_service import upload_document
router = APIRouter(prefix="/api")
# http://127.0.0.1:8000/api/question
@router.post("/question")
async def question(req:QuestionRequest):
answer = question_and_answer(req.question)
return {"message" : answer}
# http://127.0.0.1:8000/api/rag/upload
@router.post("/rag/upload")
async def fileUpload(file:UploadFile):
# 서비스 호출
return upload_document(file)
# http://127.0.0.1:8000/api/rag/question
@router.post("/rag/question")
async def question():
pass
@@ -0,0 +1,15 @@
from fastapi import APIRouter, Request
from fastapi.templating import Jinja2Templates
router = APIRouter()
templates = Jinja2Templates(directory="backend/templates")
# http://127.0.0.1:8000
@router.get("/")
async def home(request : Request):
return templates.TemplateResponse(request = request, name="index.html")
@router.get("/rag")
async def rag(request : Request):
return templates.TemplateResponse(request = request, name="rag.html")
@@ -0,0 +1,5 @@
from pydantic import BaseModel
class QuestionRequest(BaseModel):
question : str
@@ -0,0 +1,8 @@
from backend.ai.llm import watson_llm
# LLM 모델 통신
# 데이터베이스 통신
def question_and_answer(question):
response = watson_llm.invoke(question)
return response.content
@@ -0,0 +1,6 @@
# pdf 업로드 => 분할 => 인덱스 생성
def upload_document(file):
pass
# 질문 => 유사도 검색 => 문서 => llm 답변 생성
@@ -0,0 +1,44 @@
document.querySelector("button").addEventListener("click", ask)
async function ask() {
// 사용자가 질문 입력 시 질문을 서버로 전송
const question = document.querySelector('#question').value
const response = await fetch("/api/question", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({question : question})
})
// 전송 후 answer 도착 시 answer 화면에 보여주기
const answer = await response.json()
document.querySelector('#answer').textContent = answer.message
}
// 파일 업로드
document.querySelector("#uploadBtn").addEventListener("click", uploadFile)
async function uploadFile()
{
const fileInput = document.querySelector("#file");
// 첨부파일 정보 가져오기
const file = fileInput.files[0];
if(!file)
{
alert("파일을 선택해주세요.");
return;
}
// form 만들어 전송
const formData = new FormData()
formData.append("file", file)
const response = await fetch("/api/reg/question", {
method: "POST",
body: formData
})
// 전송 후 answer 도착 시 answer 화면에 보여주기
const answer = await response.json()
document.querySelector('#answer').textContent = answer.message
}
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>HOME</h1>
<ul>
<a href="/rag">RAG</a>
</ul>
<div>
<input type="text" name="question" id="question">
<button type="submit">질문</button>
</div>
<div id="answer"></div>
<script src="{{ url_for('static', path='js/index.js')}}"></script>
</body>
</html>
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>RAG</h2>
<div>
<input type="file" name="file" id="file">
<button id="uploadBtn">업로드</button>
</div>
<hr>
<div id="result"></div>
<script src="{{ url_for('static', path='js/index.js')}}"></script>
</body>
</html>
+5
View File
@@ -0,0 +1,5 @@
[project]
name = "rag-app"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
+8
View File
@@ -0,0 +1,8 @@
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "rag-app"
version = "0.1.0"
source = { virtual = "." }