diff --git a/bbit_ai/app/db/postgres/__init__.py b/bbit_ai/app/db/postgres/__init__.py index b13eb1c..f93ef1e 100644 --- a/bbit_ai/app/db/postgres/__init__.py +++ b/bbit_ai/app/db/postgres/__init__.py @@ -1,6 +1,7 @@ from .aimessage import * from .aiprofile import * from .aisession import * +from .image_ysa import * from .iot import * from .knowledge import * from .license import * diff --git a/bbit_ai/app/db/postgres/aiprofile.py b/bbit_ai/app/db/postgres/aiprofile.py index b336cf0..cc09587 100644 --- a/bbit_ai/app/db/postgres/aiprofile.py +++ b/bbit_ai/app/db/postgres/aiprofile.py @@ -41,7 +41,7 @@ def get_all_ai_bot(user_id: str, module: str) -> List[Dict]: with pg_pool.getConn() as conn: with conn.cursor() as cur: # 查询用户角色 - cur.execute("SELECT roles FROM users WHERE id = %s", (user_id,)) + cur.execute("SELECT roles FROM sys_users WHERE id = %s", (user_id,)) role_row = cur.fetchone() if not role_row: return [] # 用户不存在 diff --git a/bbit_ai/app/db/postgres/image_ysa.py b/bbit_ai/app/db/postgres/image_ysa.py new file mode 100644 index 0000000..317402e --- /dev/null +++ b/bbit_ai/app/db/postgres/image_ysa.py @@ -0,0 +1,122 @@ +import json + +from config.minIO import get_temp_url +from config.pgDb import pg_pool +from utils import MyUtils + + +def insert_ysa_image( + file_name, + resolution, + size, + cocoon_count, + max_confidence, + min_confidence, + average_confidence, + other_info, + preprocess_time_ms, + inference_time_ms, + postprocess_time_ms, + name, + image_pre, + image_after, + created_by, +): + with pg_pool.getConn() as conn: + with conn.cursor() as cursor: + other_info = json.dumps(other_info) + cursor.execute( + """ + INSERT INTO image_sca ( + upload_datetime, file_name, resolution, size, cocoon_count, max_confidence, min_confidence, + average_confidence, other_info, preprocess_time_ms, inference_time_ms, postprocess_time_ms, name, image_pre, image_after, created_by + ) + VALUES (NOW(), %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s ) + RETURNING id + """, + ( + file_name, + resolution, + size, + cocoon_count, + max_confidence, + min_confidence, + average_confidence, + other_info, + preprocess_time_ms, + inference_time_ms, + postprocess_time_ms, + name, + image_pre, + image_after, + created_by, + ), + ) + new_id = cursor.fetchone()[0] + conn.commit() + return new_id + + +def get_ysa_image_list(user_id, name, page=1, page_size=10): + """ + 获取用户已分析图片列表,带分页 + """ + offset = (page - 1) * page_size + + with pg_pool.getConn() as conn: + with conn.cursor() as cursor: + # 1️⃣ 查询总条数 + # ✅ 改进版:支持 name 为空时统计全部,不为空时模糊统计 + cursor.execute( + """ + SELECT COUNT(*) + FROM image_ysa + WHERE created_by = %s + AND (%s = '' OR name LIKE '%%' || %s || '%%') + """, + (user_id, name, name), + ) + + total = cursor.fetchone()[0] + + # 2️⃣ 查询当前页数据 + # ✅ 改进版 + cursor.execute( + """ + SELECT id, name, upload_datetime, file_name, image_pre, image_after, resolution, + size, silkworm_count, max_confidence, min_confidence, average_confidence, other_info, preprocess_time_ms, inference_time_ms, postprocess_time_ms + FROM image_ysa + WHERE created_by = %s + AND (%s = '' OR name LIKE '%%' || %s || '%%') + ORDER BY upload_datetime DESC + LIMIT %s OFFSET %s + """, + (user_id, name, name, page_size, offset), + ) + + rows = cursor.fetchall() + + result = [] + for row in rows: + result.append( + { + "id": row[0], + "name": row[1], + "upload_datetime": MyUtils.format_datetime(row[2]), + "file_name": row[3], + "image_pre": get_temp_url("image-ysa", "raw/" + row[4]), + "image_after": get_temp_url("image-ysa", "ai/" + row[5]), + "resolution": row[6], + "size": MyUtils.safe_round(row[7] / 1024, 2), + "silkworm_count": row[8], + "max_confidence": row[9], + "min_confidence": row[10], + "average_confidence": row[11], + "other_info": row[12], + "preprocess_time_ms": MyUtils.safe_round(row[13], 4), + "inference_time_ms": MyUtils.safe_round(row[14], 4), + "postprocess_time_ms": MyUtils.safe_round(row[15], 4), + } + ) + + return total, result diff --git a/bbit_ai/app/db/postgres/license.py b/bbit_ai/app/db/postgres/license.py index 01e2268..6298c6b 100644 --- a/bbit_ai/app/db/postgres/license.py +++ b/bbit_ai/app/db/postgres/license.py @@ -10,7 +10,7 @@ def insert_license_image( with conn.cursor() as cursor: cursor.execute( """ - INSERT INTO license_images ( + INSERT INTO image_license ( created_by, created_at, file_name, resolution, size, name, oss, type, content ) @@ -36,7 +36,7 @@ def get_license_image_list(user_id, page=1, page_size=10): cursor.execute( """ SELECT COUNT(*) - FROM license_images + FROM image_license WHERE created_by = %s """, (user_id,), @@ -47,7 +47,7 @@ def get_license_image_list(user_id, page=1, page_size=10): cursor.execute( """ SELECT created_at, file_name, resolution, size, name, oss, id, type, content - FROM license_images + FROM image_license WHERE created_by = %s ORDER BY created_at DESC LIMIT %s OFFSET %s diff --git a/bbit_ai/app/db/postgres/sca_image.py b/bbit_ai/app/db/postgres/sca_image.py index 7199a0a..e55fbd3 100644 --- a/bbit_ai/app/db/postgres/sca_image.py +++ b/bbit_ai/app/db/postgres/sca_image.py @@ -27,7 +27,7 @@ def insert_sca_image( other_info = json.dumps(other_info) cursor.execute( """ - INSERT INTO sca_images ( + INSERT INTO image_sca ( upload_datetime, file_name, resolution, size, cocoon_count, max_confidence, min_confidence, average_confidence, other_info, preprocess_time_ms, inference_time_ms, postprocess_time_ms, name, image_pre, image_after, created_by ) @@ -70,7 +70,7 @@ def get_sca_image_list(user_id, name, page=1, page_size=10): cursor.execute( """ SELECT COUNT(*) - FROM sca_images + FROM image_sca WHERE created_by = %s AND (%s = '' OR name LIKE '%%' || %s || '%%') """, @@ -85,7 +85,7 @@ def get_sca_image_list(user_id, name, page=1, page_size=10): """ SELECT id, name, upload_datetime, file_name, image_pre, image_after, resolution, size, cocoon_count, max_confidence, min_confidence, average_confidence, other_info, preprocess_time_ms, inference_time_ms, postprocess_time_ms - FROM sca_images + FROM image_sca WHERE created_by = %s AND (%s = '' OR name LIKE '%%' || %s || '%%') ORDER BY upload_datetime DESC diff --git a/bbit_ai/app/db/postgres/sca_video.py b/bbit_ai/app/db/postgres/sca_video.py index 93d6429..efd93a2 100644 --- a/bbit_ai/app/db/postgres/sca_video.py +++ b/bbit_ai/app/db/postgres/sca_video.py @@ -17,7 +17,7 @@ def get_sca_video_list(name, page=1, page_size=10): cursor.execute( """ SELECT COUNT(*) - FROM sca_videos + FROM video_sca WHERE (%s = '' OR name LIKE '%%' || %s || '%%') """, (name, name), @@ -30,7 +30,7 @@ def get_sca_video_list(name, page=1, page_size=10): SELECT id, name, raw_object_name, ai_object_name, duration, size, video_codec, audio_codec, overall_bit_rate, resolution, sc_analysis_time, sc_analysis_total_count, sc_analysis_max_count, sc_analysis_primary_type, sc_analysis_secondary_type, other_info, created_at - FROM sca_videos + FROM video_sca WHERE (%s = '' OR name LIKE '%%' || %s || '%%') ORDER BY created_at DESC LIMIT %s OFFSET %s @@ -67,7 +67,7 @@ def get_sca_video_list(name, page=1, page_size=10): return total, result -def get_sca_video_details(v_id): +def get_video_sca_details(v_id): """ 获取指定视频的分析明细列表 """ @@ -76,7 +76,7 @@ def get_sca_video_details(v_id): cursor.execute( """ SELECT id, v_id, time_stamp, other_info - FROM sca_video_details + FROM video_sca_details WHERE v_id = %s ORDER BY time_stamp ASC """, diff --git a/bbit_ai/app/db/postgres/system.py b/bbit_ai/app/db/postgres/system.py index 8392dd9..fa26707 100644 --- a/bbit_ai/app/db/postgres/system.py +++ b/bbit_ai/app/db/postgres/system.py @@ -446,7 +446,7 @@ def get_user_list_db_page( with conn.cursor() as cursor: # ---- 统计总数 ---- - count_sql = f"SELECT COUNT(*) FROM users u {where_clause};" + count_sql = f"SELECT COUNT(*) FROM sys_users u {where_clause};" cursor.execute(count_sql, params) total = cursor.fetchone()[0] @@ -461,7 +461,7 @@ def get_user_list_db_page( u.dept_id, d.name AS dept_name, u.created_at - FROM users u + FROM sys_users u LEFT JOIN sys_dept d ON u.dept_id = d.id {where_clause} ORDER BY u.created_at DESC @@ -511,7 +511,9 @@ def get_user_list_db_page( def db_user_name_exists(username: str) -> bool: with pg_pool.getConn() as conn: with conn.cursor() as cursor: - cursor.execute("SELECT COUNT(*) FROM users WHERE email = %s;", (username,)) + cursor.execute( + "SELECT COUNT(*) FROM sys_users WHERE email = %s;", (username,) + ) return cursor.fetchone()[0] > 0 @@ -521,7 +523,7 @@ def insert_user(data: dict) -> str: with conn.cursor() as cursor: cursor.execute( """ - INSERT INTO users (username, email, phone, is_active, dept_id, password_hash) + INSERT INTO sys_users (username, email, phone, is_active, dept_id, password_hash) VALUES (%s, %s, %s, %s, %s, %s) RETURNING id; """, ( @@ -578,7 +580,7 @@ def patch_user_db(id: str, data: dict) -> int: # 如果有需要更新的字段 if fields: - sql = f"UPDATE users SET {', '.join(fields)} WHERE id = %s" + sql = f"UPDATE sys_users SET {', '.join(fields)} WHERE id = %s" params.append(id) cursor.execute(sql, tuple(params)) @@ -603,7 +605,7 @@ def delete_user_db(id: str) -> int: with pg_pool.getConn() as conn: with conn.cursor() as cursor: cursor.execute("DELETE FROM sys_user_role WHERE user_id=%s;", (id,)) - cursor.execute("DELETE FROM users WHERE id=%s;", (id,)) + cursor.execute("DELETE FROM sys_users WHERE id=%s;", (id,)) conn.commit() return cursor.rowcount @@ -882,7 +884,7 @@ def get_dept_ids_by_user_id(user_id: UUID) -> list: # 第一步:通过 user_id 查找其所属的 dept_id with pg_pool.getConn() as conn: with conn.cursor() as cursor: - cursor.execute("SELECT dept_id FROM users WHERE id = %s", (user_id,)) + cursor.execute("SELECT dept_id FROM sys_users WHERE id = %s", (user_id,)) dept_id = cursor.fetchone() if not dept_id: @@ -914,7 +916,7 @@ def get_dept_ids_by_user_id(user_id: UUID) -> list: # 第一步:通过 user_id 查找其所属的 dept_id with pg_pool.getConn() as conn: with conn.cursor() as cursor: - cursor.execute("SELECT dept_id FROM users WHERE id = %s", (user_id,)) + cursor.execute("SELECT dept_id FROM sys_users WHERE id = %s", (user_id,)) dept_id = cursor.fetchone() if not dept_id: @@ -946,7 +948,7 @@ def get_dept_id_by_user_id(user_id: str) -> str: # 通过 user_id 查找其所属的 dept_id with pg_pool.getConn() as conn: with conn.cursor() as cursor: - cursor.execute("SELECT dept_id FROM users WHERE id = %s", (user_id,)) + cursor.execute("SELECT dept_id FROM sys_users WHERE id = %s", (user_id,)) dept_id = cursor.fetchone() dept_id = dept_id[0] return str(dept_id) diff --git a/bbit_ai/app/db/postgres/ticket.py b/bbit_ai/app/db/postgres/ticket.py index bb94a68..d7f1216 100644 --- a/bbit_ai/app/db/postgres/ticket.py +++ b/bbit_ai/app/db/postgres/ticket.py @@ -12,7 +12,7 @@ def get_ticket_image_list(user_id): moisture_content, cocoon_weight, defective_pupa_count, fresh_shell_weight, sample_count, barcode, oss, net_weight_total, evaluator, reviewer,id ,dead_pupa_count - FROM ticket_images + FROM image_ticket WHERE created_by = %s """, (user_id,), @@ -66,7 +66,7 @@ def insert_ticket_image( with conn.cursor() as cursor: cursor.execute( """ - INSERT INTO ticket_images ( + INSERT INTO image_ticket ( created_by, file_name, resolution, size, name, moisture_content, cocoon_weight, defective_pupa_count, dead_pupa_count, fresh_shell_weight, sample_count, barcode, oss, diff --git a/bbit_ai/app/db/sqlserver.py b/bbit_ai/app/db/sqlserver.py index 9ac9b4d..caec41d 100644 --- a/bbit_ai/app/db/sqlserver.py +++ b/bbit_ai/app/db/sqlserver.py @@ -1,9 +1,8 @@ +from sqlalchemy import text -from sqlalchemy import text -from sqlalchemy import text from config.pgDb import pg_pool from config.ssDb import mssql_pool -from sqlalchemy import text + def executeSQL(sql: str): """ @@ -14,11 +13,14 @@ def executeSQL(sql: str): # SQLAlchemy 2.x 返回 Row 对象,转成 dict return [dict(row._mapping) for row in result] + def get_company_list(user_id: str): # 1️⃣ 从 PostgreSQL 获取 tenant_id with pg_pool.getConn() as pg_conn: with pg_conn.cursor() as cur: - cur.execute("SELECT bbit_tenant_id FROM users WHERE id = %s", (user_id,)) + cur.execute( + "SELECT bbit_tenant_id FROM sys_users WHERE id = %s", (user_id,) + ) row = cur.fetchone() tenant_id = row[0] if row else None @@ -33,5 +35,3 @@ def get_company_list(user_id: str): with mssql_pool.getConn() as mssql_conn: result = mssql_conn.execute(query, params) return [{"id": str(row[0]), "name": row[1]} for row in result.fetchall()] - - \ No newline at end of file diff --git a/bbit_ai/app/routers/Vision.py b/bbit_ai/app/routers/Vision.py index f5231f2..a278932 100644 --- a/bbit_ai/app/routers/Vision.py +++ b/bbit_ai/app/routers/Vision.py @@ -153,6 +153,25 @@ def getSilkwormCocoonAnalysisTasks( ) +# ————————————————————————————————催青阶段分析———————————————————————————————————————————————— +@visionRouter.get("/getPromoteStageAnalysisTasks") +def getPromoteStageAnalysisTasks( + user_id: UUID = Depends(get_user_id_from_token), + name: str = "", + page: int = Query(1, ge=1), + page_size: int = Query(10, ge=1, le=100), +): + if not user_id: + return {"error": "userId is required"} + total, items = pg.get_ysa_image_list(user_id, name, page=page, page_size=page_size) + return BaseResponse( + data={ + "total": total, + "items": items, + } + ) + + # ————————————————————————————————蚕茧视频识别任务———————————————————————————————————————————————— @@ -190,4 +209,4 @@ def getAnalyticsDetailBySCVideoId( ): if not user_id: return {"error": "userId is required"} - return BaseResponse(data=pg.get_sca_video_details(vId)) + return BaseResponse(data=pg.get_video_sca_details(vId)) diff --git a/ktor/src/main/kotlin/ink/snowflake/server/model/database/UsersTable.kt b/ktor/src/main/kotlin/ink/snowflake/server/model/database/UsersTable.kt index dd52873..0dbaf40 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/model/database/UsersTable.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/model/database/UsersTable.kt @@ -5,7 +5,7 @@ import org.jetbrains.exposed.v1.core.dao.id.UUIDTable import org.jetbrains.exposed.v1.datetime.timestamp import org.jetbrains.exposed.v1.json.json -object UsersTable : UUIDTable("users") { +object UsersTable : UUIDTable("sys_users") { // 用户名 val username = varchar("username", length = 50).nullable() diff --git a/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideoAnalyticsDetailsTable.kt b/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideoAnalyticsDetailsTable.kt index 500348f..cf4b276 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideoAnalyticsDetailsTable.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideoAnalyticsDetailsTable.kt @@ -4,7 +4,7 @@ import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import org.jetbrains.exposed.v1.core.dao.id.UUIDTable -object VideoAnalyticsDetailsTable : UUIDTable("video_analytics_details") { +object VideoAnalyticsDetailsTable : UUIDTable("video_act_details") { val vId = uuid("v_id").references(VideosTable.id) val aTimeStamp = integer("time_stamp") val aTotalPeople = integer("total_people") diff --git a/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideosTable.kt b/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideosTable.kt index cfded9b..b836dba 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideosTable.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/model/database/VideosTable.kt @@ -5,7 +5,7 @@ import org.jetbrains.exposed.v1.core.dao.id.UUIDTable import org.jetbrains.exposed.v1.datetime.datetime -object VideosTable : UUIDTable("videos") { +object VideosTable : UUIDTable("video_act") { val vName = varchar("name", 255) val vObjectName = varchar("object_name", 255) val vFileName = varchar("file_name", 255) diff --git a/vue2/apps/web-antd/src/api/cv/index.ts b/vue2/apps/web-antd/src/api/cv/index.ts index 58168e8..490ca71 100644 --- a/vue2/apps/web-antd/src/api/cv/index.ts +++ b/vue2/apps/web-antd/src/api/cv/index.ts @@ -4,3 +4,4 @@ export * from './license'; export * from './sca'; export * from './sca2'; export * from './ticket'; +export * from './ysa'; diff --git a/vue2/apps/web-antd/src/api/cv/ysa.ts b/vue2/apps/web-antd/src/api/cv/ysa.ts new file mode 100644 index 0000000..841271c --- /dev/null +++ b/vue2/apps/web-antd/src/api/cv/ysa.ts @@ -0,0 +1,25 @@ +import { pyRequestClient } from '#/api/request'; + +/** + * 获取已分析的图片列表 + */ +export async function getSilkwormCocoonAnalysisTasks( + name = '', + page = 1, + pageSize = 9, +) { + return pyRequestClient.get('/cv/getPromoteStageAnalysisTasks', { + params: { name, page, page_size: pageSize }, + }); +} + +/** + * 上传图片分析任务 + */ +export async function createSilkwormCocoonAnalysisTask(formData: FormData) { + return pyRequestClient.post('/cv/createPromoteStageAnalysisTask', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); +} diff --git a/vue2/apps/web-antd/src/views/cv/ysa/index.vue b/vue2/apps/web-antd/src/views/cv/ysa/index.vue index 6f13bf1..8e4f431 100644 --- a/vue2/apps/web-antd/src/views/cv/ysa/index.vue +++ b/vue2/apps/web-antd/src/views/cv/ysa/index.vue @@ -1,5 +1,390 @@ + + - - 正在开发中,敬请期待 + + + + + + + + + + {{ fileName || '点击选择文件' }} + + + + + + + + + + + + 新建任务 + + 刷新列表 + + + + + + + {{ item.name }} + {{ item.upload_datetime }} + + + + + + 上一页 + + + 第 {{ page }} 页 / 共 {{ totalPages }} 页 + + + 下一页 + + + + + + + + 请先选择左侧列表中的分析任务 + + + + + + + + + + + + {{ key }}: + + + {{ value || '—' }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +