Change architecture, Main functionality, Little practise HTML template
This commit is contained in:
parent
20379f8d37
commit
6e8ec4f0f1
@ -1,8 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/server/floris_module/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/server/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/server/floris_module/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.12 (EvaluationEfficiencyOptimizationWind)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="bootstrap" level="application" />
|
||||
<orderEntry type="library" name="@popperjs/core" level="application" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/server/src/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</module>
|
@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (EvaluationEfficiencyOptimizationWind) (2)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (EvaluationEfficiencyOptimizationWind)" project-jdk-type="Python SDK" />
|
||||
</project>
|
6
.idea/other.xml
Normal file
6
.idea/other.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PySciProjectComponent">
|
||||
<option name="PY_INTERACTIVE_PLOTS_SUGGESTED" value="true" />
|
||||
</component>
|
||||
</project>
|
@ -5,7 +5,7 @@ import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
|
||||
const __dirname = path.resolve();
|
||||
|
||||
const config = {
|
||||
entry: './src/index.tsx',
|
||||
entry: './routers/index.tsx',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'main.js',
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
@ -1,4 +1,14 @@
|
||||
import os.path
|
||||
import sys
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
from floris import FlorisModel
|
||||
from floris.flow_visualization import visualize_cut_plane
|
||||
from floris.layout_visualization import plot_turbine_labels
|
||||
import floris.layout_visualization as layoutviz
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
_wind_direction_to_val: dict[str, float] = {
|
||||
@ -31,13 +41,34 @@ def _check_wind_direction_definition(wind_direction: str) -> bool:
|
||||
|
||||
|
||||
class FlorisULSTU(FlorisModel):
|
||||
def __init__(self, url_yaml):
|
||||
def __init__(
|
||||
self,
|
||||
url_yaml: Path = Path(__file__).parent / "gch.yaml"
|
||||
):
|
||||
super().__init__(url_yaml)
|
||||
|
||||
def set(self, **kwargs):
|
||||
if ("wind_directions" in kwargs) and (kwargs["wind_directions"] is list[str]):
|
||||
if ("wind_directions" in kwargs) and (type(kwargs["wind_directions"][0]) is str):
|
||||
kwargs["wind_directions"] = _convert_winds_list_direction_definitions(kwargs["wind_directions"])
|
||||
|
||||
super().set(**kwargs)
|
||||
|
||||
def visualisation(self):
|
||||
|
||||
|
||||
self.reset_operation()
|
||||
|
||||
horizontal_plane = self.calculate_horizontal_plane(height=90.0)
|
||||
visualize_cut_plane(
|
||||
horizontal_plane,
|
||||
)
|
||||
|
||||
# plot_turbine_labels(self, axarr[0, 0])
|
||||
filename = str(uuid.uuid4()) + ".png"
|
||||
plt.savefig(Path(__file__).parent.parent.parent / f"public/floris/{filename}")
|
||||
plt.close()
|
||||
|
||||
return filename
|
||||
|
||||
|
||||
|
3
server/floris_module/src/__init__.py
Normal file
3
server/floris_module/src/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
from .FlorisULSTU import FlorisULSTU
|
||||
|
||||
__all__ = ['FlorisULSTU']
|
@ -149,9 +149,9 @@ flow_field:
|
||||
wake:
|
||||
|
||||
###
|
||||
# Select the models to use for the simulation.
|
||||
# Select the data to use for the simulation.
|
||||
# See :py:mod:`~.wake` for a list
|
||||
# of available models and their descriptions.
|
||||
# of available data and their descriptions.
|
||||
model_strings:
|
||||
|
||||
###
|
||||
@ -190,7 +190,7 @@ wake:
|
||||
# Configure the parameters for the wake deflection model
|
||||
# selected above.
|
||||
# Additional blocks can be provided for
|
||||
# models that are not enabled, but the enabled model
|
||||
# data that are not enabled, but the enabled model
|
||||
# must have a corresponding parameter block.
|
||||
wake_deflection_parameters:
|
||||
gauss:
|
||||
@ -210,7 +210,7 @@ wake:
|
||||
# Configure the parameters for the wake velocity deficit model
|
||||
# selected above.
|
||||
# Additional blocks can be provided for
|
||||
# models that are not enabled, but the enabled model
|
||||
# data that are not enabled, but the enabled model
|
||||
# must have a corresponding parameter block.
|
||||
wake_velocity_parameters:
|
||||
cc:
|
||||
@ -234,7 +234,7 @@ wake:
|
||||
# Configure the parameters for the wake turbulence model
|
||||
# selected above.
|
||||
# Additional blocks can be provided for
|
||||
# models that are not enabled, but the enabled model
|
||||
# data that are not enabled, but the enabled model
|
||||
# must have a corresponding parameter block.
|
||||
wake_turbulence_parameters:
|
||||
crespo_hernandez:
|
@ -1,58 +0,0 @@
|
||||
from fastapi import FastAPI, Depends, Request
|
||||
from fastapi.responses import RedirectResponse, HTMLResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.future import select
|
||||
from database import SessionLocal, User, Base, engine
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from src.floris_router import router as floris_router
|
||||
from src.floris_router import get_images
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
app = FastAPI()
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
app.mount("/public", StaticFiles(directory="public"), name="public")
|
||||
|
||||
app.include_router(floris_router)
|
||||
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@app.get("/hello")
|
||||
async def hello():
|
||||
return {"message": "Hello, World!"}
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def redirect_to_docs():
|
||||
return RedirectResponse(url="/docs")
|
||||
|
||||
|
||||
@app.get("/users")
|
||||
def read_users(db: Session = Depends(get_db)):
|
||||
result = db.execute(select(User))
|
||||
users = result.scalars().all() # Получаем всех пользователей
|
||||
return users
|
||||
|
||||
|
||||
@app.get("/main", response_class=HTMLResponse)
|
||||
async def main(request: Request):
|
||||
params = {"request": request}
|
||||
params.update(await get_images())
|
||||
|
||||
return templates.TemplateResponse("main.html", params)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="localhost", port=8080) # Изменено на localhost
|
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
11
server/src/data/database.py
Normal file
11
server/src/data/database.py
Normal file
@ -0,0 +1,11 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
# TODO Maybe create env file
|
||||
DATABASE_URL = "mysql+pymysql://wind:wind@193.124.203.110:3306/wind_towers"
|
||||
|
||||
engine = create_engine(DATABASE_URL)
|
||||
session_maker = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
|
||||
|
@ -1,28 +1,15 @@
|
||||
from sqlalchemy import create_engine, Column, Integer, String
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column
|
||||
from sqlalchemy.dialects.mysql import TIMESTAMP, TIME, VARCHAR
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
DATABASE_URL = "mysql+pymysql://wind:wind@193.124.203.110:3306/wind_towers"
|
||||
|
||||
engine = create_engine(DATABASE_URL)
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase
|
||||
from sqlalchemy.dialects.mysql import TIMESTAMP, TIME, VARCHAR
|
||||
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "user" # Убедитесь, что эта таблица существует
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(50), index=True)
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class Weather(Base):
|
||||
__tablename__ = "weather"
|
||||
__tablename__ = "weather_data"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
BarTrend: Mapped[str] = mapped_column(VARCHAR(255))
|
||||
@ -46,3 +33,4 @@ class Weather(Base):
|
||||
WindDir: Mapped[str] = mapped_column(VARCHAR(50))
|
||||
WindSpeed: Mapped[float]
|
||||
WindSpeed10Min: Mapped[float]
|
||||
|
27
server/src/data/repository.py
Normal file
27
server/src/data/repository.py
Normal file
@ -0,0 +1,27 @@
|
||||
from sqlalchemy import select
|
||||
|
||||
from .database import session_maker
|
||||
from .models import Weather
|
||||
from .schemas import SWeatherInfo
|
||||
|
||||
|
||||
class WeatherRepository:
|
||||
@classmethod
|
||||
def get_all(cls):
|
||||
with session_maker() as session:
|
||||
query = (
|
||||
select(Weather)
|
||||
)
|
||||
res = session.execute(query)
|
||||
weather_models = res.scalars().all()
|
||||
return [SWeatherInfo.model_validate(weather, from_attributes=True) for weather in weather_models]
|
||||
|
||||
@classmethod
|
||||
def get_by_id(cls, id):
|
||||
with session_maker() as session:
|
||||
query = (
|
||||
select(Weather).where(Weather.id == id)
|
||||
)
|
||||
res = session.execute(query)
|
||||
weather_model = res.scalars().first()
|
||||
return SWeatherInfo.model_validate(weather_model, from_attributes=True)
|
19
server/src/data/schemas.py
Normal file
19
server/src/data/schemas.py
Normal file
@ -0,0 +1,19 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from fastapi import Query
|
||||
|
||||
|
||||
class SWeatherInfo(BaseModel):
|
||||
id: int
|
||||
WindDir: str
|
||||
WindSpeed: float
|
||||
|
||||
|
||||
class SFlorisInputParams(BaseModel):
|
||||
weather_id: int
|
||||
layout_x: list[float] = Field(Query([]))
|
||||
layout_y: list[float] = Field(Query([]))
|
||||
|
||||
|
||||
class SFlorisOutputData(BaseModel):
|
||||
file_name: str
|
||||
data: list[float]
|
@ -1,36 +0,0 @@
|
||||
from pathlib import Path
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
|
||||
STATIC_DIR = Path("public/floris")
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/floris",
|
||||
tags=["Static Files from Floris"],
|
||||
)
|
||||
|
||||
|
||||
@router.get("/get_images")
|
||||
async def get_images():
|
||||
try:
|
||||
images = [file.name for file in STATIC_DIR.iterdir() if file.is_file()]
|
||||
return {"images": images}
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/download_image/{image_name}")
|
||||
async def download_image(
|
||||
image_name: str
|
||||
):
|
||||
image_path = STATIC_DIR / image_name
|
||||
if not image_path.exists() or not image_path.is_file():
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
return FileResponse(image_path, media_type="image/jpeg", filename=image_name)
|
||||
|
||||
|
||||
|
22
server/src/main.py
Normal file
22
server/src/main.py
Normal file
@ -0,0 +1,22 @@
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from routers.floris_router import router as floris_router
|
||||
from routers.floris_template_router import router as floris_template_router
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.mount("/static", StaticFiles(directory=Path("../static")), name="static")
|
||||
app.mount("/public", StaticFiles(directory=Path("../public")), name="public")
|
||||
|
||||
app.include_router(floris_router)
|
||||
app.include_router(floris_template_router)
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# import uvicorn
|
||||
# uvicorn.run(app, host="localhost", port=8080) # Изменено на localhost
|
@ -1 +0,0 @@
|
||||
st
|
73
server/src/routers/floris_router.py
Normal file
73
server/src/routers/floris_router.py
Normal file
@ -0,0 +1,73 @@
|
||||
from http import HTTPStatus
|
||||
from pathlib import Path
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
from data.repository import WeatherRepository
|
||||
from data.schemas import SFlorisInputParams, SFlorisOutputData, SWeatherInfo
|
||||
|
||||
from FlorisULSTU import FlorisULSTU
|
||||
|
||||
FLORIS_IMAGES_PATH = Path("public/floris")
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/api/floris",
|
||||
tags=["Floris Api"],
|
||||
)
|
||||
|
||||
|
||||
@router.get("/get_windmill_data")
|
||||
async def get_windmill_data(
|
||||
data: Annotated[SFlorisInputParams, Depends()]
|
||||
):
|
||||
if len(data.layout_x) != len(data.layout_y):
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail="Length of layout x and y must be the same",
|
||||
)
|
||||
|
||||
atmosphere_param: SWeatherInfo = WeatherRepository().get_by_id(data.weather_id)
|
||||
|
||||
fmodel = FlorisULSTU()
|
||||
fmodel.set(
|
||||
layout_x=data.layout_x,
|
||||
layout_y=data.layout_y,
|
||||
wind_directions=[atmosphere_param.WindDir],
|
||||
wind_speeds=[atmosphere_param.WindSpeed],
|
||||
)
|
||||
fmodel.run()
|
||||
|
||||
data = fmodel.get_turbine_powers()[0].tolist()
|
||||
file_name = fmodel.visualisation()
|
||||
|
||||
return SFlorisOutputData(
|
||||
file_name=file_name,
|
||||
data=data
|
||||
)
|
||||
|
||||
|
||||
@router.get("/get_images")
|
||||
async def get_images():
|
||||
try:
|
||||
images = [file.name for file in FLORIS_IMAGES_PATH.iterdir() if file.is_file()]
|
||||
return {"images": images}
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/download_image/{image_name}")
|
||||
async def download_image(
|
||||
image_name: str
|
||||
):
|
||||
image_path = FLORIS_IMAGES_PATH / image_name
|
||||
if not image_path.exists() or not image_path.is_file():
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
return FileResponse(image_path, media_type="image/jpeg", filename=image_name)
|
||||
|
||||
|
||||
|
65
server/src/routers/floris_template_router.py
Normal file
65
server/src/routers/floris_template_router.py
Normal file
@ -0,0 +1,65 @@
|
||||
from pathlib import Path
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Request, Form, Depends
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from data.repository import WeatherRepository
|
||||
from data.schemas import SFlorisInputParams
|
||||
|
||||
from routers.floris_router import get_windmill_data
|
||||
|
||||
templates = Jinja2Templates(directory=Path("../templates/floris_templates"))
|
||||
|
||||
router = APIRouter(
|
||||
prefix="",
|
||||
tags=["floris_template"],
|
||||
include_in_schema=False,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/", response_class=HTMLResponse)
|
||||
async def get_main(request: Request, context: dict | None = None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
params = {"request": request, "weather": WeatherRepository.get_all()}
|
||||
|
||||
if context is not None:
|
||||
params.update(context)
|
||||
|
||||
return templates.TemplateResponse("main.html", params)
|
||||
|
||||
|
||||
def transform_windmill_data(
|
||||
options: Annotated[str, Form()],
|
||||
x: Annotated[str, Form()],
|
||||
y: Annotated[str, Form()]
|
||||
) -> SFlorisInputParams | None:
|
||||
|
||||
if not all([options, x, y]):
|
||||
return None
|
||||
|
||||
return SFlorisInputParams(
|
||||
weather_id=int(options),
|
||||
layout_x=list(map(float, x.split())),
|
||||
layout_y=list(map(float, y.split())),
|
||||
)
|
||||
|
||||
|
||||
@router.post("/", response_class=HTMLResponse)
|
||||
async def post_main(
|
||||
request: Request,
|
||||
windmill_params: Annotated[SFlorisInputParams | None, Depends(transform_windmill_data)] = None,
|
||||
):
|
||||
if windmill_params is None:
|
||||
return await get_main(request)
|
||||
|
||||
data = await get_windmill_data(windmill_params)
|
||||
context = {
|
||||
'data': data.data,
|
||||
'file_name': data.file_name,
|
||||
}
|
||||
|
||||
return await get_main(request, context)
|
85
server/templates/floris_templates/main.html
Normal file
85
server/templates/floris_templates/main.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Image Viewer</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/css/bootstrap.min.css" integrity="sha512-T584yQ/tdRR5QwOpfvDfVQUidzfgc2339Lc8uBDtcp/wYu80d7jwBgAxbyMh0a9YM9F8N3tdErpFI8iaGx6x5g==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.min.js" integrity="sha512-UR25UO94eTnCVwjbXozyeVd6ZqpaAE9naiEUBK/A+QDbfSTQFhPGj5lOR6d8tsgbBk84Ggb5A3EkjsOgPRPcKA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="row m-5">
|
||||
<form class="col" method="post">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="btn-group" data-toggle="buttons">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Wind Direction</th>
|
||||
<th scope="col">Wind Speed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
{% for row in weather %}
|
||||
<tr>
|
||||
<th>
|
||||
<label class="btn btn-outline-primary">{{ row.id }}
|
||||
<input type="radio" class="btn-check"
|
||||
name="options" id="option_{{ row.id }}" value="{{ row.id }}" autocomplete="off">
|
||||
</label>
|
||||
</th>
|
||||
<td>{{ row.WindDir }}</td>
|
||||
<td>{{ row.WindSpeed }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="input-group flex-nowrap">
|
||||
<span class="input-group-text" id="addon-wrapping">X</span>
|
||||
<input name="x" type="text" class="form-control" placeholder="X axis" aria-label="X axis" aria-describedby="addon-wrapping">
|
||||
</div>
|
||||
<div class="input-group flex-nowrap">
|
||||
<span class="input-group-text" id="addon-wrapping">Y</span>
|
||||
<input name="y" type="text" class="form-control" placeholder="Y axis" aria-label="Y axis" aria-describedby="addon-wrapping">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Submit</button>
|
||||
</form>
|
||||
<div class="col">
|
||||
{{ data }}
|
||||
{% if data is defined %}
|
||||
<img id="display-image" src="/public/floris/{{ file_name }}" alt="Selected Image">
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
function selectImage(imageName) {
|
||||
const imgElement = document.getElementById('display-image');
|
||||
imgElement.src = `/public/floris/${imageName}`;
|
||||
}
|
||||
|
||||
function generateImage() {
|
||||
alert("Image generation functionality not implemented yet.");
|
||||
}
|
||||
|
||||
function downloadImage() {
|
||||
const imgElement = document.getElementById('display-image');
|
||||
const imageName = imgElement.src.split('/').pop();
|
||||
window.location.href = `/floris/download_image/${imageName}`;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Image Viewer</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="image-viewer">
|
||||
<img id="display-image" src="/public/floris/Yaw_example.png" alt="Selected Image">
|
||||
<button onclick="generateImage()">Generate Image</button>
|
||||
<button onclick="downloadImage()">Download Image</button>
|
||||
</div>
|
||||
<div class="image-list">
|
||||
<h3>Available Images</h3>
|
||||
<ul id="image-list">
|
||||
{% for image in images %}
|
||||
<li onclick="selectImage('{{ image }}')">{{ image }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function selectImage(imageName) {
|
||||
const imgElement = document.getElementById('display-image');
|
||||
imgElement.src = `/public/floris/${imageName}`;
|
||||
}
|
||||
|
||||
function generateImage() {
|
||||
alert("Image generation functionality not implemented yet.");
|
||||
}
|
||||
|
||||
function downloadImage() {
|
||||
const imgElement = document.getElementById('display-image');
|
||||
const imageName = imgElement.src.split('/').pop();
|
||||
window.location.href = `/floris/download_image/${imageName}`;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user