Compare commits
9 Commits
9f9f462640
...
13babde93f
| Author | SHA1 | Date |
|---|---|---|
|
|
13babde93f | |
|
|
8e36e4c209 | |
|
|
ba11bc3913 | |
|
|
9d46299f8f | |
|
|
294b1353cc | |
|
|
e30b0c081e | |
|
|
9892439083 | |
|
|
dba148a3f9 | |
|
|
a1089067a6 |
18
README.md
18
README.md
|
|
@ -326,7 +326,8 @@ Authorization: Bearer <your_jwt_token>
|
||||||
"chi_exp": "日语;日本的语言",
|
"chi_exp": "日语;日本的语言",
|
||||||
"example": "日本語を勉強しています。"
|
"example": "日本語を勉強しています。"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"hiragana": ["假名注音"]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -543,8 +544,8 @@ Authorization: Bearer <your_jwt_token>
|
||||||
|
|
||||||
- **请求参数说明**:
|
- **请求参数说明**:
|
||||||
- `query`: 待翻译的文本
|
- `query`: 待翻译的文本
|
||||||
- `from_lang`: 源语言,支持值: `auto`(自动检测), `fr`(法语), `jp`(日语), `zh`(中文),默认为 `auto`
|
- `from_lang`: 源语言,支持值: `auto`(自动检测), `fra`(法语), `jp`(日语), `zh`(中文),默认为 `auto`
|
||||||
- `to_lang`: 目标语言,支持值: `fr`(法语), `jp`(日语), `zh`(中文),默认为 `zh`,不能为 `auto`
|
- `to_lang`: 目标语言,支持值: `fra`(法语), `jp`(日语), `zh`(中文),默认为 `zh`,不能为 `auto`
|
||||||
|
|
||||||
- **响应**:
|
- **响应**:
|
||||||
|
|
||||||
|
|
@ -1233,12 +1234,11 @@ curl -X GET "http://127.0.0.1:8000/api/test/pron/start?count=5&lang=fr-FR" \
|
||||||
|
|
||||||
### 15. 部署说明
|
### 15. 部署说明
|
||||||
|
|
||||||
1. 安装依赖: `pip install -r requirements.txt`
|
1. 安装依赖:`uv pip install -r requirements.txt`(或使用 `pip install -r requirements.txt`)
|
||||||
2. 配置数据库连接 (settings.py)
|
2. 配置环境:在项目根目录准备 `.env`,写入数据库、Redis、邮件、翻译等密钥(字段参考 `settings.Settings`)
|
||||||
3. 配置百度翻译API密钥 (BAIDU_APPID, BAIDU_APPKEY)
|
3. 确保 MySQL 与 Redis 服务已启动并与 `.env` 中的连接信息匹配
|
||||||
4. 启动Redis服务
|
4. 初始化数据库(首次部署):`aerich upgrade`
|
||||||
5. 运行数据库迁移
|
5. 启动服务:`uvicorn main:app --host 0.0.0.0 --port 8000`(开发环境可加 `--reload`)
|
||||||
6. 启动服务: `python main.py`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ async def search(request: Request, body: SearchRequest, user=Depends(get_current
|
||||||
query=query,
|
query=query,
|
||||||
pos=pos_contents,
|
pos=pos_contents,
|
||||||
contents=contents,
|
contents=contents,
|
||||||
|
hiragana=query_kana,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -230,50 +231,120 @@ async def search_proverb_list(query_word: ProverbSearchRequest, user=Depends(get
|
||||||
@dict_search.post("/search/proverb")
|
@dict_search.post("/search/proverb")
|
||||||
async def search_proverb(proverb_id: int = Form(...), user=Depends(get_current_user)):
|
async def search_proverb(proverb_id: int = Form(...), user=Depends(get_current_user)):
|
||||||
result = await service.accurate_idiom_proverb(search_id=proverb_id, model=ProverbFr,
|
result = await service.accurate_idiom_proverb(search_id=proverb_id, model=ProverbFr,
|
||||||
only_fields=["text", "chi_exp"])
|
only_fields=["id", "text", "chi_exp"])
|
||||||
|
|
||||||
return {"result": result}
|
return {"result": result}
|
||||||
|
|
||||||
|
|
||||||
@dict_search.post("/search/list/idiom")
|
@dict_search.post("/search/list/idiom")
|
||||||
async def search_idiom_list(query_idiom: ProverbSearchRequest, user=Depends(get_current_user)):
|
async def search_idiom_list(
|
||||||
|
query_idiom: ProverbSearchRequest,
|
||||||
|
user=Depends(get_current_user)
|
||||||
|
):
|
||||||
|
"""日语成语检索接口(带语言检测与分类逻辑)"""
|
||||||
|
|
||||||
if query_idiom.dict_language == "fr":
|
if query_idiom.dict_language == "fr":
|
||||||
raise HTTPException(status_code=400, detail="Dict language Error")
|
raise HTTPException(status_code=400, detail="Dict language Error")
|
||||||
|
|
||||||
|
# 语言检测
|
||||||
mapping_query, lang, is_kangji = await service.detect_language(text=query_idiom.query)
|
mapping_query, lang, is_kangji = await service.detect_language(text=query_idiom.query)
|
||||||
query = query_idiom.query
|
query = query_idiom.query
|
||||||
|
|
||||||
# ✅ 并发任务列表
|
# 初始化任务列表(后续依任务顺序返回)
|
||||||
tasks = [
|
tasks = []
|
||||||
service.suggest_proverb(
|
|
||||||
query=query,
|
|
||||||
lang=lang,
|
|
||||||
model=IdiomJp,
|
|
||||||
search_field="search_text",
|
|
||||||
target_field="text",
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
if lang == "zh" and is_kangji:
|
# --- 1️⃣ 日语输入 ---
|
||||||
# jp_query = all_in_kana(text=query_idiom.query)
|
if lang == "jp":
|
||||||
|
if is_kangji:
|
||||||
|
tasks.append(
|
||||||
|
service.suggest_proverb(
|
||||||
|
query=query,
|
||||||
|
lang="jp",
|
||||||
|
model=IdiomJp,
|
||||||
|
search_field="text",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
tasks.append(
|
||||||
|
service.suggest_proverb(
|
||||||
|
query=all_in_kana(query),
|
||||||
|
lang="jp",
|
||||||
|
model=IdiomJp,
|
||||||
|
search_field="search_text",
|
||||||
|
target_field="text",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tasks.append(
|
||||||
|
service.suggest_proverb(
|
||||||
|
query=query,
|
||||||
|
lang="jp",
|
||||||
|
model=IdiomJp,
|
||||||
|
search_field="search_text",
|
||||||
|
target_field="text",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- 2️⃣ 中文输入(调整优先级) ---
|
||||||
|
elif lang == "zh":
|
||||||
|
# ✅ (1) 若存在映射:mapping_query 优先匹配日语原型(text)
|
||||||
|
if is_kangji and mapping_query:
|
||||||
|
tasks.append(
|
||||||
|
service.suggest_proverb(
|
||||||
|
query=mapping_query,
|
||||||
|
lang="jp",
|
||||||
|
model=IdiomJp,
|
||||||
|
search_field="text",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# ✅ (2) 然后匹配中文释义(chi_exp 或 search_text)
|
||||||
tasks.append(
|
tasks.append(
|
||||||
service.suggest_proverb(
|
service.suggest_proverb(
|
||||||
query=mapping_query,
|
query=query,
|
||||||
lang="jp",
|
lang="zh",
|
||||||
model=IdiomJp,
|
model=IdiomJp,
|
||||||
search_field="text",
|
target_field="text",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# ✅ 并发执行(返回结果顺序与任务顺序一致)
|
# ✅ (3) 最后用假名匹配映射(辅助补全)
|
||||||
|
if is_kangji and mapping_query:
|
||||||
|
tasks.append(
|
||||||
|
service.suggest_proverb(
|
||||||
|
query=all_in_kana(mapping_query),
|
||||||
|
lang="jp",
|
||||||
|
model=IdiomJp,
|
||||||
|
search_field="search_text",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- 3️⃣ 其他语言(默认回退) ---
|
||||||
|
else:
|
||||||
|
tasks.append(
|
||||||
|
service.suggest_proverb(
|
||||||
|
query=query,
|
||||||
|
lang="jp",
|
||||||
|
model=IdiomJp,
|
||||||
|
search_field="search_text",
|
||||||
|
target_field="text",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# ✅ 并发执行任务(结果顺序与任务定义顺序一致)
|
||||||
results = await asyncio.gather(*tasks)
|
results = await asyncio.gather(*tasks)
|
||||||
|
|
||||||
# ✅ 合并结果
|
# ✅ 顺序合并 + 稳定去重
|
||||||
result = results[0]
|
seen = set()
|
||||||
if len(results) > 1:
|
ordered_unique = []
|
||||||
result[:0] = results[1] # 将中文映射查询结果插到最前面
|
for res in results:
|
||||||
|
for item in res:
|
||||||
|
key = item.get("proverb") or item.get("text")
|
||||||
|
if key and key not in seen:
|
||||||
|
seen.add(key)
|
||||||
|
ordered_unique.append(item)
|
||||||
|
|
||||||
|
return {"list": ordered_unique}
|
||||||
|
|
||||||
return {"list": result}
|
|
||||||
|
|
||||||
|
|
||||||
@dict_search.post("/search/idiom")
|
@dict_search.post("/search/idiom")
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ class WordSearchResponse(BaseModel):
|
||||||
query: str
|
query: str
|
||||||
pos: list
|
pos: list
|
||||||
contents: Union[List[SearchItemFr], List[SearchItemJp]]
|
contents: Union[List[SearchItemFr], List[SearchItemJp]]
|
||||||
|
hiragana : str
|
||||||
|
|
||||||
|
|
||||||
class ProverbSearchResponse(BaseModel):
|
class ProverbSearchResponse(BaseModel):
|
||||||
|
|
|
||||||
|
|
@ -92,9 +92,8 @@ async def suggest_proverb(
|
||||||
|
|
||||||
# ✅ 搜索条件:中文时双字段联合匹配
|
# ✅ 搜索条件:中文时双字段联合匹配
|
||||||
if lang == "zh":
|
if lang == "zh":
|
||||||
start_condition = Q(**{f"{chi_exp_field}__istartswith": keyword}) | Q(
|
start_condition = Q(**{f"{chi_exp_field}__istartswith": keyword})
|
||||||
**{f"{search_field}__istartswith": keyword})
|
contain_condition = Q(**{f"{chi_exp_field}__icontains": keyword})
|
||||||
contain_condition = Q(**{f"{chi_exp_field}__icontains": keyword}) | Q(**{f"{search_field}__icontains": keyword})
|
|
||||||
else:
|
else:
|
||||||
start_condition = Q(**{f"{search_field}__istartswith": keyword})
|
start_condition = Q(**{f"{search_field}__istartswith": keyword})
|
||||||
contain_condition = Q(**{f"{search_field}__icontains": keyword})
|
contain_condition = Q(**{f"{search_field}__icontains": keyword})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import json
|
|
||||||
import random
|
import random
|
||||||
from typing import Tuple, Dict
|
from typing import Tuple, Dict
|
||||||
|
|
||||||
|
|
@ -15,8 +14,6 @@ from settings import settings
|
||||||
translator_router = APIRouter()
|
translator_router = APIRouter()
|
||||||
|
|
||||||
# For list of language codes, please refer to `https://api.fanyi.baidu.com/doc/21`
|
# For list of language codes, please refer to `https://api.fanyi.baidu.com/doc/21`
|
||||||
from_lang = 'en'
|
|
||||||
to_lang = 'zh'
|
|
||||||
|
|
||||||
|
|
||||||
# endpoint = 'https://api.fanyi.baidu.com'
|
# endpoint = 'https://api.fanyi.baidu.com'
|
||||||
|
|
@ -81,7 +78,7 @@ async def baidu_translation(query: str, from_lang: str, to_lang: str):
|
||||||
raise HTTPException(status_code=500, detail=response.json())
|
raise HTTPException(status_code=500, detail=response.json())
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
print(json.dumps(data, indent=2, ensure_ascii=False))
|
# print(json.dumps(data, indent=2, ensure_ascii=False))
|
||||||
|
|
||||||
if "trans_result" not in data:
|
if "trans_result" not in data:
|
||||||
raise HTTPException(status_code=500, detail={"error_code": data.get("error_code"), "error_msg": data.get("error_msg")})
|
raise HTTPException(status_code=500, detail={"error_code": data.get("error_code"), "error_msg": data.get("error_msg")})
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,16 @@ async def get_search_time(request: Request):
|
||||||
if not count:
|
if not count:
|
||||||
await redis.set(key, value=0)
|
await redis.set(key, value=0)
|
||||||
count = 0
|
count = 0
|
||||||
print(count, type(count))
|
|
||||||
return {
|
return {
|
||||||
"count": int(count),
|
"count": int(count),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ulit_router.get("/search/reset", tags=["search times reset"])
|
||||||
|
async def reset_search_time(request: Request):
|
||||||
|
redis = request.app.state.redis
|
||||||
|
key = f"search_time"
|
||||||
|
|
||||||
|
count = await redis.set(key, 0)
|
||||||
|
return {
|
||||||
|
"message": "search times reset successfully",
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ from pydantic import BaseModel, field_validator, model_validator
|
||||||
|
|
||||||
class TransRequest(BaseModel):
|
class TransRequest(BaseModel):
|
||||||
query: str
|
query: str
|
||||||
from_lang: Literal['auto', 'fr', 'jp', 'zh', 'en'] = 'auto'
|
from_lang: Literal['auto', 'fra', 'jp', 'zh', 'en'] = 'auto'
|
||||||
to_lang: Literal['fr', 'jp', 'zh', 'en'] = 'zh'
|
to_lang: Literal['fra', 'jp', 'zh', 'en'] = 'zh'
|
||||||
|
|
||||||
@field_validator('from_lang', 'to_lang')
|
@field_validator('from_lang', 'to_lang')
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_lang(cls, v):
|
def validate_lang(cls, v):
|
||||||
allowed_langs = {'auto', 'fr', 'jp', 'zh', 'en'}
|
allowed_langs = {'auto', 'fra', 'jp', 'zh', 'en'}
|
||||||
if v not in allowed_langs:
|
if v not in allowed_langs:
|
||||||
raise ValueError(f'Unsupported language: {v}')
|
raise ValueError(f'Unsupported language: {v}')
|
||||||
return v
|
return v
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue