File size: 8,628 Bytes
86c6075
11bc0e5
86c6075
9508bbf
f04c960
5b88843
fb5b6b9
 
 
9508bbf
 
 
f04c960
98e5e6c
 
f04c960
75195a9
98e5e6c
 
75195a9
 
 
71774aa
75195a9
 
 
 
 
 
 
 
5b88843
71774aa
fb5b6b9
 
9508bbf
98e5e6c
9508bbf
 
 
75195a9
9508bbf
98e5e6c
9508bbf
 
 
71774aa
75195a9
9508bbf
75195a9
 
 
9508bbf
75195a9
9508bbf
75195a9
98e5e6c
 
75195a9
9508bbf
 
cf590c1
98e5e6c
fb5b6b9
 
9508bbf
 
98e5e6c
cf590c1
fb5b6b9
 
71774aa
75195a9
9508bbf
75195a9
 
 
fb5b6b9
75195a9
cf590c1
 
 
 
 
75195a9
 
5b88843
 
 
 
 
 
da0a0a8
5b88843
 
 
9508bbf
 
98e5e6c
 
9508bbf
5b88843
da0a0a8
6ce03c4
98e5e6c
6ce03c4
 
 
 
98e5e6c
6ce03c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98e5e6c
 
6ce03c4
 
 
 
98e5e6c
6ce03c4
 
 
 
98e5e6c
6ce03c4
 
 
 
 
 
 
 
 
 
 
 
98e5e6c
 
6ce03c4
 
 
98e5e6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da0a0a8
98e5e6c
 
da0a0a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98e5e6c
 
da0a0a8
 
 
 
98e5e6c
 
 
 
da0a0a8
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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"}