list_pipeline_conversations front_api
This commit is contained in:
@@ -4,6 +4,7 @@ import os
|
|||||||
import os.path as osp
|
import os.path as osp
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
import psycopg
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
@@ -118,6 +119,33 @@ class PipelineStopResponse(BaseModel):
|
|||||||
reload_required: bool
|
reload_required: bool
|
||||||
|
|
||||||
|
|
||||||
|
class ConversationListItem(BaseModel):
|
||||||
|
conversation_id: str
|
||||||
|
pipeline_id: str
|
||||||
|
message_count: int
|
||||||
|
last_updated: Optional[str] = Field(default=None)
|
||||||
|
|
||||||
|
|
||||||
|
class PipelineConversationListResponse(BaseModel):
|
||||||
|
pipeline_id: str
|
||||||
|
items: List[ConversationListItem]
|
||||||
|
count: int
|
||||||
|
|
||||||
|
|
||||||
|
class ConversationMessageItem(BaseModel):
|
||||||
|
message_type: str
|
||||||
|
content: str
|
||||||
|
sequence_number: int
|
||||||
|
created_at: str
|
||||||
|
|
||||||
|
|
||||||
|
class PipelineConversationMessagesResponse(BaseModel):
|
||||||
|
pipeline_id: str
|
||||||
|
conversation_id: str
|
||||||
|
items: List[ConversationMessageItem]
|
||||||
|
count: int
|
||||||
|
|
||||||
|
|
||||||
class ApiKeyPolicyItem(BaseModel):
|
class ApiKeyPolicyItem(BaseModel):
|
||||||
api_key: str
|
api_key: str
|
||||||
default_pipeline_id: Optional[str] = Field(default=None)
|
default_pipeline_id: Optional[str] = Field(default=None)
|
||||||
@@ -200,6 +228,8 @@ async def root():
|
|||||||
"/v1/pipelines (POST) - build config + upsert pipeline registry entry",
|
"/v1/pipelines (POST) - build config + upsert pipeline registry entry",
|
||||||
"/v1/pipelines (GET) - list registry pipeline specs",
|
"/v1/pipelines (GET) - list registry pipeline specs",
|
||||||
"/v1/pipelines/{pipeline_id} (DELETE) - disable pipeline in registry",
|
"/v1/pipelines/{pipeline_id} (DELETE) - disable pipeline in registry",
|
||||||
|
"/v1/pipelines/{pipeline_id}/conversations (GET) - list pipeline conversations",
|
||||||
|
"/v1/pipelines/{pipeline_id}/conversations/{conversation_id}/messages (GET) - list messages in a conversation",
|
||||||
"/v1/pipelines/api-keys (GET) - list API key routing policies",
|
"/v1/pipelines/api-keys (GET) - list API key routing policies",
|
||||||
"/v1/pipelines/api-keys/{api_key} (PUT) - upsert API key routing policy",
|
"/v1/pipelines/api-keys/{api_key} (PUT) - upsert API key routing policy",
|
||||||
"/v1/pipelines/api-keys/{api_key} (DELETE) - delete API key routing policy",
|
"/v1/pipelines/api-keys/{api_key} (DELETE) - delete API key routing policy",
|
||||||
@@ -630,6 +660,123 @@ async def stop_pipeline(pipeline_id: str):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(
|
||||||
|
"/v1/pipelines/{pipeline_id}/conversations",
|
||||||
|
response_model=PipelineConversationListResponse,
|
||||||
|
)
|
||||||
|
async def list_pipeline_conversations(pipeline_id: str, limit: int = 100):
|
||||||
|
if limit < 1 or limit > 500:
|
||||||
|
raise HTTPException(status_code=400, detail="limit must be between 1 and 500")
|
||||||
|
|
||||||
|
conn_str = os.environ.get("CONN_STR")
|
||||||
|
if not conn_str:
|
||||||
|
raise HTTPException(status_code=500, detail="CONN_STR not set")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with psycopg.connect(conn_str) as conn:
|
||||||
|
with conn.cursor(row_factory=psycopg.rows.dict_row) as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
conversation_id,
|
||||||
|
pipeline_id,
|
||||||
|
COUNT(*) AS message_count,
|
||||||
|
MAX(created_at) AS last_updated
|
||||||
|
FROM messages
|
||||||
|
WHERE pipeline_id = %s
|
||||||
|
GROUP BY conversation_id, pipeline_id
|
||||||
|
ORDER BY last_updated DESC
|
||||||
|
LIMIT %s
|
||||||
|
""",
|
||||||
|
(pipeline_id, limit),
|
||||||
|
)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
items = [
|
||||||
|
ConversationListItem(
|
||||||
|
conversation_id=str(row["conversation_id"]),
|
||||||
|
pipeline_id=str(row["pipeline_id"]),
|
||||||
|
message_count=int(row["message_count"]),
|
||||||
|
last_updated=(
|
||||||
|
row["last_updated"].isoformat() if row.get("last_updated") else None
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for row in rows
|
||||||
|
]
|
||||||
|
return PipelineConversationListResponse(
|
||||||
|
pipeline_id=pipeline_id, items=items, count=len(items)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(
|
||||||
|
"/v1/pipelines/{pipeline_id}/conversations/{conversation_id}/messages",
|
||||||
|
response_model=PipelineConversationMessagesResponse,
|
||||||
|
)
|
||||||
|
async def get_pipeline_conversation_messages(pipeline_id: str, conversation_id: str):
|
||||||
|
conn_str = os.environ.get("CONN_STR")
|
||||||
|
if not conn_str:
|
||||||
|
raise HTTPException(status_code=500, detail="CONN_STR not set")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with psycopg.connect(conn_str) as conn:
|
||||||
|
with conn.cursor(row_factory=psycopg.rows.dict_row) as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT 1
|
||||||
|
FROM messages
|
||||||
|
WHERE pipeline_id = %s AND conversation_id = %s
|
||||||
|
LIMIT 1
|
||||||
|
""",
|
||||||
|
(pipeline_id, conversation_id),
|
||||||
|
)
|
||||||
|
exists = cur.fetchone()
|
||||||
|
if exists is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail=(
|
||||||
|
f"conversation_id '{conversation_id}' not found for "
|
||||||
|
f"pipeline '{pipeline_id}'"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
message_type,
|
||||||
|
content,
|
||||||
|
sequence_number,
|
||||||
|
created_at
|
||||||
|
FROM messages
|
||||||
|
WHERE pipeline_id = %s AND conversation_id = %s
|
||||||
|
ORDER BY sequence_number ASC
|
||||||
|
""",
|
||||||
|
(pipeline_id, conversation_id),
|
||||||
|
)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
items = [
|
||||||
|
ConversationMessageItem(
|
||||||
|
message_type=str(row["message_type"]),
|
||||||
|
content=str(row["content"]),
|
||||||
|
sequence_number=int(row["sequence_number"]),
|
||||||
|
created_at=row["created_at"].isoformat() if row.get("created_at") else "",
|
||||||
|
)
|
||||||
|
for row in rows
|
||||||
|
]
|
||||||
|
return PipelineConversationMessagesResponse(
|
||||||
|
pipeline_id=pipeline_id,
|
||||||
|
conversation_id=conversation_id,
|
||||||
|
items=items,
|
||||||
|
count=len(items),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/v1/pipelines/api-keys", response_model=ApiKeyPolicyListResponse)
|
@app.get("/v1/pipelines/api-keys", response_model=ApiKeyPolicyListResponse)
|
||||||
async def list_pipeline_api_keys():
|
async def list_pipeline_api_keys():
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user