Kevin Hu commited on
Commit
d25ba26
·
1 Parent(s): 7ac0c02

add input variables to begin component (#3498)

Browse files

### What problem does this PR solve?

#3355

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

agent/canvas.py CHANGED
@@ -156,8 +156,12 @@ class Canvas(ABC):
156
  self.components[k]["obj"].reset()
157
  self._embed_id = ""
158
 
 
 
 
 
 
159
  def run(self, **kwargs):
160
- ans = ""
161
  if self.answer:
162
  cpn_id = self.answer[0]
163
  self.answer.pop(0)
@@ -167,10 +171,10 @@ class Canvas(ABC):
167
  ans = ComponentBase.be_output(str(e))
168
  self.path[-1].append(cpn_id)
169
  if kwargs.get("stream"):
170
- assert isinstance(ans, partial)
171
- return ans
172
- self.history.append(("assistant", ans.to_dict("records")))
173
- return ans
174
 
175
  if not self.path:
176
  self.components["begin"]["obj"].run(self.history, **kwargs)
@@ -178,6 +182,8 @@ class Canvas(ABC):
178
 
179
  self.path.append([])
180
  ran = -1
 
 
181
 
182
  def prepare2run(cpns):
183
  nonlocal ran, ans
@@ -188,14 +194,19 @@ class Canvas(ABC):
188
  self.answer.append(c)
189
  else:
190
  logging.debug(f"Canvas.prepare2run: {c}")
191
- cpids = cpn.get_dependent_components()
192
- if any([c not in self.path[-1] for c in cpids]):
193
- continue
 
 
 
194
  ans = cpn.run(self.history, **kwargs)
195
  self.path[-1].append(c)
196
  ran += 1
197
 
198
- prepare2run(self.components[self.path[-2][-1]]["downstream"])
 
 
199
  while 0 <= ran < len(self.path[-1]):
200
  logging.debug(f"Canvas.run: {ran} {self.path}")
201
  cpn_id = self.path[-1][ran]
@@ -210,28 +221,39 @@ class Canvas(ABC):
210
  assert switch_out in self.components, \
211
  "{}'s output: {} not valid.".format(cpn_id, switch_out)
212
  try:
213
- prepare2run([switch_out])
 
214
  except Exception as e:
215
  for p in [c for p in self.path for c in p][::-1]:
216
  if p.lower().find("answer") >= 0:
217
  self.get_component(p)["obj"].set_exception(e)
218
- prepare2run([p])
 
219
  break
220
  logging.exception("Canvas.run got exception")
221
  break
222
  continue
223
 
224
  try:
225
- prepare2run(cpn["downstream"])
 
226
  except Exception as e:
227
  for p in [c for p in self.path for c in p][::-1]:
228
  if p.lower().find("answer") >= 0:
229
  self.get_component(p)["obj"].set_exception(e)
230
- prepare2run([p])
 
231
  break
232
  logging.exception("Canvas.run got exception")
233
  break
234
 
 
 
 
 
 
 
 
235
  if self.answer:
236
  cpn_id = self.answer[0]
237
  self.answer.pop(0)
@@ -239,11 +261,13 @@ class Canvas(ABC):
239
  self.path[-1].append(cpn_id)
240
  if kwargs.get("stream"):
241
  assert isinstance(ans, partial)
242
- return ans
243
-
244
- self.history.append(("assistant", ans.to_dict("records")))
 
245
 
246
- return ans
 
247
 
248
  def get_component(self, cpn_id):
249
  return self.components[cpn_id]
 
156
  self.components[k]["obj"].reset()
157
  self._embed_id = ""
158
 
159
+ def get_compnent_name(self, cid):
160
+ for n in self.dsl["graph"]["nodes"]:
161
+ if cid == n["id"]: return n["data"]["name"]
162
+ return ""
163
+
164
  def run(self, **kwargs):
 
165
  if self.answer:
166
  cpn_id = self.answer[0]
167
  self.answer.pop(0)
 
171
  ans = ComponentBase.be_output(str(e))
172
  self.path[-1].append(cpn_id)
173
  if kwargs.get("stream"):
174
+ for an in ans():
175
+ yield an
176
+ else: yield ans
177
+ return
178
 
179
  if not self.path:
180
  self.components["begin"]["obj"].run(self.history, **kwargs)
 
182
 
183
  self.path.append([])
184
  ran = -1
185
+ waiting = []
186
+ without_dependent_checking = []
187
 
188
  def prepare2run(cpns):
189
  nonlocal ran, ans
 
194
  self.answer.append(c)
195
  else:
196
  logging.debug(f"Canvas.prepare2run: {c}")
197
+ if c not in without_dependent_checking:
198
+ cpids = cpn.get_dependent_components()
199
+ if any([cc not in self.path[-1] for cc in cpids]):
200
+ if c not in waiting: waiting.append(c)
201
+ continue
202
+ yield "'{}' is running...".format(self.get_compnent_name(c))
203
  ans = cpn.run(self.history, **kwargs)
204
  self.path[-1].append(c)
205
  ran += 1
206
 
207
+ for m in prepare2run(self.components[self.path[-2][-1]]["downstream"]):
208
+ yield {"content": m, "running_status": True}
209
+
210
  while 0 <= ran < len(self.path[-1]):
211
  logging.debug(f"Canvas.run: {ran} {self.path}")
212
  cpn_id = self.path[-1][ran]
 
221
  assert switch_out in self.components, \
222
  "{}'s output: {} not valid.".format(cpn_id, switch_out)
223
  try:
224
+ for m in prepare2run([switch_out]):
225
+ yield {"content": m, "running_status": True}
226
  except Exception as e:
227
  for p in [c for p in self.path for c in p][::-1]:
228
  if p.lower().find("answer") >= 0:
229
  self.get_component(p)["obj"].set_exception(e)
230
+ for m in prepare2run([p]):
231
+ yield {"content": m, "running_status": True}
232
  break
233
  logging.exception("Canvas.run got exception")
234
  break
235
  continue
236
 
237
  try:
238
+ for m in prepare2run(cpn["downstream"]):
239
+ yield {"content": m, "running_status": True}
240
  except Exception as e:
241
  for p in [c for p in self.path for c in p][::-1]:
242
  if p.lower().find("answer") >= 0:
243
  self.get_component(p)["obj"].set_exception(e)
244
+ for m in prepare2run([p]):
245
+ yield {"content": m, "running_status": True}
246
  break
247
  logging.exception("Canvas.run got exception")
248
  break
249
 
250
+ if ran >= len(self.path[-1]) and waiting:
251
+ without_dependent_checking = waiting
252
+ waiting = []
253
+ for m in prepare2run(without_dependent_checking):
254
+ yield {"content": m, "running_status": True}
255
+ ran -= 1
256
+
257
  if self.answer:
258
  cpn_id = self.answer[0]
259
  self.answer.pop(0)
 
261
  self.path[-1].append(cpn_id)
262
  if kwargs.get("stream"):
263
  assert isinstance(ans, partial)
264
+ for an in ans():
265
+ yield an
266
+ else:
267
+ yield ans
268
 
269
+ else:
270
+ raise Exception("The dialog flow has no way to interact with you. Please add an 'Interact' component to the end of the flow.")
271
 
272
  def get_component(self, cpn_id):
273
  return self.components[cpn_id]
agent/component/base.py CHANGED
@@ -13,17 +13,17 @@
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
16
- import logging
17
  from abc import ABC
18
  import builtins
19
  import json
20
  import os
21
  from functools import partial
 
22
 
23
  import pandas as pd
24
 
25
  from agent import settings
26
-
27
 
28
  _FEEDED_DEPRECATED_PARAMS = "_feeded_deprecated_params"
29
  _DEPRECATED_PARAMS = "_deprecated_params"
@@ -82,7 +82,6 @@ class ComponentParamBase(ABC):
82
  return {name: True for name in self.get_feeded_deprecated_params()}
83
 
84
  def __str__(self):
85
-
86
  return json.dumps(self.as_dict(), ensure_ascii=False)
87
 
88
  def as_dict(self):
@@ -398,8 +397,11 @@ class ComponentBase(ABC):
398
  self._param.check()
399
 
400
  def get_dependent_components(self):
401
- cpnts = [para["component_id"] for para in self._param.query if para.get("component_id") and para["component_id"].lower().find("answer") < 0]
402
- return cpnts
 
 
 
403
 
404
  def run(self, history, **kwargs):
405
  logging.debug("{}, history: {}, kwargs: {}".format(self, json.dumps(history, ensure_ascii=False),
@@ -416,7 +418,7 @@ class ComponentBase(ABC):
416
  def _run(self, history, **kwargs):
417
  raise NotImplementedError()
418
 
419
- def output(self, allow_partial=True) -> tuple[str, pd.DataFrame | partial]:
420
  o = getattr(self._param, self._param.output_var_name)
421
  if not isinstance(o, partial) and not isinstance(o, pd.DataFrame):
422
  if not isinstance(o, list): o = [o]
@@ -436,12 +438,19 @@ class ComponentBase(ABC):
436
 
437
  def reset(self):
438
  setattr(self._param, self._param.output_var_name, None)
 
439
 
440
  def set_output(self, v: pd.DataFrame):
441
  setattr(self._param, self._param.output_var_name, v)
442
 
443
  def get_input(self):
 
 
 
 
 
444
  if self._param.query:
 
445
  outs = []
446
  for q in self._param.query:
447
  if q["component_id"]:
@@ -449,9 +458,9 @@ class ComponentBase(ABC):
449
  cpn_id, key = q["component_id"].split("@")
450
  for p in self._canvas.get_component(cpn_id)["obj"]._param.query:
451
  if p["key"] == key:
452
- outs.append(pd.DataFrame([{"content": p["value"]}]))
453
  self._param.inputs.append({"component_id": q["component_id"],
454
- "content": p["value"]})
455
  break
456
  else:
457
  assert False, f"Can't find parameter '{key}' for {cpn_id}"
@@ -470,12 +479,8 @@ class ComponentBase(ABC):
470
  return df
471
 
472
  upstream_outs = []
473
- reversed_cpnts = []
474
- if len(self._canvas.path) > 1:
475
- reversed_cpnts.extend(self._canvas.path[-2])
476
- reversed_cpnts.extend(self._canvas.path[-1])
477
 
478
- logging.debug(f"{self.component_name} {reversed_cpnts[::-1]}")
479
  for u in reversed_cpnts[::-1]:
480
  if self.get_component_name(u) in ["switch", "concentrator"]: continue
481
  if self.component_name.lower() == "generate" and self.get_component_name(u) == "retrieval":
@@ -484,7 +489,7 @@ class ComponentBase(ABC):
484
  o["component_id"] = u
485
  upstream_outs.append(o)
486
  continue
487
- if self.component_name.lower()!="answer" and u not in self._canvas.get_component(self._id)["upstream"]: continue
488
  if self.component_name.lower().find("switch") < 0 \
489
  and self.get_component_name(u) in ["relevant", "categorize"]:
490
  continue
@@ -502,14 +507,14 @@ class ComponentBase(ABC):
502
  upstream_outs.append(o)
503
  break
504
 
505
- assert upstream_outs, "Can't inference the where the component input is."
506
 
507
  df = pd.concat(upstream_outs, ignore_index=True)
508
  if "content" in df:
509
  df = df.drop_duplicates(subset=['content']).reset_index(drop=True)
510
 
511
  self._param.inputs = []
512
- for _,r in df.iterrows():
513
  self._param.inputs.append({"component_id": r["component_id"], "content": r["content"]})
514
 
515
  return df
 
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
 
16
  from abc import ABC
17
  import builtins
18
  import json
19
  import os
20
  from functools import partial
21
+ from typing import Tuple, Union
22
 
23
  import pandas as pd
24
 
25
  from agent import settings
26
+ from agent.settings import flow_logger, DEBUG
27
 
28
  _FEEDED_DEPRECATED_PARAMS = "_feeded_deprecated_params"
29
  _DEPRECATED_PARAMS = "_deprecated_params"
 
82
  return {name: True for name in self.get_feeded_deprecated_params()}
83
 
84
  def __str__(self):
 
85
  return json.dumps(self.as_dict(), ensure_ascii=False)
86
 
87
  def as_dict(self):
 
397
  self._param.check()
398
 
399
  def get_dependent_components(self):
400
+ cpnts = set([para["component_id"].split("@")[0] for para in self._param.query \
401
+ if para.get("component_id") \
402
+ and para["component_id"].lower().find("answer") < 0 \
403
+ and para["component_id"].lower().find("begin") < 0])
404
+ return list(cpnts)
405
 
406
  def run(self, history, **kwargs):
407
  logging.debug("{}, history: {}, kwargs: {}".format(self, json.dumps(history, ensure_ascii=False),
 
418
  def _run(self, history, **kwargs):
419
  raise NotImplementedError()
420
 
421
+ def output(self, allow_partial=True) -> Tuple[str, Union[pd.DataFrame, partial]]:
422
  o = getattr(self._param, self._param.output_var_name)
423
  if not isinstance(o, partial) and not isinstance(o, pd.DataFrame):
424
  if not isinstance(o, list): o = [o]
 
438
 
439
  def reset(self):
440
  setattr(self._param, self._param.output_var_name, None)
441
+ self._param.inputs = []
442
 
443
  def set_output(self, v: pd.DataFrame):
444
  setattr(self._param, self._param.output_var_name, v)
445
 
446
  def get_input(self):
447
+ reversed_cpnts = []
448
+ if len(self._canvas.path) > 1:
449
+ reversed_cpnts.extend(self._canvas.path[-2])
450
+ reversed_cpnts.extend(self._canvas.path[-1])
451
+
452
  if self._param.query:
453
+ self._param.inputs = []
454
  outs = []
455
  for q in self._param.query:
456
  if q["component_id"]:
 
458
  cpn_id, key = q["component_id"].split("@")
459
  for p in self._canvas.get_component(cpn_id)["obj"]._param.query:
460
  if p["key"] == key:
461
+ outs.append(pd.DataFrame([{"content": p.get("value", "")}]))
462
  self._param.inputs.append({"component_id": q["component_id"],
463
+ "content": p.get("value", "")})
464
  break
465
  else:
466
  assert False, f"Can't find parameter '{key}' for {cpn_id}"
 
479
  return df
480
 
481
  upstream_outs = []
 
 
 
 
482
 
483
+ if DEBUG: print(self.component_name, reversed_cpnts[::-1])
484
  for u in reversed_cpnts[::-1]:
485
  if self.get_component_name(u) in ["switch", "concentrator"]: continue
486
  if self.component_name.lower() == "generate" and self.get_component_name(u) == "retrieval":
 
489
  o["component_id"] = u
490
  upstream_outs.append(o)
491
  continue
492
+ #if self.component_name.lower()!="answer" and u not in self._canvas.get_component(self._id)["upstream"]: continue
493
  if self.component_name.lower().find("switch") < 0 \
494
  and self.get_component_name(u) in ["relevant", "categorize"]:
495
  continue
 
507
  upstream_outs.append(o)
508
  break
509
 
510
+ assert upstream_outs, "Can't inference the where the component input is. Please identify whose output is this component's input."
511
 
512
  df = pd.concat(upstream_outs, ignore_index=True)
513
  if "content" in df:
514
  df = df.drop_duplicates(subset=['content']).reset_index(drop=True)
515
 
516
  self._param.inputs = []
517
+ for _, r in df.iterrows():
518
  self._param.inputs.append({"component_id": r["component_id"], "content": r["content"]})
519
 
520
  return df
agent/component/generate.py CHANGED
@@ -63,9 +63,11 @@ class Generate(ComponentBase):
63
  component_name = "Generate"
64
 
65
  def get_dependent_components(self):
66
- cpnts = [para["component_id"] for para in self._param.parameters if
67
- para.get("component_id") and para["component_id"].lower().find("answer") < 0]
68
- return cpnts
 
 
69
 
70
  def set_cite(self, retrieval_res, answer):
71
  retrieval_res = retrieval_res.dropna(subset=["vector", "content_ltks"]).reset_index(drop=True)
@@ -107,11 +109,12 @@ class Generate(ComponentBase):
107
  self._param.inputs = []
108
  for para in self._param.parameters:
109
  if not para.get("component_id"): continue
110
- if para["component_id"].split("@")[0].lower().find("begin") > 0:
 
111
  cpn_id, key = para["component_id"].split("@")
112
  for p in self._canvas.get_component(cpn_id)["obj"]._param.query:
113
  if p["key"] == key:
114
- kwargs[para["key"]] = p["value"]
115
  self._param.inputs.append(
116
  {"component_id": para["component_id"], "content": kwargs[para["key"]]})
117
  break
@@ -119,7 +122,7 @@ class Generate(ComponentBase):
119
  assert False, f"Can't find parameter '{key}' for {cpn_id}"
120
  continue
121
 
122
- cpn = self._canvas.get_component(para["component_id"])["obj"]
123
  if cpn.component_name.lower() == "answer":
124
  kwargs[para["key"]] = self._canvas.get_history(1)[0]["content"]
125
  continue
@@ -129,14 +132,12 @@ class Generate(ComponentBase):
129
  else:
130
  if cpn.component_name.lower() == "retrieval":
131
  retrieval_res.append(out)
132
- kwargs[para["key"]] = " - " + "\n - ".join(
133
- [o if isinstance(o, str) else str(o) for o in out["content"]])
134
  self._param.inputs.append({"component_id": para["component_id"], "content": kwargs[para["key"]]})
135
 
136
  if retrieval_res:
137
  retrieval_res = pd.concat(retrieval_res, ignore_index=True)
138
- else:
139
- retrieval_res = pd.DataFrame([])
140
 
141
  for n, v in kwargs.items():
142
  prompt = re.sub(r"\{%s\}" % re.escape(n), re.escape(str(v)), prompt)
@@ -158,6 +159,7 @@ class Generate(ComponentBase):
158
  return pd.DataFrame([res])
159
 
160
  msg = self._canvas.get_history(self._param.message_history_window_size)
 
161
  _, msg = message_fit_in([{"role": "system", "content": prompt}, *msg], int(chat_mdl.max_length * 0.97))
162
  if len(msg) < 2: msg.append({"role": "user", "content": ""})
163
  ans = chat_mdl.chat(msg[0]["content"], msg[1:], self._param.gen_conf())
@@ -178,6 +180,7 @@ class Generate(ComponentBase):
178
  return
179
 
180
  msg = self._canvas.get_history(self._param.message_history_window_size)
 
181
  _, msg = message_fit_in([{"role": "system", "content": prompt}, *msg], int(chat_mdl.max_length * 0.97))
182
  if len(msg) < 2: msg.append({"role": "user", "content": ""})
183
  answer = ""
 
63
  component_name = "Generate"
64
 
65
  def get_dependent_components(self):
66
+ cpnts = set([para["component_id"].split("@")[0] for para in self._param.parameters \
67
+ if para.get("component_id") \
68
+ and para["component_id"].lower().find("answer") < 0 \
69
+ and para["component_id"].lower().find("begin") < 0])
70
+ return list(cpnts)
71
 
72
  def set_cite(self, retrieval_res, answer):
73
  retrieval_res = retrieval_res.dropna(subset=["vector", "content_ltks"]).reset_index(drop=True)
 
109
  self._param.inputs = []
110
  for para in self._param.parameters:
111
  if not para.get("component_id"): continue
112
+ component_id = para["component_id"].split("@")[0]
113
+ if para["component_id"].lower().find("@") >= 0:
114
  cpn_id, key = para["component_id"].split("@")
115
  for p in self._canvas.get_component(cpn_id)["obj"]._param.query:
116
  if p["key"] == key:
117
+ kwargs[para["key"]] = p.get("value", "")
118
  self._param.inputs.append(
119
  {"component_id": para["component_id"], "content": kwargs[para["key"]]})
120
  break
 
122
  assert False, f"Can't find parameter '{key}' for {cpn_id}"
123
  continue
124
 
125
+ cpn = self._canvas.get_component(component_id)["obj"]
126
  if cpn.component_name.lower() == "answer":
127
  kwargs[para["key"]] = self._canvas.get_history(1)[0]["content"]
128
  continue
 
132
  else:
133
  if cpn.component_name.lower() == "retrieval":
134
  retrieval_res.append(out)
135
+ kwargs[para["key"]] = " - "+"\n - ".join([o if isinstance(o, str) else str(o) for o in out["content"]])
 
136
  self._param.inputs.append({"component_id": para["component_id"], "content": kwargs[para["key"]]})
137
 
138
  if retrieval_res:
139
  retrieval_res = pd.concat(retrieval_res, ignore_index=True)
140
+ else: retrieval_res = pd.DataFrame([])
 
141
 
142
  for n, v in kwargs.items():
143
  prompt = re.sub(r"\{%s\}" % re.escape(n), re.escape(str(v)), prompt)
 
159
  return pd.DataFrame([res])
160
 
161
  msg = self._canvas.get_history(self._param.message_history_window_size)
162
+ if len(msg) < 1: msg.append({"role": "user", "content": ""})
163
  _, msg = message_fit_in([{"role": "system", "content": prompt}, *msg], int(chat_mdl.max_length * 0.97))
164
  if len(msg) < 2: msg.append({"role": "user", "content": ""})
165
  ans = chat_mdl.chat(msg[0]["content"], msg[1:], self._param.gen_conf())
 
180
  return
181
 
182
  msg = self._canvas.get_history(self._param.message_history_window_size)
183
+ if len(msg) < 1: msg.append({"role": "user", "content": ""})
184
  _, msg = message_fit_in([{"role": "system", "content": prompt}, *msg], int(chat_mdl.max_length * 0.97))
185
  if len(msg) < 2: msg.append({"role": "user", "content": ""})
186
  answer = ""
agent/component/switch.py CHANGED
@@ -47,13 +47,35 @@ class SwitchParam(ComponentParamBase):
47
  class Switch(ComponentBase, ABC):
48
  component_name = "Switch"
49
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  def _run(self, history, **kwargs):
51
  for cond in self._param.conditions:
52
  res = []
53
  for item in cond["items"]:
54
- out = self._canvas.get_component(item["cpn_id"])["obj"].output()[1]
55
- cpn_input = "" if "content" not in out.columns else " ".join([str(s) for s in out["content"]])
56
- res.append(self.process_operator(cpn_input, item["operator"], item["value"]))
 
 
 
 
 
 
 
 
 
 
57
  if cond["logical_operator"] != "and" and any(res):
58
  return Switch.be_output(cond["to"])
59
 
 
47
  class Switch(ComponentBase, ABC):
48
  component_name = "Switch"
49
 
50
+ def get_dependent_components(self):
51
+ res = []
52
+ for cond in self._param.conditions:
53
+ for item in cond["items"]:
54
+ if not item["cpn_id"]: continue
55
+ if item["cpn_id"].find("begin") >= 0:
56
+ continue
57
+ cid = item["cpn_id"].split("@")[0]
58
+ res.append(cid)
59
+
60
+ return list(set(res))
61
+
62
  def _run(self, history, **kwargs):
63
  for cond in self._param.conditions:
64
  res = []
65
  for item in cond["items"]:
66
+ if not item["cpn_id"]:continue
67
+ cid = item["cpn_id"].split("@")[0]
68
+ if item["cpn_id"].find("@") > 0:
69
+ cpn_id, key = item["cpn_id"].split("@")
70
+ for p in self._canvas.get_component(cid)["obj"]._param.query:
71
+ if p["key"] == key:
72
+ res.append(self.process_operator(p.get("value",""), item["operator"], item.get("value", "")))
73
+ break
74
+ else:
75
+ out = self._canvas.get_component(cid)["obj"].output()[1]
76
+ cpn_input = "" if "content" not in out.columns else " ".join([str(s) for s in out["content"]])
77
+ res.append(self.process_operator(cpn_input, item["operator"], item.get("value", "")))
78
+
79
  if cond["logical_operator"] != "and" and any(res):
80
  return Switch.be_output(cond["to"])
81
 
api/apps/canvas_app.py CHANGED
@@ -15,11 +15,12 @@
15
  #
16
  import logging
17
  import json
 
18
  from functools import partial
19
  from flask import request, Response
20
  from flask_login import login_required, current_user
21
  from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService
22
- from api import settings
23
  from api.utils import get_uuid
24
  from api.utils.api_utils import get_json_result, server_error_response, validate_request, get_data_error_result
25
  from agent.canvas import Canvas
@@ -36,8 +37,7 @@ def templates():
36
  @login_required
37
  def canvas_list():
38
  return get_json_result(data=sorted([c.to_dict() for c in \
39
- UserCanvasService.query(user_id=current_user.id)],
40
- key=lambda x: x["update_time"] * -1)
41
  )
42
 
43
 
@@ -46,10 +46,10 @@ def canvas_list():
46
  @login_required
47
  def rm():
48
  for i in request.json["canvas_ids"]:
49
- if not UserCanvasService.query(user_id=current_user.id, id=i):
50
  return get_json_result(
51
  data=False, message='Only owner of canvas authorized for this operation.',
52
- code=settings.RetCode.OPERATING_ERROR)
53
  UserCanvasService.delete_by_id(i)
54
  return get_json_result(data=True)
55
 
@@ -73,7 +73,7 @@ def save():
73
  if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
74
  return get_json_result(
75
  data=False, message='Only owner of canvas authorized for this operation.',
76
- code=settings.RetCode.OPERATING_ERROR)
77
  UserCanvasService.update_by_id(req["id"], req)
78
  return get_json_result(data=req)
79
 
@@ -99,7 +99,7 @@ def run():
99
  if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
100
  return get_json_result(
101
  data=False, message='Only owner of canvas authorized for this operation.',
102
- code=settings.RetCode.OPERATING_ERROR)
103
 
104
  if not isinstance(cvs.dsl, str):
105
  cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False)
@@ -110,26 +110,18 @@ def run():
110
  canvas = Canvas(cvs.dsl, current_user.id)
111
  if "message" in req:
112
  canvas.messages.append({"role": "user", "content": req["message"], "id": message_id})
113
- if len([m for m in canvas.messages if m["role"] == "user"]) > 1:
114
- # ten = TenantService.get_info_by(current_user.id)[0]
115
- # req["message"] = full_question(ten["tenant_id"], ten["llm_id"], canvas.messages)
116
- pass
117
  canvas.add_user_input(req["message"])
118
- answer = canvas.run(stream=stream)
119
- logging.debug(canvas)
120
  except Exception as e:
121
  return server_error_response(e)
122
 
123
- assert answer is not None, "The dialog flow has no way to interact with you. Please add an 'Interact' component to the end of the flow."
124
-
125
  if stream:
126
- assert isinstance(answer,
127
- partial), "The dialog flow has no way to interact with you. Please add an 'Interact' component to the end of the flow."
128
-
129
  def sse():
130
  nonlocal answer, cvs
131
  try:
132
- for ans in answer():
 
 
 
133
  for k in ans.keys():
134
  final_ans[k] = ans[k]
135
  ans = {"answer": ans["content"], "reference": ans.get("reference", [])}
@@ -142,6 +134,7 @@ def run():
142
  cvs.dsl = json.loads(str(canvas))
143
  UserCanvasService.update_by_id(req["id"], cvs.to_dict())
144
  except Exception as e:
 
145
  yield "data:" + json.dumps({"code": 500, "message": str(e),
146
  "data": {"answer": "**ERROR**: " + str(e), "reference": []}},
147
  ensure_ascii=False) + "\n\n"
@@ -154,13 +147,15 @@ def run():
154
  resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")
155
  return resp
156
 
157
- final_ans["content"] = "\n".join(answer["content"]) if "content" in answer else ""
158
- canvas.messages.append({"role": "assistant", "content": final_ans["content"], "id": message_id})
159
- if final_ans.get("reference"):
160
- canvas.reference.append(final_ans["reference"])
161
- cvs.dsl = json.loads(str(canvas))
162
- UserCanvasService.update_by_id(req["id"], cvs.to_dict())
163
- return get_json_result(data={"answer": final_ans["content"], "reference": final_ans.get("reference", [])})
 
 
164
 
165
 
166
  @manager.route('/reset', methods=['POST'])
@@ -175,7 +170,7 @@ def reset():
175
  if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
176
  return get_json_result(
177
  data=False, message='Only owner of canvas authorized for this operation.',
178
- code=settings.RetCode.OPERATING_ERROR)
179
 
180
  canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
181
  canvas.reset()
 
15
  #
16
  import logging
17
  import json
18
+ import traceback
19
  from functools import partial
20
  from flask import request, Response
21
  from flask_login import login_required, current_user
22
  from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService
23
+ from api.settings import RetCode
24
  from api.utils import get_uuid
25
  from api.utils.api_utils import get_json_result, server_error_response, validate_request, get_data_error_result
26
  from agent.canvas import Canvas
 
37
  @login_required
38
  def canvas_list():
39
  return get_json_result(data=sorted([c.to_dict() for c in \
40
+ UserCanvasService.query(user_id=current_user.id)], key=lambda x: x["update_time"]*-1)
 
41
  )
42
 
43
 
 
46
  @login_required
47
  def rm():
48
  for i in request.json["canvas_ids"]:
49
+ if not UserCanvasService.query(user_id=current_user.id,id=i):
50
  return get_json_result(
51
  data=False, message='Only owner of canvas authorized for this operation.',
52
+ code=RetCode.OPERATING_ERROR)
53
  UserCanvasService.delete_by_id(i)
54
  return get_json_result(data=True)
55
 
 
73
  if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
74
  return get_json_result(
75
  data=False, message='Only owner of canvas authorized for this operation.',
76
+ code=RetCode.OPERATING_ERROR)
77
  UserCanvasService.update_by_id(req["id"], req)
78
  return get_json_result(data=req)
79
 
 
99
  if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
100
  return get_json_result(
101
  data=False, message='Only owner of canvas authorized for this operation.',
102
+ code=RetCode.OPERATING_ERROR)
103
 
104
  if not isinstance(cvs.dsl, str):
105
  cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False)
 
110
  canvas = Canvas(cvs.dsl, current_user.id)
111
  if "message" in req:
112
  canvas.messages.append({"role": "user", "content": req["message"], "id": message_id})
 
 
 
 
113
  canvas.add_user_input(req["message"])
 
 
114
  except Exception as e:
115
  return server_error_response(e)
116
 
 
 
117
  if stream:
 
 
 
118
  def sse():
119
  nonlocal answer, cvs
120
  try:
121
+ for ans in canvas.run(stream=True):
122
+ if ans.get("running_status"):
123
+ yield "data:" + json.dumps({"code": 0, "message": "", "data": ans}, ensure_ascii=False) + "\n\n"
124
+ continue
125
  for k in ans.keys():
126
  final_ans[k] = ans[k]
127
  ans = {"answer": ans["content"], "reference": ans.get("reference", [])}
 
134
  cvs.dsl = json.loads(str(canvas))
135
  UserCanvasService.update_by_id(req["id"], cvs.to_dict())
136
  except Exception as e:
137
+ traceback.print_exc()
138
  yield "data:" + json.dumps({"code": 500, "message": str(e),
139
  "data": {"answer": "**ERROR**: " + str(e), "reference": []}},
140
  ensure_ascii=False) + "\n\n"
 
147
  resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")
148
  return resp
149
 
150
+ for answer in canvas.run(stream=False):
151
+ if answer.get("running_status"): continue
152
+ final_ans["content"] = "\n".join(answer["content"]) if "content" in answer else ""
153
+ canvas.messages.append({"role": "assistant", "content": final_ans["content"], "id": message_id})
154
+ if final_ans.get("reference"):
155
+ canvas.reference.append(final_ans["reference"])
156
+ cvs.dsl = json.loads(str(canvas))
157
+ UserCanvasService.update_by_id(req["id"], cvs.to_dict())
158
+ return get_json_result(data={"answer": final_ans["content"], "reference": final_ans.get("reference", [])})
159
 
160
 
161
  @manager.route('/reset', methods=['POST'])
 
170
  if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
171
  return get_json_result(
172
  data=False, message='Only owner of canvas authorized for this operation.',
173
+ code=RetCode.OPERATING_ERROR)
174
 
175
  canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
176
  canvas.reset()
api/apps/document_app.py CHANGED
@@ -563,13 +563,13 @@ def parse():
563
  self.filepath = filepath
564
 
565
  def read(self):
566
- with open(self.filepath, "r") as f:
567
  return f.read()
568
 
569
- r = re.search(r"filename=\"([^\"])\"", json.dumps(res_headers))
570
- if not r or r.group(1):
571
  return get_json_result(
572
- data=False, message="Can't not identify downloaded file", code=RetCode.ARGUMENT_ERROR)
573
  f = File(r.group(1), os.path.join(download_path, r.group(1)))
574
  txt = FileService.parse_docs([f], current_user.id)
575
  return get_json_result(data=txt)
 
563
  self.filepath = filepath
564
 
565
  def read(self):
566
+ with open(self.filepath, "rb") as f:
567
  return f.read()
568
 
569
+ r = re.search(r"filename=\"([^\"]+)\"", str(res_headers))
570
+ if not r or not r.group(1):
571
  return get_json_result(
572
+ data=False, message="Can't not identify downloaded file", code=settings.RetCode.ARGUMENT_ERROR)
573
  f = File(r.group(1), os.path.join(download_path, r.group(1)))
574
  txt = FileService.parse_docs([f], current_user.id)
575
  return get_json_result(data=txt)
api/db/services/dialog_service.py CHANGED
@@ -98,7 +98,8 @@ def message_fit_in(msg, max_length=4000):
98
  return c, msg
99
 
100
  msg_ = [m for m in msg[:-1] if m["role"] == "system"]
101
- msg_.append(msg[-1])
 
102
  msg = msg_
103
  c = count()
104
  if c < max_length:
 
98
  return c, msg
99
 
100
  msg_ = [m for m in msg[:-1] if m["role"] == "system"]
101
+ if len(msg) > 1:
102
+ msg_.append(msg[-1])
103
  msg = msg_
104
  c = count()
105
  if c < max_length: