3 Revize 1922d13167 ... 593abaca66

Autor SHA1 Zpráva Datum
  xie 593abaca66 更新 před 1 týdnem
  xie a1eb8512d6 Merge remote-tracking branch 'origin/master' před 1 týdnem
  xie 9b15c27155 1. 支持高并发的文章生成请求; před 1 týdnem
7 změnil soubory, kde provedl 454 přidání a 204 odebrání
  1. 1 1
      .gitignore
  2. 9 16
      core/api_get_article2.py
  3. 131 59
      gpt/chatgpt.py
  4. 111 106
      gpt/get_article2.py
  5. 200 20
      mock/mock_request.py
  6. 1 1
      tools/audio.py
  7. 1 1
      tools/thread_pool_manager.py

+ 1 - 1
.gitignore

@@ -1,7 +1,7 @@
 .*
 /*.txt
 test*.py
-/test
+/test/
 /log
 *.docx
 *.pdf

+ 9 - 16
core/api_get_article2.py

@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-from fastapi import FastAPI, Form, HTTPException, Request,status,APIRouter,Query,Path, Depends
+from fastapi import FastAPI, Form, HTTPException, Request,status,APIRouter,Query,Path, Depends, BackgroundTasks
 from tools.loglog import logger,log_err_e
 
 from core.respone_format import *
@@ -11,12 +11,8 @@ import asyncio
 
 router = APIRouter()
 
-async def get_article_dependency():
-    article_generator = GetArticle()
-    try:
-        yield article_generator
-    finally:
-        await article_generator.cleanup()
+get_article = GetArticle()
+
 
 class Word(BaseModel):
     meaning_id:int = Field(..., description="单词的词义id")
@@ -35,14 +31,12 @@ class ArticleRequest(BaseModel):
 
 
 @router.post("/article/reading-comprehension")
-async def post_article(
+def post_article(
     json_data:ArticleRequest,
     request:Request,
-    get_article: GetArticle = Depends(get_article_dependency)
+    background_tasks: BackgroundTasks,
 ):
-    """
-    异步处理文章生成请求
-    """
+
     json_data = json_data.model_dump()
     real_ip = request.headers.get("X-Real-IP","0.0.0.0")
 
@@ -54,16 +48,15 @@ async def post_article(
     exercise_id = json_data["exercise_id"]
 
     try:
-       
-        r = await get_article.submit_task(
+        r = get_article.submit_task(
             real_ip=real_ip,
             core_words=core_words,
             take_count=take_count,
             demo_name=demo_name,
             reading_level=reading_level,
             article_length=article_length,
-            exercise_id=exercise_id
-
+            exercise_id=exercise_id,
+            background_tasks=background_tasks
         )
         return r if not isinstance(r,str) else resp_500(message=r)
 

+ 131 - 59
gpt/chatgpt.py

@@ -1,22 +1,22 @@
 # -*- coding:utf-8 -*-
 if __name__ == '__main__':
     import os
+
     os.chdir("..")
 
-import requests
-import random
-import json
 import time
-from tools.loglog import logger,simple_logger
-from tools.new_mysql import MySQLUploader
-from typing import Optional, Dict, Any,Union
+from typing import Dict, Any, Union
+
 import httpx
-import asyncio
+import requests
 
+from tools.loglog import logger, simple_logger, log_err_e
+from tools.new_mysql import MySQLUploader
 
 m = MySQLUploader()
 
-def get_openai_model(model_text:str):
+
+def get_openai_model(model_text: str):
     """模糊获得模型名"""
     if "3.5" in model_text or "3.5-turbo" in model_text or "3.5turbo" in model_text:
         model = "gpt-3.5-turbo"
@@ -29,16 +29,16 @@ def get_openai_model(model_text:str):
     return model
 
 
-def insert_ip_token(ip,demo_name,gpt_content,prompt_tokens,completion_tokens,total_tokens):
+def insert_ip_token(ip, demo_name, gpt_content, prompt_tokens, completion_tokens, total_tokens):
     sql = "insert into consumer_token (ip,demo_name,gpt_content,prompt_tokens,completion_tokens,total_tokens) values (%s,%s,%s,%s,%s,%s)"
-    m.execute_(sql,(ip,demo_name,str(gpt_content),prompt_tokens,completion_tokens,total_tokens))
+    m.execute_(sql, (ip, demo_name, str(gpt_content), prompt_tokens, completion_tokens, total_tokens))
+
 
-def get_answer_from_gpt(question,real_ip="localhost",demo_name="无",model="gpt-4o",max_tokens=3500,temperature:float=0,
-                        json_resp:Union[Dict[Any, Any],bool]=False,n=1,check_fucn=None,sys_prompt=None):
+def get_answer_from_gpt(question, real_ip="localhost", demo_name="无", model="gpt-4o", max_tokens=3500, temperature: float = 0,
+                        json_resp: Union[Dict[Any, Any], bool] = False, n=1, check_fucn=None, sys_prompt=None):
     model = get_openai_model(model)
 
-   
-    d2 = {"model": model,"messages": [],"max_tokens": max_tokens,"temperature": temperature,'n': n}
+    d2 = {"model": model, "messages": [], "max_tokens": max_tokens, "temperature": temperature, 'n': n}
     if sys_prompt:
         d2['messages'].append({"role": "system", "content": sys_prompt})
     d2['messages'].append({"role": "user", "content": question})
@@ -52,36 +52,33 @@ def get_answer_from_gpt(question,real_ip="localhost",demo_name="无",model="gpt-
 
     for num_count in range(3):
         try:
-           
+
             response = requests.post(f'http://170.106.108.95/v1/chat/completions', json=d2)
             r_json = response.json()
-            if r2:= r_json.get("choices",None):
-                if n>1:
+            if r2 := r_json.get("choices", None):
+                if n > 1:
                     gpt_res = []
                     for i in r2:
                         gpt_res.append(i["message"]["content"])
                 else:
-                    gpt_res= r2[0]["message"]["content"]
+                    gpt_res = r2[0]["message"]["content"]
 
-               
                 gpt_content = str(gpt_res)
                 prompt_tokens = r_json["usage"]["prompt_tokens"]
                 completion_tokens = r_json["usage"]["completion_tokens"]
                 total_tokens = r_json["usage"]["total_tokens"]
-                insert_ip_token(real_ip,demo_name,gpt_content,prompt_tokens,completion_tokens,total_tokens)
+                insert_ip_token(real_ip, demo_name, gpt_content, prompt_tokens, completion_tokens, total_tokens)
 
                 simple_logger.info(f"问题日志:\n{question}\n回答日志:\n{gpt_res}")
 
-               
                 if not check_fucn:
                     return gpt_res
 
-               
                 check_result = check_fucn(str(gpt_res))
-                if check_result: 
+                if check_result:
                     return gpt_res
                 else:
-                    raise Exception(f"第{num_count+1}次共3次,GPT的校验没有通过,校验函数:{check_fucn.__name__}")
+                    raise Exception(f"第{num_count + 1}次共3次,GPT的校验没有通过,校验函数:{check_fucn.__name__}")
 
             elif r_json.get("message") == "IP address blocked":
                 print("IP address blocked")
@@ -95,8 +92,9 @@ def get_answer_from_gpt(question,real_ip="localhost",demo_name="无",model="gpt-
 
     logger.critical("get_answer_from_gpt 严重错误,3次后都失败了")
 
-async def get_article_gpt_pydantic(question, real_ip="localhost", demo_name="无", model="gpt-4o", max_tokens=3500, temperature:float=0, n=1,
-                        check_fucn=None, sys_prompt=None, client=None):
+
+def get_article_gpt_pydantic(question, real_ip="localhost", demo_name="无", model="gpt-4.1", max_tokens=3500, temperature: float = 0, n=1,
+                             check_fucn=None, sys_prompt=None):
     """
     异步获取文章
     :param question: 问题
@@ -108,50 +106,126 @@ async def get_article_gpt_pydantic(question, real_ip="localhost", demo_name="无
     :param n: 生成数量
     :param check_fucn: 校验函数
     :param sys_prompt: 系统提示
-    :param client: httpx.AsyncClient实例
     :return: 文章内容
     """
-   
-    d2 = {"model": model, "messages": [], "max_tokens": max_tokens, "temperature": temperature, "response_format":"article"}
+
+    d2 = {"model": model, "messages": [], "max_tokens": max_tokens, "temperature": temperature, "n": n, "response_format": {'type': 'json_schema',
+                                                                                                                            'json_schema': {
+                                                                                                                                'name': 'Article',
+                                                                                                                                'schema': {'$defs': {
+                                                                                                                                    'Candidate': {
+                                                                                                                                        'properties': {
+                                                                                                                                            'label': {
+                                                                                                                                                'title': 'Label',
+                                                                                                                                                'type': 'string'},
+                                                                                                                                            'text': {
+                                                                                                                                                'title': 'Text',
+                                                                                                                                                'type': 'string'},
+                                                                                                                                            'isRight': {
+                                                                                                                                                'title': 'Isright',
+                                                                                                                                                'type': 'integer'}},
+                                                                                                                                        'required': [
+                                                                                                                                            'label',
+                                                                                                                                            'text',
+                                                                                                                                            'isRight'],
+                                                                                                                                        'title': 'Candidate',
+                                                                                                                                        'type': 'object'},
+                                                                                                                                    'DifficultSentence': {
+                                                                                                                                        'properties': {
+                                                                                                                                            'english': {
+                                                                                                                                                'title': 'English',
+                                                                                                                                                'type': 'string'},
+                                                                                                                                            'chinese': {
+                                                                                                                                                'title': 'Chinese',
+                                                                                                                                                'type': 'string'}},
+                                                                                                                                        'required': [
+                                                                                                                                            'english',
+                                                                                                                                            'chinese'],
+                                                                                                                                        'title': 'DifficultSentence',
+                                                                                                                                        'type': 'object'},
+                                                                                                                                    'Question': {
+                                                                                                                                        'properties': {
+                                                                                                                                            'trunk': {
+                                                                                                                                                'title': 'Trunk',
+                                                                                                                                                'type': 'string'},
+                                                                                                                                            'analysis': {
+                                                                                                                                                'title': 'Analysis',
+                                                                                                                                                'type': 'string'},
+                                                                                                                                            'candidates': {
+                                                                                                                                                'items': {
+                                                                                                                                                    '$ref': '#/$defs/Candidate'},
+                                                                                                                                                'title': 'Candidates',
+                                                                                                                                                'type': 'array'}},
+                                                                                                                                        'required': [
+                                                                                                                                            'trunk',
+                                                                                                                                            'analysis',
+                                                                                                                                            'candidates'],
+                                                                                                                                        'title': 'Question',
+                                                                                                                                        'type': 'object'}},
+                                                                                                                                           'properties': {
+                                                                                                                                               'difficultSentences': {
+                                                                                                                                                   'items': {
+                                                                                                                                                       '$ref': '#/$defs/DifficultSentence'},
+                                                                                                                                                   'title': 'Difficultsentences',
+                                                                                                                                                   'type': 'array'},
+                                                                                                                                               'usedMeanIds': {
+                                                                                                                                                   'items': {
+                                                                                                                                                       'type': 'integer'},
+                                                                                                                                                   'title': 'Usedmeanids',
+                                                                                                                                                   'type': 'array'},
+                                                                                                                                               'questions': {
+                                                                                                                                                   'items': {
+                                                                                                                                                       '$ref': '#/$defs/Question'},
+                                                                                                                                                   'title': 'Questions',
+                                                                                                                                                   'type': 'array'},
+                                                                                                                                               'englishArticle': {
+                                                                                                                                                   'title': 'Englisharticle',
+                                                                                                                                                   'type': 'string'},
+                                                                                                                                               'chineseArticle': {
+                                                                                                                                                   'title': 'Chinesearticle',
+                                                                                                                                                   'type': 'string'},
+                                                                                                                                               'allWordAmount': {
+                                                                                                                                                   'title': 'Allwordamount',
+                                                                                                                                                   'type': 'integer'}},
+                                                                                                                                           'required': [
+                                                                                                                                               'difficultSentences',
+                                                                                                                                               'usedMeanIds',
+                                                                                                                                               'questions',
+                                                                                                                                               'englishArticle',
+                                                                                                                                               'chineseArticle',
+                                                                                                                                               'allWordAmount'],
+                                                                                                                                           'title': 'Article',
+                                                                                                                                           'type': 'object'}}}}
     if sys_prompt:
         d2['messages'].append({"role": "system", "content": sys_prompt})
     d2['messages'].append({"role": "user", "content": question})
 
     for num_count in range(3):
         try:
-           
-            if client is None:
-                async with httpx.AsyncClient() as temp_client:
-                    response = await temp_client.post('http://170.106.108.95/get_article', json=d2)
-            else:
-                response = await client.post('http://170.106.108.95/get_article', json=d2)
-                
-            r_str = response.json() 
+            response = requests.post('http://170.106.108.95/v1/chat/completions', json=d2)
+            r_json = response.json()
+            simple_logger.info(f"问题日志:\n{question}\n回答日志:\n{r_json}")
+            return r_json
+
+            #
+
+            #
 
-            simple_logger.info(f"问题日志:\n{question}\n回答日志:\n{r_str}")
 
-           
-            if not check_fucn:
-                return r_str
 
-           
-            check_result = check_fucn(r_str)
 
-            if check_result: 
-                return r_str
-            else:
-                raise Exception(f"第{num_count + 1}次共3次,GPT的校验没有通过,校验函数:{check_fucn.__name__}")
 
         except httpx.HTTPError as e:
             logger.error(f"HTTP请求错误: {str(e)}")
-            if num_count < 2: 
-                await asyncio.sleep(10)
+            if num_count < 2:
+                time.sleep(10)
             else:
                 raise
         except Exception as e:
-            logger.error(f"其他错误: {str(e)}")
+            log_err_e(e, "其他错误")
+
             if num_count < 2:
-                await asyncio.sleep(10)
+                time.sleep(10)
             else:
                 raise
 
@@ -159,25 +233,23 @@ async def get_article_gpt_pydantic(question, real_ip="localhost", demo_name="无
     raise Exception("获取文章失败,已达到最大重试次数")
 
 
-def parse_gpt_phon_to_tuplelist(text:str) -> list:
+def parse_gpt_phon_to_tuplelist(text: str) -> list:
     """解析gpt返回的音标数据"""
     result = []
     if not text:
         return []
     for i in text.split("\n"):
         ii = i.split("***")
-        if len(ii)>=3:
-            result.append((ii[0].strip(),ii[1].strip(),ii[2].strip()))
+        if len(ii) >= 3:
+            result.append((ii[0].strip(), ii[1].strip(), ii[2].strip()))
     return result
 
 
 if __name__ == '__main__':
-
     question = "hello"
-   
 
     sys_prompt = "你是一个专业的英语老师,擅长根据用户提供的词汇生成对应的英语文章和中文翻译和4个配套选择题。"
-    q= """下面我会为你提供两组数据,[单词组1]和[单词组2](里面包含词义id,英语单词,中文词义),优先使用[单词组1]内的单词,请根据这些单词的中文词义,生成一篇带中文翻译的考场英语文章,英语文章和中文翻译要有[标题]。注意这个单词有多个词义时,生成的英语文章一定要用提供的中文词义。并挑选一句复杂的句子和其中文翻译,放入difficultSentences。英语文章,放入"englishArticle"中。中文翻译,放入"chineseArticle"中。最终文中使用到的单词id放入"usedMeanIds"中。4个选择题,放入questions字段。questions结构下有4个选择题对象,其中trunk是[英语]问题文本,analysis是[中文]的问题分析,candidates是4个ABCD选项,内部有label是指选项序号A B C D ,text是[英语]选项文本,isRight是否正确答案1是正确0是错误。
+    q = """下面我会为你提供两组数据,[单词组1]和[单词组2](里面包含词义id,英语单词,中文词义),优先使用[单词组1]内的单词,请根据这些单词的中文词义,生成一篇带中文翻译的考场英语文章,英语文章和中文翻译要有[标题]。注意这个单词有多个词义时,生成的英语文章一定要用提供的中文词义。并挑选一句复杂的句子和其中文翻译,放入difficultSentences。英语文章,放入"englishArticle"中。中文翻译,放入"chineseArticle"中。最终文中使用到的单词id放入"usedMeanIds"中。4个选择题,放入questions字段。questions结构下有4个选择题对象,其中trunk是[英语]问题文本,analysis是[中文]的问题分析,candidates是4个ABCD选项,内部有label是指选项序号A B C D ,text是[英语]选项文本,isRight是否正确答案1是正确0是错误。
 
 要求:
 1.必须用提供的这个词义的单词,其他单词使用常见、高中难度的的单词。文章整体难度适中,大约和中国的高中生,中国CET-6,雅思6分这样的难度标准。
@@ -189,6 +261,6 @@ if __name__ == '__main__':
 提供[单词组1]:4238 penalty:惩罚, 刑罚;4591 bare:赤裸的, 无遮蔽的;4227 stable:畜舍, 马厩;4236 psychology:心理学;4245 offense:进攻, 攻势, 冒犯, 触怒, 过错;4237 innocent:清白的, 无辜的, 天真的;4228 refrigerator:冰箱, 冷库;4247 tissue:(动植物)组织;4250 awareness:察觉, 觉悟, 意识;4234 mode:方式, 模式;4224 neat:整洁, 利索;4225 statistics:统计;4251 random:任意的, 随机的;4201 laundry:洗衣房;4545 barrel:桶, 一桶之量;4249 recruit:招募, 新成员;4229 pregnant:怀孕的, 孕育的;4235 relevant:有关的, 相关联的;4252 incentive:刺激, 激励, 鼓励;4194 grave:坟墓, 墓穴;
 提供[单词组2]:;
 """
-    resp = get_article_gpt_pydantic(question=q,temperature=0.9,sys_prompt=sys_prompt,model="gpt-4.1")
+    resp = get_answer_from_gpt(question=question, temperature=0.9, sys_prompt=sys_prompt, model="gpt-4.1")
     print(type(resp))
-    print(resp)
+    print(resp)

+ 111 - 106
gpt/get_article2.py

@@ -12,12 +12,16 @@ from pydantic import BaseModel
 from cachetools import TTLCache
 from concurrent.futures import wait
 from random import randint, shuffle, sample
-import json
+import json,time
 import requests
 from openpyxl import load_workbook
 from tenacity import retry, stop_after_attempt, wait_fixed
 import httpx
 import asyncio
+from threading import Lock
+from collections import defaultdict
+from fastapi import BackgroundTasks
+
 
 
 def get_article_difficulty(article) -> int:
@@ -84,18 +88,12 @@ def merge_and_split(list1, list2):
 class GetArticle:
     def __init__(self):
         self.m = MySQLUploader() 
-        self.client = httpx.AsyncClient(
-            timeout=httpx.Timeout(180.0), 
-            limits=httpx.Limits(
-                max_keepalive_connections=100, 
-                max_connections=1000, 
-                keepalive_expiry=90.0 
-            )
-        )
-
-        self.callback_url_dict = {}
-        self.real_ip_dict = {} 
-        self.demo_name = {}
+
+       
+        self.callback_url_dict = defaultdict(str)
+        self.real_ip_dict = defaultdict(str) 
+        self.demo_name = defaultdict(str)
+
 
         self.article_result = {} 
 
@@ -106,6 +104,8 @@ class GetArticle:
        
         self.exchange_data: dict[str, list] = {} 
         self.read_spring_bamboo_exchange_table()
+                    
+
 
    
     def read_spring_bamboo_exchange_table(self):
@@ -122,7 +122,7 @@ class GetArticle:
         wb.close()
 
    
-    async def parser_insert_to_mysql(self, resp_result):
+    def parser_insert_to_mysql(self, resp_result):
         try:
             for single_article in resp_result['articles']:
                 article = single_article['body']
@@ -133,12 +133,13 @@ class GetArticle:
                 sql = "INSERT INTO spring_bamboo_article (article_json,difficult_level) VALUES (%s,%s)"
                 self.m.execute_(sql, (article_json, difficult_value))
         except Exception as e:
+           
             logger.error(f"插入数据库时发生错误: {str(e)}")
-            raise
 
    
-    async def submit_task(self, real_ip: str, core_words: list, take_count: int,
-                          demo_name: str, reading_level: int, article_length: int, exercise_id: int):
+    def submit_task(self, real_ip: str, core_words: list, take_count: int,
+                          demo_name: str, reading_level: int, article_length: int, exercise_id: int,
+                          background_tasks: BackgroundTasks):
         """
         core_words: 词义数据组
         take_count: 取文章数量 (int类型,正常是2篇,最大8篇)
@@ -146,27 +147,89 @@ class GetArticle:
         reading_level:阅读等级
         article_length:文章长度
         exercise_id:学案id
+        background_tasks: FastAPI的后台任务管理器
         """
         task_id = randint(10000000, 99999999)
-       
         logger.info(f"reading-comprehension 生成文章id。学案id:{exercise_id},task_id:{task_id}")
 
         try:
             self.real_ip_dict[task_id] = real_ip
             self.demo_name[task_id] = demo_name
 
-            resp_result = await self.run_task(core_words, task_id, take_count, reading_level, article_length)
-            await self.parser_insert_to_mysql(resp_result) 
-            logger.success(f"reading-comprehension 文章2任务完成。学案id:{exercise_id},taskid:{task_id}\n{resp_result}")
+            resp_result = self.run_task(core_words, task_id, take_count, reading_level, article_length)
+            
+           
+            background_tasks.add_task(self.parser_insert_to_mysql, resp_result)
+            
+            logger.success(f"reading-comprehension 文章2任务完成。学案id:{exercise_id},taskid:{task_id}")
             return resp_result
         except Exception as e:
             err_msg = f"GetArticle提交任务失败{type(e).__name__},{e}"
             log_err_e(e, msg="GetArticle提交任务失败;")
             return err_msg
+        finally:
+           
+            self.real_ip_dict.pop(task_id, None)
+            self.demo_name.pop(task_id, None)
+
+   
+    def __parse_gpt_resp(self,gpt_resp:dict,core_words:list):
+        return_json = {"articles": []} 
+        for choice in gpt_resp["choices"]:
+            single_article_dict = json.loads(choice["message"]["content"])
+
+            allWordAmount = 0 
+           
+            articleWordAmount = get_article_words_count(single_article_dict["englishArticle"])
+            allWordAmount += articleWordAmount
+
+            for i in single_article_dict["questions"]:
+                count_trunk = get_article_words_count(i["trunk"])
+                count_candidates = sum([get_article_words_count(ii["text"]) for ii in i["candidates"]])
+                allWordAmount += count_trunk
+                allWordAmount += count_candidates
+
+           
+            usedMeanIds: list = single_article_dict['usedMeanIds'] 
+           
+            article_words = split_text_to_word(single_article_dict['englishArticle'])
+           
+            for i in core_words:
+                meaning_id = i.get('meaning_id', 0)
+                if not meaning_id:
+                    continue
+                word = i["spell"]
+                if meaning_id not in usedMeanIds and word in self.exchange_data: 
+                    words_exchanges_list = self.exchange_data[word]
+                    for exchange_word in words_exchanges_list:
+                        if exchange_word in article_words:
+                            usedMeanIds.append(meaning_id)
+                            break
+
+           
+            single_article_dict["body"] = single_article_dict.pop("englishArticle")
+            single_article_dict["chinese"] = single_article_dict.pop("chineseArticle")
+
+           
+            for q in single_article_dict['questions']:
+                data = q['candidates']
+                shuffled_candidates = sample(data, len(data))
+
+                labels = ['A', 'B', 'C', 'D']
+                for index, candidate in enumerate(shuffled_candidates):
+                    candidate['label'] = labels[index]
+                q['candidates'] = shuffled_candidates
+
+           
+            return_json['articles'].append({**single_article_dict, "allWordAmount": allWordAmount, "articleWordAmount": articleWordAmount})
+
+        return return_json
+
+
 
    
     @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
-    async def get_article(self, core_words: list, task_id: int, reading_level, article_length) -> dict:
+    def get_article(self, core_words: list, task_id: int, reading_level, article_length,n) -> dict:
        
         if not article_length:
             if 0 < reading_level <= 10:
@@ -208,7 +271,7 @@ class GetArticle:
 
        
         shuffle(core_words)
-        core_words_meaning_str = ";".join([str(i['meaning_id']) + ' ' + i["spell"] + ":" + i["meaning"] for i in core_words])
+        core_words_meaning_str = "; ".join([f"[{i['meaning_id']}  {i['spell']} {i['meaning']}]" for i in core_words])
 
         no_escape_code = r"\\n\\n"
 
@@ -232,53 +295,12 @@ class GetArticle:
             real_ip = self.real_ip_dict[task_id]
             demo_name = self.demo_name[task_id]
 
-            r_json = json.loads(await get_article_gpt_pydantic(q, temperature=0.9, real_ip=real_ip, demo_name=demo_name, model='gpt-4.1',
-                                                               check_fucn=CheckArticleResult.get_article_1, max_tokens=4000,
-                                                               sys_prompt=sys_prompt, client=self.client))
-           
-            allWordAmount = 0 
-           
-            articleWordAmount = get_article_words_count(r_json["englishArticle"])
-            allWordAmount += articleWordAmount
+            gpt_resp = get_article_gpt_pydantic(q, temperature=1.2, real_ip=real_ip, demo_name=demo_name, model='gpt-4.1',
+                                                               check_fucn=CheckArticleResult.get_article_1, max_tokens=8000,
+                                                               sys_prompt=sys_prompt,n=n)
+            multi_articles_dict = self.__parse_gpt_resp(gpt_resp=gpt_resp,core_words=core_words)
+            return multi_articles_dict
 
-            for i in r_json["questions"]:
-                count_trunk = get_article_words_count(i["trunk"])
-                count_candidates = sum([get_article_words_count(ii["text"]) for ii in i["candidates"]])
-                allWordAmount += count_trunk
-                allWordAmount += count_candidates
-
-           
-            usedMeanIds: list = r_json['usedMeanIds'] 
-           
-            article_words = split_text_to_word(r_json['englishArticle'])
-           
-            for i in core_words:
-                meaning_id = i.get('meaning_id', 0)
-                if not meaning_id:
-                    continue
-                word = i["spell"]
-                if meaning_id not in usedMeanIds and word in self.exchange_data: 
-                    words_exchanges_list = self.exchange_data[word]
-                    for exchange_word in words_exchanges_list:
-                        if exchange_word in article_words:
-                            usedMeanIds.append(meaning_id)
-                            break
-
-           
-            r_json["body"] = r_json.pop("englishArticle")
-            r_json["chinese"] = r_json.pop("chineseArticle")
-
-           
-            for q in r_json['questions']:
-                data = q['candidates']
-                shuffled_candidates = sample(data, len(data))
-
-                labels = ['A', 'B', 'C', 'D']
-                for index, candidate in enumerate(shuffled_candidates):
-                    candidate['label'] = labels[index]
-                q['candidates'] = shuffled_candidates
-
-            return {**r_json, "allWordAmount": allWordAmount, "articleWordAmount": articleWordAmount}
         except httpx.HTTPError as e:
             logger.error(f"HTTP请求错误: {str(e)}")
             raise
@@ -289,8 +311,9 @@ class GetArticle:
             log_err_e(e, f"gpt生成文章回复其他错误.")
             raise
 
+
    
-    async def run_get_article_task(self, core_words, task_id, take_count, reading_level, article_length) -> dict:
+    def run_get_article_task(self, core_words, task_id, take_count, reading_level, article_length) -> dict:
         """
         :param core_words: 核心单词数据,优先级1;可能为空
         :param task_id: 任务id
@@ -300,51 +323,33 @@ class GetArticle:
         :return:
         """
         try:
-            tasks = []
-            for i in range(take_count):
-                tasks.append(
-                    self.get_article(core_words, task_id, reading_level, article_length))
-
-            results = await asyncio.gather(*tasks, return_exceptions=True)
-
-           
-            for result in results:
-                if isinstance(result, Exception):
-                    continue
-
-            return {"articles": results}
+            return_json = self.get_article(core_words, task_id, reading_level, article_length,n=take_count)
+            return return_json
         except Exception as e:
             logger.error(f"运行文章任务时发生错误: {str(e)}")
             raise
 
    
-    async def run_task(self, core_words, task_id, take_count, reading_level, article_length):
+    def run_task(self, core_words, task_id, take_count, reading_level, article_length):
         try:
-            outside_json = await self.run_get_article_task(core_words, task_id, take_count, reading_level, article_length)
+            outside_json = self.run_get_article_task(core_words, task_id, take_count, reading_level, article_length)
             return outside_json
         except Exception as e:
             log_err_e(e, msg="外层总任务捕获错误")
-        finally:
-            self.real_ip_dict.pop(task_id)
-            self.demo_name.pop(task_id)
 
-    async def cleanup(self):
+    def cleanup(self):
         """清理所有资源"""
-        try:
-           
-            if hasattr(self, 'client'):
-                await self.client.aclose()
-           
-            self.real_ip_dict.clear()
-            self.demo_name.clear()
-            self.callback_url_dict.clear()
-            self.article_result.clear()
-
-        except Exception as e:
-            logger.error(f"清理资源时发生错误: {str(e)}")
-            raise
+        pass
+       
+       
+       
+       
+       
+       
+       
+       
+       
+       
+       
+       
 
-    def __del__(self):
-        """析构函数,确保资源被正确释放"""
-        if hasattr(self, 'client'):
-            asyncio.create_task(self.cleanup())

+ 200 - 20
mock/mock_request.py

@@ -1,9 +1,17 @@
 # -*- coding:utf-8 -*-
 #
-import requests
-import time
 import json 
+import time
 from functools import wraps
+from random import shuffle,sample,randint
+from threading import Thread
+from concurrent.futures import ThreadPoolExecutor,wait
+
+import httpx
+import requests
+from pydantic import BaseModel
+from typing import List
+
 
 product_adress = "http://111.231.167.191" 
 test_address = "http://111.231.167.191:8004" 
@@ -11,7 +19,32 @@ test_address2 = "http://111.231.167.191:8003"
 
 local_adress = "http://127.0.0.1:9000" 
 
-use_address = test_address 
+use_address = local_adress 
+
+class DifficultSentence(BaseModel):
+    english: str
+    chinese: str
+
+class Candidate(BaseModel):
+    label: str
+    text: str
+    isRight: int
+
+class Question(BaseModel):
+    trunk: str
+    analysis: str
+    candidates: List[Candidate]
+
+class Article(BaseModel):
+    difficultSentences: List[DifficultSentence]
+    usedMeanIds: List[int]
+    questions: List[Question]
+    englishArticle: str
+    chineseArticle: str
+    allWordAmount: int
+
+class ArticleData(BaseModel):
+    articles: List[Article]
 
 
 def time_use(fn):
@@ -25,7 +58,7 @@ def time_use(fn):
             print(f'函数:{fn.__name__} 一共用时', cha, '秒')
         return res 
 
-    return cc 
+    return cc
 
 
 def test_connect():
@@ -100,29 +133,157 @@ def get_article2():
 @time_use
 def get_article2_1():
     """新的获取文章"""
-    json_data = {'core_words': [{'spell': 'sudden', 'meaning': '突然的, 意外的', 'word_id': 1114468, 'meaning_id': 1734},
-                                {'spell': 'frighten', 'meaning': '惊吓, 惊恐', 'word_id': 899278, 'meaning_id': 1735},
-                                {'spell': 'relation', 'meaning': '关系, 联系, 亲戚, 亲属', 'word_id': 1061800, 'meaning_id': 1736},
-                                {'spell': 'agreement', 'meaning': '协议,协定', 'word_id': 753401, 'meaning_id': 1743},
-                                {'spell': 'pool', 'meaning': '游泳池, 池子', 'word_id': 1035634, 'meaning_id': 1747},
-                                {'spell': 'risk', 'meaning': '冒险, 风险', 'word_id': 1069002, 'meaning_id': 1748},
-                                {'spell': 'centre', 'meaning': '中心', 'word_id': 806629, 'meaning_id': 1749},
-                                {'spell': 'shut', 'meaning': '关上, 关闭', 'word_id': 1088662, 'meaning_id': 1751},
-                                {'spell': 'piano', 'meaning': '钢琴', 'word_id': 1027211, 'meaning_id': 1752},
-                                {'spell': 'trust', 'meaning': '信任, 信赖', 'word_id': 1142977, 'meaning_id': 1753},
-                                {'spell': 'camera', 'meaning': '照相机', 'word_id': 799656, 'meaning_id': 1754},
-                                {'spell': 'course', 'meaning': '课程', 'word_id': 834016, 'meaning_id': 399},
-                                {'spell': 'thought', 'meaning': '思想, 想法', 'word_id': 1130826, 'meaning_id': 685}],
-                 'take_count': 4, 'student_stage': 3, 'demo_name': '春笋英语',"exercise_id":999,"article_length":200}
+    core_words_list = [{'spell': 'sudden', 'meaning': '突然的, 意外的', 'word_id': 1114468, 'meaning_id': 1734},
+                       {'spell': 'frighten', 'meaning': '惊吓, 惊恐', 'word_id': 899278, 'meaning_id': 1735},
+                       {'spell': 'relation', 'meaning': '关系, 联系, 亲戚, 亲属', 'word_id': 1061800, 'meaning_id': 1736},
+                       {'spell': 'agreement', 'meaning': '协议,协定', 'word_id': 753401, 'meaning_id': 1743},
+                       {'spell': 'risk', 'meaning': '冒险, 风险', 'word_id': 1069002, 'meaning_id': 1748},
+                       {'spell': 'centre', 'meaning': '中心', 'word_id': 806629, 'meaning_id': 1749},
+                       {'spell': 'shut', 'meaning': '关上, 关闭', 'word_id': 1088662, 'meaning_id': 1751},
+                       {'spell': 'thought', 'meaning': '思想, 想法', 'word_id': 1130826, 'meaning_id': 685},
+                       {'spell': 'information', 'meaning': '消息, 信息', 'word_id': 940351, 'meaning_id': 487, 'serial': 330},
+                       {'spell': 'bright', 'meaning': '聪明的', 'word_id': 793695, 'meaning_id': 1451, 'serial': 1048},
+                       {'spell': 'international', 'meaning': '国际的', 'word_id': 945460, 'meaning_id': 1683, 'serial': 1232},
+                       {'spell': 'shelf', 'meaning': '架子, 搁板', 'word_id': 1086743, 'meaning_id': 1838, 'serial': 1366},
+                       {'spell': 'cave', 'meaning': '洞穴, 山洞', 'word_id': 805431, 'meaning_id': 2167, 'serial': 1639},
+                       {'spell': 'gym', 'meaning': '健身房, 体育馆', 'word_id': 915473, 'meaning_id': 2217, 'serial': 1683},
+                       {'spell': 'properly', 'meaning': '适当地, 正确地', 'word_id': 1045343, 'meaning_id': 2257, 'serial': 1720},
+                       {'spell': 'platform', 'meaning': '平台', 'word_id': 1031256, 'meaning_id': 2269, 'serial': 1730},
+                       {'spell': 'sweep', 'meaning': '打扫, 清扫', 'word_id': 1118098, 'meaning_id': 2321, 'serial': 1775},
+                       {'spell': 'clinic', 'meaning': '诊所, 门诊部', 'word_id': 815699, 'meaning_id': 2471, 'serial': 1898},
+                       {'spell': 'sauce', 'meaning': '酱油, 调味料', 'word_id': 1076452, 'meaning_id': 2501, 'serial': 1927},
+                       {'spell': 'retell', 'meaning': '重讲, 复述', 'word_id': 1065717, 'meaning_id': 2546, 'serial': 1970},
+                       {'spell': 'specific', 'meaning': '具体的, 明确的', 'word_id': 1099668, 'meaning_id': 3089, 'serial': 2421},
+                       {'spell': 'religion', 'meaning': '宗教', 'word_id': 1062490, 'meaning_id': 3358, 'serial': 2626},
+                       {'spell': 'collapse', 'meaning': '倒塌, 崩溃', 'word_id': 819500, 'meaning_id': 3667, 'serial': 2872},
+                       {'spell': 'bare', 'meaning': '光秃秃的', 'word_id': 777035, 'meaning_id': 4592, 'serial': 3650},
+                       {'spell': 'defendant', 'meaning': '被告的, 被告人', 'word_id': 1174797, 'meaning_id': 4975, 'serial': 3979},
+                       {'spell': 'interact', 'meaning': '互相作用, 互动', 'word_id': 943776, 'meaning_id': 5117, 'serial': 4103},
+                       {'spell': 'fact', 'meaning': '事实, 真相', 'word_id': 882302, 'meaning_id': 425, 'serial': 289},
+                       {'spell': 'except', 'meaning': '除了…之外', 'word_id': 878228, 'meaning_id': 814, 'serial': 561},
+                       {'spell': 'opposite', 'meaning': '相反, 对面', 'word_id': 1008508, 'meaning_id': 1650, 'serial': 1207},
+                       {'spell': 'clerk', 'meaning': '职员, 店员', 'word_id': 815428, 'meaning_id': 1826, 'serial': 1354},
+                       {'spell': 'chief', 'meaning': '主要的,首要的', 'word_id': 810493, 'meaning_id': 2067, 'serial': 1552},
+                       {'spell': 'congratulation', 'meaning': '祝贺, 贺辞', 'word_id': 826539, 'meaning_id': 2187, 'serial': 1657},
+                       {'spell': 'chest', 'meaning': '大箱子', 'word_id': 810293, 'meaning_id': 2223, 'serial': 1689},
+                       {'spell': 'monitor', 'meaning': '班长', 'word_id': 988984, 'meaning_id': 2262, 'serial': 1724},
+                       {'spell': 'accurate', 'meaning': '正确的, 精确的', 'word_id': 747138, 'meaning_id': 2278, 'serial': 1739},
+                       {'spell': 'investigate', 'meaning': '调查, 研究', 'word_id': 947316, 'meaning_id': 2359, 'serial': 1806},
+                       {'spell': 'forecast', 'meaning': '预报, 预测', 'word_id': 895859, 'meaning_id': 2495, 'serial': 1921},
+                       {'spell': 'sausage', 'meaning': '香肠, 腊肠', 'word_id': 1076506, 'meaning_id': 2536, 'serial': 1961},
+                       {'spell': 'insurance', 'meaning': '保险', 'word_id': 943100, 'meaning_id': 3044, 'serial': 2380},
+                       {'spell': 'reveal', 'meaning': '揭示, 暴露, 展现', 'word_id': 1066342, 'meaning_id': 3246, 'serial': 2544},
+                       {'spell': 'perception', 'meaning': '观念, 知觉, 觉察', 'word_id': 1174551, 'meaning_id': 3516, 'serial': 2749},
+                       {'spell': 'violation', 'meaning': '妨碍, 侵犯, 违犯', 'word_id': 1174695, 'meaning_id': 4452, 'serial': 3528},
+                       {'spell': 'convey', 'meaning': '表达', 'word_id': 830280, 'meaning_id': 4931, 'serial': 3938},
+                       {'spell': 'migration', 'meaning': '迁移, 移居', 'word_id': 1175117, 'meaning_id': 5069, 'serial': 4063}
+                       ]
+    shuffle(core_words_list)
+    core_words_chiose_list = sample(core_words_list,5)
+    json_data = {'core_words': core_words_chiose_list,
+                 'take_count': 8, 'student_stage': 2, 'demo_name': '春笋英语', "exercise_id": randint(100,999),
+                 "article_length": 120, "reading_level": 5}
 
     r = requests.post(f"{use_address}/article/reading-comprehension", json=json_data)
     r_json = r.json()
+    print(r_json)
     try:
         return r_json
     except Exception as e:
         print("春笋文章reading-comprehension错误", e)
         print("错误数据", r_json)
 
+@time_use
+def get_article2_2():
+    """测试通过requests来直接访问openai"""
+    core_words_list = [{'spell': 'sudden', 'meaning': '突然的, 意外的', 'word_id': 1114468, 'meaning_id': 1734},
+                       {'spell': 'frighten', 'meaning': '惊吓, 惊恐', 'word_id': 899278, 'meaning_id': 1735},
+                       {'spell': 'relation', 'meaning': '关系, 联系, 亲戚, 亲属', 'word_id': 1061800, 'meaning_id': 1736},
+                       {'spell': 'agreement', 'meaning': '协议,协定', 'word_id': 753401, 'meaning_id': 1743},
+                       {'spell': 'risk', 'meaning': '冒险, 风险', 'word_id': 1069002, 'meaning_id': 1748},
+                       {'spell': 'centre', 'meaning': '中心', 'word_id': 806629, 'meaning_id': 1749},
+                       {'spell': 'shut', 'meaning': '关上, 关闭', 'word_id': 1088662, 'meaning_id': 1751},
+                       {'spell': 'thought', 'meaning': '思想, 想法', 'word_id': 1130826, 'meaning_id': 685},
+                       {'spell': 'information', 'meaning': '消息, 信息', 'word_id': 940351, 'meaning_id': 487, 'serial': 330},
+                       {'spell': 'bright', 'meaning': '聪明的', 'word_id': 793695, 'meaning_id': 1451, 'serial': 1048},
+                       {'spell': 'international', 'meaning': '国际的', 'word_id': 945460, 'meaning_id': 1683, 'serial': 1232},
+                       {'spell': 'shelf', 'meaning': '架子, 搁板', 'word_id': 1086743, 'meaning_id': 1838, 'serial': 1366},
+                       {'spell': 'cave', 'meaning': '洞穴, 山洞', 'word_id': 805431, 'meaning_id': 2167, 'serial': 1639},
+                       {'spell': 'gym', 'meaning': '健身房, 体育馆', 'word_id': 915473, 'meaning_id': 2217, 'serial': 1683},
+                       {'spell': 'properly', 'meaning': '适当地, 正确地', 'word_id': 1045343, 'meaning_id': 2257, 'serial': 1720},
+                       {'spell': 'platform', 'meaning': '平台', 'word_id': 1031256, 'meaning_id': 2269, 'serial': 1730},
+                       {'spell': 'sweep', 'meaning': '打扫, 清扫', 'word_id': 1118098, 'meaning_id': 2321, 'serial': 1775},
+                       {'spell': 'clinic', 'meaning': '诊所, 门诊部', 'word_id': 815699, 'meaning_id': 2471, 'serial': 1898},
+                       {'spell': 'sauce', 'meaning': '酱油, 调味料', 'word_id': 1076452, 'meaning_id': 2501, 'serial': 1927},
+                       {'spell': 'retell', 'meaning': '重讲, 复述', 'word_id': 1065717, 'meaning_id': 2546, 'serial': 1970},
+                       {'spell': 'specific', 'meaning': '具体的, 明确的', 'word_id': 1099668, 'meaning_id': 3089, 'serial': 2421},
+                       {'spell': 'religion', 'meaning': '宗教', 'word_id': 1062490, 'meaning_id': 3358, 'serial': 2626},
+                       {'spell': 'collapse', 'meaning': '倒塌, 崩溃', 'word_id': 819500, 'meaning_id': 3667, 'serial': 2872},
+                       {'spell': 'bare', 'meaning': '光秃秃的', 'word_id': 777035, 'meaning_id': 4592, 'serial': 3650},
+                       {'spell': 'defendant', 'meaning': '被告的, 被告人', 'word_id': 1174797, 'meaning_id': 4975, 'serial': 3979},
+                       {'spell': 'interact', 'meaning': '互相作用, 互动', 'word_id': 943776, 'meaning_id': 5117, 'serial': 4103},
+                       {'spell': 'fact', 'meaning': '事实, 真相', 'word_id': 882302, 'meaning_id': 425, 'serial': 289},
+                       {'spell': 'except', 'meaning': '除了…之外', 'word_id': 878228, 'meaning_id': 814, 'serial': 561},
+                       {'spell': 'opposite', 'meaning': '相反, 对面', 'word_id': 1008508, 'meaning_id': 1650, 'serial': 1207},
+                       {'spell': 'clerk', 'meaning': '职员, 店员', 'word_id': 815428, 'meaning_id': 1826, 'serial': 1354},
+                       {'spell': 'chief', 'meaning': '主要的,首要的', 'word_id': 810493, 'meaning_id': 2067, 'serial': 1552},
+                       {'spell': 'congratulation', 'meaning': '祝贺, 贺辞', 'word_id': 826539, 'meaning_id': 2187, 'serial': 1657},
+                       {'spell': 'chest', 'meaning': '大箱子', 'word_id': 810293, 'meaning_id': 2223, 'serial': 1689},
+                       {'spell': 'monitor', 'meaning': '班长', 'word_id': 988984, 'meaning_id': 2262, 'serial': 1724},
+                       {'spell': 'accurate', 'meaning': '正确的, 精确的', 'word_id': 747138, 'meaning_id': 2278, 'serial': 1739},
+                       {'spell': 'investigate', 'meaning': '调查, 研究', 'word_id': 947316, 'meaning_id': 2359, 'serial': 1806},
+                       {'spell': 'forecast', 'meaning': '预报, 预测', 'word_id': 895859, 'meaning_id': 2495, 'serial': 1921},
+                       {'spell': 'sausage', 'meaning': '香肠, 腊肠', 'word_id': 1076506, 'meaning_id': 2536, 'serial': 1961},
+                       {'spell': 'insurance', 'meaning': '保险', 'word_id': 943100, 'meaning_id': 3044, 'serial': 2380},
+                       {'spell': 'reveal', 'meaning': '揭示, 暴露, 展现', 'word_id': 1066342, 'meaning_id': 3246, 'serial': 2544},
+                       {'spell': 'perception', 'meaning': '观念, 知觉, 觉察', 'word_id': 1174551, 'meaning_id': 3516, 'serial': 2749},
+                       {'spell': 'violation', 'meaning': '妨碍, 侵犯, 违犯', 'word_id': 1174695, 'meaning_id': 4452, 'serial': 3528},
+                       {'spell': 'convey', 'meaning': '表达', 'word_id': 830280, 'meaning_id': 4931, 'serial': 3938},
+                       {'spell': 'migration', 'meaning': '迁移, 移居', 'word_id': 1175117, 'meaning_id': 5069, 'serial': 4063}
+                       ]
+    shuffle(core_words_list)
+    core_words_chiose_list = sample(core_words_list,5)
+    core_words_meaning_str = "; ".join([f"[{i['meaning_id']}  {i['spell']} {i['meaning']}]" for i in core_words_chiose_list])
+
+    question = f"""下面我会为你提供一组数据,[单词组](里面包含词义id,英语单词,中文词义),请根据这些单词的中文词义,生成一篇带中文翻译的考场英语文章,英语文章和中文翻译要有[标题]。注意这个单词有多个词义时,生成的英语文章一定要用提供的中文词义。并挑选一句复杂的句子和其中文翻译,放入difficultSentences。英语文章,放入"englishArticle"中。中文翻译,放入"chineseArticle"中。最终文中使用到的单词id放入"usedMeanIds"中。4个选择题,放入questions字段。questions结构下有4个选择题对象,其中trunk是[英语]问题文本,analysis是[中文]的问题分析,candidates是4个ABCD选项,内部有label是指选项序号A B C D ,text是[英语]选项文本,isRight是否正确答案1是正确0是错误。
+
+要求:
+1.必须用提供的这个词义的单词,其他单词使用最简单最容易没有难度的单词。文章整体非常简洁,通俗易懂,适合初学者,刚入门,单词全是最常见的,语句通顺即可。选择题难度尽可能简单,参考中国小学生水平
+2.优先保证文章语句通顺,意思不要太生硬。不要为了使用特定的单词,造成文章语义前后不搭,允许不使用个别词义。
+3.文章中使用提供单词,一定要和提供单词的中文词义匹配,尤其是一词多义时,务必使用提供单词的词义。必须要用提供单词的词义。如果用到的词义与提供单词词义不一致,请不要使用这个单词。
+4.生成的文章要求120词左右,可以用\\n\\n字符分段,一般1-2个段落左右。第一段是文章标题。
+5.允许不使用[单词组]的个别单词,优先保证文章整体意思通顺连贯和故事完整。
+6.注意回复字段的中英文,englishArticle是英文,chineseArticle是中文,其中trunk是英文,analysis是中文,text是英文。
+
+提供[单词组]:{core_words_meaning_str}
+"""
+
+    url = "http://170.106.108.95/v1/chat/completions"
+
+   
+    headers = {
+        "Authorization": f"Bearer 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",
+        "Content-Type": "application/json"
+    }
+
+   
+    data = {
+        "model": "gpt-4.1", 
+        "messages": [
+           
+            {"role": "user", "content": question}
+        ],
+        "max_tokens": 4000, 
+        "temperature": 1.2, 
+        "n":8,
+        "response_format": {'type': 'json_schema', 'json_schema': {'name': 'Article', 'schema': {'$defs': {'Candidate': {'properties': {'label': {'title': 'Label', 'type': 'string'}, 'text': {'title': 'Text', 'type': 'string'}, 'isRight': {'title': 'Isright', 'type': 'integer'}}, 'required': ['label', 'text', 'isRight'], 'title': 'Candidate', 'type': 'object'}, 'DifficultSentence': {'properties': {'english': {'title': 'English', 'type': 'string'}, 'chinese': {'title': 'Chinese', 'type': 'string'}}, 'required': ['english', 'chinese'], 'title': 'DifficultSentence', 'type': 'object'}, 'Question': {'properties': {'trunk': {'title': 'Trunk', 'type': 'string'}, 'analysis': {'title': 'Analysis', 'type': 'string'}, 'candidates': {'items': {'$ref': '#/$defs/Candidate'}, 'title': 'Candidates', 'type': 'array'}}, 'required': ['trunk', 'analysis', 'candidates'], 'title': 'Question', 'type': 'object'}}, 'properties': {'difficultSentences': {'items': {'$ref': '#/$defs/DifficultSentence'}, 'title': 'Difficultsentences', 'type': 'array'}, 'usedMeanIds': {'items': {'type': 'integer'}, 'title': 'Usedmeanids', 'type': 'array'}, 'questions': {'items': {'$ref': '#/$defs/Question'}, 'title': 'Questions', 'type': 'array'}, 'englishArticle': {'title': 'Englisharticle', 'type': 'string'}, 'chineseArticle': {'title': 'Chinesearticle', 'type': 'string'}, 'allWordAmount': {'title': 'Allwordamount', 'type': 'integer'}}, 'required': ['difficultSentences', 'usedMeanIds', 'questions', 'englishArticle', 'chineseArticle', 'allWordAmount'], 'title': 'Article', 'type': 'object'}}}
+    }
+
+   
+    response = httpx.post(url, headers=headers, json=data,timeout=300)
+    print(response.json())
+    return response.json()
+
 
 def download_word():
     from make_docx_demo.data import test_json2
@@ -183,12 +344,31 @@ def run_all_test_cese():
    
 
 
+@time_use
+def multi_request():
+    with ThreadPoolExecutor(max_workers=50) as executor:
+       
+        futures = [executor.submit(get_article2_1) for _ in range(30)]
+       
+
+       
+        wait(futures)
+        print("完成等待")
+        for index,future in enumerate(futures,start=1):
+            future.result() 
+            print(f"完成循环{index}")
+
+
 if __name__ == '__main__':
-    run_all_test_cese()
    
-
+    multi_request()
 
    
    
+
+   
+
    
    
+
+   

+ 1 - 1
tools/audio.py

@@ -82,7 +82,7 @@ class GetAudio:
         self.token = None
         self.lock = Lock()
 
-        self.re_compile = re.compile("[.!?;*]")
+        self.re_compile = re.compile("[.!?;*\"]")
 
    
     def upload_file_to_oss(self, word_or_hash_name, oss_file_name, local_file_path):

+ 1 - 1
tools/thread_pool_manager.py

@@ -2,4 +2,4 @@
 from concurrent.futures import ThreadPoolExecutor, wait
 
 
-pool_executor = ThreadPoolExecutor(max_workers=20)
+pool_executor = ThreadPoolExecutor(max_workers=200)