seekerj commited on
Commit
4556150
1 Parent(s): 99a0342

add: handle error

Browse files
Files changed (4) hide show
  1. app.py +183 -222
  2. data_model.py +118 -0
  3. init.sh +1 -1
  4. message_enum.py +17 -0
app.py CHANGED
@@ -9,239 +9,185 @@ import shutil
9
  import traceback
10
  import uuid
11
  from collections import deque
12
- from datetime import datetime
13
- from enum import Enum
14
  from functools import partial
15
- from typing import Any, Optional
 
16
 
17
  import fire
 
 
18
  import uvicorn
19
  from fastapi import FastAPI, Request
20
- from fastapi.responses import StreamingResponse
21
  from fastapi.staticfiles import StaticFiles
22
  from loguru import logger
23
- from metagpt.actions.action import Action
24
- from metagpt.actions.action_output import ActionOutput
25
  from metagpt.config import CONFIG
26
  from metagpt.logs import set_llm_stream_logfunc
27
  from metagpt.schema import Message
28
- from pydantic import BaseModel, Field
29
-
 
 
 
 
 
 
 
 
 
 
 
 
30
  from software_company import RoleRun, SoftwareCompany
31
 
32
 
33
- class QueryAnswerType(Enum):
34
- Query = "Q"
35
- Answer = "A"
36
-
37
-
38
- class SentenceType(Enum):
39
- TEXT = "text"
40
- HIHT = "hint"
41
- ACTION = "action"
42
- ERROR = "error"
43
-
44
-
45
- class MessageStatus(Enum):
46
- COMPLETE = "complete"
47
-
48
-
49
- class SentenceValue(BaseModel):
50
- answer: str
51
-
52
-
53
- class Sentence(BaseModel):
54
- type: str
55
- id: Optional[str] = None
56
- value: SentenceValue
57
- is_finished: Optional[bool] = None
58
-
59
-
60
- class Sentences(BaseModel):
61
- id: Optional[str] = None
62
- action: Optional[str] = None
63
- role: Optional[str] = None
64
- skill: Optional[str] = None
65
- description: Optional[str] = None
66
- timestamp: str = Field(default_factory=lambda: datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%z"))
67
- status: str
68
- contents: list[dict]
69
-
70
-
71
- class NewMsg(BaseModel):
72
- """Chat with MetaGPT"""
73
-
74
- query: str = Field(description="Problem description")
75
- config: dict[str, Any] = Field(description="Configuration information")
76
-
77
-
78
- class ErrorInfo(BaseModel):
79
- error: str = None
80
- traceback: str = None
81
-
82
-
83
- class ThinkActStep(BaseModel):
84
- id: str
85
- status: str
86
- title: str
87
- timestamp: str = Field(default_factory=lambda: datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%z"))
88
- description: str
89
- content: Sentence = None
90
-
91
-
92
- class ThinkActPrompt(BaseModel):
93
- message_id: int = None
94
- timestamp: str = Field(default_factory=lambda: datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%z"))
95
- step: ThinkActStep = None
96
- skill: Optional[str] = None
97
- role: Optional[str] = None
98
-
99
- def update_think(self, tc_id, action: Action):
100
- self.step = ThinkActStep(
101
- id=str(tc_id),
102
- status="running",
103
- title=action.desc,
104
- description=action.desc,
105
- )
106
-
107
- def update_act(self, message: ActionOutput | str, is_finished: bool = True):
108
- if is_finished:
109
- self.step.status = "finish"
110
- self.step.content = Sentence(
111
- type=SentenceType.TEXT.value,
112
- id=str(1),
113
- value=SentenceValue(answer=message.content if is_finished else message),
114
- is_finished=is_finished,
115
- )
116
-
117
- @staticmethod
118
- def guid32():
119
- return str(uuid.uuid4()).replace("-", "")[0:32]
120
-
121
- @property
122
- def prompt(self):
123
- return self.json(exclude_unset=True)
124
-
125
-
126
- class MessageJsonModel(BaseModel):
127
- steps: list[Sentences]
128
- qa_type: str
129
- created_at: datetime = Field(default_factory=datetime.now)
130
- query_time: datetime = Field(default_factory=datetime.now)
131
- answer_time: datetime = Field(default_factory=datetime.now)
132
- score: Optional[int] = None
133
- feedback: Optional[str] = None
134
-
135
- def add_think_act(self, think_act_prompt: ThinkActPrompt):
136
- s = Sentences(
137
- action=think_act_prompt.step.title,
138
- skill=think_act_prompt.skill,
139
- description=think_act_prompt.step.description,
140
- timestamp=think_act_prompt.timestamp,
141
- status=think_act_prompt.step.status,
142
- contents=[think_act_prompt.step.content.dict()],
143
- )
144
- self.steps.append(s)
145
-
146
- @property
147
- def prompt(self):
148
- return self.json(exclude_unset=True)
149
-
150
-
151
- async def create_message(req_model: NewMsg, request: Request):
152
- """
153
- Session message stream
154
- """
155
- tc_id = 0
156
- try:
157
- exclude_keys = CONFIG.get("SERVER_METAGPT_CONFIG_EXCLUDE", [])
158
- config = {k.upper(): v for k, v in req_model.config.items() if k not in exclude_keys}
159
- set_context(config, uuid.uuid4().hex)
160
-
161
- msg_queue = deque()
162
- CONFIG.LLM_STREAM_LOG = lambda x: msg_queue.appendleft(x) if x else None
163
-
164
- role = SoftwareCompany()
165
- role.recv(message=Message(content=req_model.query))
166
- answer = MessageJsonModel(
167
- steps=[
168
- Sentences(
169
- contents=[
170
- Sentence(
171
- type=SentenceType.TEXT.value, value=SentenceValue(answer=req_model.query), is_finished=True
172
- )
173
- ],
174
- status=MessageStatus.COMPLETE.value,
175
- )
176
- ],
177
- qa_type=QueryAnswerType.Answer.value,
178
- )
179
-
180
  task = None
181
-
182
- async def stop_if_disconnect():
183
- while not await request.is_disconnected():
184
- await asyncio.sleep(1)
185
-
186
- if task is None:
187
- return
188
-
189
- if not task.done():
190
- task.cancel()
191
- logger.info(f"cancel task {task}")
192
-
193
- asyncio.create_task(stop_if_disconnect())
194
-
195
- while True:
196
- tc_id += 1
197
- if await request.is_disconnected():
198
- return
199
- think_result: RoleRun = await role.think()
200
- if not think_result: # End of conversion
201
- break
202
-
203
- think_act_prompt = ThinkActPrompt(role=think_result.role.profile)
204
- think_act_prompt.update_think(tc_id, think_result)
205
- yield think_act_prompt.prompt + "\n\n"
206
- task = asyncio.create_task(role.act())
207
-
208
- while not await request.is_disconnected():
209
- if msg_queue:
210
- think_act_prompt.update_act(msg_queue.pop(), False)
211
- yield think_act_prompt.prompt + "\n\n"
212
- continue
213
-
214
- if task.done():
 
 
 
 
 
 
 
 
215
  break
216
 
217
- await asyncio.sleep(0.5)
218
- else:
219
- task.cancel()
220
- return
221
-
222
- act_result = await task
223
- think_act_prompt.update_act(act_result)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  yield think_act_prompt.prompt + "\n\n"
225
- answer.add_think_act(think_act_prompt)
226
- yield answer.prompt + "\n\n" # Notify the front-end that the message is complete.
227
- except asyncio.CancelledError:
228
- task.cancel()
229
- except Exception as ex:
230
- description = str(ex)
231
- answer = traceback.format_exc()
232
  step = ThinkActStep(
233
  id=tc_id,
234
  status="failed",
235
- title=description,
236
  description=description,
237
  content=Sentence(type=SentenceType.ERROR.value, id=1, value=SentenceValue(answer=answer), is_finished=True),
238
  )
239
- think_act_prompt = ThinkActPrompt(step=step)
240
- yield think_act_prompt.prompt + "\n\n"
241
- finally:
242
- CONFIG.WORKSPACE_PATH: pathlib.Path
243
- if CONFIG.WORKSPACE_PATH.exists():
244
- shutil.rmtree(CONFIG.WORKSPACE_PATH)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
 
247
  default_llm_stream_log = partial(print, end="")
@@ -252,24 +198,35 @@ def llm_stream_log(msg):
252
  CONFIG._get("LLM_STREAM_LOG", default_llm_stream_log)(msg)
253
 
254
 
255
- def set_context(context, uid):
256
- context["WORKSPACE_PATH"] = pathlib.Path("workspace", uid)
257
- for old, new in (("DEPLOYMENT_ID", "DEPLOYMENT_NAME"), ("OPENAI_API_BASE", "OPENAI_BASE_URL")):
258
- if old in context and new not in context:
259
- context[new] = context[old]
260
- CONFIG.set_context(context)
261
- return context
262
-
263
-
264
  class ChatHandler:
265
  @staticmethod
266
  async def create_message(req_model: NewMsg, request: Request):
267
  """Message stream, using SSE."""
268
- event = create_message(req_model, request)
269
  headers = {"Cache-Control": "no-cache", "Connection": "keep-alive"}
270
  return StreamingResponse(event, headers=headers, media_type="text/event-stream")
271
 
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  app = FastAPI()
274
 
275
  app.mount(
@@ -284,7 +241,12 @@ app.add_api_route(
284
  methods=["post"],
285
  summary="Session message sending (streaming response)",
286
  )
287
-
 
 
 
 
 
288
 
289
  app.mount(
290
  "/",
@@ -292,7 +254,6 @@ app.mount(
292
  name="static",
293
  )
294
 
295
-
296
  set_llm_stream_logfunc(llm_stream_log)
297
 
298
 
 
9
  import traceback
10
  import uuid
11
  from collections import deque
 
 
12
  from functools import partial
13
+ from json import JSONDecodeError
14
+ from typing import Dict
15
 
16
  import fire
17
+ import openai
18
+ import tenacity
19
  import uvicorn
20
  from fastapi import FastAPI, Request
21
+ from fastapi.responses import StreamingResponse, JSONResponse
22
  from fastapi.staticfiles import StaticFiles
23
  from loguru import logger
 
 
24
  from metagpt.config import CONFIG
25
  from metagpt.logs import set_llm_stream_logfunc
26
  from metagpt.schema import Message
27
+ from openai import OpenAI
28
+
29
+ from data_model import (
30
+ NewMsg,
31
+ MessageJsonModel,
32
+ Sentences,
33
+ Sentence,
34
+ SentenceType,
35
+ SentenceValue,
36
+ ThinkActPrompt,
37
+ LLMAPIkeyTest,
38
+ ThinkActStep,
39
+ )
40
+ from message_enum import QueryAnswerType, MessageStatus
41
  from software_company import RoleRun, SoftwareCompany
42
 
43
 
44
+ class Service:
45
+ @classmethod
46
+ async def create_message(cls, req_model: NewMsg, request: Request):
47
+ """
48
+ Session message stream
49
+ """
50
+ tc_id = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  task = None
52
+ try:
53
+ exclude_keys = CONFIG.get("SERVER_METAGPT_CONFIG_EXCLUDE", [])
54
+ config = {k.upper(): v for k, v in req_model.config.items() if k not in exclude_keys}
55
+ cls._set_context(config)
56
+ msg_queue = deque()
57
+ CONFIG.LLM_STREAM_LOG = lambda x: msg_queue.appendleft(x) if x else None
58
+
59
+ role = SoftwareCompany()
60
+ role.recv(message=Message(content=req_model.query))
61
+ answer = MessageJsonModel(
62
+ steps=[
63
+ Sentences(
64
+ contents=[
65
+ Sentence(
66
+ type=SentenceType.TEXT.value, value=SentenceValue(answer=req_model.query), is_finished=True
67
+ )
68
+ ],
69
+ status=MessageStatus.COMPLETE.value,
70
+ )
71
+ ],
72
+ qa_type=QueryAnswerType.Answer.value,
73
+ )
74
+
75
+ async def stop_if_disconnect():
76
+ while not await request.is_disconnected():
77
+ await asyncio.sleep(1)
78
+
79
+ if task is None:
80
+ return
81
+
82
+ if not task.done():
83
+ task.cancel()
84
+ logger.info(f"cancel task {task}")
85
+
86
+ asyncio.create_task(stop_if_disconnect())
87
+
88
+ while True:
89
+ tc_id += 1
90
+ if await request.is_disconnected():
91
+ return
92
+ think_result: RoleRun = await role.think()
93
+ if not think_result: # End of conversion
94
  break
95
 
96
+ think_act_prompt = ThinkActPrompt(role=think_result.role.profile)
97
+ think_act_prompt.update_think(tc_id, think_result)
98
+ yield think_act_prompt.prompt + "\n\n"
99
+ task = asyncio.create_task(role.act())
100
+
101
+ while not await request.is_disconnected():
102
+ if msg_queue:
103
+ think_act_prompt.update_act(msg_queue.pop(), False)
104
+ yield think_act_prompt.prompt + "\n\n"
105
+ continue
106
+
107
+ if task.done():
108
+ break
109
+
110
+ await asyncio.sleep(0.5)
111
+ else:
112
+ task.cancel()
113
+ return
114
+
115
+ act_result = await task
116
+ think_act_prompt.update_act(act_result)
117
+ yield think_act_prompt.prompt + "\n\n"
118
+ answer.add_think_act(think_act_prompt)
119
+ yield answer.prompt + "\n\n" # Notify the front-end that the message is complete.
120
+ except asyncio.CancelledError:
121
+ task.cancel()
122
+ except tenacity.RetryError as retry_error:
123
+ yield cls.handle_retry_error(tc_id, retry_error)
124
+ except Exception as ex:
125
+ description = str(ex)
126
+ answer = traceback.format_exc()
127
+ think_act_prompt = cls.create_error_think_act_prompt(tc_id, description, description, answer)
128
  yield think_act_prompt.prompt + "\n\n"
129
+ finally:
130
+ CONFIG.WORKSPACE_PATH: pathlib.Path
131
+ if CONFIG.WORKSPACE_PATH.exists():
132
+ shutil.rmtree(CONFIG.WORKSPACE_PATH)
133
+
134
+ @staticmethod
135
+ def create_error_think_act_prompt(tc_id: int, title, description: str, answer: str) -> ThinkActPrompt:
136
  step = ThinkActStep(
137
  id=tc_id,
138
  status="failed",
139
+ title=title,
140
  description=description,
141
  content=Sentence(type=SentenceType.ERROR.value, id=1, value=SentenceValue(answer=answer), is_finished=True),
142
  )
143
+ return ThinkActPrompt(step=step)
144
+
145
+ @classmethod
146
+ def handle_retry_error(cls, tc_id: int, error: tenacity.RetryError):
147
+ # Known exception handling logic
148
+ try:
149
+ # Try to get the original exception
150
+ original_exception = error.last_attempt.exception()
151
+ while isinstance(original_exception, tenacity.RetryError):
152
+ original_exception = original_exception.last_attempt.exception()
153
+
154
+ if isinstance(original_exception, openai.AuthenticationError):
155
+ answer = original_exception.message
156
+ title = "OpenAI AuthenticationError"
157
+ think_act_prompt = cls.create_error_think_act_prompt(tc_id, title, title, answer)
158
+ return think_act_prompt.prompt + "\n\n"
159
+ elif isinstance(original_exception, openai.APITimeoutError):
160
+ answer = original_exception.message
161
+ title = "OpenAI APITimeoutError"
162
+ think_act_prompt = cls.create_error_think_act_prompt(tc_id, title, title, answer)
163
+ return think_act_prompt.prompt + "\n\n"
164
+ elif isinstance(original_exception, JSONDecodeError):
165
+ answer = str(original_exception)
166
+ title = "MetaGPT Error"
167
+ description = "LLM return result parsing error"
168
+ think_act_prompt = cls.create_error_think_act_prompt(tc_id, title, description, answer)
169
+ return think_act_prompt.prompt + "\n\n"
170
+ else:
171
+ return cls.handle_unexpected_error(tc_id, error)
172
+ except Exception:
173
+ return cls.handle_unexpected_error(tc_id, error)
174
+
175
+ @classmethod
176
+ def handle_unexpected_error(cls, tc_id, error):
177
+ description = str(error)
178
+ answer = traceback.format_exc()
179
+ think_act_prompt = cls.create_error_think_act_prompt(tc_id, description, description, answer)
180
+ return think_act_prompt.prompt + "\n\n"
181
+
182
+ @staticmethod
183
+ def _set_context(context: Dict) -> Dict:
184
+ uid = uuid.uuid4().hex
185
+ context["WORKSPACE_PATH"] = pathlib.Path("workspace", uid)
186
+ for old, new in (("DEPLOYMENT_ID", "DEPLOYMENT_NAME"), ("OPENAI_API_BASE", "OPENAI_BASE_URL")):
187
+ if old in context and new not in context:
188
+ context[new] = context[old]
189
+ CONFIG.set_context(context)
190
+ return context
191
 
192
 
193
  default_llm_stream_log = partial(print, end="")
 
198
  CONFIG._get("LLM_STREAM_LOG", default_llm_stream_log)(msg)
199
 
200
 
 
 
 
 
 
 
 
 
 
201
  class ChatHandler:
202
  @staticmethod
203
  async def create_message(req_model: NewMsg, request: Request):
204
  """Message stream, using SSE."""
205
+ event = Service.create_message(req_model, request)
206
  headers = {"Cache-Control": "no-cache", "Connection": "keep-alive"}
207
  return StreamingResponse(event, headers=headers, media_type="text/event-stream")
208
 
209
 
210
+ class LLMAPIHandler:
211
+ @staticmethod
212
+ async def check_openai_key(req_model: LLMAPIkeyTest):
213
+ try:
214
+ # Listing all available models.
215
+ client = OpenAI(api_key=req_model.api_key)
216
+ response = client.models.list()
217
+ model_set = {model.id for model in response.data}
218
+ if req_model.llm_type in model_set:
219
+ logger.info("API Key is valid.")
220
+ return JSONResponse({"valid": True})
221
+ else:
222
+ logger.info("API Key is invalid.")
223
+ return JSONResponse({"valid": False, "message": "Model not found"})
224
+ except Exception as e:
225
+ # If the request fails, return False
226
+ logger.info(f"Error: {e}")
227
+ return JSONResponse({"valid": False, "message": str(e)})
228
+
229
+
230
  app = FastAPI()
231
 
232
  app.mount(
 
241
  methods=["post"],
242
  summary="Session message sending (streaming response)",
243
  )
244
+ app.add_api_route(
245
+ "/api/test-api-key",
246
+ endpoint=LLMAPIHandler.check_openai_key,
247
+ methods=["post"],
248
+ summary="LLM APIkey detection",
249
+ )
250
 
251
  app.mount(
252
  "/",
 
254
  name="static",
255
  )
256
 
 
257
  set_llm_stream_logfunc(llm_stream_log)
258
 
259
 
data_model.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import uuid
2
+ from datetime import datetime
3
+ from typing import Any, Optional, Union
4
+
5
+ from metagpt.actions.action import Action
6
+ from metagpt.actions.action_output import ActionOutput
7
+ from pydantic import BaseModel, Field
8
+
9
+ from message_enum import SentenceType
10
+
11
+
12
+ class SentenceValue(BaseModel):
13
+ answer: str
14
+
15
+
16
+ class Sentence(BaseModel):
17
+ type: str
18
+ id: Optional[str] = None
19
+ value: SentenceValue
20
+ is_finished: Optional[bool] = None
21
+
22
+
23
+ class Sentences(BaseModel):
24
+ id: Optional[str] = None
25
+ action: Optional[str] = None
26
+ role: Optional[str] = None
27
+ skill: Optional[str] = None
28
+ description: Optional[str] = None
29
+ timestamp: str = Field(default_factory=lambda: datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%z"))
30
+ status: str
31
+ contents: list[dict]
32
+
33
+
34
+ class NewMsg(BaseModel):
35
+ """Chat with MetaGPT"""
36
+
37
+ query: str = Field(description="Problem description")
38
+ config: dict[str, Any] = Field(description="Configuration information")
39
+
40
+
41
+ class LLMAPIkeyTest(BaseModel):
42
+ """APIkey"""
43
+
44
+ api_key: str = Field(description="API Key")
45
+ llm_type: str = Field(description="Model Type")
46
+
47
+
48
+ class ErrorInfo(BaseModel):
49
+ error: str = None
50
+ traceback: str = None
51
+
52
+
53
+ class ThinkActStep(BaseModel):
54
+ id: str
55
+ status: str
56
+ title: str
57
+ timestamp: str = Field(default_factory=lambda: datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%z"))
58
+ description: str
59
+ content: Sentence = None
60
+
61
+
62
+ class ThinkActPrompt(BaseModel):
63
+ message_id: int = None
64
+ timestamp: str = Field(default_factory=lambda: datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f%z"))
65
+ step: ThinkActStep = None
66
+ skill: Optional[str] = None
67
+ role: Optional[str] = None
68
+
69
+ def update_think(self, tc_id, action: Action):
70
+ self.step = ThinkActStep(
71
+ id=str(tc_id),
72
+ status="running",
73
+ title=action.desc,
74
+ description=action.desc,
75
+ )
76
+
77
+ def update_act(self, message: Union[ActionOutput, str], is_finished: bool = True):
78
+ if is_finished:
79
+ self.step.status = "finish"
80
+ self.step.content = Sentence(
81
+ type=SentenceType.TEXT.value,
82
+ id=str(1),
83
+ value=SentenceValue(answer=message.content if is_finished else message),
84
+ is_finished=is_finished,
85
+ )
86
+
87
+ @staticmethod
88
+ def guid32():
89
+ return str(uuid.uuid4()).replace("-", "")[0:32]
90
+
91
+ @property
92
+ def prompt(self):
93
+ return self.json(exclude_unset=True)
94
+
95
+
96
+ class MessageJsonModel(BaseModel):
97
+ steps: list[Sentences]
98
+ qa_type: str
99
+ created_at: datetime = Field(default_factory=datetime.now)
100
+ query_time: datetime = Field(default_factory=datetime.now)
101
+ answer_time: datetime = Field(default_factory=datetime.now)
102
+ score: Optional[int] = None
103
+ feedback: Optional[str] = None
104
+
105
+ def add_think_act(self, think_act_prompt: ThinkActPrompt):
106
+ s = Sentences(
107
+ action=think_act_prompt.step.title,
108
+ skill=think_act_prompt.skill,
109
+ description=think_act_prompt.step.description,
110
+ timestamp=think_act_prompt.timestamp,
111
+ status=think_act_prompt.step.status,
112
+ contents=[think_act_prompt.step.content.dict()],
113
+ )
114
+ self.steps.append(s)
115
+
116
+ @property
117
+ def prompt(self):
118
+ return self.json(exclude_unset=True)
init.sh CHANGED
@@ -17,7 +17,7 @@ done
17
 
18
  rm -rf static
19
 
20
- wget -O dist.tar.gz https://public-frontend-1300249583.cos.ap-nanjing.myqcloud.com/test-hp-metagpt-web/dist-20231228184832.tar.gz
21
  tar xvzf dist.tar.gz
22
  mv dist static
23
  rm dist.tar.gz
 
17
 
18
  rm -rf static
19
 
20
+ wget -O dist.tar.gz https://public-frontend-1300249583.cos.ap-nanjing.myqcloud.com/test-hp-metagpt-web/dist-20240117181055.tar.gz
21
  tar xvzf dist.tar.gz
22
  mv dist static
23
  rm dist.tar.gz
message_enum.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+
4
+ class QueryAnswerType(Enum):
5
+ Query = "Q"
6
+ Answer = "A"
7
+
8
+
9
+ class SentenceType(Enum):
10
+ TEXT = "text"
11
+ HIHT = "hint"
12
+ ACTION = "action"
13
+ ERROR = "error"
14
+
15
+
16
+ class MessageStatus(Enum):
17
+ COMPLETE = "complete"