Arcadia822 commited on
Commit
bb5c80a
·
unverified ·
2 Parent(s): 959e7485a7f031

Merge pull request #16 from codedog-ai/feat/#2-coding-problem-mgmt

Browse files
README.md CHANGED
@@ -19,21 +19,25 @@ license: mit
19
 
20
  ## config
21
 
22
- | Environment Variable | Necessary | Default | Description |
23
- | ----------------------------- | --------- | ------- | ---------------------------------------- |
24
- | CODEDOG_SERVER | No | 0.0.0.0 | Server address |
25
- | CODEDOG_PORT | No | 32167 | Server port |
26
- | CODEDOG_WORKER_NUM | No | 1 | Server worker number |
27
- | OPENAI_API_KEY | Yes | | Api Key for calling openai api |
28
- | OPENAI_PROXY | No | | openai proxy |
29
- | AZURE_OPENAI | No | | use azure openai if not blank |
30
- | AZURE_OPENAI_API_KEY | No | | azure openai api key |
31
- | AZURE_OPENAI_API_BASE | No | | azure openai api base |
32
- | AZURE_OPENAI_DEPLOYMENT_ID | No | | azure openai deployment id for gpt 3.5 |
33
- | AZURE_OPENAI_EMBEDDING_DEP_ID | No | | azure openai deployment id for embedding |
34
- | QDRANT_API | No | | use qdrant api if not blank |
35
- | QDRANT_API_KEY | No | | qdrant api key |
36
- | QDRANT_API_BASE | No | | qdrant api base |
 
 
 
 
37
 
38
  ## setup
39
 
 
19
 
20
  ## config
21
 
22
+ | Environment Variable | Necessary | Default | Description |
23
+ | ----------------------------- | --------- | --------- | ---------------------------------------- |
24
+ | CODEDOG_SERVER | No | 0.0.0.0 | Server address |
25
+ | CODEDOG_PORT | No | 32167 | Server port |
26
+ | CODEDOG_WORKER_NUM | No | 1 | Server worker number |
27
+ | OPENAI_API_KEY | Yes | | Api Key for calling openai api |
28
+ | OPENAI_PROXY | No | | openai proxy |
29
+ | AZURE_OPENAI | No | | use azure openai if not blank |
30
+ | AZURE_OPENAI_API_KEY | No | | azure openai api key |
31
+ | AZURE_OPENAI_API_BASE | No | | azure openai api base |
32
+ | AZURE_OPENAI_DEPLOYMENT_ID | No | | azure openai deployment id for gpt 3.5 |
33
+ | AZURE_OPENAI_EMBEDDING_DEP_ID | No | | azure openai deployment id for embedding |
34
+ | QDRANT_API | No | | use qdrant api if not blank |
35
+ | QDRANT_API_KEY | No | | qdrant api key |
36
+ | QDRANT_API_BASE | No | | qdrant api base |
37
+ | REDIS_HOST | No | 127.0.0.1 | redis host. used for orm |
38
+ | REDIS_PORT | No | 6379 | redis port |
39
+ | REDIS_PASSWORD | No | | redis password |
40
+ | REDIS_SSL | No | | connect use ssl if not blank |
41
 
42
  ## setup
43
 
edu_assistant/learning_tasks/coding_problem.py CHANGED
@@ -4,9 +4,11 @@ from langchain.chains.base import Chain
4
  from langchain.memory import ConversationBufferMemory
5
  from langchain.schema import BaseRetriever
6
  from pydantic import BaseModel, Field
 
7
 
8
  from edu_assistant.learning_tasks.base import BaseTask
9
  from edu_assistant.utils.langchain_utils import load_llm
 
10
 
11
  TEMPLATE = """The following is a friendly conversation between a human and an ai.
12
  The ai is talkative and provides lots of specific details from its context.
@@ -38,24 +40,33 @@ The code is written by a student aged 5-10 and mostly like to buggy or bad perfo
38
  DEFAULT_FIRST_QUESTION = "请问这段代码中有什么问题吗?"
39
 
40
 
41
- class CodingProblem(BaseModel):
 
 
42
  question: str = Field()
43
  standard_answer: str = Field(default="")
44
  analysis: str = Field(default="")
45
- extra: list[str] = Field(default_factory=lambda _: list())
 
46
 
47
  # TODO: Add cache to expr function with pydantic 2 computed_field decorator.
48
  # Wait for langchain to support pydantic2.
49
 
 
 
 
 
 
 
50
  def expr(self, lang=""):
51
- expr = f"Question:\n```\n{self.question}\n```\n"
52
  expr += (
53
- f"Question Standard Answer (There might be others):\n```{lang}\n{self.standard_answer}```"
54
  if self.standard_answer
55
  else ""
56
  )
57
- expr += f"Solution Analysis:\n```{self.analysis}```\n" if self.analysis else ""
58
- expr += "".join(self.extra) + "\n"
59
  return expr
60
 
61
  def __str__(self):
@@ -84,6 +95,16 @@ class CodingProblemAnalysis(BaseTask):
84
  self._session_store = {}
85
  self._knowledge = knowledge
86
 
 
 
 
 
 
 
 
 
 
 
87
  def start_analysis(self, problem: CodingProblem, answer: CodingAnswer, first_question: str = None) -> dict:
88
  """start analysis of a coding problem and incorrect answer.
89
 
@@ -116,6 +137,9 @@ class CodingProblemAnalysis(BaseTask):
116
  """
117
  assert question
118
 
 
 
 
119
  chain = self._session_store[session_id]
120
 
121
  result = chain({"input": question})
@@ -129,7 +153,9 @@ class CodingProblemAnalysis(BaseTask):
129
  memory = ConversationBufferMemory()
130
  prompt = PromptTemplate.from_template(
131
  TEMPLATE.format(
132
- instruction=self.instruction, problem=problem.expr(lang=self.lang), answer=answer.expr(lang=self.lang)
 
 
133
  )
134
  )
135
 
@@ -148,13 +174,3 @@ class CodingProblemAnalysis(BaseTask):
148
  return_source_documents=True,
149
  combine_docs_chain_kwargs={"prompt": prompt},
150
  )
151
-
152
- @staticmethod
153
- def build_coding_problem(question: str, standard_answer: str = "", analysis: str = "", extra: list[str] = None):
154
- extra = [] if extra is None else extra
155
- return CodingProblem(question=question, standard_answer=standard_answer, analysis=analysis, extra=extra)
156
-
157
- @staticmethod
158
- def build_coding_answer(answer: str, extra: list[str] = None):
159
- extra = [] if extra is None else extra
160
- return CodingAnswer(answer=answer, extra=extra)
 
4
  from langchain.memory import ConversationBufferMemory
5
  from langchain.schema import BaseRetriever
6
  from pydantic import BaseModel, Field
7
+ from pydantic_redis import Model, Store
8
 
9
  from edu_assistant.learning_tasks.base import BaseTask
10
  from edu_assistant.utils.langchain_utils import load_llm
11
+ from edu_assistant.utils.redis_utils import get_redis_config
12
 
13
  TEMPLATE = """The following is a friendly conversation between a human and an ai.
14
  The ai is talkative and provides lots of specific details from its context.
 
40
  DEFAULT_FIRST_QUESTION = "请问这段代码中有什么问题吗?"
41
 
42
 
43
+ class CodingProblem(Model):
44
+ _primary_key_field: str = "title"
45
+ title: str = Field()
46
  question: str = Field()
47
  standard_answer: str = Field(default="")
48
  analysis: str = Field(default="")
49
+ language: str = Field(default="")
50
+ extra: str = Field(default_factory=lambda: list())
51
 
52
  # TODO: Add cache to expr function with pydantic 2 computed_field decorator.
53
  # Wait for langchain to support pydantic2.
54
 
55
+ @staticmethod
56
+ def enable_redis_orm():
57
+ store = Store(name="coding_problems", redis_config=get_redis_config(), life_span_in_seconds=3600 * 24 * 30)
58
+
59
+ store.register_model(CodingProblem)
60
+
61
  def expr(self, lang=""):
62
+ expr = f"## Question\n\n```\n{self.question}\n```\n\n"
63
  expr += (
64
+ f"## Standard Answer (There might be others)\n\n```{lang}\n{self.standard_answer}\n```\n\n"
65
  if self.standard_answer
66
  else ""
67
  )
68
+ expr += f"## Analysis\n\n```\n{self.analysis}\n```\n\n" if self.analysis else ""
69
+ expr += "## Extra\n\n" + "".join(self.extra) + "\n"
70
  return expr
71
 
72
  def __str__(self):
 
95
  self._session_store = {}
96
  self._knowledge = knowledge
97
 
98
+ @staticmethod
99
+ def build_coding_problem(question: str, standard_answer: str = "", analysis: str = "", extra: list[str] = None):
100
+ extra = [] if extra is None else extra
101
+ return CodingProblem(question=question, standard_answer=standard_answer, analysis=analysis, extra=extra)
102
+
103
+ @staticmethod
104
+ def build_coding_answer(answer: str, extra: list[str] = None):
105
+ extra = [] if extra is None else extra
106
+ return CodingAnswer(answer=answer, extra=extra)
107
+
108
  def start_analysis(self, problem: CodingProblem, answer: CodingAnswer, first_question: str = None) -> dict:
109
  """start analysis of a coding problem and incorrect answer.
110
 
 
137
  """
138
  assert question
139
 
140
+ if session_id not in self._session_store:
141
+ return {}
142
+
143
  chain = self._session_store[session_id]
144
 
145
  result = chain({"input": question})
 
153
  memory = ConversationBufferMemory()
154
  prompt = PromptTemplate.from_template(
155
  TEMPLATE.format(
156
+ instruction=self.instruction,
157
+ problem=problem.expr(lang=problem.language or self.lang or ""),
158
+ answer=answer.expr(lang=problem.language or self.lang or ""),
159
  )
160
  )
161
 
 
174
  return_source_documents=True,
175
  combine_docs_chain_kwargs={"prompt": prompt},
176
  )
 
 
 
 
 
 
 
 
 
 
edu_assistant/utils/redis_utils.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from functools import lru_cache
3
+
4
+ from pydantic_redis import RedisConfig
5
+ from redis import Redis
6
+
7
+ host = os.environ.get("REDIS_HOST", "localhost")
8
+ port = int(os.environ.get("REDIS_PORT", 6379))
9
+ password = os.environ.get("REDIS_PASSWORD", None)
10
+ ssl = True if os.environ.get("REDIS_SSL") else False
11
+
12
+
13
+ @lru_cache(maxsize=1)
14
+ def get_redis_client():
15
+ return Redis(host=host, port=port, password=password, ssl=ssl)
16
+
17
+
18
+ @lru_cache(maxsize=1)
19
+ def get_redis_config():
20
+ return RedisConfig(host=host, port=port, password=password, ssl=ssl)
examples/coding_problem.py CHANGED
@@ -4,9 +4,11 @@ from edu_assistant.learning_tasks import CodingProblemAnalysis
4
 
5
  # 创建一个CodingProblem实例
6
  problem = CodingProblemAnalysis.build_coding_problem(
 
7
  question="请编写一个函数,该函数接收一个整数列表,并返回该列表的最大值。",
8
  standard_answer="def find_max(lst):\n\treturn max(lst)",
9
  analysis="在这个问题中,我们需要使用Python的内置函数max来找到列表的最大值。",
 
10
  )
11
 
12
  # 创建一个CodingAnswer实例
 
4
 
5
  # 创建一个CodingProblem实例
6
  problem = CodingProblemAnalysis.build_coding_problem(
7
+ title="求解最大值",
8
  question="请编写一个函数,该函数接收一个整数列表,并返回该列表的最大值。",
9
  standard_answer="def find_max(lst):\n\treturn max(lst)",
10
  analysis="在这个问题中,我们需要使用Python的内置函数max来找到列表的最大值。",
11
+ language="python",
12
  )
13
 
14
  # 创建一个CodingAnswer实例
