From 50380f199be4a6e4e19c819b3c6b9e271d40eb7f Mon Sep 17 00:00:00 2001 From: Sindhuja Jeyabal Date: Wed, 4 Jun 2025 12:06:46 +0100 Subject: [PATCH 1/5] prompt management add/update/get --- backend/app/api/main.py | 2 + backend/app/api/routes/prompts.py | 114 ++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 backend/app/api/routes/prompts.py diff --git a/backend/app/api/main.py b/backend/app/api/main.py index 2ba2079a..dc5fde0e 100644 --- a/backend/app/api/main.py +++ b/backend/app/api/main.py @@ -14,6 +14,7 @@ utils, onboarding, credentials, + prompts, ) from app.core.config import settings @@ -30,6 +31,7 @@ api_router.include_router(threads.router) api_router.include_router(users.router) api_router.include_router(utils.router) +api_router.include_router(prompts.router) if settings.ENVIRONMENT == "local": api_router.include_router(private.router) diff --git a/backend/app/api/routes/prompts.py b/backend/app/api/routes/prompts.py new file mode 100644 index 00000000..24e28a3f --- /dev/null +++ b/backend/app/api/routes/prompts.py @@ -0,0 +1,114 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlmodel import Session +from typing import List, Optional +from langfuse.client import Langfuse +from pydantic import BaseModel + +from app.api.deps import get_current_user_org, get_db +from app.crud.credentials import get_provider_credential +from app.models import UserOrganization +from app.utils import APIResponse + +router = APIRouter(prefix="/prompts", tags=["prompts"]) + +class PromptCreateRequest(BaseModel): + project_id: int + name: str + type: str + prompt: str + version: int + labels: Optional[List[str]] = None + tags: Optional[List[str]] = None + model: Optional[str] = None + temperature: Optional[float] = None + supported_languages: Optional[List[str]] = None + +class PromptGetRequest(BaseModel): + project_id: int + name: str + type: Optional[str] = None + version: Optional[int] = None + labels: Optional[List[str]] = None + tags: Optional[List[str]] = None + +class PromptUpdateRequest(BaseModel): + project_id: int + name: str + type: Optional[str] = None + prompt: Optional[str] = None + labels: Optional[List[str]] = None + tags: Optional[List[str]] = None + model: Optional[str] = None + temperature: Optional[float] = None + supported_languages: Optional[List[str]] = None + +def initialize_langfuse( + project_id: int, + _session: Session, + _current_user: UserOrganization, +): + langfuse_credentials = get_provider_credential( + session=_session, + org_id=_current_user.organization_id, + provider="langfuse", + project_id=project_id, + ) + if not langfuse_credentials or "api_key" not in langfuse_credentials: + raise HTTPException(status_code=400, detail="Langfuse API key not configured for this organization.") + return Langfuse(api_key=langfuse_credentials["api_key"]) + +@router.post("/", response_model=APIResponse[dict]) +def create_new_prompt( + request: PromptCreateRequest, + _session: Session = Depends(get_db), + _current_user: UserOrganization = Depends(get_current_user_org) +): + langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) + langfuse_client.create_prompt( + name=request.name, + type=request.type, + prompt=request.prompt, + labels=request.labels, + tags=request.tags, + config={ + "model": request.model, + "temperature": request.temperature, + "supported_languages": request.supported_languages, + }, + ) + return APIResponse.success_response( + message="Prompt created successfully", + data=request.dict(), + ) + +@router.get("/") +def get_prompt( + request: PromptGetRequest, + _session: Session = Depends(get_db), + _current_user: UserOrganization = Depends(get_current_user_org) +): + langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) + prompt = langfuse_client.get_prompt(request.name, request.type, request.version) + return APIResponse.success_response( + message="Prompt fetched successfully", + data=prompt, + ) + +@router.put("/") +def update_prompt( + request: PromptUpdateRequest, + _session: Session = Depends(get_db), + _current_user: UserOrganization = Depends(get_current_user_org) +): + langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) + langfuse_client.update_prompt( + request.name, + request.type, + request.version, + request.prompt, + request.labels, + ) + return APIResponse.success_response( + message="Prompt updated successfully", + data=request.dict(), + ) \ No newline at end of file From 755a775242d17c28ec2b79d4e95bbeeeb95a0b9f Mon Sep 17 00:00:00 2001 From: Sindhuja Jeyabal Date: Fri, 6 Jun 2025 10:24:22 +0100 Subject: [PATCH 2/5] adding prompt table p1 --- backend/app/api/routes/prompts.py | 26 ++++++++++++++++++++++++-- backend/app/crud/prompt.py | 18 ++++++++++++++++++ backend/app/models/__init__.py | 2 ++ backend/app/models/prompt.py | 6 ++++++ 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 backend/app/crud/prompt.py create mode 100644 backend/app/models/prompt.py diff --git a/backend/app/api/routes/prompts.py b/backend/app/api/routes/prompts.py index 24e28a3f..d1fd17d5 100644 --- a/backend/app/api/routes/prompts.py +++ b/backend/app/api/routes/prompts.py @@ -1,5 +1,5 @@ from fastapi import APIRouter, Depends, HTTPException -from sqlmodel import Session +from sqlmodel import Session, select from typing import List, Optional from langfuse.client import Langfuse from pydantic import BaseModel @@ -8,6 +8,7 @@ from app.crud.credentials import get_provider_credential from app.models import UserOrganization from app.utils import APIResponse +from app.crud.prompt import add_prompt, get_prompt_by_name, list_prompts router = APIRouter(prefix="/prompts", tags=["prompts"]) @@ -66,7 +67,7 @@ def create_new_prompt( langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) langfuse_client.create_prompt( name=request.name, - type=request.type, + type="text", prompt=request.prompt, labels=request.labels, tags=request.tags, @@ -76,6 +77,9 @@ def create_new_prompt( "supported_languages": request.supported_languages, }, ) + # Add prompt name to Prompt table if not exists using CRUD + if not get_prompt_by_name(_session, request.name): + add_prompt(_session, request.name) return APIResponse.success_response( message="Prompt created successfully", data=request.dict(), @@ -87,6 +91,10 @@ def get_prompt( _session: Session = Depends(get_db), _current_user: UserOrganization = Depends(get_current_user_org) ): + # Fetch prompt name from Prompt table using CRUD + prompt_row = get_prompt_by_name(_session, request.name) + if not prompt_row: + raise HTTPException(status_code=404, detail="Prompt not found in DB") langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) prompt = langfuse_client.get_prompt(request.name, request.type, request.version) return APIResponse.success_response( @@ -100,6 +108,10 @@ def update_prompt( _session: Session = Depends(get_db), _current_user: UserOrganization = Depends(get_current_user_org) ): + # Ensure prompt name exists in Prompt table using CRUD + prompt_row = get_prompt_by_name(_session, request.name) + if not prompt_row: + raise HTTPException(status_code=404, detail="Prompt not found in DB for update") langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) langfuse_client.update_prompt( request.name, @@ -111,4 +123,14 @@ def update_prompt( return APIResponse.success_response( message="Prompt updated successfully", data=request.dict(), + ) + +# Optionally, add a list endpoint for all prompt names +@router.get("/list") +def list_prompt_names(_session: Session = Depends(get_db)): + prompts = list_prompts(_session) + names = [p.name for p in prompts] + return APIResponse.success_response( + message="Prompt names fetched successfully", + data=names, ) \ No newline at end of file diff --git a/backend/app/crud/prompt.py b/backend/app/crud/prompt.py new file mode 100644 index 00000000..8e08325c --- /dev/null +++ b/backend/app/crud/prompt.py @@ -0,0 +1,18 @@ +from sqlmodel import Session, select +from app.models import Prompt +from typing import Optional, List + +def add_prompt(session: Session, name: str) -> Prompt: + prompt = Prompt(name=name) + session.add(prompt) + session.commit() + session.refresh(prompt) + return prompt + +def get_prompt_by_name(session: Session, name: str) -> Optional[Prompt]: + statement = select(Prompt).where(Prompt.name == name) + return session.exec(statement).first() + +def list_prompts(session: Session) -> List[Prompt]: + statement = select(Prompt) + return list(session.exec(statement)) \ No newline at end of file diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py index f88e019d..a51d1f08 100644 --- a/backend/app/models/__init__.py +++ b/backend/app/models/__init__.py @@ -53,3 +53,5 @@ ) from .threads import OpenAI_Thread, OpenAIThreadBase, OpenAIThreadCreate + +from .prompt import Prompt diff --git a/backend/app/models/prompt.py b/backend/app/models/prompt.py new file mode 100644 index 00000000..46dc0c0c --- /dev/null +++ b/backend/app/models/prompt.py @@ -0,0 +1,6 @@ +from sqlmodel import SQLModel, Field +from typing import Optional + +class Prompt(SQLModel, table=True): + id: int = Field(default=None, primary_key=True) + name: str = Field(index=True, unique=True) \ No newline at end of file From 53033301e225008cd34d0bb4f99107890c743e94 Mon Sep 17 00:00:00 2001 From: sindj Date: Fri, 6 Jun 2025 10:25:50 +0100 Subject: [PATCH 3/5] add prompt table alembic migrations p2 --- backend/app/alembic/versions/498f84cee26c_.py | 25 +++++++++++++++++ .../alembic/versions/auto_add_prompt_table.py | 28 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 backend/app/alembic/versions/498f84cee26c_.py create mode 100644 backend/app/alembic/versions/auto_add_prompt_table.py diff --git a/backend/app/alembic/versions/498f84cee26c_.py b/backend/app/alembic/versions/498f84cee26c_.py new file mode 100644 index 00000000..478fdb08 --- /dev/null +++ b/backend/app/alembic/versions/498f84cee26c_.py @@ -0,0 +1,25 @@ +"""empty message + +Revision ID: 498f84cee26c +Revises: 904ed70e7dab, auto_add_prompt_table +Create Date: 2025-06-05 19:58:06.778925 + +""" +from alembic import op +import sqlalchemy as sa +import sqlmodel.sql.sqltypes + + +# revision identifiers, used by Alembic. +revision = '498f84cee26c' +down_revision = ('904ed70e7dab', 'auto_add_prompt_table') +branch_labels = None +depends_on = None + + +def upgrade(): + pass + + +def downgrade(): + pass diff --git a/backend/app/alembic/versions/auto_add_prompt_table.py b/backend/app/alembic/versions/auto_add_prompt_table.py new file mode 100644 index 00000000..01559f4a --- /dev/null +++ b/backend/app/alembic/versions/auto_add_prompt_table.py @@ -0,0 +1,28 @@ +"""add prompt table + +Revision ID: auto_add_prompt_table +Revises: +Create Date: 2024-06-10 + +""" +from alembic import op +import sqlalchemy as sa +import sqlmodel.sql.sqltypes + +# revision identifiers, used by Alembic. +revision = "auto_add_prompt_table" +down_revision = None +branch_labels = None +depends_on = None + +def upgrade(): + op.create_table( + "prompt", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("name"), + ) + +def downgrade(): + op.drop_table("prompt") \ No newline at end of file From 1a1ebb83b0b662792a4d3dc8fb4da9e1cc35cf2a Mon Sep 17 00:00:00 2001 From: sindj Date: Mon, 23 Jun 2025 13:48:52 +0100 Subject: [PATCH 4/5] adding project_id, org_id, and timestamp fields to prompt table; fixing alembic migrations versions --- backend/app/alembic/versions/498f84cee26c_.py | 2 +- .../alembic/versions/auto_add_prompt_table.py | 10 +++- backend/app/api/routes/prompts.py | 20 +++++--- backend/app/crud/prompt.py | 51 ++++++++++++++++--- backend/app/models/prompt.py | 10 +++- 5 files changed, 76 insertions(+), 17 deletions(-) diff --git a/backend/app/alembic/versions/498f84cee26c_.py b/backend/app/alembic/versions/498f84cee26c_.py index 478fdb08..085c12c6 100644 --- a/backend/app/alembic/versions/498f84cee26c_.py +++ b/backend/app/alembic/versions/498f84cee26c_.py @@ -12,7 +12,7 @@ # revision identifiers, used by Alembic. revision = '498f84cee26c' -down_revision = ('904ed70e7dab', 'auto_add_prompt_table') +down_revision = 'auto_add_prompt_table' branch_labels = None depends_on = None diff --git a/backend/app/alembic/versions/auto_add_prompt_table.py b/backend/app/alembic/versions/auto_add_prompt_table.py index 01559f4a..78a8dd1a 100644 --- a/backend/app/alembic/versions/auto_add_prompt_table.py +++ b/backend/app/alembic/versions/auto_add_prompt_table.py @@ -1,7 +1,7 @@ """add prompt table Revision ID: auto_add_prompt_table -Revises: +Revises: 904ed70e7dab Create Date: 2024-06-10 """ @@ -11,7 +11,7 @@ # revision identifiers, used by Alembic. revision = "auto_add_prompt_table" -down_revision = None +down_revision = "904ed70e7dab" branch_labels = None depends_on = None @@ -20,6 +20,12 @@ def upgrade(): "prompt", sa.Column("id", sa.Integer(), nullable=False), sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("inserted_at", sa.DateTime(), nullable=False), + sa.Column("updated_at", sa.DateTime(), nullable=False), + sa.Column("organization_id", sa.Integer(), nullable=False), + sa.Column("project_id", sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(["organization_id"], ["organization.id"], name="prompt_organization_id_fkey", ondelete="CASCADE"), + sa.ForeignKeyConstraint(["project_id"], ["project.id"], name="prompt_project_id_fkey", ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("name"), ) diff --git a/backend/app/api/routes/prompts.py b/backend/app/api/routes/prompts.py index d1fd17d5..9ad2c8fa 100644 --- a/backend/app/api/routes/prompts.py +++ b/backend/app/api/routes/prompts.py @@ -32,6 +32,9 @@ class PromptGetRequest(BaseModel): labels: Optional[List[str]] = None tags: Optional[List[str]] = None +class PromptListRequest(BaseModel): + project_id: int + class PromptUpdateRequest(BaseModel): project_id: int name: str @@ -78,8 +81,8 @@ def create_new_prompt( }, ) # Add prompt name to Prompt table if not exists using CRUD - if not get_prompt_by_name(_session, request.name): - add_prompt(_session, request.name) + if not get_prompt_by_name(_session, request.name, request.project_id, _current_user.organization_id): + add_prompt(_session, request.name, request.project_id, _current_user.organization_id) return APIResponse.success_response( message="Prompt created successfully", data=request.dict(), @@ -92,7 +95,7 @@ def get_prompt( _current_user: UserOrganization = Depends(get_current_user_org) ): # Fetch prompt name from Prompt table using CRUD - prompt_row = get_prompt_by_name(_session, request.name) + prompt_row = get_prompt_by_name(_session, request.name, request.project_id, _current_user.organization_id) if not prompt_row: raise HTTPException(status_code=404, detail="Prompt not found in DB") langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) @@ -109,7 +112,7 @@ def update_prompt( _current_user: UserOrganization = Depends(get_current_user_org) ): # Ensure prompt name exists in Prompt table using CRUD - prompt_row = get_prompt_by_name(_session, request.name) + prompt_row = get_prompt_by_name(_session, request.name, request.project_id, _current_user.organization_id) if not prompt_row: raise HTTPException(status_code=404, detail="Prompt not found in DB for update") langfuse_client = initialize_langfuse(request.project_id, _session, _current_user) @@ -120,6 +123,7 @@ def update_prompt( request.prompt, request.labels, ) + prompt_row = update_prompt(_session, request.name, request.project_id, _current_user.organization_id) return APIResponse.success_response( message="Prompt updated successfully", data=request.dict(), @@ -127,8 +131,12 @@ def update_prompt( # Optionally, add a list endpoint for all prompt names @router.get("/list") -def list_prompt_names(_session: Session = Depends(get_db)): - prompts = list_prompts(_session) +def list_prompt_names( + request: PromptListRequest, + _session: Session = Depends(get_db), + _current_user: UserOrganization = Depends(get_current_user_org) +): + prompts = list_prompts(_session, project_id=request.project_id, organization_id=_current_user.organization_id) names = [p.name for p in prompts] return APIResponse.success_response( message="Prompt names fetched successfully", diff --git a/backend/app/crud/prompt.py b/backend/app/crud/prompt.py index 8e08325c..657608ca 100644 --- a/backend/app/crud/prompt.py +++ b/backend/app/crud/prompt.py @@ -1,18 +1,55 @@ from sqlmodel import Session, select from app.models import Prompt from typing import Optional, List +from app.core.util import now -def add_prompt(session: Session, name: str) -> Prompt: - prompt = Prompt(name=name) +def add_prompt(session: Session, name: str, project_id: int, organization_id: int) -> Prompt: + if not name: + raise ValueError("Name cannot be empty") + if project_id <= 0: + raise ValueError("Project ID must be a positive integer") + if organization_id <= 0: + raise ValueError("Organization ID must be a positive integer") + + prompt = Prompt(name=name, project_id=project_id, organization_id=organization_id, inserted_at=now(), updated_at=now()) session.add(prompt) - session.commit() + try: + session.commit() + except Exception as e: + session.rollback() + raise e session.refresh(prompt) return prompt -def get_prompt_by_name(session: Session, name: str) -> Optional[Prompt]: - statement = select(Prompt).where(Prompt.name == name) +def get_prompt_by_name(session: Session, name: str, project_id: int, organization_id: int) -> Optional[Prompt]: + if not name: + raise ValueError("Name cannot be empty") + if project_id <= 0: + raise ValueError("Project ID must be a positive integer") + if organization_id <= 0: + raise ValueError("Organization ID must be a positive integer") + + statement = select(Prompt).where(Prompt.project_id == project_id & Prompt.organization_id == organization_id & Prompt.name == name) return session.exec(statement).first() -def list_prompts(session: Session) -> List[Prompt]: - statement = select(Prompt) +def update_prompt(session: Session, name: str, project_id: int, organization_id: int) -> Optional[Prompt]: + try: + statement = select(Prompt).where(Prompt.project_id == project_id & Prompt.organization_id == organization_id & Prompt.name == name) + prompt = session.exec(statement).first() + if not prompt: + raise ValueError(f"No prompt found with name '{name}' for project_id '{project_id}' and organization_id '{organization_id}'") + prompt.updated_at = now() + session.commit() + session.refresh(prompt) + except Exception as e: + session.rollback() + raise e + return prompt + +def list_prompts(session: Session, project_id: int, organization_id: int) -> List[Prompt]: + if project_id <= 0: + raise ValueError("Project ID must be a positive integer") + if organization_id <= 0: + raise ValueError("Organization ID must be a positive integer") + statement = select(Prompt).where(Prompt.project_id == project_id & Prompt.organization_id == organization_id) return list(session.exec(statement)) \ No newline at end of file diff --git a/backend/app/models/prompt.py b/backend/app/models/prompt.py index 46dc0c0c..af9f6e01 100644 --- a/backend/app/models/prompt.py +++ b/backend/app/models/prompt.py @@ -1,6 +1,14 @@ from sqlmodel import SQLModel, Field from typing import Optional +from datetime import datetime +from app.core.util import now + class Prompt(SQLModel, table=True): id: int = Field(default=None, primary_key=True) - name: str = Field(index=True, unique=True) \ No newline at end of file + name: str = Field(index=True, unique=True) + project_id: int = Field(foreign_key="project.id", nullable=False, ondelete="CASCADE") + organization_id: int = Field(foreign_key="organization.id", nullable=False, ondelete="CASCADE") + inserted_at: datetime = Field(default_factory=now, nullable=False) + updated_at: datetime = Field(default_factory=now, nullable=False) + \ No newline at end of file From 273f8ac79f5c9315e6d2a02dce1f3e10cc2977ae Mon Sep 17 00:00:00 2001 From: sindj Date: Tue, 24 Jun 2025 11:46:24 +0100 Subject: [PATCH 5/5] fix alembic migration file --- backend/app/alembic/versions/498f84cee26c_.py | 25 ------------ .../8c3a36b508f1_add_prompts_table.py | 39 +++++++++++++++++++ .../alembic/versions/auto_add_prompt_table.py | 34 ---------------- 3 files changed, 39 insertions(+), 59 deletions(-) delete mode 100644 backend/app/alembic/versions/498f84cee26c_.py create mode 100644 backend/app/alembic/versions/8c3a36b508f1_add_prompts_table.py delete mode 100644 backend/app/alembic/versions/auto_add_prompt_table.py diff --git a/backend/app/alembic/versions/498f84cee26c_.py b/backend/app/alembic/versions/498f84cee26c_.py deleted file mode 100644 index 085c12c6..00000000 --- a/backend/app/alembic/versions/498f84cee26c_.py +++ /dev/null @@ -1,25 +0,0 @@ -"""empty message - -Revision ID: 498f84cee26c -Revises: 904ed70e7dab, auto_add_prompt_table -Create Date: 2025-06-05 19:58:06.778925 - -""" -from alembic import op -import sqlalchemy as sa -import sqlmodel.sql.sqltypes - - -# revision identifiers, used by Alembic. -revision = '498f84cee26c' -down_revision = 'auto_add_prompt_table' -branch_labels = None -depends_on = None - - -def upgrade(): - pass - - -def downgrade(): - pass diff --git a/backend/app/alembic/versions/8c3a36b508f1_add_prompts_table.py b/backend/app/alembic/versions/8c3a36b508f1_add_prompts_table.py new file mode 100644 index 00000000..dc37b4f8 --- /dev/null +++ b/backend/app/alembic/versions/8c3a36b508f1_add_prompts_table.py @@ -0,0 +1,39 @@ +"""add prompts table + +Revision ID: 8c3a36b508f1 +Revises: 904ed70e7dab +Create Date: 2025-06-24 10:20:21.933351 + +""" +from alembic import op +import sqlalchemy as sa +import sqlmodel.sql.sqltypes + + +# revision identifiers, used by Alembic. +revision = '8c3a36b508f1' +down_revision = '904ed70e7dab' +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_table('prompt', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('project_id', sa.Integer(), nullable=False), + sa.Column('organization_id', sa.Integer(), nullable=False), + sa.Column('inserted_at', sa.DateTime(), nullable=False), + sa.Column('updated_at', sa.DateTime(), nullable=False), + sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ondelete='CASCADE'), + sa.ForeignKeyConstraint(['project_id'], ['project.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_prompt_name'), 'prompt', ['name'], unique=True) + # ### end Alembic commands ### + + +def downgrade(): + op.drop_index(op.f('ix_prompt_name'), table_name='prompt') + op.drop_table('prompt') + # ### end Alembic commands ### \ No newline at end of file diff --git a/backend/app/alembic/versions/auto_add_prompt_table.py b/backend/app/alembic/versions/auto_add_prompt_table.py deleted file mode 100644 index 78a8dd1a..00000000 --- a/backend/app/alembic/versions/auto_add_prompt_table.py +++ /dev/null @@ -1,34 +0,0 @@ -"""add prompt table - -Revision ID: auto_add_prompt_table -Revises: 904ed70e7dab -Create Date: 2024-06-10 - -""" -from alembic import op -import sqlalchemy as sa -import sqlmodel.sql.sqltypes - -# revision identifiers, used by Alembic. -revision = "auto_add_prompt_table" -down_revision = "904ed70e7dab" -branch_labels = None -depends_on = None - -def upgrade(): - op.create_table( - "prompt", - sa.Column("id", sa.Integer(), nullable=False), - sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column("inserted_at", sa.DateTime(), nullable=False), - sa.Column("updated_at", sa.DateTime(), nullable=False), - sa.Column("organization_id", sa.Integer(), nullable=False), - sa.Column("project_id", sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(["organization_id"], ["organization.id"], name="prompt_organization_id_fkey", ondelete="CASCADE"), - sa.ForeignKeyConstraint(["project_id"], ["project.id"], name="prompt_project_id_fkey", ondelete="CASCADE"), - sa.PrimaryKeyConstraint("id"), - sa.UniqueConstraint("name"), - ) - -def downgrade(): - op.drop_table("prompt") \ No newline at end of file