From fe6c84e310f3c621a5db58761a3b779b29fedcac Mon Sep 17 00:00:00 2001 From: Miyamizu-MitsuhaSang <2510681107@qq.com> Date: Mon, 3 Nov 2025 00:12:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=B0=9A=E8=AF=AD=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=EF=BC=8C=E8=B0=83=E6=95=B4=E6=90=9C=E7=B4=A2=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 27 +++++++++++++++++---------- app/api/search_dict/routes.py | 9 ++++++++- app/api/search_dict/service.py | 26 ++++++++++++++------------ app/models/fr.py | 1 + scripts/update_fr.py | 17 ++++++++--------- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 31440d7..7abc3be 100644 --- a/README.md +++ b/README.md @@ -334,16 +334,19 @@ Authorization: Bearer #### 2.2 法语谚语详情 - **接口**: `POST /search/proverb` -- **描述**: 通过谚语ID获取法语谚语原文与中文解释。 +- **描述**: 根据谚语ID返回法语谚语全文与中文释义。 - **需要认证**: 是 -- **查询参数**: - - `proverb_id`: 谚语ID (integer) +- **请求类型**: `application/x-www-form-urlencoded` +- **表单字段**: + - `proverb_id`: 谚语ID (integer,必填) - **响应**: ```json { - "proverb_text": "Petit à petit, l'oiseau fait son nid.", - "chi_exp": "循序渐进才能取得成功。" + "result": { + "proverb_text": "Petit à petit, l'oiseau fait son nid.", + "chi_exp": "循序渐进才能取得成功。" + } } ``` @@ -380,14 +383,13 @@ Authorization: Bearer #### 2.4 谚语联想建议 - **接口**: `POST /search/proverb/list` -- **描述**: 按输入内容(自动识别法语或中文)返回谚语候选列表。 +- **描述**: 按输入内容返回谚语候选列表,后端会自动检测输入语言(中文/日文假名/拉丁字母),无法识别时退回法语字段搜索。 - **需要认证**: 是 - **请求体**: ```json { - "query": "慢", - "language": "fr" + "query": "慢" } ``` @@ -405,6 +407,9 @@ Authorization: Bearer } ``` +- **状态码**: + - `200`: 查询成功 + --- ### 3. 翻译模块 (`/translate`) @@ -437,6 +442,7 @@ Authorization: Bearer } ``` +- **限制**: 依赖 Redis 计数器做限流,同一用户每秒最多 2 次请求(超出返回 `429`) - **状态码**: - `200`: 翻译成功 - `401`: 未授权 @@ -452,7 +458,7 @@ Authorization: Bearer - `from_lang`: 源语言,默认为 `auto` - `to_lang`: 目标语言,默认为 `zh` -- **限制**: 每秒最多2次请求 +- **限制**: 与标准翻译接口共享限流计数,同一用户每秒最多2次请求 - **状态码**: - `200`: 翻译成功 - `429`: 请求频率过高 @@ -770,7 +776,8 @@ Authorization: Bearer - **需要认证**: 是 - **查询参数**: - `count`: 抽题数量 (integer,默认 `20`) - - `lang`: 语种代码,支持 `fr-FR`(法语)、`ja-JP`(日语),默认 `fr-FR` +- **表单字段**: + - `lang`: 语种代码(`fr-FR` 或 `ja-JP`,默认 `fr-FR`)。由于实现方式,FastAPI 将其视为 form-data 字段,GET 请求需通过 form 提交或在调试文档中直接填写。 - **响应**: ```json diff --git a/app/api/search_dict/routes.py b/app/api/search_dict/routes.py index 241635d..7e57937 100644 --- a/app/api/search_dict/routes.py +++ b/app/api/search_dict/routes.py @@ -1,6 +1,6 @@ from typing import Literal, List -from fastapi import APIRouter, Depends, HTTPException, Request +from fastapi import APIRouter, Depends, HTTPException, Request, Form from app.api.search_dict import service from app.api.search_dict.search_schemas import SearchRequest, WordSearchResponse, SearchItemFr, SearchItemJp, \ @@ -167,10 +167,17 @@ async def search_word_list(query_word: SearchRequest, user=Depends(get_current_u @dict_search.post("/search/proverb/list") async def search_proverb_list(query_word: ProverbSearchRequest): lang = service.detect_language(text=query_word.query) + query = normalize_text(query_word.query) if lang == "fr" else query_word.query suggest_proverbs = await service.suggest_proverb( query=query_word.query, lang=lang, model=ProverbFr, + search_field="search_text", ) # TODO 使用法语词典时是否存在用英语输入的情况 return {"list": suggest_proverbs} + +@dict_search.post("/search/proverb") +async def search_proverb(proverb_id:int = Form(...), user=Depends(get_current_user)): + result = await service.accurate_proverb(proverb_id=proverb_id) + return {"result": result} diff --git a/app/api/search_dict/service.py b/app/api/search_dict/service.py index 184efaa..11cfb55 100644 --- a/app/api/search_dict/service.py +++ b/app/api/search_dict/service.py @@ -39,12 +39,13 @@ async def accurate_proverb(proverb_id: int) -> ProverbSearchResponse: async def suggest_proverb( - query: str, - lang: Literal["fr", "zh", "jp"], - model: Type[Model], - proverb_field: str = "text", - chi_exp_field: str = "chi_exp", - limit: int = 10, + query: str, + lang: Literal["fr", "zh", "jp"], + model: Type[Model], + search_field: str = "search_text", + target_field: str = "text", + chi_exp_field: str = "chi_exp", + limit: int = 10, ) -> List[Dict[str, str]]: """ 通用搜索建议函数,用于多语言谚语表。 @@ -71,15 +72,15 @@ async def suggest_proverb( startswith_field = f"{chi_exp_field}__istartswith" contains_field = f"{chi_exp_field}__icontains" else: - startswith_field = f"{proverb_field}__istartswith" - contains_field = f"{proverb_field}__icontains" + startswith_field = f"{search_field}__istartswith" + contains_field = f"{search_field}__icontains" # ✅ 1. 开头匹配 start_matches = await ( model.filter(**{startswith_field: keyword}) .order_by("-freq") .limit(limit) - .values("id", proverb_field, chi_exp_field) + .values("id", target_field, search_field, chi_exp_field) ) # ✅ 2. 包含匹配(非开头) @@ -89,7 +90,7 @@ async def suggest_proverb( ) .order_by("-freq") .limit(limit) - .values("id", proverb_field, chi_exp_field) + .values("id", target_field, search_field, chi_exp_field) ) # ✅ 3. 合并去重并保持顺序 @@ -100,7 +101,8 @@ async def suggest_proverb( seen_ids.add(row["id"]) results.append({ "id": row["id"], - "proverb": row[proverb_field], + "proverb": row[target_field], + "search_text": row[search_field], "chi_exp": row[chi_exp_field] }) @@ -225,4 +227,4 @@ async def __main(): if __name__ == '__main__': # asyncio.run(__main()) - print(detect_language(text="ahsjdasd")) \ No newline at end of file + print(detect_language(text="ahsjdasd")) diff --git a/app/models/fr.py b/app/models/fr.py index 422c745..fe96fc6 100644 --- a/app/models/fr.py +++ b/app/models/fr.py @@ -48,6 +48,7 @@ class ProverbFr(Model): text = fields.TextField(description="法语谚语及常用表达") chi_exp = fields.TextField(description="中文释义") freq = fields.IntField(default=0) + search_text = fields.TextField() created_at = fields.DatetimeField(auto_now_add=True) class Meta: diff --git a/scripts/update_fr.py b/scripts/update_fr.py index 243aefb..b1e1362 100644 --- a/scripts/update_fr.py +++ b/scripts/update_fr.py @@ -2,7 +2,7 @@ import asyncio from pathlib import Path import pandas as pd -from tortoise import Tortoise, connections +from tortoise import Tortoise from tortoise.exceptions import MultipleObjectsReturned from app.models.fr import DefinitionFr, WordlistFr @@ -101,14 +101,13 @@ async def varification_eg(): async def main(): await Tortoise.init(config=TORTOISE_ORM) - await DefinitionFr.all().delete() # TRUNCATE TABLE definitions_fr; - conn = connections.get("default") - await conn.execute_script(""" - ALTER TABLE definitions_fr AUTO_INCREMENT = 1; - """) - await import_def_fr() - # await import_wordlist_fr() - + # await DefinitionFr.all().delete() # TRUNCATE TABLE definitions_fr; + # conn = connections.get("default") + # await conn.execute_script(""" + # ALTER TABLE definitions_fr AUTO_INCREMENT = 1; + # """) + # await import_def_fr() + # # await import_wordlist_fr() if __name__ == "__main__": asyncio.run(main())