Skip to content

Commit

Permalink
feat: 支持通过调用AI大模型进行答题 (#413)
Browse files Browse the repository at this point in the history
* feat: 支持通过调用AI大模型进行答题

* optimize: 优化答案是否匹配的提示逻辑

* feat: 支持通过HTTP代理调用大模型
  • Loading branch information
Kenxu2022 authored Dec 29, 2024
1 parent 3369cae commit 5c87647
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 4 deletions.
101 changes: 101 additions & 0 deletions api/answer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from api.logger import logger
import random
from urllib3 import disable_warnings,exceptions
from openai import OpenAI
import httpx
# 关闭警告
disable_warnings(exceptions.InsecureRequestWarning)

Expand Down Expand Up @@ -273,3 +275,102 @@ def _query(self, q_info: dict):
def _init_tiku(self):
# self.load_token()
self.api = self._conf['url']

class AI(Tiku):
# AI大模型答题实现
def __init__(self) -> None:
super().__init__()
self.name = 'AI大模型答题'

def _query(self, q_info: dict):
if self.http_proxy:
proxy = self.http_proxy
httpx_client = httpx.Client(proxy=proxy)
client = OpenAI(http_client=httpx_client, base_url = self.endpoint,api_key = self.key)
else:
client = OpenAI(base_url = self.endpoint,api_key = self.key)
# 判断题目类型
if q_info['type'] == "single":
completion = client.chat.completions.create(
model = self.model,
messages=[
{
"role": "system",
"content": "本题为单选题,你只能选择一个选项,请根据题目和选项回答问题,以json格式输出正确的选项内容,特别注意回答的内容需要去除选项内容前的字母,示例回答:{\"Answer\": [\"答案\"]}。除此之外不要输出任何多余的内容。如果你使用了互联网搜索,也请不要返回搜索的结果和参考资料"
},
{
"role": "user",
"content": f"题目:{q_info['title']}\n选项:{q_info['options']}"
}
]
)
elif q_info['type'] == 'multiple':
completion = client.chat.completions.create(
model = self.model,
messages=[
{
"role": "system",
"content": "本题为多选题,你必须选择两个或以上选项,请根据题目和选项回答问题,以json格式输出正确的选项内容,特别注意回答的内容需要去除选项内容前的字母,示例回答:{\"Answer\": [\"答案1\",\n\"答案2\",\n\"答案3\"]}。除此之外不要输出任何多余的内容。如果你使用了互联网搜索,也请不要返回搜索的结果和参考资料"
},
{
"role": "user",
"content": f"题目:{q_info['title']}\n选项:{q_info['options']}"
}
]
)
elif q_info['type'] == 'completion':
completion = client.chat.completions.create(
model = self.model,
messages=[
{
"role": "system",
"content": "本题为填空题,你必须根据语境和相关知识填入合适的内容,请根据题目回答问题,以json格式输出正确的答案,示例回答:{\"Answer\": [\"答案\"]}。除此之外不要输出任何多余的内容。如果你使用了互联网搜索,也请不要返回搜索的结果和参考资料"
},
{
"role": "user",
"content": f"题目:{q_info['title']}"
}
]
)
elif q_info['type'] == 'judgement':
completion = client.chat.completions.create(
model = self.model,
messages=[
{
"role": "system",
"content": "本题为判断题,你只能回答正确或者错误,请根据题目回答问题,以json格式输出正确的答案,示例回答:{\"Answer\": [\"正确\"]}。除此之外不要输出任何多余的内容。如果你使用了互联网搜索,也请不要返回搜索的结果和参考资料"
},
{
"role": "user",
"content": f"题目:{q_info['title']}"
}
]
)
else:
completion = client.chat.completions.create(
model = self.model,
messages=[
{
"role": "system",
"content": "本题为简答题,你必须根据语境和相关知识填入合适的内容,请根据题目回答问题,以json格式输出正确的答案,示例回答:{\"Answer\": [\"这是我的答案\"]}。除此之外不要输出任何多余的内容。如果你使用了互联网搜索,也请不要返回搜索的结果和参考资料"
},
{
"role": "user",
"content": f"题目:{q_info['title']}"
}
]
)

try:
response = json.loads(completion.choices[0].message.content)
sep = "\n"
return sep.join(response['Answer']).strip()
except:
logger.error("无法解析大模型输出内容")
return None

def _init_tiku(self):
self.endpoint = self._conf['endpoint']
self.key = self._conf['key']
self.model = self._conf['model']
self.http_proxy = self._conf['http_proxy']
8 changes: 5 additions & 3 deletions api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,11 @@ def multi_cut(answer: str) -> list[str]:
if res in o:
answer = o[:1]
break
# 如果未能匹配, 依然随机答题
logger.info(f"找到答案但答案未能匹配 -> {res}\t随机选择答案")
answer = answer if answer else random_answer(q["options"])
if not answer: # 检查 answer 是否为空
logger.warning(f"找到答案但答案未能匹配 -> {res}\t随机选择答案")
answer = random_answer(q["options"]) # 如果为空,则随机选择答案
else:
logger.info(f"成功获取到答案:{answer}")
# 填充答案
q["answerField"][f'answer{q["id"]}'] = answer
logger.info(f'{q["title"]} 填写答案为 {answer}')
Expand Down
8 changes: 8 additions & 0 deletions config_template.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ speed = 1
; 可选项 :
; 1. TikuYanxi(言溪题库 https://tk.enncy.cn/)
; 2. TikuAdapter(开源项目 https://github.com/DokiDoki1103/tikuAdapter)
; 3. AI(需自行寻找兼容openai格式的API Endpoint和Key)
provider=TikuYanxi
; 是否直接提交答题,填写false表示答完题后不提交而是保存,随后你可以自行前往学习通修改或提交
; 填写true表示直接提交,不保证正确率!不正确的填写会被视为false
Expand All @@ -23,6 +24,13 @@ submit=false
tokens=
; 用于TikuAdapter题库的url
url=
; 用于AI大模型答题的API Endpoint和Key
; 请注意API Endpoint可能需要带上/v1路径,例如: https://example.com/v1
endpoint=
key=
model=
; 可选配置请求大模型时使用的代理,填写示例:http://examples.com
http_proxy=
; 用于判断判断题对应的选项,不要留有空格,不要留有引号,逗号为英文逗号
true_list=正确,对,√,是
false_list=错误,错,×,否,不对,不正确
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ argparse
loguru
celery
flask
fonttools
fonttools
openai

1 comment on commit 5c87647

@phone-helper
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

咋用,能教我吗,谢谢

Please sign in to comment.