fix install diogram
This commit is contained in:
@@ -24,6 +24,7 @@ from sqlalchemy.orm import Session as SASession
|
||||
|
||||
from bd import make_engine
|
||||
from bd.tables.response import Response, Answer
|
||||
from bd.tables.poll import Poll
|
||||
from bd.tables.scale import ScaleDimension, ChoiceScore
|
||||
from bd.tables.radar_result import RadarResult, RadarResultItem
|
||||
from route.radar_svg_gen import save_radar_svg
|
||||
@@ -110,7 +111,8 @@ def compute_radar(response_id: uuid.UUID, session: SASession) -> RadarResult:
|
||||
session.add(result)
|
||||
session.flush() # чтобы получить result.id до добавления items
|
||||
|
||||
for dim in sorted(dimensions, key=lambda d: (d.position is None, d.position)):
|
||||
dims_sorted = sorted(dimensions, key=lambda d: (d.position is None, d.position))
|
||||
for dim in dims_sorted:
|
||||
item = RadarResultItem(
|
||||
result_id=result.id,
|
||||
dimension_id=dim.id,
|
||||
@@ -121,29 +123,35 @@ def compute_radar(response_id: uuid.UUID, session: SASession) -> RadarResult:
|
||||
)
|
||||
session.add(item)
|
||||
|
||||
session.commit()
|
||||
session.refresh(result)
|
||||
|
||||
# Сохраняем SVG-файл на сервере
|
||||
# Генерируем SVG до коммита — result.id уже известен после flush(),
|
||||
# items_data строим из scores_map/dimensions (они в памяти, не из БД).
|
||||
# Так result + items + image_path фиксируются в одной транзакции.
|
||||
items_data = [
|
||||
{
|
||||
"dimension_name": item.dimension_name,
|
||||
"dimension_color": item.dimension_color,
|
||||
"value": item.value,
|
||||
"dimension_name": dim.name,
|
||||
"dimension_color": dim.color,
|
||||
"value": scores_map[dim.id],
|
||||
}
|
||||
for item in sorted(result.items, key=lambda i: (i.dimension_position is None, i.dimension_position))
|
||||
for dim in dims_sorted
|
||||
]
|
||||
max_val = max((it["value"] for it in items_data), default=1.0)
|
||||
max_val = max(max_val, 14.0)
|
||||
try:
|
||||
rel_path = save_radar_svg(str(result.id), items_data, max_val)
|
||||
with session.begin_nested():
|
||||
result.image_path = rel_path
|
||||
session.commit()
|
||||
session.refresh(result)
|
||||
poll = session.get(Poll, resp.poll_id)
|
||||
poll_title = poll.title if poll else "unknown"
|
||||
user_id_str = str(resp.user_id) if resp.user_id else "anonymous"
|
||||
rel_path = save_radar_svg(
|
||||
str(result.id), items_data,
|
||||
max_val=0.0, # автомасштаб: шкала строится от данных
|
||||
poll_title=poll_title,
|
||||
user_id=user_id_str,
|
||||
scale_padding=0.2, # +20% запаса над максимумом
|
||||
min_scale=5.0, # шкала не менее 5 даже для малых значений
|
||||
)
|
||||
result.image_path = rel_path
|
||||
except Exception:
|
||||
pass # не ломаем сдачу, если запись файла не удалась
|
||||
pass # не ломаем сдачу, если генерация файла не удалась
|
||||
|
||||
session.commit() # единственный коммит: result + items + image_path
|
||||
session.refresh(result)
|
||||
return result
|
||||
|
||||
|
||||
@@ -186,7 +194,7 @@ def get_radar_result(response_id: str):
|
||||
|
||||
@router.get("/responses/{response_id}/radar/image")
|
||||
def get_radar_image(response_id: str):
|
||||
"""Отдаёт SVG-файл диаграммы для скачивания."""
|
||||
"""Отдаёт SVG-файл диаграммы. Если файл отсутствует — пересчитывает автоматически."""
|
||||
Session = get_session()
|
||||
try:
|
||||
rid = uuid.UUID(response_id)
|
||||
@@ -198,16 +206,21 @@ def get_radar_image(response_id: str):
|
||||
.filter(RadarResult.response_id == rid)
|
||||
.first()
|
||||
)
|
||||
if not result or not result.image_path:
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
if not result:
|
||||
raise HTTPException(status_code=404, detail="Radar result not found. Submit the response first.")
|
||||
app_path = os.getenv("APP_PATH", "/app")
|
||||
full_path = os.path.join(app_path, result.image_path)
|
||||
if not os.path.isfile(full_path):
|
||||
raise HTTPException(status_code=404, detail="Image file missing on server")
|
||||
full_path = os.path.join(app_path, result.image_path) if result.image_path else None
|
||||
# Файл удалён или отсутствует — пересчитываем с актуальным алгоритмом
|
||||
if not full_path or not os.path.isfile(full_path):
|
||||
result = compute_radar(rid, session)
|
||||
full_path = os.path.join(app_path, result.image_path) if result.image_path else None
|
||||
if not full_path or not os.path.isfile(full_path):
|
||||
raise HTTPException(status_code=500, detail="Failed to generate radar image")
|
||||
return FileResponse(
|
||||
full_path,
|
||||
media_type="image/svg+xml",
|
||||
filename=f"radar_{response_id}.svg",
|
||||
headers={"Content-Disposition": f'attachment; filename="radar_{response_id}.svg"'},
|
||||
)
|
||||
|
||||
|
||||
@@ -237,9 +250,8 @@ def get_user_radar_history(user_id: str):
|
||||
|
||||
|
||||
def _result_to_out(result: RadarResult) -> RadarResultOut:
|
||||
image_url: Optional[str] = None
|
||||
if result.image_path:
|
||||
image_url = f"/responses/{result.response_id}/radar/image"
|
||||
# image_url возвращаем всегда — endpoint пересоздаст SVG если файл отсутствует
|
||||
image_url = f"/responses/{result.response_id}/radar/image"
|
||||
return RadarResultOut(
|
||||
id=str(result.id),
|
||||
response_id=str(result.response_id),
|
||||
|
||||
Reference in New Issue
Block a user