ngxquang commited on
Commit
4c7b93d
1 Parent(s): 25b822d

feat: metadata service

Browse files
.env ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # PROJECT INFORMATION
2
+ HOST=0.0.0.0
3
+ PORT=7860
4
+ CORS_HEADERS=["*"]
5
+ CORS_ORIGINS=["*"]
6
+ POLICY_FILE_PATH="./policy.json"
Dockerfile ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.8-slim
2
+
3
+ RUN apt-get update && \
4
+ apt-get install git bash wget iputils-ping -y && \
5
+ apt clean && \
6
+ rm -rf /var/cache/apt/*
7
+
8
+ WORKDIR /code
9
+
10
+ COPY requirements.txt /code/requirements.txt
11
+
12
+ # PYTHONDONTWRITEBYTECODE=1: Disables the creation of .pyc files (compiled bytecode)
13
+ # PYTHONUNBUFFERED=1: Disables buffering of the standard output stream
14
+ # PYTHONIOENCODING: specifies the encoding to be used for the standard input, output, and error streams
15
+ ENV PYTHONDONTWRITEBYTECODE=1 \
16
+ PYTHONUNBUFFERED=1 \
17
+ PYTHONIOENCODING=utf-8
18
+
19
+ RUN pip install -U pip && \
20
+ python -m pip install -r /code/requirements.txt
21
+
22
+ RUN useradd -m -u 1000 user
23
+
24
+ USER user
25
+
26
+ ENV HOME=/home/user \
27
+ PATH=/home/user/.local/bin:$PATH
28
+
29
+ WORKDIR $HOME/app
30
+
31
+ COPY --chown=user . $HOME/app
32
+
33
+ CMD python ./src/main.py
policy.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "service_account",
3
+ "project_id": "vinid-playground",
4
+ "private_key_id": "5546404edff790939b5175043e6b50edd10332ab",
5
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDOBfBeBGUTEliR\nIeLJ5lye2zJ3OCOjmZrvLI6afHVse215ND2MP5OvfLHhjdDhglbLYbNeBUQCHUYl\n2nCjBrMgyOv05dWr/nVWqIvMnAMrm65HC5x1eTT2SPaRq+IXFgjA6sNwnmO9bfIV\n3GYcGXxQvBZyWG1EleG02Ptu0KQ8i0SFgFsplmVfM26iIwQV7HaPuyzXIpWnyGs9\nbKE7Rw2RTnVFhW0rt3mFsPynri6VXB8X9snFcFr/VEBD2+Nr15/aqh/omKvrC5RL\nT1SXH64XezWiVT2dxMw+Ls5ZugiwxK1FhTU2VmRa+QGeT7iclmBp03ZhfaUj/gg2\nE4dJucjjAgMBAAECggEAQ75NLsT4LUC7kaFYTrYqH2wJGI2DnoBcIyf+Dgs9mzms\nog2M7WhcWfhBD18P3475li+eiJxno+BXWAwPPHPwA6g9eg325/KoR6HtMg7ctgKf\nWCoXvMLpqNAOD5E6qweqQjEPqaDTQA7+arTJeJTivTNTmC6+Yy57hHlSl7oQPv2f\nL0Datre9kpEvgqVYi207EO4CF3+JMIaqNR4sSd6CpQnaLuCEyrvds+X3MMCSYR+N\nJoDjs/FeR2q/hDtPaulxmv1M7rR89k9JHMouszjxX4kBtVhKQeMo7JXd8FQgPvyK\nqpVteMhQrYGjE5HSaF3QU01yhv3xWbcoWltUYSNR1QKBgQDqTGjTAQcwo/Ig5Nbj\nta3ZcHeQLyhZ7PICtV6SHGbB8rI1GYPojdQCqF6bj3RPTsr6O/XIKrpc13tkLloR\n+YaGnHtj91CgOf8Iy5Uw5rkG4zfb/vmUxElrzPUESX1QO+GSx9nEJxnoEgvtjobi\nmRtajGiJAKgBzPwT3v+hg3BOdQKBgQDhGxPciFnvLbTO8DWPESunafZaP7z5StOG\nVYa+y8fSvOQ9ExR/6lUBLQaxcJ0BjtTg3Bk26QO+CDAFdH4iObG3JEk9D+VrRYL9\n3PqJ+s6tCxJovSeYjHAHKfrsCvMyVxh1gVJR7SyJna1zOhVIGnD1ZfuNRdajR1IL\ny9ou+67+9wKBgQCsPEleu8W+UvbeiXsS3+6SBqROIOyH1rA9n3iK7kf30WKBuGUI\noqI05fLOZlF5L5H1C/jtEcP4FgvGJHDf/8+NyyDF5vulHZ1GqOneje18i7H3jmOI\nohbbIUsIwMFXJv32+eUy1g+sUv/jvT+Y+jZqhQcfl5Tp5fd04ByJbec0NQKBgQDM\nMBqhBVHGwgfrWjrK7oFRl61uCbjpzHT4umXCdehpAQxrVf5XVYEL0wLqO0M/4Ya5\n/QwmIdFSM+0TVasAcqMAhDqm1997oY8DpcnhFQ8aKhvlxAbBukn4RZ0lNX2KYTR/\nifHY/LFUlyF5jus0/z8Nahd2+y2J6CzFJIFh8sy22wKBgH/flv5SiFZPM21fh3VC\nSC7KOlJBNVrEloGdc91vGH2cDGuMZhJh+YHiOBXzf0751qqqJhGzbpi2tNQn3M+Q\n2Iglw6JU6+i8XMDw5HJszjfp2KYPXKHmoPFVsqQ0U5AkEyglbveLX94CRZt1ON/a\nXgoIt1blT7sM2raf6+Gl+SdM\n-----END PRIVATE KEY-----\n",
6
+ "client_email": "iac-demo@vinid-playground.iam.gserviceaccount.com",
7
+ "client_id": "103848892899493800751",
8
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
+ "token_uri": "https://oauth2.googleapis.com/token",
10
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/iac-demo%40vinid-playground.iam.gserviceaccount.com",
12
+ "universe_domain": "googleapis.com"
13
+ }
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi==0.103.1
2
+ uvicorn==0.23.2
3
+ pydantic-settings==2.0.3
4
+ firebase_admin
5
+ # Project settings, for development only
6
+ # pre-commit
src/__init__.py ADDED
File without changes
src/__pycache__/config.cpython-311.pyc ADDED
Binary file (1.13 kB). View file
 
src/__pycache__/main.cpython-311.pyc ADDED
Binary file (3.09 kB). View file
 
src/config.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ from pydantic_settings import BaseSettings
4
+
5
+ FILE = Path(__file__)
6
+ ROOT = FILE.parent.parent
7
+
8
+
9
+ class Settings(BaseSettings):
10
+ # API SETTINGS
11
+ HOST: str
12
+ PORT: int
13
+ CORS_ORIGINS: list
14
+ CORS_HEADERS: list
15
+ POLICY_FILE_PATH: str
16
+
17
+ class Config:
18
+ env_file = ROOT / ".env"
19
+
20
+
21
+ settings = Settings()
src/itr/__init__.py ADDED
File without changes
src/itr/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (200 Bytes). View file
 
src/itr/__pycache__/router.cpython-311.pyc ADDED
Binary file (4.44 kB). View file
 
src/itr/router.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, status, Response, Path
2
+ from fastapi.responses import JSONResponse, StreamingResponse
3
+ from pydantic import BaseModel
4
+
5
+ # from google.cloud import storage
6
+ from config import settings
7
+ import datetime
8
+ import firebase_admin
9
+ from firebase_admin import credentials
10
+ from firebase_admin import storage
11
+
12
+ from google.cloud import storage
13
+ from pathlib import Path
14
+
15
+ import numpy as np
16
+ import csv
17
+ import json
18
+ import os
19
+
20
+ # cred = credentials.Certificate(settings.POLICY_FILE_PATH)
21
+ # app = firebase_admin.initialize_app(cred, {'storageBucket': 'cnc-designs.appspot.com'}, name='storage')
22
+ # bucket = storage.bucket(app=app)
23
+
24
+ CWD = Path(__file__).parent
25
+
26
+ # client = storage.Client()
27
+ client = storage.Client.from_service_account_json(
28
+ os.path.join(CWD.parent.parent, settings.POLICY_FILE_PATH)
29
+ )
30
+ bucket = client.bucket("thangtd1")
31
+
32
+ router = APIRouter()
33
+
34
+
35
+ @router.get("/{video}/metadata")
36
+ async def get_length(video: str) -> JSONResponse:
37
+ print(video)
38
+ try:
39
+ path_file = "metadata/" + video + ".json"
40
+ blob = bucket.blob(path_file)
41
+
42
+ metadata = {}
43
+
44
+ with blob.open("r") as f:
45
+ metadata = json.load(f)
46
+
47
+ except Exception:
48
+ return JSONResponse(
49
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
50
+ content={"message": "err"},
51
+ )
52
+
53
+ return JSONResponse(status_code=status.HTTP_200_OK, content=metadata)
54
+
55
+
56
+ @router.get("/{video}/keyframes/list")
57
+ async def get_list_keyframes(video: str) -> JSONResponse:
58
+ path_file = "Keyframes/" + video
59
+ list_keyframes = []
60
+ meta_data = []
61
+
62
+ path_meta_file = "map-keyframes/" + video + ".csv"
63
+
64
+ blob = bucket.blob(path_meta_file)
65
+ with blob.open("r") as f:
66
+ reader = csv.reader(f)
67
+ meta_data = list(reader)
68
+ # print(meta_data[0])
69
+ meta_data = np.array(meta_data[1:])
70
+
71
+ for blob in client.list_blobs("thangtd1", prefix=path_file):
72
+ list_keyframes.append([str(blob.name)])
73
+
74
+ list_keyframes = np.array(list_keyframes)
75
+
76
+ list_keyframes = np.append(list_keyframes, meta_data, axis=1)
77
+
78
+ return JSONResponse(
79
+ status_code=status.HTTP_200_OK,
80
+ content={"list_keyframes": list_keyframes.tolist()},
81
+ )
82
+
83
+
84
+ @router.get("/stream_video/{bucket_name}/{video_blob_name}")
85
+ async def stream_video(
86
+ bucket_name: str,
87
+ video_blob_name: str,
88
+ response: Response = None,
89
+ ) -> JSONResponse:
90
+ path_file = "Video/" + video_blob_name
91
+
92
+ # blob = bucket.blob(path_file)
93
+
94
+ # url = blob.generate_signed_url(
95
+ # This URL is valid for 15 minutes
96
+ # expiration=datetime.timedelta(minutes=15),
97
+ # Allow GET requests using this URL.
98
+ # method='GET'
99
+ # )
100
+
101
+ # print(url)
102
+
103
+ # return JSONResponse(status_code=status.HTTP_200_OK, content = {"url" : url})
104
+
105
+ # if not blob.exists():
106
+ # return StreamingResponse(
107
+ # content_generator([b"Video not found"]), media_type="text/plain"
108
+ # )
109
+
110
+ # # Stream the video in chunks
111
+ # def content_generator():
112
+ # for chunk in blob.download_as_bytes(start=0, end=blob.size, raw_download=True):
113
+ # yield chunk
114
+
115
+ # return StreamingResponse(content_generator(), media_type="video/mp4")
src/itr/router/README.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # BEiT-3 Weight and Sentencepiece models
2
+
3
+ 1. Please download [beit3_base_patch16_384_retrieval.pth](https://conversationhub.blob.core.windows.net/beit-share-public/beit3/f30k_retrieval/beit3_base_patch16_384_f30k_retrieval.pth?sv=2021-10-04&st=2023-06-08T11%3A16%3A02Z&se=2033-06-09T11%3A16%3A00Z&sr=c&sp=r&sig=N4pfCVmSeq4L4tS8QbrFVsX6f6q844eft8xSuXdxU48%3D) and [beit3.spm](https://conversationhub.blob.core.windows.net/beit-share-public/beit3/sentencepiece/beit3.spm?sv=2021-10-04&st=2023-06-08T11%3A16%3A02Z&se=2033-06-09T11%3A16%3A00Z&sr=c&sp=r&sig=N4pfCVmSeq4L4tS8QbrFVsX6f6q844eft8xSuXdxU48%3D) model.
4
+
5
+ 2. Put those 2 model inside this folder
6
+
src/main.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from config import settings
5
+ from fastapi import FastAPI, Request, status
6
+ from fastapi.exceptions import RequestValidationError
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.responses import JSONResponse, RedirectResponse
9
+ from itr.router import router as router
10
+
11
+ import os
12
+
13
+ os.environ["KMP_DUPLICATE_LIB_OK"] = "True"
14
+
15
+
16
+ app = FastAPI(title="Metadata API")
17
+
18
+ SERVICE_ROOT = Path(__file__).parent.parent
19
+
20
+
21
+ app.add_middleware(
22
+ CORSMiddleware,
23
+ allow_origins=["*"],
24
+ allow_headers=["*"],
25
+ allow_credentials=True,
26
+ allow_methods=["*"],
27
+ )
28
+
29
+
30
+ @app.exception_handler(RequestValidationError)
31
+ async def validation_exception_handler(request: Request, exc: RequestValidationError):
32
+ # Get the original 'detail' list of errors
33
+ details = exc.errors()
34
+ error_details = []
35
+
36
+ for error in details:
37
+ error_details.append({"error": f"{error['msg']} {str(error['loc'])}"})
38
+ return JSONResponse(content={"message": error_details})
39
+
40
+
41
+ @app.on_event("startup")
42
+ async def startup_event():
43
+ pass
44
+
45
+
46
+ @app.get("/", include_in_schema=False)
47
+ async def root() -> None:
48
+ return RedirectResponse("/docs")
49
+
50
+
51
+ @app.get("/health", status_code=status.HTTP_200_OK, tags=["health"])
52
+ async def perform_healthcheck() -> None:
53
+ return JSONResponse(content={"message": "success"})
54
+
55
+
56
+ app.include_router(router)
57
+
58
+
59
+ # Start API
60
+ if __name__ == "__main__":
61
+ import uvicorn
62
+
63
+ uvicorn.run("main:app", host=settings.HOST, port=settings.PORT, reload=True)