flare / project_controller.py
ciyidogan's picture
Update project_controller.py
86c6075 verified
raw
history blame
8.63 kB
from fastapi import APIRouter, HTTPException, Request, Depends
from config_provider import get_config, service_config
from service_config import ServiceConfig
import datetime
import json
import copy
router = APIRouter()
def get_utc_now():
return datetime.datetime.utcnow().isoformat()
@router.get("/list")
def list_projects(config: ServiceConfig = Depends(get_config)):
return config.projects
@router.get("/{project_name}/latest")
def get_latest_project_version(project_name: str, config: ServiceConfig = Depends(get_config)):
project = config.projects.get(project_name)
if not project:
raise HTTPException(status_code=404, detail="Project not found")
if not project.get("versions"):
raise HTTPException(status_code=404, detail="No versions found")
latest = max(project["versions"], key=lambda v: v["version_number"])
return {
"version_number": latest["version_number"],
"published": latest.get("published", False),
"intents": latest.get("intents", []),
"llm": latest.get("llm", {}),
"last_updated": project.get("last_updated", get_utc_now())
}
@router.post("/update")
async def update_project(request: Request, config: ServiceConfig = Depends(get_config)):
data = await request.json()
project_name = data.get("project_name")
client_last_updated = data.get("client_last_updated")
new_data = data.get("new_data")
project = config.projects.get(project_name)
if not project:
raise HTTPException(status_code=404, detail="Project not found")
if project.get("last_updated") != client_last_updated:
raise HTTPException(status_code=409, detail="Record updated by another user. Please reload.")
latest = max(project["versions"], key=lambda v: v["version_number"])
if latest.get("published"):
raise HTTPException(status_code=400, detail="Cannot edit a published version.")
latest.update(new_data)
project["last_updated"] = get_utc_now()
with open(config.config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
return {"message": f"Project {project_name} updated"}
@router.post("/publish")
async def publish_project(request: Request, config: ServiceConfig = Depends(get_config)):
data = await request.json()
project_name = data.get("project_name")
client_last_updated = data.get("client_last_updated")
project = config.projects.get(project_name)
if not project:
raise HTTPException(status_code=404, detail="Project not found")
if project.get("last_updated") != client_last_updated:
raise HTTPException(status_code=409, detail="Record updated by another user. Please reload.")
latest = max(project["versions"], key=lambda v: v["version_number"])
if latest.get("published"):
raise HTTPException(status_code=400, detail="Version already published.")
llm = latest.get("llm", {})
if not llm.get("repo_id"):
raise HTTPException(status_code=400, detail="repo_id is required")
if llm.get("use_fine_tune") and not llm.get("fine_tune_zip"):
raise HTTPException(status_code=400, detail="fine_tune_zip is required when use_fine_tune is true")
latest["published"] = True
latest["last_updated"] = get_utc_now()
new_version_number = latest["version_number"] + 1
new_version = copy.deepcopy(latest)
new_version["version_number"] = new_version_number
new_version["published"] = False
new_version["last_updated"] = get_utc_now()
new_version["intents"] = []
new_version["llm"] = copy.deepcopy(llm)
project["versions"].append(new_version)
project["last_updated"] = get_utc_now()
with open(config.config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
return {"message": f"Project {project_name} version published and new draft version {new_version_number} created"}
@router.post("/add_intent")
async def add_intent(request: Request, config: ServiceConfig = Depends(get_config)):
data = await request.json()
project_name = data.get("project_name")
intent_name = data.get("intent_name")
project = config.projects.get(project_name)
if not project:
raise HTTPException(status_code=404, detail="Project not found")
latest = max(project["versions"], key=lambda v: v["version_number"])
if any(intent["name"] == intent_name for intent in latest.get("intents", [])):
raise HTTPException(status_code=400, detail="Intent with this name already exists.")
latest.setdefault("intents", []).append({
"name": intent_name,
"examples": [],
"parameters": [],
"action": "",
"fallback_timeout_message": "",
"fallback_error_message": "",
"humanization_prompt": ""
})
project["last_updated"] = get_utc_now()
with open(config.config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
return {"message": f"Intent {intent_name} added to project {project_name}"}
@router.post("/delete_intent")
async def delete_intent(request: Request, config: ServiceConfig = Depends(get_config)):
data = await request.json()
project_name = data.get("project_name")
intent_name = data.get("intent_name")
project = config.projects.get(project_name)
if not project:
raise HTTPException(status_code=404, detail="Project not found")
latest = max(project["versions"], key=lambda v: v["version_number"])
intents = latest.get("intents", [])
new_intents = [intent for intent in intents if intent["name"] != intent_name]
if len(new_intents) == len(intents):
raise HTTPException(status_code=404, detail="Intent not found.")
latest["intents"] = new_intents
project["last_updated"] = get_utc_now()
with open(config.config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
return {"message": f"Intent {intent_name} deleted from project {project_name}"}
@router.post("/update_intent")
async def update_intent(request: Request, config: ServiceConfig = Depends(get_config)):
data = await request.json()
project_name = data.get("project_name")
intent_name = data.get("intent_name")
intent_data = data.get("intent_data")
if not project_name or not intent_name or not intent_data:
raise HTTPException(status_code=400, detail="project_name, intent_name, and intent_data are required")
project = config.projects.get(project_name)
if not project:
raise HTTPException(status_code=404, detail="Project not found")
latest = max(project["versions"], key=lambda v: v["version_number"])
updated = False
for intent in latest.get("intents", []):
if intent.get("name") == intent_name:
intent.update(intent_data)
updated = True
break
if not updated:
raise HTTPException(status_code=404, detail="Intent not found in project")
project["last_updated"] = get_utc_now()
with open(config.config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
return {"message": f"Intent {intent_name} updated in project {project_name}"}
@router.post("/seed/test_data")
def seed_test_data(config: ServiceConfig = Depends(get_config)):
config.projects = {
"demo-project": {
"enabled": True,
"last_updated": get_utc_now(),
"versions": [
{
"version_number": 1,
"published": True,
"last_updated": get_utc_now(),
"intents": [{"name": "weather-intent"}, {"name": "currency-intent"}],
"llm": {
"repo_id": "demo/repo",
"use_fine_tune": False
}
},
{
"version_number": 2,
"published": False,
"last_updated": get_utc_now(),
"intents": [],
"llm": {
"repo_id": "demo/repo",
"use_fine_tune": False
}
}
]
}
}
with open(config.config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
return {"message": "Test data seeded"}
@router.post("/clear/all")
def clear_all(config: ServiceConfig = Depends(get_config)):
config.projects = {}
with open(config.config_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
return {"message": "All projects cleared"}