diff --git a/backend/alembic/versions/8fe654655905_004_add_aimodel_auto.py b/backend/alembic/versions/8fe654655905_004_add_aimodel_auto.py
new file mode 100644
index 00000000..35b05838
--- /dev/null
+++ b/backend/alembic/versions/8fe654655905_004_add_aimodel_auto.py
@@ -0,0 +1,43 @@
+"""004_add_aimodel_auto
+
+Revision ID: 8fe654655905
+Revises: d116056121c3
+Create Date: 2025-05-07 15:51:34.768842
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel.sql.sqltypes
+from sqlalchemy.dialects import postgresql
+
+# revision identifiers, used by Alembic.
+revision = '8fe654655905'
+down_revision = 'd116056121c3'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('ai_model',
+ sa.Column('id', sa.BigInteger(), nullable=False),
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False),
+ sa.Column('type', sa.Integer(), nullable=False),
+ sa.Column('api_key', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
+ sa.Column('endpoint', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False),
+ sa.Column('max_context_window', sa.Integer(), nullable=False),
+ sa.Column('temperature', sa.Float(), nullable=False),
+ sa.Column('status', sa.Boolean(), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
+ sa.Column('create_time', sa.BigInteger(), nullable=False),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_ai_model_id'), 'ai_model', ['id'], unique=False)
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_index(op.f('ix_ai_model_id'), table_name='ai_model')
+ op.drop_table('ai_model')
+ # ### end Alembic commands ###
diff --git a/backend/apps/api.py b/backend/apps/api.py
index 0c0d312b..478d86b3 100644
--- a/backend/apps/api.py
+++ b/backend/apps/api.py
@@ -1,6 +1,6 @@
from fastapi import APIRouter
-from apps.system.api import login, user
+from apps.system.api import login, user, aimodel
from apps.settings.api import terminology
from apps.datasource.api import datasource
@@ -8,6 +8,7 @@ from apps.datasource.api import datasource
api_router = APIRouter()
api_router.include_router(login.router)
api_router.include_router(user.router)
+api_router.include_router(aimodel.router)
api_router.include_router(terminology.router)
api_router.include_router(datasource.router)
diff --git a/backend/apps/system/api/aimodel.py b/backend/apps/system/api/aimodel.py
new file mode 100644
index 00000000..a3284125
--- /dev/null
+++ b/backend/apps/system/api/aimodel.py
@@ -0,0 +1,86 @@
+from datetime import datetime
+from fastapi import APIRouter
+from sqlmodel import select
+from apps.system.models.system_modle import AiModelDetail
+from apps.system.schemas.system_schema import model_status
+from common.core.deps import SessionDep
+from common.core.pagination import Paginator
+from common.core.schemas import PaginatedResponse, PaginationParams
+from common.utils.time import get_timestamp
+
+router = APIRouter(tags=["system/aimodel"], prefix="/system/aimodel")
+
+
+@router.get("/pager/{pageNum}/{pageSize}", response_model=PaginatedResponse[AiModelDetail])
+async def pager(
+ session: SessionDep,
+ pageNum: int,
+ pageSize: int
+):
+ pagination = PaginationParams(page=pageNum, size=pageSize)
+ paginator = Paginator(session)
+ filters = {}
+ return await paginator.get_paginated_response(
+ model=AiModelDetail,
+ pagination=pagination,
+ **filters)
+
+@router.get("/{id}", response_model=AiModelDetail)
+async def get_model_by_id(
+ session: SessionDep,
+ id: int
+):
+ term = session.get(AiModelDetail, id)
+ return term
+
+@router.post("", response_model=AiModelDetail)
+async def add_model(
+ session: SessionDep,
+ creator: AiModelDetail
+):
+ data = AiModelDetail.model_validate(creator)
+ data.create_time = get_timestamp()
+ session.add(data)
+ session.commit()
+ return creator
+
+@router.put("", response_model=AiModelDetail)
+async def update_terminology(
+ session: SessionDep,
+ model: AiModelDetail
+):
+ model.id = int(model.id)
+ term = session.exec(select(AiModelDetail).where(AiModelDetail.id == model.id)).first()
+ update_data = model.model_dump(exclude_unset=True)
+ for field, value in update_data.items():
+ setattr(term, field, value)
+ session.add(term)
+ session.commit()
+ return model
+
+@router.delete("/{id}", response_model=AiModelDetail)
+async def delete_terminology(
+ session: SessionDep,
+ id: int
+):
+ term = session.exec(select(AiModelDetail).where(AiModelDetail.id == id)).first()
+ session.delete(term)
+ session.commit()
+ return {
+ "message": f"AiModel with ID {id} deleted successfully."
+ }
+
+
+@router.patch("/status", response_model=dict)
+async def status(session: SessionDep, dto: model_status):
+ ids = dto.ids
+ status = dto.status
+ if not ids:
+ return {"message": "ids is empty"}
+ statement = select(AiModelDetail).where(AiModelDetail.id.in_(ids))
+ terms = session.exec(statement).all()
+ for term in terms:
+ term.status = status
+ session.add(term)
+ session.commit()
+ return {"message": f"AiModel with IDs {ids} updated successfully."}
\ No newline at end of file
diff --git a/backend/apps/system/models/system_modle.py b/backend/apps/system/models/system_modle.py
new file mode 100644
index 00000000..cc35045e
--- /dev/null
+++ b/backend/apps/system/models/system_modle.py
@@ -0,0 +1,18 @@
+
+from sqlmodel import BigInteger, Field, SQLModel
+from common.core.models import SnowflakeBase
+
+
+class AiModelBase:
+ name: str = Field(max_length=255, nullable=False)
+ type: int = Field(nullable=False)
+
+class AiModelDetail(AiModelBase, SnowflakeBase, table=True):
+ __tablename__ = "ai_model"
+ api_key: str | None = Field(max_length=255, nullable=True)
+ endpoint: str = Field(max_length=255, nullable=False)
+ max_context_window: int = Field(default=0)
+ temperature: float = Field(default=0.0)
+ status: bool = Field(default=True)
+ description: str | None = Field(max_length=255, nullable=True)
+ create_time: int = Field(default=0, sa_type=BigInteger())
\ No newline at end of file
diff --git a/backend/apps/system/schemas/system_schema.py b/backend/apps/system/schemas/system_schema.py
new file mode 100644
index 00000000..237612cd
--- /dev/null
+++ b/backend/apps/system/schemas/system_schema.py
@@ -0,0 +1,5 @@
+from pydantic import BaseModel
+
+class model_status(BaseModel):
+ status: bool
+ ids: list[int]
\ No newline at end of file
diff --git a/backend/common/core/models.py b/backend/common/core/models.py
index 57718314..d6488f59 100644
--- a/backend/common/core/models.py
+++ b/backend/common/core/models.py
@@ -13,21 +13,7 @@ class SnowflakeBase(SQLModel):
nullable=False
)
- @field_validator("id", mode="before")
- def validate_id(cls, v):
- if isinstance(v, str):
- if not v:
- return None
- try:
- return int(v)
- except ValueError:
- raise ValueError("Invalid bigint string")
- elif isinstance(v, int):
- return v
- raise TypeError("BigInt must be int or string")
-
-
class Config:
json_encoders = {
- int: lambda v: str(v) if v > 2**53-1 else v
+ int: lambda v: str(v) if isinstance(v, int) and v > (2**53 - 1) else v
}
\ No newline at end of file
diff --git a/backend/common/utils/time.py b/backend/common/utils/time.py
new file mode 100644
index 00000000..7612c5f2
--- /dev/null
+++ b/backend/common/utils/time.py
@@ -0,0 +1,6 @@
+from datetime import datetime
+
+
+def get_timestamp():
+ dt_millis = int(datetime.now().timestamp() * 1000)
+ return dt_millis
\ No newline at end of file
diff --git a/backend/scripts/alembic/auto.sh b/backend/scripts/alembic/auto.sh
new file mode 100755
index 00000000..d94dfd21
--- /dev/null
+++ b/backend/scripts/alembic/auto.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+NC='\033[0m' # No Color
+
+usage() {
+ echo -e "${GREEN}Usage:${NC} $0 [\"migration message\"]"
+ echo -e "Example: $0 \"Added user table\""
+ exit 1
+}
+
+if [ "$#" -eq 0 ]; then
+ echo -e "${RED}Error:${NC} No migration message provided"
+ usage
+fi
+
+echo -e "${GREEN}Generating migration with message:${NC} \"$1\""
+alembic revision --autogenerate -m "$1"
+
+if [ $? -eq 0 ]; then
+ echo -e "${GREEN}Migration created successfully!${NC}"
+else
+ echo -e "${RED}Error:${NC} Failed to create migration"
+ exit 1
+fi
\ No newline at end of file
diff --git a/frontend/components.d.ts b/frontend/components.d.ts
index dc9c610f..706ada35 100644
--- a/frontend/components.d.ts
+++ b/frontend/components.d.ts
@@ -11,6 +11,7 @@ declare module 'vue' {
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
+ ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
@@ -22,7 +23,9 @@ declare module 'vue' {
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
+ ElPagination: typeof import('element-plus/es')['ElPagination']
ElSelect: typeof import('element-plus/es')['ElSelect']
+ ElSlider: typeof import('element-plus/es')['ElSlider']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
diff --git a/frontend/src/api/system.ts b/frontend/src/api/system.ts
new file mode 100644
index 00000000..106fa74c
--- /dev/null
+++ b/frontend/src/api/system.ts
@@ -0,0 +1,10 @@
+import { request } from '@/utils/request'
+
+export const modelApi = {
+ pager: (pageNumber: number, pageSize: number) => request.get(`/system/aimodel/pager/${pageNumber}/${pageSize}`),
+ add: (data: any) => request.post('/system/aimodel', data),
+ edit: (data: any) => request.put('/system/aimodel', data),
+ delete: (id: number) => request.delete(`/system/aimodel/${id}`),
+ query: (id: number) => request.get(`/system/aimodel/${id}`),
+ status: (data: any) => request.patch('/system/aimodel/status', data),
+}
\ No newline at end of file
diff --git a/frontend/src/assets/svg/operate/ope-disable.svg b/frontend/src/assets/svg/operate/ope-disable.svg
new file mode 100644
index 00000000..7821cfb1
--- /dev/null
+++ b/frontend/src/assets/svg/operate/ope-disable.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/svg/operate/ope-enable.svg b/frontend/src/assets/svg/operate/ope-enable.svg
new file mode 100644
index 00000000..4c4c44e6
--- /dev/null
+++ b/frontend/src/assets/svg/operate/ope-enable.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/utils/request.ts b/frontend/src/utils/request.ts
index 5cc881f7..b7d31333 100644
--- a/frontend/src/utils/request.ts
+++ b/frontend/src/utils/request.ts
@@ -83,7 +83,7 @@ class HttpService {
// Response interceptor
this.instance.interceptors.response.use(
(response: AxiosResponse) => {
- console.log(`[Response] ${response.config.url}`, response.data)
+ // console.log(`[Response] ${response.config.url}`, response.data)
// Return raw response if configured
if ((response.config as FullRequestConfig).requestOptions?.rawResponse) {
@@ -164,8 +164,7 @@ class HttpService {
// ElMessage.error(errorMessage)
ElMessage({
message: errorMessage,
- type: 'error',
- duration: 0
+ type: 'error'
})
}
diff --git a/frontend/src/views/system/model/index.vue b/frontend/src/views/system/model/index.vue
index ebe7f3bc..276aaec8 100644
--- a/frontend/src/views/system/model/index.vue
+++ b/frontend/src/views/system/model/index.vue
@@ -1,3 +1,517 @@
- this is ai model page
-
\ No newline at end of file
+