examples/coding_problem_orm.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ from edu_assistant.learning_tasks.coding_problem import CodingProblem
4
+
5
+
6
+ def load_problems(file_path: str):
7
+ """load problems from json file and insert into redis orm.
8
+
9
+ Args:
10
+ file_path (str): file path to json file.
11
+ """
12
+ with open(file_path, "r", encoding="utf-8") as f:
13
+ problems_data = json.load(f)
14
+
15
+ CodingProblem.enable_redis_orm()
16
+ problems = [CodingProblem.parse_obj(problem_data) for problem_data in problems_data]
17
+ CodingProblem.insert(problems)
18
+
19
+
20
+ if __name__ == "__main__":
21
+ load_problems("examples/coding_problems.json")
examples/coding_problems.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "title": "Find Max Number",
4
+ "question": "请编写一个函数,该函数接收一个整数列表,并返回该列表的最大值",
5
+ "standard_answer": "def find_max(lst):\n\treturn max(lst)",
6
+ "analysis": "在这个问题中,我们需要使用Python的内置函数max来找到列表的最大值。",
7
+ "language": "python"
8
+ }
9
+ ]
poetry.lock CHANGED
The diff for this file is too large to render. See raw diff
 
pyproject.toml CHANGED
@@ -18,6 +18,8 @@ uvicorn = "^0.21.1"
18
  qdrant-client = "^1.3.1"
19
  tiktoken = "^0.4.0"
20
  gradio = "^3.37.0"
 
 
21
 
22
  [tool.poetry.group.dev]
23
  optional = true
 
18
  qdrant-client = "^1.3.1"
19
  tiktoken = "^0.4.0"
20
  gradio = "^3.37.0"
21
+ redis = "^4.6.0"
22
+ pydantic-redis = "^0.4.3"
23
 
24
  [tool.poetry.group.dev]
25
  optional = true
webui/__init__.py ADDED
File without changes
webui/coding_problem.py CHANGED
@@ -1,4 +1,197 @@
 
 
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  with gr.Blocks() as coding_problem_ui:
4
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
  import gradio as gr
4
+ from fastapi.encoders import jsonable_encoder
5
+ from langchain.callbacks import get_openai_callback
6
+
7
+ from edu_assistant.learning_tasks.coding_problem import (
8
+ DEFAULT_FIRST_QUESTION,
9
+ CodingProblem,
10
+ CodingProblemAnalysis,
11
+ )
12
+
13
+ CodingProblem.enable_redis_orm()
14
+ task = CodingProblemAnalysis()
15
+
16
+
17
+ def get_problems() -> list[str]:
18
+ data = CodingProblem.select(columns=["title"])
19
+ if not data:
20
+ return []
21
+ titles = [problem_data["title"] for problem_data in data]
22
+ return titles
23
+
24
+
25
+ def update_problems():
26
+ titles = get_problems()
27
+ gr.Info("更新题目列表成功")
28
+ return gr.Dropdown.update(choices=titles)
29
+
30
+
31
+ def select_problem(title: str):
32
+ problem: CodingProblem = CodingProblem.select(ids=[title])[0]
33
+ return (
34
+ problem.expr(),
35
+ problem.title,
36
+ problem.language,
37
+ problem.question,
38
+ problem.analysis,
39
+ problem.standard_answer,
40
+ json.dumps(problem.extra, ensure_ascii=False, indent=4),
41
+ )
42
+
43
+
44
+ def update_problem(title, language, problem, analysis, answer, extra):
45
+ # TODO: add language
46
+ try:
47
+ extra_data = json.loads(extra)
48
+ except json.JSONDecodeError:
49
+ extra_data = [extra]
50
+
51
+ CodingProblem.update(
52
+ title,
53
+ data={
54
+ "title": title,
55
+ "language": language,
56
+ "question": problem,
57
+ "analysis": analysis,
58
+ "standard_answer": answer,
59
+ "extra": extra_data,
60
+ },
61
+ )
62
+ gr.Info("更新题目成功")
63
+
64
+
65
+ def delete_problem(title):
66
+ CodingProblem.delete(ids=[title])
67
+ gr.Info("删除题目成功")
68
+
69
+ return "", "", "", "", "", "", "", ""
70
+
71
+
72
+ def analysis_problem(title, code, extra: str = ""):
73
+ problem = CodingProblem.select(ids=[title])[0]
74
+ answer = CodingProblemAnalysis.build_coding_answer(answer=code)
75
+
76
+ with get_openai_callback() as cb:
77
+ result = task.start_analysis(problem, answer)
78
+ status = {"tokens": cb.total_tokens, "cost": f"${cb.total_cost:.4f}"}
79
+
80
+ answer = result["response"]
81
+ session_id = result["session_id"]
82
+ docs = jsonable_encoder(result.get("source_documents", []))
83
+ return [(DEFAULT_FIRST_QUESTION, answer)], session_id, status, docs
84
+
85
+
86
+ def chat(message, chat_history, session_id):
87
+ if not session_id:
88
+ return "", "", {"tokens": 0}, []
89
+ with get_openai_callback() as cb:
90
+ result = task.ask(message, session_id=session_id)
91
+ if not result:
92
+ raise gr.Error("Session expired. Please recreate a new problem analysis session.")
93
+
94
+ session_id = result["session_id"]
95
+ docs = jsonable_encoder(result.get("source_documents", []))
96
+
97
+ bot_message = result["response"]
98
+ chat_history.append((message, bot_message))
99
+
100
+ status = {"tokens": cb.total_tokens, "cost": f"${cb.total_cost:.4f}"}
101
+
102
+ return "", chat_history, status, docs
103
+
104
 
