tekville
commited on
Commit
ยท
ff72db3
0
Parent(s):
Initial commit
Browse files- .dockerignore +28 -0
- .gitattributes +35 -0
- .gitignore +114 -0
- Dockerfile +69 -0
- Dockerfile copy +27 -0
- README.md +12 -0
- app/__init__.py +0 -0
- app/main.py +16 -0
- app/modules/embedding.py +60 -0
- app/modules/evaluation.py +89 -0
- app/routers/__init__.py +0 -0
- app/routers/search.py +58 -0
- app/routers/upload.py +60 -0
- app/routers/user.py +127 -0
- app/templates/search.html +168 -0
- app/templates/upload.html +142 -0
- app/uploaded_files copy/a.txt +0 -0
- config/database.py +39 -0
- gradio/app.py +23 -0
- models/user_info.py +25 -0
- readme.txt +63 -0
- requirements.txt +48 -0
- uploaded_files/a.txt +0 -0
.dockerignore
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Git ๊ด๋ จ ํ์ผ
|
2 |
+
.git
|
3 |
+
.gitignore
|
4 |
+
|
5 |
+
# ๊ฐ์ํ๊ฒฝ
|
6 |
+
.venv
|
7 |
+
__pycache__
|
8 |
+
|
9 |
+
# ์บ์ ํ์ผ
|
10 |
+
*.pyc
|
11 |
+
*.pyo
|
12 |
+
*.log
|
13 |
+
*.tmp
|
14 |
+
|
15 |
+
# ๋น๋ ๊ฒฐ๊ณผ๋ฌผ
|
16 |
+
dist/
|
17 |
+
build/
|
18 |
+
rag/
|
19 |
+
*.egg-info/
|
20 |
+
|
21 |
+
# ์์คํ
ํ์ผ
|
22 |
+
.DS_Store
|
23 |
+
Thumbs.db
|
24 |
+
|
25 |
+
# IDE ์ค์ ํ์ผ
|
26 |
+
.idea/
|
27 |
+
.vscode/
|
28 |
+
*.code-workspace
|
.gitattributes
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
env/
|
12 |
+
venv/
|
13 |
+
ENV/
|
14 |
+
env.bak/
|
15 |
+
venv.bak/
|
16 |
+
*.egg
|
17 |
+
*.egg-info/
|
18 |
+
dist/
|
19 |
+
build/
|
20 |
+
*.wheel
|
21 |
+
.venv/
|
22 |
+
fastapi/
|
23 |
+
rag/
|
24 |
+
|
25 |
+
# PyInstaller
|
26 |
+
# Usually these files are written by a python script from a template
|
27 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
28 |
+
*.manifest
|
29 |
+
*.spec
|
30 |
+
|
31 |
+
# Installer logs
|
32 |
+
pip-log.txt
|
33 |
+
pip-delete-this-directory.txt
|
34 |
+
|
35 |
+
# Unit test / coverage reports
|
36 |
+
htmlcov/
|
37 |
+
.tox/
|
38 |
+
.nox/
|
39 |
+
.coverage
|
40 |
+
*.coverage
|
41 |
+
.cache
|
42 |
+
nosetests.xml
|
43 |
+
coverage.xml
|
44 |
+
*.cover
|
45 |
+
*.py,cover
|
46 |
+
.hypothesis/
|
47 |
+
pytest_cache/
|
48 |
+
cover/
|
49 |
+
|
50 |
+
# Jupyter Notebook
|
51 |
+
.ipynb_checkpoints
|
52 |
+
|
53 |
+
# PyCharm
|
54 |
+
.idea/
|
55 |
+
|
56 |
+
# VSCode
|
57 |
+
.vscode/
|
58 |
+
*.code-workspace
|
59 |
+
|
60 |
+
# MyPy
|
61 |
+
.mypy_cache/
|
62 |
+
|
63 |
+
# Pyre
|
64 |
+
.pyre/
|
65 |
+
|
66 |
+
# Pytype
|
67 |
+
.pytype/
|
68 |
+
|
69 |
+
# Celery beat schedule file
|
70 |
+
celerybeat-schedule
|
71 |
+
|
72 |
+
# Django stuff:
|
73 |
+
*.log
|
74 |
+
local_settings.py
|
75 |
+
db.sqlite3
|
76 |
+
db.sqlite3-journal
|
77 |
+
|
78 |
+
# Flask stuff:
|
79 |
+
instance/
|
80 |
+
.webassets-cache
|
81 |
+
|
82 |
+
# Scrapy stuff:
|
83 |
+
.scrapy
|
84 |
+
|
85 |
+
# Sphinx documentation
|
86 |
+
docs/_build/
|
87 |
+
|
88 |
+
# PyBuilder
|
89 |
+
target/
|
90 |
+
|
91 |
+
# dotenv
|
92 |
+
.env
|
93 |
+
*.env
|
94 |
+
|
95 |
+
# IDEs and editors
|
96 |
+
*.swp
|
97 |
+
*~
|
98 |
+
.vimrc
|
99 |
+
.history
|
100 |
+
.idea/
|
101 |
+
*.sublime-project
|
102 |
+
*.sublime-workspace
|
103 |
+
|
104 |
+
# macOS
|
105 |
+
.DS_Store
|
106 |
+
|
107 |
+
# Windows
|
108 |
+
Thumbs.db
|
109 |
+
desktop.ini
|
110 |
+
|
111 |
+
# Logs
|
112 |
+
*.log
|
113 |
+
*.out
|
114 |
+
*.err
|
Dockerfile
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Build Stage
|
2 |
+
FROM python:3.11-slim as builder
|
3 |
+
|
4 |
+
# ์ฌ์ฉ์ ํ๊ฒฝ ๋ณ์ ์ค์
|
5 |
+
ENV HOME=/home/user \
|
6 |
+
PATH=/home/user/.local/bin:$PATH
|
7 |
+
|
8 |
+
# ์ฌ์ฉ์ ์์ฑ ๋ฐ ๊ถํ ์ค์
|
9 |
+
RUN useradd -m -d $HOME -s /bin/bash user
|
10 |
+
|
11 |
+
# ์์
๋๋ ํฐ๋ฆฌ ์ค์
|
12 |
+
WORKDIR $HOME/app
|
13 |
+
|
14 |
+
# ์์คํ
ํจํค์ง ์
๋ฐ์ดํธ ๋ฐ ํ์ ํจํค์ง ์ค์น
|
15 |
+
RUN apt-get update && apt-get install -y \
|
16 |
+
build-essential \
|
17 |
+
libmariadb-dev \
|
18 |
+
git \
|
19 |
+
&& rm -rf /var/lib/apt/lists/*
|
20 |
+
|
21 |
+
# Python ํจํค์ง ๊ด๋ฆฌ
|
22 |
+
RUN pip install --upgrade pip
|
23 |
+
|
24 |
+
# ์์กด์ฑ ํ์ผ ๋ณต์ฌ
|
25 |
+
COPY --chown=user:user requirements.txt ./
|
26 |
+
|
27 |
+
# Python ํจํค์ง ์ค์น
|
28 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
29 |
+
|
30 |
+
# Runtime Stage
|
31 |
+
FROM python:3.11-slim
|
32 |
+
|
33 |
+
# ์ฌ์ฉ์ ํ๊ฒฝ ๋ณ์ ์ค์
|
34 |
+
ENV HOME=/home/user \
|
35 |
+
PATH=/home/user/.local/bin:$PATH
|
36 |
+
|
37 |
+
# ์ฌ์ฉ์ ์์ฑ ๋ฐ ๊ถํ ์ค์
|
38 |
+
RUN useradd -m -d $HOME -s /bin/bash user
|
39 |
+
|
40 |
+
# ์์
๋๋ ํฐ๋ฆฌ ์ค์
|
41 |
+
WORKDIR $HOME/app
|
42 |
+
|
43 |
+
# ํ์ํ ์์คํ
ํจํค์ง ์ค์น
|
44 |
+
RUN apt-get update && apt-get install -y \
|
45 |
+
libmariadb-dev \
|
46 |
+
wget \
|
47 |
+
git \
|
48 |
+
&& rm -rf /var/lib/apt/lists/*
|
49 |
+
|
50 |
+
# Build Stage์์ ์ค์น๋ Python ํจํค์ง ๋ณต์ฌ
|
51 |
+
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
|
52 |
+
COPY --from=builder /usr/local/bin /usr/local/bin
|
53 |
+
|
54 |
+
# ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋ ๋ณต์ฌ
|
55 |
+
COPY --chown=user:user . .
|
56 |
+
|
57 |
+
# ํฌํธ ๋
ธ์ถ (FastAPI ๊ธฐ๋ณธ ํฌํธ: 8000)
|
58 |
+
EXPOSE 8000
|
59 |
+
|
60 |
+
# ์
๋ก๋ ๋๋ ํฐ๋ฆฌ ์์ฑ ๋ฐ ๊ถํ ์ค์
|
61 |
+
RUN mkdir -p $HOME/app/uploaded_files && \
|
62 |
+
chown -R user:user $HOME/app/uploaded_files && \
|
63 |
+
chmod -R 777 $HOME/app/uploaded_files
|
64 |
+
|
65 |
+
# ์ ํ๋ฆฌ์ผ์ด์
์คํ์ ์ฌ์ฉ์ ๊ถํ์ผ๋ก ์คํ
|
66 |
+
USER user
|
67 |
+
|
68 |
+
# FastAPI ์คํ ๋ช
๋ น
|
69 |
+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
Dockerfile copy
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Python 3.11 ์ด๋ฏธ์ง ์ฌ์ฉ
|
2 |
+
FROM python:3.11-slim
|
3 |
+
|
4 |
+
# ์์
๋๋ ํฐ๋ฆฌ ์ค์
|
5 |
+
WORKDIR /app
|
6 |
+
|
7 |
+
# ์์คํ
ํจํค์ง ์
๋ฐ์ดํธ ๋ฐ ํ์ ํจํค์ง ์ค์น
|
8 |
+
RUN apt-get update && apt-get install -y \
|
9 |
+
build-essential \
|
10 |
+
libmariadb-dev \
|
11 |
+
&& rm -rf /var/lib/apt/lists/*
|
12 |
+
|
13 |
+
# ์์กด์ฑ ํ์ผ ๋ณต์ฌ
|
14 |
+
COPY requirements.txt .
|
15 |
+
|
16 |
+
# Python ํจํค์ง ์ค์น
|
17 |
+
RUN pip install --upgrade pip \
|
18 |
+
&& pip install --no-cache-dir -r requirements.txt
|
19 |
+
|
20 |
+
# ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋ ๋ณต์ฌ
|
21 |
+
COPY . .
|
22 |
+
|
23 |
+
# ํฌํธ ๋
ธ์ถ (FastAPI ๊ธฐ๋ณธ ํฌํธ: 8000)
|
24 |
+
EXPOSE 8000
|
25 |
+
|
26 |
+
# FastAPI ์คํ ๋ช
๋ น
|
27 |
+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
README.md
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Rag
|
3 |
+
emoji: ๐
|
4 |
+
colorFrom: yellow
|
5 |
+
colorTo: yellow
|
6 |
+
sdk: docker
|
7 |
+
pinned: false
|
8 |
+
license: apache-2.0
|
9 |
+
short_description: rag
|
10 |
+
---
|
11 |
+
|
12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app/__init__.py
ADDED
File without changes
|
app/main.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI
|
2 |
+
from app.routers import upload,search,user
|
3 |
+
#from config.database import engine
|
4 |
+
# from models.user_info import Base
|
5 |
+
|
6 |
+
app = FastAPI()
|
7 |
+
|
8 |
+
# ๋ผ์ฐํฐ ์ถ๊ฐ
|
9 |
+
app.include_router(upload.router)
|
10 |
+
app.include_router(search.router)
|
11 |
+
# app.include_router(user.router)
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ ์์ฑ
|
16 |
+
#Base.metadata.create_all(bind=engine)
|
app/modules/embedding.py
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import asyncio
|
3 |
+
from langchain.document_loaders import PyPDFLoader
|
4 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
5 |
+
from langchain.vectorstores import FAISS
|
6 |
+
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
|
7 |
+
|
8 |
+
async def process_and_store_file(file_path, user_id, websocket=None, upload_directory="./uploaded_files"):
|
9 |
+
try:
|
10 |
+
# 1. PDF ํ์ผ ๋ก๋
|
11 |
+
if websocket:
|
12 |
+
await websocket.send_text("1. PDF ํ์ผ ๋ก๋ ์ค...")
|
13 |
+
loader = PyPDFLoader(file_path)
|
14 |
+
documents = loader.load()
|
15 |
+
if websocket:
|
16 |
+
await websocket.send_text(f"PDF ํ์ผ ๋ก๋ ์๋ฃ: {len(documents)} ๋ฌธ์")
|
17 |
+
except Exception as e:
|
18 |
+
if websocket:
|
19 |
+
await websocket.send_text(f"PDF ํ์ผ ๋ก๋ ์ค๋ฅ: {e}")
|
20 |
+
return
|
21 |
+
|
22 |
+
try:
|
23 |
+
# 2. ํ
์คํธ ๋ถํ
|
24 |
+
if websocket:
|
25 |
+
await websocket.send_text("2. ํ
์คํธ ๋ถํ ์ค...")
|
26 |
+
text_splitter = RecursiveCharacterTextSplitter(chunk_size=3000, chunk_overlap=500)
|
27 |
+
docs = text_splitter.split_documents(documents)
|
28 |
+
if websocket:
|
29 |
+
await websocket.send_text(f"ํ
์คํธ ๋ถํ ์๋ฃ: {len(docs)} ์ฒญํฌ")
|
30 |
+
except Exception as e:
|
31 |
+
if websocket:
|
32 |
+
await websocket.send_text(f"ํ
์คํธ ๋ถํ ์ค๋ฅ: {e}")
|
33 |
+
return
|
34 |
+
|
35 |
+
try:
|
36 |
+
# 3. ์๋ฒ ๋ฉ ์์ฑ ๋ฐ ๋ฒกํฐํ
|
37 |
+
if websocket:
|
38 |
+
await websocket.send_text("3. ์๋ฒ ๋ฉ ์์ฑ ๋ฐ ๋ฒกํฐํ ์ค...")
|
39 |
+
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
|
40 |
+
vectors = FAISS.from_documents(docs, embeddings)
|
41 |
+
|
42 |
+
# 4. ๋ฒกํฐ ์ ์ฅ
|
43 |
+
db_path = os.path.join(upload_directory, "faiss_index")
|
44 |
+
vectors.save_local(db_path)
|
45 |
+
if websocket:
|
46 |
+
await websocket.send_text(f"FAISS ์ธ๋ฑ์ค ์ ์ฅ ์๋ฃ: {db_path}")
|
47 |
+
except Exception as e:
|
48 |
+
if websocket:
|
49 |
+
await websocket.send_text(f"๋ฒกํฐํ ์ค๋ฅ: {e}")
|
50 |
+
return
|
51 |
+
finally:
|
52 |
+
# 5. ํ์ผ ์ญ์
|
53 |
+
try:
|
54 |
+
if os.path.exists(file_path):
|
55 |
+
os.remove(file_path)
|
56 |
+
if websocket:
|
57 |
+
await websocket.send_text(f"ํ์ผ ์ญ์ ์๋ฃ: {file_path}")
|
58 |
+
except Exception as e:
|
59 |
+
if websocket:
|
60 |
+
await websocket.send_text(f"ํ์ผ ์ญ์ ์ค๋ฅ: {e}")
|
app/modules/evaluation.py
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from huggingface_hub import InferenceClient
|
3 |
+
|
4 |
+
class Evaluation:
|
5 |
+
def __init__(self, model: str = "Qwen/Qwen2.5-72B-Instruct"):
|
6 |
+
"""
|
7 |
+
Args:
|
8 |
+
model (str): ์ฌ์ฉํ Hugging Face ๋ชจ๋ธ ์ด๋ฆ (๊ธฐ๋ณธ๊ฐ: Qwen/Qwen2.5-72B-Instruct).
|
9 |
+
"""
|
10 |
+
self.api_key = os.getenv("HF_API_KEY")
|
11 |
+
if not self.api_key:
|
12 |
+
raise ValueError("HF_API_KEY ํ๊ฒฝ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.")
|
13 |
+
self.client = InferenceClient(api_key=self.api_key)
|
14 |
+
self.model = model
|
15 |
+
|
16 |
+
def evaluate(self, instruction: str, answer: str) -> str:
|
17 |
+
"""
|
18 |
+
์ฌ์ฉ์์ ๋ต๋ณ๊ณผ ํ๊ฐ ๊ธฐ์ค์ ๊ธฐ๋ฐ์ผ๋ก AI ๋ชจ๋ธ ํ๊ฐ๋ฅผ ์ํํฉ๋๋ค.
|
19 |
+
|
20 |
+
Args:
|
21 |
+
instruction (str): ํ๊ฐ ๊ธฐ์ค์ด ํฌํจ๋ ์ง์นจ.
|
22 |
+
answer (str): ์ฌ์ฉ์ ๋ต๋ณ.
|
23 |
+
|
24 |
+
Returns:
|
25 |
+
str: ํ๊ฐ ๊ฒฐ๊ณผ.
|
26 |
+
"""
|
27 |
+
messages = [
|
28 |
+
{"role": "system", "content": "์์
๋๊ตฌ ๊ตฌ์ฑ ๋ง๋ฒ์ฌ์
๋๋ค. ํด์ฆ, ๊ณผ์ , ํ ๋ก ์ ์์ฑํ ์ ์์ต๋๋ค."},
|
29 |
+
{"role": "user", "content": instruction},
|
30 |
+
]
|
31 |
+
|
32 |
+
try:
|
33 |
+
stream = self.client.chat.completions.create(
|
34 |
+
model=self.model,
|
35 |
+
messages=messages,
|
36 |
+
temperature=0.2,
|
37 |
+
max_tokens=2048,
|
38 |
+
top_p=0.7,
|
39 |
+
stream=True,
|
40 |
+
)
|
41 |
+
|
42 |
+
result = ""
|
43 |
+
for chunk in stream:
|
44 |
+
if "delta" in chunk.choices[0]:
|
45 |
+
result += chunk.choices[0].delta.content
|
46 |
+
print(f"Intermediate result: {result}") # ๋๋ฒ๊น
์ฉ ์ถ๋ ฅ
|
47 |
+
|
48 |
+
return result.strip()
|
49 |
+
|
50 |
+
except Exception as e:
|
51 |
+
error_message = f"An error occurred during evaluation: {e}"
|
52 |
+
print(error_message) # ๋๋ฒ๊น
์ฉ ์ถ๋ ฅ
|
53 |
+
return error_message
|
54 |
+
|
55 |
+
async def evaluate_stream(self, instruction: str):
|
56 |
+
"""
|
57 |
+
๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌํฉ๋๋ค.
|
58 |
+
|
59 |
+
Args:
|
60 |
+
instruction (str): ํ๊ฐ ๊ธฐ์ค์ด ํฌํจ๋ ์ง์นจ.
|
61 |
+
|
62 |
+
Yields:
|
63 |
+
str: ์ค์๊ฐ ํ๊ฐ ๊ฒฐ๊ณผ.
|
64 |
+
"""
|
65 |
+
messages = [
|
66 |
+
{"role": "system", "content": "์ ์๋์๊ฒ ๊ผญ ํ์ํ ์์
๋๊ตฌ ๊ตฌ์ฑ ๋ง๋ฒ์ฌ์
๋๋ค."},
|
67 |
+
{"role": "user", "content": instruction},
|
68 |
+
]
|
69 |
+
|
70 |
+
try:
|
71 |
+
stream = self.client.chat.completions.create(
|
72 |
+
model=self.model,
|
73 |
+
messages=messages,
|
74 |
+
temperature=0.2,
|
75 |
+
max_tokens=2048,
|
76 |
+
top_p=0.7,
|
77 |
+
stream=True,
|
78 |
+
)
|
79 |
+
|
80 |
+
for chunk in stream:
|
81 |
+
if "delta" in chunk.choices[0]:
|
82 |
+
content = chunk.choices[0].delta.content
|
83 |
+
print(f"Streaming result: {content}") # ๋๋ฒ๊น
์ฉ ์ถ๋ ฅ
|
84 |
+
yield content
|
85 |
+
|
86 |
+
except Exception as e:
|
87 |
+
error_message = f"Error: {e}"
|
88 |
+
print(error_message) # ๋๋ฒ๊น
์ฉ ์ถ๋ ฅ
|
89 |
+
yield error_message
|
app/routers/__init__.py
ADDED
File without changes
|
app/routers/search.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, Request, Form
|
2 |
+
from fastapi.responses import HTMLResponse, StreamingResponse
|
3 |
+
from fastapi.templating import Jinja2Templates
|
4 |
+
from langchain.vectorstores import FAISS
|
5 |
+
from langchain.embeddings import HuggingFaceEmbeddings
|
6 |
+
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
7 |
+
from app.modules.evaluation import Evaluation # ํ๊ฐ ๋ชจ๋ ์ํฌํธ
|
8 |
+
import os
|
9 |
+
|
10 |
+
router = APIRouter()
|
11 |
+
|
12 |
+
# ๋ก์ปฌ ๋ชจ๋ธ ๋ก๋ (HuggingFace T5 ์ฌ์ฉ)
|
13 |
+
# tokenizer = AutoTokenizer.from_pretrained("gogamza/kobart-base-v2")
|
14 |
+
# model = AutoModelForSeq2SeqLM.from_pretrained("gogamza/kobart-base-v2")
|
15 |
+
|
16 |
+
# def summarize_text(text: str, max_length=150):
|
17 |
+
# inputs = tokenizer.encode("summarize: " + text, return_tensors="pt", max_length=512, truncation=True)
|
18 |
+
# outputs = model.generate(inputs, max_length=512, min_length=50, length_penalty=2.0, num_beams=4, early_stopping=True)
|
19 |
+
# return tokenizer.decode(outputs[0], skip_special_tokens=True)
|
20 |
+
|
21 |
+
# ํ
ํ๋ฆฟ ์ค์
|
22 |
+
templates = Jinja2Templates(directory="app/templates")
|
23 |
+
|
24 |
+
# ์
๋ก๋๋ ํ์ผ๋ก๋ถํฐ ์์ฑ๋ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฒฝ๋ก ์ค์
|
25 |
+
UPLOAD_DIRECTORY = "./uploaded_files"
|
26 |
+
db_path = os.path.join(UPLOAD_DIRECTORY, "faiss_index")
|
27 |
+
|
28 |
+
# ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ก๋
|
29 |
+
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
|
30 |
+
|
31 |
+
@router.get("/search", response_class=HTMLResponse)
|
32 |
+
async def search_page(request: Request):
|
33 |
+
return templates.TemplateResponse("search.html", {"request": request})
|
34 |
+
|
35 |
+
|
36 |
+
@router.post("/search/stream")
|
37 |
+
async def search_stream(query: str = Form(...), model: str = Form(...)):
|
38 |
+
# ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ก๋
|
39 |
+
vector_db = FAISS.load_local(db_path, embeddings, allow_dangerous_deserialization=True)
|
40 |
+
results = vector_db.similarity_search(query, k=5)
|
41 |
+
|
42 |
+
# ๊ฒ์๋ ๊ฒฐ๊ณผ ํ
์คํธ๋ฅผ ์ฐ๊ฒฐ
|
43 |
+
full_text = "\n\n".join([result.page_content for result in results])
|
44 |
+
|
45 |
+
# ํ๊ฐ ๋ชจ๋ ์ด๊ธฐํ
|
46 |
+
evaluator = Evaluation(model=model)
|
47 |
+
|
48 |
+
# ํ๊ฐ ๊ธฐ์ค
|
49 |
+
instruction = (
|
50 |
+
f"๋ค์ ํ
์คํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก {query}\n\n{full_text}"
|
51 |
+
)
|
52 |
+
|
53 |
+
|
54 |
+
async def stream():
|
55 |
+
async for data in evaluator.evaluate_stream(instruction):
|
56 |
+
yield data
|
57 |
+
|
58 |
+
return StreamingResponse(stream(), media_type="text/plain")
|
app/routers/upload.py
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, File, UploadFile, Request, WebSocket, WebSocketDisconnect
|
2 |
+
from fastapi.responses import HTMLResponse, RedirectResponse
|
3 |
+
from fastapi.templating import Jinja2Templates
|
4 |
+
from app.modules.embedding import process_and_store_file
|
5 |
+
import shutil
|
6 |
+
import os
|
7 |
+
import uuid
|
8 |
+
import asyncio
|
9 |
+
|
10 |
+
router = APIRouter()
|
11 |
+
|
12 |
+
# ์
๋ก๋๋ ํ์ผ์ ์ ์ฅํ ๋๋ ํ ๋ฆฌ ์ค์
|
13 |
+
UPLOAD_DIRECTORY = "./uploaded_files"
|
14 |
+
if not os.path.exists(UPLOAD_DIRECTORY):
|
15 |
+
os.makedirs(UPLOAD_DIRECTORY, exist_ok=True)
|
16 |
+
os.chmod(UPLOAD_DIRECTORY, 0o777)
|
17 |
+
|
18 |
+
# ํ
ํ๋ฆฟ ๋๋ ํ ๋ฆฌ ์ค์
|
19 |
+
templates = Jinja2Templates(directory="app/templates")
|
20 |
+
|
21 |
+
# WebSocket ์ฐ๊ฒฐ ๊ด๋ฆฌ
|
22 |
+
connections = {}
|
23 |
+
|
24 |
+
@router.get("/", response_class=HTMLResponse)
|
25 |
+
async def main(request: Request):
|
26 |
+
return templates.TemplateResponse("upload.html", {"request": request})
|
27 |
+
|
28 |
+
@router.post("/uploadfile/{user_id}/")
|
29 |
+
async def upload_file(user_id: str, file: UploadFile = File(...)):
|
30 |
+
# ๊ณ ์ ํ์ผ ์ด๋ฆ ์์ฑ
|
31 |
+
unique_filename = f"{uuid.uuid4()}_{file.filename}"
|
32 |
+
file_location = os.path.join(UPLOAD_DIRECTORY, unique_filename)
|
33 |
+
|
34 |
+
# ํ์ผ ์ ์ฅ
|
35 |
+
try:
|
36 |
+
with open(file_location, "wb") as buffer:
|
37 |
+
shutil.copyfileobj(file.file, buffer)
|
38 |
+
print(f"File saved at {file_location}")
|
39 |
+
except Exception as e:
|
40 |
+
return {"error": f"ํ์ผ ์ ์ฅ ์ค๋ฅ: {e}"}
|
41 |
+
|
42 |
+
# ๋น๋๊ธฐ ์์
์คํ
|
43 |
+
asyncio.create_task(process_and_store_file(file_location, user_id, connections.get(user_id), UPLOAD_DIRECTORY))
|
44 |
+
|
45 |
+
return {"info": f"File '{file.filename}' uploaded successfully."}
|
46 |
+
|
47 |
+
@router.websocket("/ws/{user_id}")
|
48 |
+
async def websocket_endpoint(websocket: WebSocket, user_id: str):
|
49 |
+
await websocket.accept()
|
50 |
+
connections[user_id] = websocket # WebSocket ์ฐ๊ฒฐ ์ ์ฅ
|
51 |
+
try:
|
52 |
+
while True:
|
53 |
+
data = await websocket.receive_text()
|
54 |
+
print(f"Received from {user_id}: {data}")
|
55 |
+
except WebSocketDisconnect:
|
56 |
+
print(f"User {user_id} disconnected")
|
57 |
+
del connections[user_id] # ์ฐ๊ฒฐ ์ ๊ฑฐ
|
58 |
+
except Exception as e:
|
59 |
+
print(f"Error with user {user_id}: {e}")
|
60 |
+
del connections[user_id] # ์ฐ๊ฒฐ ์ ๊ฑฐ
|
app/routers/user.py
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# from fastapi import APIRouter, Depends, HTTPException
|
2 |
+
# from sqlalchemy.orm import Session
|
3 |
+
# from models.user_info import UserInfo
|
4 |
+
# from config.database import get_db
|
5 |
+
# from typing import Optional
|
6 |
+
# from datetime import datetime
|
7 |
+
|
8 |
+
# router = APIRouter()
|
9 |
+
|
10 |
+
# # ์ฌ์ฉ์ ์กฐํ
|
11 |
+
# @router.get("/users/{user_id}")
|
12 |
+
# async def get_user(user_id: str, db: Session = Depends(get_db)):
|
13 |
+
# user = db.query(UserInfo).filter(UserInfo.id == user_id).first()
|
14 |
+
# if not user:
|
15 |
+
# raise HTTPException(status_code=404, detail="User not found")
|
16 |
+
# return user
|
17 |
+
|
18 |
+
# # ์ฌ์ฉ์ ์์ฑ
|
19 |
+
# @router.post("/users")
|
20 |
+
# async def create_user(
|
21 |
+
# id: str,
|
22 |
+
# preferred_username: Optional[str] = None,
|
23 |
+
# mobile: Optional[str] = None,
|
24 |
+
# business_cd: Optional[str] = None,
|
25 |
+
# role_seq: Optional[int] = None,
|
26 |
+
# name: Optional[str] = None,
|
27 |
+
# email: Optional[str] = None,
|
28 |
+
# profile: Optional[str] = None,
|
29 |
+
# school_code: Optional[str] = None,
|
30 |
+
# grade: Optional[int] = None,
|
31 |
+
# class_name: Optional[str] = None,
|
32 |
+
# student_no: Optional[int] = None,
|
33 |
+
# creator_id: Optional[str] = None,
|
34 |
+
# creator_ip: Optional[str] = None,
|
35 |
+
# db: Session = Depends(get_db)
|
36 |
+
# ):
|
37 |
+
# new_user = UserInfo(
|
38 |
+
# id=id,
|
39 |
+
# preferred_username=preferred_username,
|
40 |
+
# mobile=mobile,
|
41 |
+
# business_cd=business_cd,
|
42 |
+
# role_seq=role_seq,
|
43 |
+
# name=name,
|
44 |
+
# email=email,
|
45 |
+
# profile=profile,
|
46 |
+
# school_code=school_code,
|
47 |
+
# grade=grade,
|
48 |
+
# class_name=class_name,
|
49 |
+
# student_no=student_no,
|
50 |
+
# created_at=datetime.now(),
|
51 |
+
# creator_id=creator_id,
|
52 |
+
# creator_ip=creator_ip,
|
53 |
+
# )
|
54 |
+
# db.add(new_user)
|
55 |
+
# db.commit()
|
56 |
+
# db.refresh(new_user)
|
57 |
+
# return new_user
|
58 |
+
|
59 |
+
# # ์ฌ์ฉ์ ๋ชฉ๋ก ์กฐํ
|
60 |
+
# @router.get("/users")
|
61 |
+
# async def list_users(db: Session = Depends(get_db)):
|
62 |
+
# return db.query(UserInfo).all()
|
63 |
+
|
64 |
+
# # ์ฌ์ฉ์ ์
๋ฐ์ดํธ
|
65 |
+
# @router.put("/users/{user_id}")
|
66 |
+
# async def update_user(
|
67 |
+
# user_id: str,
|
68 |
+
# preferred_username: Optional[str] = None,
|
69 |
+
# mobile: Optional[str] = None,
|
70 |
+
# business_cd: Optional[str] = None,
|
71 |
+
# role_seq: Optional[int] = None,
|
72 |
+
# name: Optional[str] = None,
|
73 |
+
# email: Optional[str] = None,
|
74 |
+
# profile: Optional[str] = None,
|
75 |
+
# school_code: Optional[str] = None,
|
76 |
+
# grade: Optional[int] = None,
|
77 |
+
# class_name: Optional[str] = None,
|
78 |
+
# student_no: Optional[int] = None,
|
79 |
+
# updater_id: Optional[str] = None,
|
80 |
+
# updater_ip: Optional[str] = None,
|
81 |
+
# db: Session = Depends(get_db)
|
82 |
+
# ):
|
83 |
+
# user = db.query(UserInfo).filter(UserInfo.id == user_id).first()
|
84 |
+
# if not user:
|
85 |
+
# raise HTTPException(status_code=404, detail="User not found")
|
86 |
+
|
87 |
+
# # ํ๋ ์
๋ฐ์ดํธ
|
88 |
+
# if preferred_username is not None:
|
89 |
+
# user.preferred_username = preferred_username
|
90 |
+
# if mobile is not None:
|
91 |
+
# user.mobile = mobile
|
92 |
+
# if business_cd is not None:
|
93 |
+
# user.business_cd = business_cd
|
94 |
+
# if role_seq is not None:
|
95 |
+
# user.role_seq = role_seq
|
96 |
+
# if name is not None:
|
97 |
+
# user.name = name
|
98 |
+
# if email is not None:
|
99 |
+
# user.email = email
|
100 |
+
# if profile is not None:
|
101 |
+
# user.profile = profile
|
102 |
+
# if school_code is not None:
|
103 |
+
# user.school_code = school_code
|
104 |
+
# if grade is not None:
|
105 |
+
# user.grade = grade
|
106 |
+
# if class_name is not None:
|
107 |
+
# user.class_name = class_name
|
108 |
+
# if student_no is not None:
|
109 |
+
# user.student_no = student_no
|
110 |
+
|
111 |
+
# user.updated_at = datetime.now()
|
112 |
+
# user.updater_id = updater_id
|
113 |
+
# user.updater_ip = updater_ip
|
114 |
+
|
115 |
+
# db.commit()
|
116 |
+
# db.refresh(user)
|
117 |
+
# return user
|
118 |
+
|
119 |
+
# # ์ฌ์ฉ์ ์ญ์
|
120 |
+
# @router.delete("/users/{user_id}")
|
121 |
+
# async def delete_user(user_id: str, db: Session = Depends(get_db)):
|
122 |
+
# user = db.query(UserInfo).filter(UserInfo.id == user_id).first()
|
123 |
+
# if not user:
|
124 |
+
# raise HTTPException(status_code=404, detail="User not found")
|
125 |
+
# db.delete(user)
|
126 |
+
# db.commit()
|
127 |
+
# return {"message": "User deleted successfully"}
|
app/templates/search.html
ADDED
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="ko">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>๋ฌธ์ ๊ฒ์</title>
|
7 |
+
<style>
|
8 |
+
.container {
|
9 |
+
width: 50%;
|
10 |
+
margin: 0 auto;
|
11 |
+
padding: 20px;
|
12 |
+
text-align: center;
|
13 |
+
border: 1px solid #ccc;
|
14 |
+
border-radius: 8px;
|
15 |
+
background-color: #f9f9f9;
|
16 |
+
}
|
17 |
+
.search-bar {
|
18 |
+
display: flex;
|
19 |
+
justify-content: center;
|
20 |
+
align-items: center;
|
21 |
+
gap: 10px;
|
22 |
+
}
|
23 |
+
input[type="text"], select {
|
24 |
+
padding: 10px;
|
25 |
+
border: 1px solid #ccc;
|
26 |
+
border-radius: 4px;
|
27 |
+
font-size: 14px;
|
28 |
+
}
|
29 |
+
input[type="text"] {
|
30 |
+
flex: 1;
|
31 |
+
}
|
32 |
+
select {
|
33 |
+
flex: 0.5;
|
34 |
+
}
|
35 |
+
button {
|
36 |
+
padding: 10px 20px;
|
37 |
+
background-color: #007bff;
|
38 |
+
color: white;
|
39 |
+
border: none;
|
40 |
+
border-radius: 4px;
|
41 |
+
cursor: pointer;
|
42 |
+
font-size: 14px;
|
43 |
+
}
|
44 |
+
button:hover {
|
45 |
+
background-color: #0056b3;
|
46 |
+
}
|
47 |
+
.results, .evaluation, .stream-output {
|
48 |
+
margin-top: 5px;
|
49 |
+
}
|
50 |
+
.stream-output {
|
51 |
+
text-align: left;
|
52 |
+
white-space: pre-wrap;
|
53 |
+
border: 1px solid #ccc;
|
54 |
+
padding: 10px;
|
55 |
+
height: 500px;
|
56 |
+
overflow-y: scroll;
|
57 |
+
}
|
58 |
+
nav {
|
59 |
+
background-color: #333;
|
60 |
+
padding: 10px;
|
61 |
+
text-align: center;
|
62 |
+
}
|
63 |
+
nav ul {
|
64 |
+
list-style-type: none;
|
65 |
+
padding: 0;
|
66 |
+
margin: 0;
|
67 |
+
}
|
68 |
+
nav ul li {
|
69 |
+
display: inline;
|
70 |
+
margin: 0 15px;
|
71 |
+
}
|
72 |
+
nav ul li a {
|
73 |
+
color: white;
|
74 |
+
text-decoration: none;
|
75 |
+
font-weight: bold;
|
76 |
+
}
|
77 |
+
nav ul li a:hover {
|
78 |
+
text-decoration: underline;
|
79 |
+
}
|
80 |
+
</style>
|
81 |
+
</head>
|
82 |
+
<body>
|
83 |
+
<header>
|
84 |
+
<nav>
|
85 |
+
<ul>
|
86 |
+
<li><a href="/search">๋ฌธ์ ๊ฒ์</a></li>
|
87 |
+
<li><a href="/">ํ์ผ ์
๋ก๋</a></li>
|
88 |
+
</ul>
|
89 |
+
</nav>
|
90 |
+
</header>
|
91 |
+
<div class="container">
|
92 |
+
<h2>๋ฌธ์ ๊ฒ์</h2>
|
93 |
+
<form id="search-form" class="search-bar">
|
94 |
+
<input type="text" id="query" name="query" placeholder="๊ฒ์์ด๋ฅผ ์
๋ ฅํ์ธ์..." required>
|
95 |
+
<select id="model" name="model">
|
96 |
+
<option value="Qwen/Qwen2.5-72B-Instruct">Qwen/Qwen2.5-72B-Instruct</option>
|
97 |
+
<option value="meta-llama/Llama-3.3-70B-Instruct">meta-llama/Llama-3.3-70B-Instruct</option>
|
98 |
+
<option value="CohereForAI/c4ai-command-r-plus-08-2024">CohereForAI/c4ai-command-r-plus-08-2024</option>
|
99 |
+
<option value="Qwen/QwQ-32B-Preview">Qwen/QwQ-32B-Preview</option>
|
100 |
+
<option value="nvidia/Llama-3.1-Nemotron-70B-Instruct-HF">nvidia/Llama-3.1-Nemotron-70B-Instruct-HF</option>
|
101 |
+
<option value="Qwen/Qwen2.5-Coder-32B-Instruct">Qwen/Qwen2.5-Coder-32B-Instruct</option>
|
102 |
+
<option value="meta-llama/Llama-3.2-11B-Vision-Instruct">meta-llama/Llama-3.2-11B-Vision-Instruct</option>
|
103 |
+
<option value="NousResearch/Hermes-3-Llama-3.1-8B">NousResearch/Hermes-3-Llama-3.1-8B</option>
|
104 |
+
<option value="mistralai/Mistral-Nemo-Instruct-2407">mistralai/Mistral-Nemo-Instruct-2407</option>
|
105 |
+
<option value="microsoft/Phi-3.5-mini-instruct">microsoft/Phi-3.5-mini-instruct</option>
|
106 |
+
</select>
|
107 |
+
<button type="submit">๊ฒ์</button>
|
108 |
+
</form>
|
109 |
+
<h3>์ค์๊ฐ ๊ฒฐ๊ณผ</h3>
|
110 |
+
<div id="stream-output" class="stream-output">
|
111 |
+
|
112 |
+
<div id="stream-content">
|
113 |
+
<!-- ์ค์๊ฐ ๋ฐ์ดํฐ๊ฐ ์ฌ๊ธฐ์ ํ์๋ฉ๋๋ค -->
|
114 |
+
</div>
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
|
118 |
+
<script>
|
119 |
+
let currentController = null; // ํ์ฌ ์์ฒญ์ ์ ์ดํ AbortController
|
120 |
+
|
121 |
+
document.getElementById("search-form").addEventListener("submit", async (event) => {
|
122 |
+
event.preventDefault(); // ๊ธฐ๋ณธ ํผ ์ ์ถ ๋ฐฉ์ง
|
123 |
+
const query = document.getElementById("query").value;
|
124 |
+
const model = document.getElementById("model").value;
|
125 |
+
const outputContainer = document.getElementById("stream-content");
|
126 |
+
|
127 |
+
// ์ด์ ์์ฒญ ์ค๋จ
|
128 |
+
if (currentController) {
|
129 |
+
currentController.abort();
|
130 |
+
}
|
131 |
+
currentController = new AbortController();
|
132 |
+
const signal = currentController.signal;
|
133 |
+
|
134 |
+
// ์ถ๋ ฅ ์ด๊ธฐํ
|
135 |
+
outputContainer.textContent = "๊ฒ์ ์ค...\n";
|
136 |
+
|
137 |
+
try {
|
138 |
+
const response = await fetch("/search/stream", {
|
139 |
+
method: "POST",
|
140 |
+
headers: {
|
141 |
+
"Content-Type": "application/x-www-form-urlencoded"
|
142 |
+
},
|
143 |
+
body: new URLSearchParams({ query, model }),
|
144 |
+
signal, // AbortController์ signal ์ ๋ฌ
|
145 |
+
});
|
146 |
+
|
147 |
+
const reader = response.body.getReader();
|
148 |
+
const decoder = new TextDecoder("utf-8");
|
149 |
+
|
150 |
+
while (true) {
|
151 |
+
const { value, done } = await reader.read();
|
152 |
+
if (done) break;
|
153 |
+
outputContainer.textContent += decoder.decode(value);
|
154 |
+
outputContainer.scrollTop = outputContainer.scrollHeight; // ์คํฌ๋กค ์๋ ์ด๋
|
155 |
+
}
|
156 |
+
} catch (error) {
|
157 |
+
if (error.name === "AbortError") {
|
158 |
+
outputContainer.textContent += "\n์์ฒญ์ด ์ทจ์๋์์ต๋๋ค.\n";
|
159 |
+
} else {
|
160 |
+
outputContainer.textContent = `์ค๋ฅ ๋ฐ์: ${error.message}`;
|
161 |
+
}
|
162 |
+
} finally {
|
163 |
+
currentController = null; // ํ์ฌ ์์ฒญ ์๋ฃ ํ ์ด๊ธฐํ
|
164 |
+
}
|
165 |
+
});
|
166 |
+
</script>
|
167 |
+
</body>
|
168 |
+
</html>
|
app/templates/upload.html
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="ko">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>ํ์ผ ์
๋ก๋</title>
|
7 |
+
<style>
|
8 |
+
body {
|
9 |
+
font-family: Arial, sans-serif;
|
10 |
+
background-color: #f4f4f4;
|
11 |
+
margin: 0;
|
12 |
+
padding: 0;
|
13 |
+
}
|
14 |
+
.container {
|
15 |
+
width: 50%;
|
16 |
+
margin: 50px auto;
|
17 |
+
padding: 20px;
|
18 |
+
text-align: center;
|
19 |
+
border: 1px solid #ccc;
|
20 |
+
border-radius: 8px;
|
21 |
+
background-color: #ffffff;
|
22 |
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
23 |
+
}
|
24 |
+
input[type="file"] {
|
25 |
+
margin: 10px 0;
|
26 |
+
padding: 10px;
|
27 |
+
}
|
28 |
+
button {
|
29 |
+
padding: 10px 20px;
|
30 |
+
background-color: #007bff;
|
31 |
+
color: white;
|
32 |
+
border: none;
|
33 |
+
border-radius: 4px;
|
34 |
+
cursor: pointer;
|
35 |
+
font-size: 16px;
|
36 |
+
}
|
37 |
+
button:hover {
|
38 |
+
background-color: #0056b3;
|
39 |
+
}
|
40 |
+
.status {
|
41 |
+
margin-top: 20px;
|
42 |
+
text-align: left;
|
43 |
+
font-size: 14px;
|
44 |
+
}
|
45 |
+
.status p {
|
46 |
+
background-color: #e9f4ff;
|
47 |
+
border-left: 4px solid #007bff;
|
48 |
+
padding: 10px;
|
49 |
+
margin: 5px 0;
|
50 |
+
}
|
51 |
+
nav {
|
52 |
+
background-color: #333;
|
53 |
+
padding: 10px;
|
54 |
+
text-align: center;
|
55 |
+
}
|
56 |
+
nav ul {
|
57 |
+
list-style-type: none;
|
58 |
+
padding: 0;
|
59 |
+
margin: 0;
|
60 |
+
}
|
61 |
+
nav ul li {
|
62 |
+
display: inline;
|
63 |
+
margin: 0 15px;
|
64 |
+
}
|
65 |
+
nav ul li a {
|
66 |
+
color: white;
|
67 |
+
text-decoration: none;
|
68 |
+
font-weight: bold;
|
69 |
+
}
|
70 |
+
nav ul li a:hover {
|
71 |
+
text-decoration: underline;
|
72 |
+
}
|
73 |
+
</style>
|
74 |
+
</head>
|
75 |
+
<body>
|
76 |
+
<header>
|
77 |
+
<nav>
|
78 |
+
<ul>
|
79 |
+
<li><a href="/search">๋ฌธ์ ๊ฒ์</a></li>
|
80 |
+
<li><a href="/">ํ์ผ ์
๋ก๋</a></li>
|
81 |
+
</ul>
|
82 |
+
</nav>
|
83 |
+
</header>
|
84 |
+
<div class="container">
|
85 |
+
<h2>ํ์ผ ์
๋ก๋</h2>
|
86 |
+
<form id="upload-form" enctype="multipart/form-data">
|
87 |
+
<input type="file" name="file" required>
|
88 |
+
<button type="submit">์
๋ก๋</button>
|
89 |
+
</form>
|
90 |
+
<div class="status" id="status">
|
91 |
+
<h3>์
๋ก๋ ์ํ</h3>
|
92 |
+
</div>
|
93 |
+
</div>
|
94 |
+
|
95 |
+
<script>
|
96 |
+
const form = document.getElementById('upload-form');
|
97 |
+
const statusDiv = document.getElementById('status');
|
98 |
+
const userId = "user123"; // ๊ณ ์ ์ฌ์ฉ์ ID (๋์ ์ผ๋ก ์ค์ ๊ฐ๋ฅ)
|
99 |
+
|
100 |
+
// WebSocket ์ค์
|
101 |
+
const socket = new WebSocket(`ws://127.0.0.1:8000/ws/${userId}`);
|
102 |
+
|
103 |
+
socket.onmessage = (event) => {
|
104 |
+
const message = event.data;
|
105 |
+
const p = document.createElement('p');
|
106 |
+
p.textContent = message;
|
107 |
+
statusDiv.appendChild(p);
|
108 |
+
};
|
109 |
+
|
110 |
+
socket.onerror = () => {
|
111 |
+
const p = document.createElement('p');
|
112 |
+
p.textContent = "WebSocket ์ฐ๊ฒฐ ์ค๋ฅ.";
|
113 |
+
p.style.color = "red";
|
114 |
+
statusDiv.appendChild(p);
|
115 |
+
};
|
116 |
+
|
117 |
+
form.addEventListener('submit', async (e) => {
|
118 |
+
e.preventDefault();
|
119 |
+
statusDiv.innerHTML = '<h3>์
๋ก๋ ์ํ</h3>';
|
120 |
+
const formData = new FormData(form);
|
121 |
+
|
122 |
+
|
123 |
+
// ํ์ผ ์
๋ก๋ ์์ฒญ
|
124 |
+
const response = await fetch(`/uploadfile/${userId}/`, {
|
125 |
+
method: "POST",
|
126 |
+
body: formData,
|
127 |
+
});
|
128 |
+
|
129 |
+
if (response.ok) {
|
130 |
+
const p = document.createElement('p');
|
131 |
+
p.textContent = "ํ์ผ ์
๋ก๋ ์ฑ๊ณต!";
|
132 |
+
statusDiv.appendChild(p);
|
133 |
+
} else {
|
134 |
+
const p = document.createElement('p');
|
135 |
+
p.textContent = "ํ์ผ ์
๋ก๋ ์คํจ.";
|
136 |
+
p.style.color = "red";
|
137 |
+
statusDiv.appendChild(p);
|
138 |
+
}
|
139 |
+
});
|
140 |
+
</script>
|
141 |
+
</body>
|
142 |
+
</html>
|
app/uploaded_files copy/a.txt
ADDED
File without changes
|
config/database.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# import os
|
2 |
+
# from sqlalchemy import create_engine
|
3 |
+
# from sqlalchemy.ext.declarative import declarative_base
|
4 |
+
# from sqlalchemy.orm import sessionmaker
|
5 |
+
# from sqlalchemy.exc import SQLAlchemyError
|
6 |
+
|
7 |
+
# # MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์
|
8 |
+
# DATABASE_URL = os.getenv("DATABASE_URL", "mysql+mysqlconnector://root:[email protected]:3306/chathess")
|
9 |
+
|
10 |
+
# # SQLAlchemy ์์ง ์์ฑ (์์ธ ์ฒ๋ฆฌ ์ถ๊ฐ)
|
11 |
+
# try:
|
12 |
+
# engine = create_engine(DATABASE_URL)
|
13 |
+
# print("Database engine created successfully.")
|
14 |
+
# except SQLAlchemyError as e:
|
15 |
+
# print("Failed to create database engine.")
|
16 |
+
# print("Error:", e)
|
17 |
+
# engine = None
|
18 |
+
|
19 |
+
# # ์ธ์
์์ฑ (์์ง์ด None์ด๋ฉด ์ธ์
์ด๊ธฐํ ์ ํจ)
|
20 |
+
# if engine:
|
21 |
+
# SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
22 |
+
# else:
|
23 |
+
# SessionLocal = None
|
24 |
+
|
25 |
+
# # Base ํด๋์ค ์์ฑ
|
26 |
+
# Base = declarative_base()
|
27 |
+
|
28 |
+
# # ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์
์์กด์ฑ
|
29 |
+
# def get_db():
|
30 |
+
# if not SessionLocal:
|
31 |
+
# print("Database session is not available.")
|
32 |
+
# raise RuntimeError("Database is not initialized.")
|
33 |
+
|
34 |
+
# db = SessionLocal()
|
35 |
+
# try:
|
36 |
+
# yield db
|
37 |
+
# finally:
|
38 |
+
# db.close()
|
39 |
+
|
gradio/app.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# import gradio as gr
|
2 |
+
# from transformers import pipeline
|
3 |
+
|
4 |
+
# # Hugging Face ์ด๋ฏธ์ง ์์ฑ ๋ชจ๋ธ ๋ก๋
|
5 |
+
# image_generator = pipeline("image-generation", model="CompVis/stable-diffusion-v1-4")
|
6 |
+
|
7 |
+
# # ํจ์ ์ ์
|
8 |
+
# def generate_image(prompt):
|
9 |
+
# result = image_generator(prompt)
|
10 |
+
# return result[0]["image"]
|
11 |
+
|
12 |
+
# # Gradio ์ธํฐํ์ด์ค
|
13 |
+
# demo = gr.Interface(
|
14 |
+
# fn=generate_image, # ํจ์ ์ฐ๊ฒฐ
|
15 |
+
# inputs=gr.Textbox(label="Image Prompt"), # ์
๋ ฅ ํ
์คํธ ๋ฐ์ค
|
16 |
+
# outputs="image", # ์ถ๋ ฅ ์ด๋ฏธ์ง
|
17 |
+
# title="Image Generation with Stable Diffusion",
|
18 |
+
# description="Enter a prompt, and the Stable Diffusion model will generate an image.",
|
19 |
+
# )
|
20 |
+
|
21 |
+
# # ์ธํฐํ์ด์ค ์คํ
|
22 |
+
# if __name__ == "__main__":
|
23 |
+
# demo.launch()
|
models/user_info.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# from sqlalchemy import Column, String, BigInteger, DateTime, ForeignKey
|
2 |
+
# from config.database import Base
|
3 |
+
# from sqlalchemy.dialects.mysql import TINYINT # MySQL TINYINT ํ์
|
4 |
+
|
5 |
+
# class UserInfo(Base):
|
6 |
+
# __tablename__ = "USER_INFO"
|
7 |
+
|
8 |
+
# id = Column(String(36), primary_key=True, comment="ID")
|
9 |
+
# preferred_username = Column(String(50), nullable=True, comment="๋ก๊ทธ์ธ์์ด๋")
|
10 |
+
# mobile = Column(String(15), nullable=True, comment="๋ชจ๋ฐ์ผ")
|
11 |
+
# business_cd = Column(String(8), nullable=True, comment="์์๊ธฐ๊ด์ผ๋ จ๋ฒ")
|
12 |
+
# role_seq = Column(BigInteger, ForeignKey("ROLE.SEQ"), nullable=True, comment="์ญํ ์ผ๋ จ๋ฒํธ")
|
13 |
+
# name = Column(String(255), nullable=True, comment="์ฌ์ฉ์์ด๋ฆ")
|
14 |
+
# email = Column(String(255), nullable=True, comment="์ด๋ฉ์ผ")
|
15 |
+
# profile = Column(String(255), nullable=True, comment="ํ๋กํ")
|
16 |
+
# school_code = Column(String(50), nullable=True, comment="ํ๊ต์ฝ๋")
|
17 |
+
# grade = Column(TINYINT, nullable=True, comment="ํ๋
")
|
18 |
+
# class_name = Column(String(50), nullable=True, comment="ํ๊ธ")
|
19 |
+
# student_no = Column(TINYINT, nullable=True, comment="ํ์๋ฒํธ")
|
20 |
+
# created_at = Column(DateTime, nullable=False, comment="์์ฑ์ผ")
|
21 |
+
# creator_id = Column(String(36), nullable=True, comment="์์ฑ์์์ด๋")
|
22 |
+
# creator_ip = Column(String(50), nullable=True, comment="์์ฑ์IP")
|
23 |
+
# updated_at = Column(DateTime, nullable=True, comment="์์ ์ผ")
|
24 |
+
# updater_id = Column(String(36), nullable=True, comment="์์ ์์์ด๋")
|
25 |
+
# updater_ip = Column(String(50), nullable=True, comment="์์ ์IP")
|
readme.txt
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ํ๋ก์ ํธ ๊ตฌ์ฑ (Windows ํ๊ฒฝ)
|
2 |
+
|
3 |
+
# 1. ํ๋ก์ ํธ ํด๋ ์์ฑ ๋ฐ ํ์ผ ๊ตฌ์ฑ (Windows ๋ช
๋ น์ด)
|
4 |
+
# - ํ๋ก์ ํธ ํด๋: fastapi_upload_project
|
5 |
+
# - ํด๋ ๊ตฌ์กฐ:
|
6 |
+
RAG/
|
7 |
+
โโโ .venv/ # ๊ฐ์ํ๊ฒฝ ํด๋
|
8 |
+
โโโ .vscode/ # VSCode ์ค์ ํด๋
|
9 |
+
โโโ app/ # FastAPI ์ ํ๋ฆฌ์ผ์ด์
ํด๋
|
10 |
+
โ โโโ __pycache__/ # ์บ์ ํ์ผ (์๋ ์์ฑ)
|
11 |
+
โ โโโ resources/ # ์ถ๊ฐ์ ์ธ ๋ฆฌ์์ค (XML ๋ฑ)
|
12 |
+
โ โโโ routers/ # ๋ผ์ฐํฐ ํด๋
|
13 |
+
โ โ โโโ __init__.py # ๋ผ์ฐํฐ ์ด๊ธฐํ ํ์ผ
|
14 |
+
โ โ โโโ user.py # ์ฌ์ฉ์ ๊ด๋ จ ๋ผ์ฐํฐ
|
15 |
+
โ โ โโโ search.py # ๊ฒ์ ๊ด๋ จ ๋ผ์ฐํฐ
|
16 |
+
โ โ โโโ upload.py # ์
๋ก๋ ๊ด๋ จ ๋ผ์ฐํฐ
|
17 |
+
โ โโโ templates/ # HTML ํ
ํ๋ฆฟ ํด๋
|
18 |
+
โ โ โโโ upload.html # ์
๋ก๋ ํ์ด์ง
|
19 |
+
โ โ โโโ search.html # ๊ฒ์ ํ์ด์ง
|
20 |
+
โ โโโ main.py # FastAPI ์ ํ๋ฆฌ์ผ์ด์
์ง์
์
|
21 |
+
โโโ config/ # ์ค์ ๊ด๋ จ ํด๋
|
22 |
+
โ โโโ __pycache__/ # ์บ์ ํ์ผ (์๋ ์์ฑ)
|
23 |
+
โ โโโ database.py # SQLAlchemy ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์
|
24 |
+
โ โโโ mybatis_manager.py # XML ๋งคํผ ๋ฐ SQL ์คํ ๊ด๋ฆฌ
|
25 |
+
โโโ mapper/ # MyBatis XML ๋งคํผ ํด๋
|
26 |
+
โ โโโ user_mapper.xml # ์ฌ์ฉ์ ๋งคํผ XML
|
27 |
+
โ โโโ order_mapper.xml # ์ฃผ๋ฌธ ๋งคํผ XML
|
28 |
+
โ โโโ product_mapper.xml # ์ํ ๋งคํผ XML
|
29 |
+
โโโ models/ # ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ธ ํด๋
|
30 |
+
โ โโโ __pycache__/ # ์บ์ ํ์ผ (์๋ ์์ฑ)
|
31 |
+
โ โโโ user_info.py # ์ฌ์ฉ์ ์ ๋ณด ๋ชจ๋ธ
|
32 |
+
โโโ uploaded_files/ # ์
๋ก๋๋ ํ์ผ ์ ์ฅ์
|
33 |
+
โโโ .gitignore # Git ๋ฌด์ ํ์ผ
|
34 |
+
โโโ requirements.txt # Python ํจํค์ง ์์กด์ฑ
|
35 |
+
โโโ readme.txt # ํ๋ก์ ํธ ์ค๋ช
ํ์ผ
|
36 |
+
|
37 |
+
|
38 |
+
# ๋ผ์ฐํฐ ์ถ๊ฐ
|
39 |
+
# main.py ํ์ผ์ ๋ผ์ฐํฐ ์ถ๊ฐ
|
40 |
+
app.include_router(upload.router)
|
41 |
+
|
42 |
+
# FastAPI ๋ผ์ฐํฐ ํ์ผ ์์ฑ
|
43 |
+
# app/routers/upload.py ํ์ผ์ ํ์ผ ์
๋ก๋ ๊ด๋ จ ๋ผ์ฐํฐ ์์ฑ
|
44 |
+
|
45 |
+
-------------------------------------------------------------------------
|
46 |
+
# ๊ฐ์ ํ๊ฒฝ ์์ฑ ๋ฐ ํจํค์ง ์ค์น (Windows)
|
47 |
+
# Python ๊ฐ์ ํ๊ฒฝ์ ์์ฑํ๊ณ ํ์ํ ํจํค์ง๋ฅผ ์ค์นํ์ธ์.
|
48 |
+
#
|
49 |
+
# python -m venv rag
|
50 |
+
# rag\Scripts\activate
|
51 |
+
# ./rag/scripts/activate.ps1(powershell evn switching)
|
52 |
+
# pip install -r requirements.txt
|
53 |
+
|
54 |
+
# FastAPI ์๋ฒ ์คํ
|
55 |
+
# FastAPI ์๋ฒ๋ฅผ ์คํํ์ธ์.
|
56 |
+
# uvicorn app.main:app --reload
|
57 |
+
# pytorch ์ค์น๋ฅผ ์ํด ํ์ด์ฌ ๋ฒ์ 3.11๋ก ๋ฎ์ถค
|
58 |
+
pip install torch --extra-index-url https://download.pytorch.org/whl/cpu
|
59 |
+
|
60 |
+
-------------------------------------------------------------------------
|
61 |
+
# 7. Docker ์ด๋ฏธ์ง ๋น๋&์คํ
|
62 |
+
# docker build -t app .
|
63 |
+
# docker run -d -p 8000:8000 app
|
requirements.txt
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Web framework
|
2 |
+
fastapi[all]
|
3 |
+
|
4 |
+
# Database interaction
|
5 |
+
#sqlalchemy
|
6 |
+
#mysql-connector-python
|
7 |
+
|
8 |
+
# ASGI server
|
9 |
+
uvicorn
|
10 |
+
|
11 |
+
# File upload support
|
12 |
+
python-multipart
|
13 |
+
|
14 |
+
# Template engine
|
15 |
+
Jinja2
|
16 |
+
|
17 |
+
# LangChain for LLMs and AI workflow management
|
18 |
+
langchain
|
19 |
+
|
20 |
+
# LangChain HuggingFace integration
|
21 |
+
langchain-huggingface>=0.1.2
|
22 |
+
|
23 |
+
# Vector search and similarity
|
24 |
+
faiss-cpu
|
25 |
+
|
26 |
+
# OpenAI API (uncomment if needed)
|
27 |
+
#openai
|
28 |
+
|
29 |
+
# PDF processing
|
30 |
+
pypdf2
|
31 |
+
pypdf
|
32 |
+
|
33 |
+
# Community package for LangChain
|
34 |
+
langchain-community>=0.0.1
|
35 |
+
|
36 |
+
# Hugging Face integration
|
37 |
+
huggingface-hub>=0.23.0
|
38 |
+
|
39 |
+
protobuf
|
40 |
+
|
41 |
+
# Sentence Transformers for embeddings
|
42 |
+
sentence-transformers>=2.2.0, <4.0.0
|
43 |
+
|
44 |
+
# PyTorch installation from CPU-specific index
|
45 |
+
torch --extra-index-url https://download.pytorch.org/whl/cpu
|
46 |
+
|
47 |
+
# Gradio for building UI
|
48 |
+
#gradio
|
uploaded_files/a.txt
ADDED
File without changes
|