scene.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. from fastapi import APIRouter, Depends, Request
  2. from sqlalchemy.orm import Session
  3. from pydantic import BaseModel
  4. from typing import Optional
  5. from database import get_db
  6. from models.scene import Scene, FirstScene, SecondScene, ThirdScene, RecognitionRecord, SceneTemplate
  7. import time
  8. router = APIRouter()
  9. @router.get("/get_scene_list")
  10. async def get_scene_list(db: Session = Depends(get_db)):
  11. """获取场景列表"""
  12. scenes = db.query(Scene).filter(Scene.is_deleted == 0).all()
  13. return {
  14. "statusCode": 200,
  15. "msg": "success",
  16. "data": [{"id": s.id, "scene_name": s.scene_name, "scene_en_name": s.scene_en_name} for s in scenes]
  17. }
  18. @router.get("/get_first_scene_list")
  19. async def get_first_scene_list(scene_id: int, db: Session = Depends(get_db)):
  20. """获取一级场景列表"""
  21. scenes = db.query(FirstScene).filter(
  22. FirstScene.scene_id == scene_id,
  23. FirstScene.is_deleted == 0
  24. ).all()
  25. return {
  26. "statusCode": 200,
  27. "msg": "success",
  28. "data": [{"id": s.id, "first_scene_name": s.first_scene_name} for s in scenes]
  29. }
  30. @router.get("/get_second_scene_list")
  31. async def get_second_scene_list(first_scene_id: int, db: Session = Depends(get_db)):
  32. """获取二级场景列表"""
  33. scenes = db.query(SecondScene).filter(
  34. SecondScene.first_scene_id == first_scene_id,
  35. SecondScene.is_deleted == 0
  36. ).all()
  37. return {
  38. "statusCode": 200,
  39. "msg": "success",
  40. "data": [{"id": s.id, "second_scene_name": s.second_scene_name} for s in scenes]
  41. }
  42. @router.get("/get_third_scene_list")
  43. async def get_third_scene_list(second_scene_id: int, db: Session = Depends(get_db)):
  44. """获取三级场景列表"""
  45. scenes = db.query(ThirdScene).filter(
  46. ThirdScene.second_scene_id == second_scene_id,
  47. ThirdScene.is_deleted == 0
  48. ).all()
  49. return {
  50. "statusCode": 200,
  51. "msg": "success",
  52. "data": [{
  53. "id": s.id,
  54. "third_scene_name": s.third_scene_name,
  55. "correct_example_image": s.correct_example_image,
  56. "wrong_example_image": s.wrong_example_image
  57. } for s in scenes]
  58. }
  59. @router.get("/get_third_scene_example_image")
  60. async def get_third_scene_example_image(third_scene_name: str, db: Session = Depends(get_db)):
  61. """获取三级场景示例图"""
  62. if not third_scene_name:
  63. return {"statusCode": 400, "msg": "三级场景名称不能为空"}
  64. scene = db.query(ThirdScene).filter(
  65. ThirdScene.third_scene_name == third_scene_name,
  66. ThirdScene.is_deleted == 0
  67. ).first()
  68. if not scene:
  69. return {"statusCode": 404, "msg": "三级场景不存在"}
  70. return {
  71. "statusCode": 200,
  72. "msg": "success",
  73. "data": {
  74. "id": scene.id,
  75. "third_scene_name": scene.third_scene_name,
  76. "correct_example_image": scene.correct_example_image,
  77. "wrong_example_image": scene.wrong_example_image
  78. }
  79. }
  80. @router.get("/get_history_recognition_record")
  81. async def get_history_recognition_record(request: Request, db: Session = Depends(get_db)):
  82. """获取隐患识别历史记录"""
  83. user = request.state.user
  84. if not user:
  85. return {"statusCode": 401, "msg": "未授权"}
  86. # 获取所有记录(不限制数量)
  87. records = db.query(RecognitionRecord).filter(
  88. RecognitionRecord.user_id == user.userCode,
  89. RecognitionRecord.is_deleted == 0
  90. ).order_by(RecognitionRecord.updated_at.desc()).all()
  91. # 计算总数
  92. total = db.query(RecognitionRecord).filter(
  93. RecognitionRecord.user_id == user.userCode,
  94. RecognitionRecord.is_deleted == 0
  95. ).count()
  96. return {
  97. "statusCode": 200,
  98. "msg": "success",
  99. "data": [{
  100. "id": r.id,
  101. "title": r.title,
  102. "original_image_url": r.original_image_url,
  103. "recognition_image_url": r.recognition_image_url,
  104. "labels": r.labels,
  105. "created_at": r.created_at
  106. } for r in records],
  107. "total": total
  108. }
  109. @router.get("/get_recognition_record_detail")
  110. async def get_recognition_record_detail(recognition_id: int, db: Session = Depends(get_db)):
  111. """获取识别记录详情"""
  112. record = db.query(RecognitionRecord).filter(
  113. RecognitionRecord.id == recognition_id,
  114. RecognitionRecord.is_deleted == 0
  115. ).first()
  116. if not record:
  117. return {"statusCode": 404, "msg": "记录不存在"}
  118. # 将 Description 字符串转换为数组
  119. third_scenes = []
  120. if record.description:
  121. third_scenes = record.description.split(" ")
  122. return {
  123. "statusCode": 200,
  124. "msg": "success",
  125. "data": {
  126. "id": record.id,
  127. "user_id": record.user_id,
  128. "title": record.title,
  129. "description": record.description,
  130. "original_image_url": record.original_image_url,
  131. "recognition_image_url": record.recognition_image_url,
  132. "labels": record.labels,
  133. "third_scenes": third_scenes,
  134. "tag_type": record.tag_type,
  135. "scene_match": record.scene_match,
  136. "tip_accuracy": record.tip_accuracy,
  137. "effect_evaluation": record.effect_evaluation,
  138. "user_remark": record.user_remark,
  139. "created_at": record.created_at,
  140. "updated_at": record.updated_at
  141. }
  142. }
  143. class DeleteRecognitionRequest(BaseModel):
  144. recognition_id: int
  145. @router.post("/delete_recognition_record")
  146. async def delete_recognition_record(data: DeleteRecognitionRequest, request: Request, db: Session = Depends(get_db)):
  147. """删除识别记录(软删除)"""
  148. user = request.state.user
  149. if not user:
  150. return {"statusCode": 401, "msg": "未授权"}
  151. db.query(RecognitionRecord).filter(
  152. RecognitionRecord.id == data.recognition_id,
  153. RecognitionRecord.user_id == user.userCode
  154. ).update({
  155. "is_deleted": 1,
  156. "deleted_at": int(time.time())
  157. })
  158. db.commit()
  159. return {"statusCode": 200, "msg": "删除成功"}
  160. class EvaluationRequest(BaseModel):
  161. id: int
  162. scene_match: Optional[int] = None
  163. tip_accuracy: Optional[int] = None
  164. effect_evaluation: Optional[int] = None
  165. user_remark: Optional[str] = None
  166. @router.post("/submit_evaluation")
  167. async def submit_evaluation(data: EvaluationRequest, db: Session = Depends(get_db)):
  168. """提交点评"""
  169. record = db.query(RecognitionRecord).filter(
  170. RecognitionRecord.id == data.id,
  171. RecognitionRecord.is_deleted == 0
  172. ).first()
  173. if not record:
  174. return {"statusCode": 404, "msg": "记录不存在"}
  175. # 更新评价字段
  176. if data.scene_match is not None:
  177. record.scene_match = data.scene_match
  178. if data.tip_accuracy is not None:
  179. record.tip_accuracy = data.tip_accuracy
  180. if data.effect_evaluation is not None:
  181. record.effect_evaluation = data.effect_evaluation
  182. if data.user_remark is not None:
  183. record.user_remark = data.user_remark
  184. record.updated_at = int(time.time())
  185. db.commit()
  186. return {"statusCode": 200, "msg": "success"}
  187. @router.get("/get_latest_recognition_record")
  188. async def get_latest_recognition_record(request: Request, db: Session = Depends(get_db)):
  189. """获取最新识别记录"""
  190. user = request.state.user
  191. if not user:
  192. return {"statusCode": 401, "msg": "未授权"}
  193. record = db.query(RecognitionRecord).filter(
  194. RecognitionRecord.user_id == user.userCode,
  195. RecognitionRecord.is_deleted == 0
  196. ).order_by(RecognitionRecord.created_at.desc()).first()
  197. # 如果数据为空,则构建一个假数据 effect_evaluation=1 给前端
  198. if not record:
  199. return {
  200. "statusCode": 200,
  201. "msg": "success",
  202. "data": {
  203. "effect_evaluation": 1
  204. }
  205. }
  206. return {
  207. "statusCode": 200,
  208. "msg": "success",
  209. "data": {
  210. "id": record.id,
  211. "title": record.title,
  212. "original_image_url": record.original_image_url,
  213. "recognition_image_url": record.recognition_image_url,
  214. "labels": record.labels,
  215. "created_at": record.created_at,
  216. "effect_evaluation": record.effect_evaluation
  217. }
  218. }
  219. # ============================================================
  220. # 场景模板接口(对齐Go版本)
  221. # ============================================================
  222. class SceneTemplateCreate(BaseModel):
  223. """创建场景模板请求"""
  224. scene_name: str
  225. scene_type: str
  226. scene_desc: str = ""
  227. model_name: str
  228. @router.post("/scene_template")
  229. async def create_scene_template(data: SceneTemplateCreate, db: Session = Depends(get_db)):
  230. """创建场景模板"""
  231. template = SceneTemplate(
  232. scene_name=data.scene_name,
  233. scene_type=data.scene_type,
  234. scene_desc=data.scene_desc,
  235. model_name=data.model_name,
  236. created_at=int(time.time()),
  237. updated_at=int(time.time()),
  238. is_deleted=0
  239. )
  240. db.add(template)
  241. db.commit()
  242. db.refresh(template)
  243. return {
  244. "statusCode": 200,
  245. "msg": "创建成功",
  246. "data": {"id": template.id}
  247. }
  248. @router.get("/scene_templates")
  249. async def get_scene_templates(
  250. page: int = 1,
  251. page_size: int = 20,
  252. db: Session = Depends(get_db)
  253. ):
  254. """获取场景模板列表(分页)"""
  255. # 限制page_size最大值
  256. if page_size > 100:
  257. page_size = 100
  258. offset = (page - 1) * page_size
  259. # 查询总数
  260. total = db.query(SceneTemplate).filter(
  261. SceneTemplate.is_deleted == 0
  262. ).count()
  263. # 查询列表
  264. templates = db.query(SceneTemplate).filter(
  265. SceneTemplate.is_deleted == 0
  266. ).order_by(SceneTemplate.created_at.desc()).offset(offset).limit(page_size).all()
  267. return {
  268. "statusCode": 200,
  269. "msg": "success",
  270. "data": {
  271. "total": total,
  272. "items": [
  273. {
  274. "id": t.id,
  275. "scene_name": t.scene_name,
  276. "scene_type": t.scene_type,
  277. "scene_desc": t.scene_desc,
  278. "model_name": t.model_name,
  279. "created_at": t.created_at
  280. }
  281. for t in templates
  282. ]
  283. }
  284. }
  285. @router.get("/recognition_records")
  286. async def get_recognition_records(
  287. request: Request,
  288. scene_type: str = "",
  289. page: int = 1,
  290. page_size: int = 20,
  291. db: Session = Depends(get_db)
  292. ):
  293. """获取识别记录列表(分页+筛选)- 符合REST规范"""
  294. user = request.state.user
  295. if not user:
  296. return {"statusCode": 401, "msg": "未授权"}
  297. # 限制page_size最大值
  298. if page_size > 100:
  299. page_size = 100
  300. # 构建查询条件
  301. query = db.query(RecognitionRecord).filter(
  302. RecognitionRecord.user_id == user.userCode,
  303. RecognitionRecord.is_deleted == 0
  304. )
  305. # 场景类型筛选
  306. if scene_type:
  307. query = query.filter(RecognitionRecord.scene_type == scene_type)
  308. # 查询总数
  309. total = query.count()
  310. # 分页查询
  311. offset = (page - 1) * page_size
  312. records = query.order_by(
  313. RecognitionRecord.created_at.desc()
  314. ).offset(offset).limit(page_size).all()
  315. return {
  316. "statusCode": 200,
  317. "msg": "success",
  318. "data": {
  319. "total": total,
  320. "items": [
  321. {
  322. "id": r.id,
  323. "scene_type": r.scene_type,
  324. "original_image_url": r.original_image_url,
  325. "result_image_url": r.recognition_image_url,
  326. "hazard_count": r.hazard_count,
  327. "current_step": r.current_step,
  328. "created_at": r.created_at
  329. }
  330. for r in records
  331. ]
  332. }
  333. }