105
  with gr.Blocks() as coding_problem_ui:
106
+ with gr.Row():
107
+ with gr.Column(scale=6):
108
+ problem_selector = gr.Dropdown(choices=get_problems(), show_label=False, interactive=True)
109
+ with gr.Column():
110
+ refresh_btn = gr.Button(value="刷新")
111
+ with gr.Row():
112
+ with gr.Column(scale=6):
113
+ with gr.Tab(label="错误代码分析"):
114
+ with gr.Row():
115
+ with gr.Column(scale=3):
116
+ with gr.Row():
117
+ problem_view = gr.Markdown(label="题目")
118
+ with gr.Row():
119
+ code_view = gr.Textbox(label="代码", lines=10, interactive=True)
120
+ with gr.Column(scale=3):
121
+ with gr.Row():
122
+ chat_box = gr.Chatbot(height=500)
123
+ with gr.Row():
124
+ chat_input = gr.Textbox(interactive=True)
125
+ with gr.Column():
126
+ with gr.Row():
127
+ analysis_btn = gr.Button(value="分析")
128
+ with gr.Row():
129
+ status = gr.JSON(value="""{"tokens":0}""")
130
+ with gr.Row():
131
+ session_id = gr.Textbox(label="Session", interactive=False, value="")
132
+ with gr.Row():
133
+ docs = gr.JSON(value="""["docs"]""", label="Docs")
134
+ with gr.Row():
135
+ clear = gr.ClearButton([problem_view, code_view, problem_selector, session_id, docs])
136
+
137
+ with gr.Tab(label="题库管理"):
138
+ with gr.Row():
139
+ with gr.Column(scale=6):
140
+ with gr.Row():
141
+ title_edit = gr.Textbox(label="标题", interactive=True)
142
+ with gr.Row():
143
+ language_edit = gr.Dropdown(
144
+ choices=["python", "cpp", "java"],
145
+ label="���言",
146
+ interactive=True,
147
+ allow_custom_value=True,
148
+ )
149
+ with gr.Column():
150
+ manage_update = gr.Button(value="更新")
151
+ manage_delete = gr.Button(value="删除", variant="stop")
152
+ with gr.Row():
153
+ with gr.Column():
154
+ problem_edit = gr.Textbox(label="题目", lines=10, max_lines=100, interactive=True)
155
+ with gr.Column():
156
+ analysis_edit = gr.Textbox(label="解析", lines=10, max_lines=100, interactive=True)
157
+ with gr.Row():
158
+ answer_edit = gr.Textbox(label="标准答案", lines=10, max_lines=100, interactive=True)
159
+ with gr.Row():
160
+ extra_edit = gr.Textbox(label="额外信息", lines=10, max_lines=100, interactive=True)
161
+
162
+ refresh_btn.click(update_problems, [], [problem_selector])
163
+ problem_selector.select(
164
+ select_problem,
165
+ [
166
+ problem_selector,
167
+ ],
168
+ [problem_view, title_edit, language_edit, problem_edit, analysis_edit, answer_edit, extra_edit],
169
+ )
170
+ analysis_btn.click(
171
+ analysis_problem,
172
+ [problem_selector, code_view],
173
+ [chat_box, session_id, status, docs],
174
+ )
175
+ chat_input.submit(chat, [chat_input, chat_box, session_id], [chat_input, chat_box, status, docs])
176
+
177
+ manage_update.click(
178
+ update_problem, [title_edit, language_edit, problem_edit, analysis_edit, answer_edit, extra_edit], []
179
+ )
180
+ manage_delete.click(
181
+ delete_problem,
182
+ [problem_selector],
183
+ [
184
+ problem_selector,
185
+ problem_view,
186
+ title_edit,
187
+ language_edit,
188
+ problem_edit,
189
+ analysis_edit,
190
+ answer_edit,
191
+ extra_edit,
192
+ ],
193
+ )
194
+
195
+ if __name__ == "__main__":
196
+ coding_problem_ui.queue()
197
+ coding_problem_ui.launch(max_threads=2)
webui/qa.py CHANGED
@@ -38,7 +38,7 @@ def recreate(instruction):
38
 
