diff --git a/pyproject.toml b/pyproject.toml index be67773..9861e88 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,4 +66,5 @@ dependencies = [ "python-magic>=0.4.27", "ddgs>=9.14.1", "aiofiles>=24.1.0", + "fast-langdetect>=1.0.0", ] diff --git a/src/server/deep_agent/agents/main_agent.py b/src/server/deep_agent/agents/main_agent.py index 9fbad53..e909ecf 100755 --- a/src/server/deep_agent/agents/main_agent.py +++ b/src/server/deep_agent/agents/main_agent.py @@ -1,15 +1,17 @@ import logging -from typing import Callable +from typing import Callable, Any, Optional, Dict from dataclasses import dataclass from deepagents import create_deep_agent from deepagents.backends import FilesystemBackend, CompositeBackend, StateBackend -from langchain.agents.middleware import SummarizationMiddleware, ToolRetryMiddleware, wrap_model_call, ModelRequest, ModelResponse, wrap_tool_call, dynamic_prompt -from langchain_core.messages import ToolMessage, SystemMessage +from fast_langdetect import detect +from langchain.agents.middleware import SummarizationMiddleware, ToolRetryMiddleware, wrap_model_call, ModelRequest, ModelResponse, wrap_tool_call, dynamic_prompt, before_model, AgentMiddleware, hook_config +from langchain_core.messages import ToolMessage, SystemMessage, AIMessage, HumanMessage from langgraph.checkpoint.mongodb import MongoDBSaver from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer from langgraph.constants import END from langgraph.prebuilt.tool_node import ToolCallRequest +from langgraph.runtime import Runtime from langgraph.store.memory import InMemoryStore from langgraph.types import Command from pymongo import MongoClient @@ -96,7 +98,7 @@ async def report_control(request: ToolCallRequest, handler: Callable[[ToolCallRe def user_role_prompt(request: ModelRequest) -> str: """Generate system prompts based on use_report status and language preference.""" use_report = request.runtime.context.use_report - language = request.runtime.context.language # 默认简体中文 + language = request.runtime.context.language # ==================== 报告功能状态提示(支持中英文) ==================== if use_report: @@ -132,7 +134,13 @@ def user_role_prompt(request: ModelRequest) -> str: CRITICAL: - Be sure to use the above settings when generating line drawings/images. - Do not refer to these three settings repeatedly when generating reports or text-only answers.""" - + langguage_prompt = f""" + ## Custom Language Rules + - All content of the final report and all reply content MUST be fully written in: {language} + - No mixed languages, no bilingual contrast, no extra English annotations. + - Maintain native, fluent, professional expression conforming to the language habits of {language}. + - All professional terms, captions, notes and reference descriptions must follow the unified {language} specification. + """ final_prompt = backend_prompt + SYSTEM_PROMPT_MAPPING[f'SYSTEM_BASE_PROMPT_en'] + report_status + SYSTEM_PROMPT_MAPPING[f"SYSTEM_RULES_PROMPT_en"] logger.info( @@ -142,6 +150,58 @@ def user_role_prompt(request: ModelRequest) -> str: return final_prompt +from langchain.agents.middleware import AgentState + + +class LanguageDetectionMiddleware(AgentMiddleware): + """使用 fast-langdetect(基于 fastText)自动检测语言""" + + def __init__(self, min_length: int = 8, default_lang: str = "zh"): + self.min_length = min_length + self.default_lang = default_lang + + def before_model(self, state: AgentState, runtime=None) -> Optional[Dict[str, Any]]: + messages = state.get("messages", []) + if not messages: + return None + + last_msg = messages[-1] + if not isinstance(last_msg, HumanMessage): + return None + + content = last_msg.content if hasattr(last_msg, "content") else str(last_msg) + content = content[0].get("text").strip() + + if len(content) < self.min_length: + return None + + try: + detected_lang = "en" + confidence = 0 + # 单语言检测(最常用) + res = detect(text=content, model="auto", k=1) + if res and res[0].get("lang") and res[0].get("score", 0) > 0.5: + detected_lang = res[0]["lang"] + confidence = res[0]["score"] + + print(f"🔍 fast-langdetect 检测到: {detected_lang} (score={confidence:.4f})") + + runtime.context.language = detected_lang + + return { + "language": detected_lang, + "preferred_language": detected_lang, + "language_confidence": float(confidence), + } + + except Exception as e: + print(f"语言检测失败: {e}") + return {"language": self.default_lang} + + async def abefore_model(self, state: AgentState, runtime=None): + return self.before_model(state, runtime) + + def build_main_agent(workspace_dir, enable_thinking): research_subagent = build_researcher_subagent(workspace_dir) # painter_subagent = build_painter_subagent(workspace_dir) @@ -151,6 +211,7 @@ def build_main_agent(workspace_dir, enable_thinking): user_profile_subagent ] middleware = [ + LanguageDetectionMiddleware(min_length=8, default_lang="en"), user_role_prompt, report_control, SummarizationMiddleware( diff --git a/src/server/deep_agent/agents/researcher.py b/src/server/deep_agent/agents/researcher.py index 6cae7bd..ccf00df 100755 --- a/src/server/deep_agent/agents/researcher.py +++ b/src/server/deep_agent/agents/researcher.py @@ -1,3 +1,5 @@ +from langchain.agents.middleware import dynamic_prompt, ModelRequest + from src.server.deep_agent.init_prompt import build_researcher_prompt from src.server.deep_agent.tools.crawl_tool import create_crawl4ai_batch_tool from src.server.deep_agent.tools.report_generator_tool import create_report_generator_tool @@ -6,6 +8,52 @@ from src.server.deep_agent.tools.structured_retrieval_tool import create_structu from src.server.deep_agent.tools.user_persona_tool import query_report_profile +@dynamic_prompt +def language_control(request: ModelRequest) -> str: + """Generate system prompts based on use_report status and language preference.""" + language = request.runtime.context.language # 默认简体中文 + + final_prompt = f""" +You are a professional furniture design researcher. + +Your primary goal: +- Generate a high-quality, structured furniture design research report based on the user's request and user profile. +- The report should be clear, insightful, and written in well-structured Markdown format. +- It should include design trends, materials, color directions, representative cases, and relevant references. + +You are allowed to: +- Retrieve user profile information (e.g., style, room type, preferences) +- Generate research keywords +- Search for relevant topics and sources +- Crawl and read web content +- Extract structured insights +- Generate the final report + +Tool usage guidelines: +- If necessary, first retrieve the user profile to better understand preferences. +- Use meaningful and relevant keywords for research. +- When crawling web content, try to process multiple sources efficiently (avoid repeated calls). +- Focus on extracting key insights such as trends, materials, colors, and case studies. +- Use the report_generator tool to produce the final report. + +Important rules: +- Your objective is to complete a high-quality report, not to strictly follow a fixed sequence of steps. +- You may adapt your approach depending on the situation. +- Avoid calling the same tool repeatedly (especially crawl tools). +- If some data is missing, proceed with available information and clearly mention any limitations. +- Once the report is generated, consider the task complete and stop further actions. + +## Custom Language Rules +- All content of the final report and all reply content MUST be fully written in: {language} +- No mixed languages, no bilingual contrast, no extra English annotations. +- Maintain native, fluent, professional expression conforming to the language habits of {language}. +- All professional terms, captions, notes and reference descriptions must follow the unified {language} specification. + +""" + + return final_prompt + + def build_researcher_subagent(workspace_dir): crawl4ai_batch = create_crawl4ai_batch_tool(workspace_dir) structured_retrieval = create_structured_retrieval_tool(workspace_dir) @@ -28,10 +76,11 @@ This sub-agent will: - Produce a complete research report Do NOT use this sub-agent for: -- User profile collection (handled by user_profile_subagent) +- User profile collection - Image generation or editing tasks """, "system_prompt": build_researcher_prompt(), + "middleware": [language_control], "tools": [ query_report_profile, topic_research, diff --git a/src/server/deep_agent/agents/user_profile.py b/src/server/deep_agent/agents/user_profile.py index ba3b577..99cab30 100755 --- a/src/server/deep_agent/agents/user_profile.py +++ b/src/server/deep_agent/agents/user_profile.py @@ -1,6 +1,101 @@ +from langchain.agents.middleware import dynamic_prompt, ModelRequest + from src.server.deep_agent.init_prompt import build_user_persona_prompt from src.server.deep_agent.tools.user_persona_tool import query_report_profile, update_report_profile, check_profile_complete + +@dynamic_prompt +def language_control(request: ModelRequest) -> str: + """Generate system prompts based on use_report status and language preference.""" + language = request.runtime.context.language # 默认简体中文 + + final_prompt = f""" + You are a user profile collection assistant. + + Your goal: + - Extract and maintain structured user profile information from the conversation. + - The profile is used for generating furniture design reports. + + Profile fields may include: + - style (design style or aesthetic preference) + - room_type (type of room or space) + - budget (optional) + - other relevant design preferences + + What you should do: + - Understand the user's input and identify any profile-related information. + - If new information is found, update the profile accordingly. + - If no new information is provided, keep the existing profile unchanged. + - Ensure previously stored information is preserved unless the user explicitly modifies it. + + Tool usage guidelines: + - Use query_report_profile when you need to know the current profile. + - Use update_report_profile only when new or updated information is detected. + - Use check_profile_complete to determine if required fields are sufficient for report generation. + + Behavior rules: + - Do NOT generate reports. + - Do NOT guess or fabricate missing information. + - Only extract information that is clearly stated or strongly implied by the user. + - Be concise and structured in your output. + + When profile is incomplete: + - Ask the user for the missing information in a natural way. + + When profile is complete: + - Respond with a clear signal that profile collection is done, for example: + "Profile is complete. Ready for report generation." + + Language rules: + - Always respond in the same language as the user. + - Do not mix languages. + - Keep the output consistent and natural. + + Strict Language Enforcement: + - You MUST use only one language in the entire response. + - The language must match the user's input. + - Mixing multiple languages is strictly prohibited. + """ + + final_prompt = f""" +You are a professional furniture design researcher. + +## Core Objectives +- Generate high-quality, in-depth & structured furniture design research reports in standard Markdown format. +- Strictly combine user requirements and complete user profile information for customized analysis. +- The report must cover: design trend analysis, mainstream material selection, color palette orientation, classic representative cases and industry reference information. + +## Permitted Capabilities +- Retrieve and parse user profile data (design style preference, room type, usage scenario, aesthetic tendency, etc.). +- Extract core research keywords for industry investigation. +- Search, crawl and summarize multi-source industry information. +- Refine structured, actionable design insights. +- Call the report_generator tool to output the final standardized report. + +## Tool Usage Specifications +- Prioritize obtaining complete user profile before research to improve report relevance. +- Use precise, industry-oriented search keywords. +- Crawl and integrate multiple sources at one time to avoid redundant and repeated tool calls. +- Focus on screening effective information: trend characteristics, material performance, color matching logic, typical brand cases. +- Do not over-rely on tool processes; flexibly adjust research ideas according to information integrity. + +## Critical Rules +- Task priority: deliver a complete, high-quality research report. +- No rigid step-by-step execution; adjust research logic adaptively based on actual conditions. +- Prohibit frequent repeated calls to crawl and search tools. +- If partial industry data is missing, continue writing with existing valid information and mark data limitations clearly in the report. +- Stop all tool calls and work immediately after the final report is generated. + +## Custom Language Rules +- All content of the final report and all reply content MUST be fully written in: {language} +- No mixed languages, no bilingual contrast, no extra English annotations. +- Maintain native, fluent, professional expression conforming to the language habits of {language}. +- All professional terms, captions, notes and reference descriptions must follow the unified {language} specification. +""" + + return final_prompt + + user_profile_subagent = { "name": "user_profile_subagent", "description": """ @@ -22,6 +117,7 @@ Do NOT use this sub-agent for: - Image generation or editing """, "system_prompt": build_user_persona_prompt(), + "middleware": [language_control], "tools": [ query_report_profile, update_report_profile, diff --git a/src/server/deep_agent/tools/research_tool.py b/src/server/deep_agent/tools/research_tool.py index 0e63eea..46f70aa 100755 --- a/src/server/deep_agent/tools/research_tool.py +++ b/src/server/deep_agent/tools/research_tool.py @@ -79,8 +79,8 @@ from langchain.tools import tool @tool async def topic_research(topic: List[str], max_urls: int = 5) -> str: """ - 深度调研工具(DuckDuckGo版本)。 - 根据多个主题关键词进行搜索,返回去重后的高质量 URL 列表(JSON字符串)。 + In-depth research tool (DuckDuckGo version). + Search based on multiple topic keywords and return a high-quality URL list (JSON string) after deduplication. """ # DuckDuckGo 是同步库,需要丢到线程池 diff --git a/src/server/deep_agent/tools/user_persona_tool.py b/src/server/deep_agent/tools/user_persona_tool.py index 21bcb2b..f8767d9 100755 --- a/src/server/deep_agent/tools/user_persona_tool.py +++ b/src/server/deep_agent/tools/user_persona_tool.py @@ -13,7 +13,7 @@ collection = db["user_profiles"] @tool def query_report_profile(config: RunnableConfig, ) -> dict: """ - 查询用户报告画像 + Query user report portrait """ thread_id = config['configurable']['thread_id'] doc = collection.find_one({"thread_id": thread_id}) @@ -28,7 +28,7 @@ def query_report_profile(config: RunnableConfig, ) -> dict: @tool def update_report_profile(config: RunnableConfig, profile: dict) -> dict: """ - 更新用户画像信息 + Update user portrait information """ thread_id = config['configurable']['thread_id'] collection.update_one( @@ -47,7 +47,7 @@ def update_report_profile(config: RunnableConfig, profile: dict) -> dict: @tool def check_profile_complete(profile: dict) -> dict: """ - 判断画像是否完整 + Determine whether the image is complete """ required = ["style", "room_type", "budget"] missing = [f for f in required if f not in profile] diff --git a/uv.lock b/uv.lock index 837170f..3aacc4c 100755 --- a/uv.lock +++ b/uv.lock @@ -699,6 +699,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + [[package]] name = "crawl4ai" version = "0.8.6" @@ -1142,6 +1154,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/51/37/b3ea9cd5558ff4cb51957caca2193981c6b0ff30bd0d2630ac62505d99d0/fake_useragent-2.2.0-py3-none-any.whl", hash = "sha256:67f35ca4d847b0d298187443aaf020413746e56acd985a611908c73dba2daa24", size = 161695, upload-time = "2025-04-14T15:32:17.732Z" }, ] +[[package]] +name = "fast-langdetect" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fasttext-predict" }, + { name = "requests" }, + { name = "robust-downloader" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/15/85b0137066be418b6249d8e8d98e2b16c072c65b80c293b9438fdea1be5e/fast_langdetect-1.0.0.tar.gz", hash = "sha256:ea8ac6a8914e0ff1bfc1bbc0f25992eb913ddb69e63ea1b24e907e263d0cd113", size = 796192, upload-time = "2025-09-17T06:32:26.86Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/71/0db1ac89f8661048ebc22d62f503a2e147cb6872c5f2aeb659c1f02c1694/fast_langdetect-1.0.0-py3-none-any.whl", hash = "sha256:aab9e3435cc667ac8ba8b1a38872f75492f65b7087901d0f3a02a88d436cd22a", size = 789944, upload-time = "2025-09-17T06:32:25.363Z" }, +] + [[package]] name = "fastapi" version = "0.136.0" @@ -1282,6 +1308,50 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6b/fd/5390ec4f49100f3ecb9968a392f9e6d039f1e3fe0ecd28443716ff01e589/fastar-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:76c1359314355eafbc6989f20fb1ad565a3d10200117923b9da765a17e2f6f11", size = 461049, upload-time = "2026-04-13T17:11:25.918Z" }, ] +[[package]] +name = "fasttext-predict" +version = "0.9.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0e/9defbb9385bcb1104cc1d686a14f7d9fafe5fe43f220cccb00f33d91bb47/fasttext_predict-0.9.2.4.tar.gz", hash = "sha256:18a6fb0d74c7df9280db1f96cb75d990bfd004fa9d669493ea3dd3d54f84dbc7", size = 16332, upload-time = "2024-11-23T17:24:44.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/fa/612bf85ce8928120843279ae256f4fffbb9758af81536ddf25f9136b1759/fasttext_predict-0.9.2.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dcf8661da4f515551523470a745df246121f7e19736fcf3f48f04287963e6279", size = 104836, upload-time = "2024-11-23T17:23:25.219Z" }, + { url = "https://files.pythonhosted.org/packages/7a/04/106b6fe3f980d6a4f41bfb3106be22d42f87b1e8beb2959361ee4ee08960/fasttext_predict-0.9.2.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99dbfcc3f353da2639fd04fc574a65ff4195b018311f790583147cdc6eb122f4", size = 97377, upload-time = "2024-11-23T17:23:26.319Z" }, + { url = "https://files.pythonhosted.org/packages/57/b9/b4962c92bd93dd234ea1d1cab643a86d948dab3f269e34a554a004ed6524/fasttext_predict-0.9.2.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:427e99ba963b2c744ed7233304037a83b7adece97de6f361cfd356aa43cb87f3", size = 283102, upload-time = "2024-11-23T17:23:27.497Z" }, + { url = "https://files.pythonhosted.org/packages/1d/18/92203820cf00b9a34f40f10456e4ed3019010a9b13a87e11d8b98cd98933/fasttext_predict-0.9.2.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b9480cc75a906571a8e5fc717b91b4783f1820aaa5ed36a304d689280de8602", size = 307416, upload-time = "2024-11-23T17:23:28.68Z" }, + { url = "https://files.pythonhosted.org/packages/06/8d/334cd9acb84e569d37617444661ca7b59d1bc1a83abe42aa845d23fb1273/fasttext_predict-0.9.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11ef7af2a4431c76d2226e47334e86b9c4a78a98f6cb68b1ce9a1fc20e04c904", size = 296055, upload-time = "2024-11-23T17:23:29.934Z" }, + { url = "https://files.pythonhosted.org/packages/08/0b/2c83cc67eb5a29f182c8ea425e4b026db0593712edb8eaaf082501ca349f/fasttext_predict-0.9.2.4-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:ecb0b854596ba847742597b35c2d0134fcf3a59214d09351d01535854078d56b", size = 237279, upload-time = "2024-11-23T17:23:31.358Z" }, + { url = "https://files.pythonhosted.org/packages/14/81/0f1b3bda499ffeb7109fe51d9321dc74100db5a4801e3f9a9efe2348922d/fasttext_predict-0.9.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fbbcfefac10f625d95fc42f28d76cc5bf0c12875f147b5a79108a2669e64a2dc", size = 1214253, upload-time = "2024-11-23T17:23:33.529Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e6/b1a177a990c29b043a9658f9f4ec7234576ad31939362f9760c237f91d6d/fasttext_predict-0.9.2.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a8cb78a00c04b7eb7da18b4805f8557b36911dc4375c947d8938897d2e131841", size = 1099909, upload-time = "2024-11-23T17:23:34.983Z" }, + { url = "https://files.pythonhosted.org/packages/09/a0/7f23c7c4398f399552f39144849868991da543b66b9bfa8f49a6550fdd46/fasttext_predict-0.9.2.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:299ae56ad53e1381c65030143da7bcae12546fd32bc019215592ec1ee40fd19e", size = 1384102, upload-time = "2024-11-23T17:23:37.237Z" }, + { url = "https://files.pythonhosted.org/packages/e4/2c/568cf15fd48e4cefd0e605af62da5f5f51db3b012f8441d201d0a1173eb1/fasttext_predict-0.9.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:091938062002fe30d214f6e493a3a1e6180d401212d37eea23c29f4b55f3f347", size = 1281283, upload-time = "2024-11-23T17:23:39.676Z" }, + { url = "https://files.pythonhosted.org/packages/e7/68/0967ec3d5333c23fae1f1bdb851fa896f8f6068ef0ca3a8afee1aa2ee57d/fasttext_predict-0.9.2.4-cp312-cp312-win32.whl", hash = "sha256:981b8d9734623f8f9a8003970f765e14b1d91ee82c59c35e8eba6b76368fa95e", size = 91089, upload-time = "2024-11-23T17:23:41.082Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c5/11c1f50b47f492d562974878ec34b6a0b84699f8b05e1cc3a75c65349784/fasttext_predict-0.9.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:bd3c33971c241577b0767e55d97acfda790f77378f9d5ee7872b6ee4bd63130b", size = 104889, upload-time = "2024-11-23T17:23:42.193Z" }, + { url = "https://files.pythonhosted.org/packages/89/fc/5cd65224c33e33d6faec3fa1047162dc266ed2213016139d936bd36fb7c3/fasttext_predict-0.9.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ddb85e62c95e4e02d417c782e3434ef65554df19e3522f5230f6be15a9373c05", size = 104916, upload-time = "2024-11-23T17:23:43.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/53/8d542773e32c9d98dd8c680e390fe7e6d4fc92ab3439dc1bb8e70c46c7ad/fasttext_predict-0.9.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:102129d45cf98dda871e83ae662f71d999b9ef6ff26bc842ffc1520a1f82930c", size = 97502, upload-time = "2024-11-23T17:23:44.447Z" }, + { url = "https://files.pythonhosted.org/packages/50/99/049fd6b01937705889bd9a00c31e5c55f0ae4b7704007b2ef7a82bf2b867/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ba6a0fbf8cb2141b8ca2bc461db97af8ac31a62341e4696a75048b9de39e10", size = 282951, upload-time = "2024-11-23T17:23:46.31Z" }, + { url = "https://files.pythonhosted.org/packages/83/cb/79b71709edbb53c3c5f8a8b60fe2d3bc98d28a8e75367c89afedf3307aa9/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c7a779215571296ecfcf86545cb30ec3f1c6f43cbcd69f83cc4f67049375ea1", size = 307377, upload-time = "2024-11-23T17:23:47.685Z" }, + { url = "https://files.pythonhosted.org/packages/7c/4a/b15b7be003e76613173cc77d9c6cce4bf086073079354e0177deaa768f59/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddd2f03f3f206585543f5274b1dbc5f651bae141a1b14c9d5225c2a12e5075c2", size = 295746, upload-time = "2024-11-23T17:23:49.024Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d3/f030cd45bdd4b052fcf23e730fdf0804e024b0cad43d7c7f8704faaec2f5/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:748f9edc3222a1fb7a61331c4e06d3b7f2390ae493f91f09d372a00b81762a8d", size = 236939, upload-time = "2024-11-23T17:23:50.306Z" }, + { url = "https://files.pythonhosted.org/packages/a2/01/6f2985afd58fdc5f4ecd058d5d9427d03081d468960982df97316c03f6bb/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1aee47a40757cd24272b34eaf9ceeea86577fd0761b0fd0e41599c6549abdf04", size = 1214189, upload-time = "2024-11-23T17:23:51.647Z" }, + { url = "https://files.pythonhosted.org/packages/75/07/931bcdd4e2406e45e54d57e056c2e0766616a5280a18fbf6ef078aa439ab/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6ff0f152391ee03ffc18495322100c01735224f7843533a7c4ff33c8853d7be1", size = 1099889, upload-time = "2024-11-23T17:23:53.127Z" }, + { url = "https://files.pythonhosted.org/packages/a2/eb/6521b4bbf387252a96a6dc0f54986f078a93db0a9d4ba77258dcf1fa8be7/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4d92f5265318b41d6e68659fd459babbff692484e492c5013995b90a56b517c9", size = 1383959, upload-time = "2024-11-23T17:23:54.521Z" }, + { url = "https://files.pythonhosted.org/packages/b7/6b/d56606761afb3a3912c52971f0f804e2e9065f049c412b96c47d6fca6218/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3a7720cce1b8689d88df76cac1425e84f9911c69a4e40a5309d7d3435e1bb97c", size = 1281097, upload-time = "2024-11-23T17:23:55.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/83/55bb4a37bb3b3a428941f4e1323c345a662254f576f8860b3098d9742510/fasttext_predict-0.9.2.4-cp313-cp313-win32.whl", hash = "sha256:d16acfced7871ed0cd55b476f0dbdddc7a5da1ffc9745a3c5674846cf1555886", size = 91137, upload-time = "2024-11-23T17:23:57.886Z" }, + { url = "https://files.pythonhosted.org/packages/9c/1d/c1ccc8790ce54200c84164d99282f088dddb9760aeefc8860856aafa40b4/fasttext_predict-0.9.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:96a23328729ce62a851f8953582e576ca075ee78d637df4a78a2b3609784849e", size = 104896, upload-time = "2024-11-23T17:23:59.028Z" }, + { url = "https://files.pythonhosted.org/packages/a4/c9/a1ccc749c59e2480767645ecc03bd842a7fa5b2b780d69ac370e6f8298d2/fasttext_predict-0.9.2.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b1357d0d9d8568db84668b57e7c6880b9c46f757e8954ad37634402d36f09dba", size = 109401, upload-time = "2024-11-23T17:24:00.191Z" }, + { url = "https://files.pythonhosted.org/packages/90/1f/33182b76eb0524155e8ff93e7939feaf5325385e5ff2a154f383d9a02317/fasttext_predict-0.9.2.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9604c464c5d86c7eba34b040080be7012e246ef512b819e428b7deb817290dae", size = 102131, upload-time = "2024-11-23T17:24:02.052Z" }, + { url = "https://files.pythonhosted.org/packages/2b/df/1886daea373382e573f28ce49e3fc8fb6b0ee0c84e2b0becf5b254cd93fb/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6da186c2e4497cbfaba9c5424e58c7b72728b25d980829eb96daccd7cface1", size = 287396, upload-time = "2024-11-23T17:24:03.294Z" }, + { url = "https://files.pythonhosted.org/packages/35/8f/d1c2c0f0251bee898d508253a437683b0480a1074cfb25ded1f7fdbb925a/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:366ed2ca4f4170418f3585e92059cf17ee2c963bf179111c5b8ba48f06cd69d1", size = 311090, upload-time = "2024-11-23T17:24:04.625Z" }, + { url = "https://files.pythonhosted.org/packages/5d/52/07d6ed46148662fae84166bc69d944caca87fabc850ebfbd9640b20dafe7/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f1877edbb815a43e7d38cc7332202e759054cf0b5a4b7e34a743c0f5d6e7333", size = 300359, upload-time = "2024-11-23T17:24:06.486Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a1/751ff471a991e5ed0bae9e7fa6fc8d8ab76b233a7838a27d70d62bed0c8e/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_31_armv7l.whl", hash = "sha256:f63c31352ba6fc910290b0fe12733770acd8cfa0945fcb9cf3984d241abcfc9d", size = 241164, upload-time = "2024-11-23T17:24:08.501Z" }, + { url = "https://files.pythonhosted.org/packages/94/19/e251f699a0e9c001fa672ea0929c456160faa68ecfafc19e8def09982b6a/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:898e14b03fbfb0a8d9a5185a0a00ff656772b3baa37cad122e06e8e4d6da3832", size = 1218629, upload-time = "2024-11-23T17:24:10.04Z" }, + { url = "https://files.pythonhosted.org/packages/1d/46/1af2f779f8cfd746496a226581f747d3051888e3e3c5b2ca37231e5d04f8/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:a33bb5832a69fc54d18cadcf015677c1acb5ccc7f0125d261df2a89f8aff01f6", size = 1100535, upload-time = "2024-11-23T17:24:11.5Z" }, + { url = "https://files.pythonhosted.org/packages/4c/b7/900ccd74a9ba8be7ca6d04bba684e9c43fb0dbed8a3d12ec0536228e2c32/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7fe9e98bd0701d598bf245eb2fbf592145cd03551684a2102a4b301294b9bd87", size = 1387651, upload-time = "2024-11-23T17:24:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5a/99fdaed054079f7c96e70df0d7016c4eb6b9e487a614396dd8f849244a52/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dcb8c5a74c1785f005fd83d445137437b79ac70a2dfbfe4bb1b09aa5643be545", size = 1286189, upload-time = "2024-11-23T17:24:14.615Z" }, + { url = "https://files.pythonhosted.org/packages/87/6a/9114d65b3f7a9c20a62b9d2ca3b770ee65de849e4131cc7aa58cdc50cb07/fasttext_predict-0.9.2.4-cp313-cp313t-win32.whl", hash = "sha256:a85c7de3d4480faa12b930637fca9c23144d1520786fedf9ba8edd8642ed4aea", size = 95905, upload-time = "2024-11-23T17:24:15.868Z" }, + { url = "https://files.pythonhosted.org/packages/31/fb/6d251f3fdfe3346ee60d091f55106513e509659ee005ad39c914182c96f4/fasttext_predict-0.9.2.4-cp313-cp313t-win_amd64.whl", hash = "sha256:be0933fa4af7abae09c703d28f9e17c80e7069eb6f92100b21985b777f4ea275", size = 110325, upload-time = "2024-11-23T17:24:16.984Z" }, +] + [[package]] name = "fastuuid" version = "0.14.0" @@ -1344,6 +1414,7 @@ dependencies = [ { name = "deepagents" }, { name = "end" }, { name = "faiss-cpu" }, + { name = "fast-langdetect" }, { name = "fastapi", extra = ["standard"] }, { name = "field" }, { name = "gunicorn" }, @@ -1409,6 +1480,7 @@ requires-dist = [ { name = "deepagents", specifier = ">=0.4.3" }, { name = "end", specifier = ">=1.3.1" }, { name = "faiss-cpu", specifier = ">=1.13.2" }, + { name = "fast-langdetect", specifier = ">=1.0.0" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.128.0" }, { name = "field", specifier = ">=0.2.0" }, { name = "gunicorn", specifier = ">=25.0.1" }, @@ -4671,6 +4743,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/62/b88e5879512c55b8ee979c666ee6902adc4ed05007226de266410ae27965/rignore-0.7.6-cp314-cp314t-win_arm64.whl", hash = "sha256:b83adabeb3e8cf662cabe1931b83e165b88c526fa6af6b3aa90429686e474896", size = 656035, upload-time = "2025-11-05T21:41:31.13Z" }, ] +[[package]] +name = "robust-downloader" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorlog" }, + { name = "requests" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/20/8d28efa080f58fa06f6378875ac482ee511c076369e5293a2e65128cf9a0/robust-downloader-0.0.2.tar.gz", hash = "sha256:08c938b96e317abe6b037e34230a91bda9b5d613f009bca4a47664997c61de90", size = 15785, upload-time = "2023-11-13T03:00:20.637Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/a1/779e9d0ebbdc704411ce30915a1105eb01aeaa9e402d7e446613ff8fb121/robust_downloader-0.0.2-py3-none-any.whl", hash = "sha256:8fe08bfb64d714fd1a048a7df6eb7b413eb4e624309a49db2c16fbb80a62869d", size = 15534, upload-time = "2023-11-13T03:00:18.957Z" }, +] + [[package]] name = "rpds-py" version = "0.30.0"