39
 
40
  def clear(msg, chatbot, session_id, telemetry, docs):
41
- return "", "", '', '{"tokens":0}', '["docs"]'
42
 
43
 
44
  with gr.Blocks() as qa_ui:
@@ -52,7 +52,7 @@ with gr.Blocks() as qa_ui:
52
  with gr.Row():
53
  with gr.Column(scale=6):
54
  with gr.Row():
55
- chatbot = gr.Chatbot(height=400)
56
  with gr.Row():
57
  msg = gr.Textbox()
58
  with gr.Column(scale=1):
@@ -62,7 +62,8 @@ with gr.Blocks() as qa_ui:
62
  telemetry = gr.JSON(value="""{"tokens":0}""", label="Telemetry")
63
  with gr.Row():
64
  docs = gr.JSON(value="""["docs"]""", label="Docs")
 
 
65
 
66
  clear_btn.click(clear, [msg, chatbot, session_id, telemetry, docs], [msg, chatbot, session_id, telemetry, docs])
67
  msg.submit(respond, [msg, chatbot, session_id], [msg, chatbot, session_id, telemetry, docs])
68
- apply.click(recreate, [instruction], [])
 
38
 
39
 
40
  def clear(msg, chatbot, session_id, telemetry, docs):
41
+ return "", "", "", '{"tokens":0}', '["docs"]'
42
 
43
 
44
  with gr.Blocks() as qa_ui:
 
52
  with gr.Row():
53
  with gr.Column(scale=6):
54
  with gr.Row():
55
+ chatbot = gr.Chatbot(height=500)
56
  with gr.Row():
57
  msg = gr.Textbox()
58
  with gr.Column(scale=1):
 
62
  telemetry = gr.JSON(value="""{"tokens":0}""", label="Telemetry")
63
  with gr.Row():
64
  docs = gr.JSON(value="""["docs"]""", label="Docs")
65
+ with gr.Row():
66
+ instruction = gr.Textbox(label="Instruction", value=DEFAULT_INSTRUCTION, interactive=False)
67
 
68
  clear_btn.click(clear, [msg, chatbot, session_id, telemetry, docs], [msg, chatbot, session_id, telemetry, docs])
69
  msg.submit(respond, [msg, chatbot, session_id], [msg, chatbot, session_id, telemetry, docs])
 
webui/ui.py CHANGED
@@ -1,8 +1,8 @@
1
  import gradio as gr
2
- from coding_problem import coding_problem_ui
3
- from qa import qa_ui
4
 
5
  from edu_assistant import version
 
 
6
 
7
  with gr.Blocks() as ui:
8
  with gr.Row():
@@ -15,4 +15,5 @@ with gr.Blocks() as ui:
15
  coding_problem_ui.render()
16
 
17
  if __name__ == "__main__":
 
18
  ui.launch()
 
1
  import gradio as gr
 
 
2
 
3
  from edu_assistant import version
4
+ from webui.coding_problem import coding_problem_ui
5
+ from webui.qa import qa_ui
6
 
7
  with gr.Blocks() as ui:
8
  with gr.Row():
 
15
  coding_problem_ui.render()
16
 
17
  if __name__ == "__main__":
18
+ ui.queue()
19
  ui.launch()