xiaogpt 2.82__tar.gz → 2.84__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {xiaogpt-2.82 → xiaogpt-2.84}/PKG-INFO +5 -2
  2. {xiaogpt-2.82 → xiaogpt-2.84}/README.md +2 -1
  3. {xiaogpt-2.82 → xiaogpt-2.84}/pyproject.toml +3 -1
  4. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/tts/base.py +1 -1
  5. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/utils.py +22 -1
  6. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/xiaogpt.py +8 -22
  7. {xiaogpt-2.82 → xiaogpt-2.84}/LICENSE +0 -0
  8. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/__init__.py +0 -0
  9. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/__main__.py +0 -0
  10. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/__init__.py +0 -0
  11. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/base_bot.py +0 -0
  12. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/chatgptapi_bot.py +0 -0
  13. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/doubao_bot.py +0 -0
  14. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/gemini_bot.py +0 -0
  15. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/glm_bot.py +0 -0
  16. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/langchain_bot.py +0 -0
  17. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/llama_bot.py +0 -0
  18. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/moonshot_bot.py +0 -0
  19. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/qwen_bot.py +0 -0
  20. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/bot/yi_bot.py +0 -0
  21. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/cli.py +0 -0
  22. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/config.py +0 -0
  23. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/langchain/callbacks.py +0 -0
  24. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/langchain/chain.py +0 -0
  25. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/langchain/examples/email/mail_box.py +0 -0
  26. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/langchain/examples/email/mail_summary_tools.py +0 -0
  27. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/tts/__init__.py +0 -0
  28. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/tts/mi.py +0 -0
  29. {xiaogpt-2.82 → xiaogpt-2.84}/xiaogpt/tts/tetos.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xiaogpt
3
- Version: 2.82
3
+ Version: 2.84
4
4
  Summary: Play ChatGPT or other LLM with xiaomi AI speaker
5
5
  Author-Email: yihong0618 <zouzou0208@gmail.com>
6
6
  License: MIT
@@ -25,6 +25,7 @@ Requires-Dist: tetos>=0.2.1
25
25
  Requires-Dist: groq>=0.5.0
26
26
  Requires-Dist: pyyaml>=6.0.1
27
27
  Requires-Dist: langchain-community>=0.0.38
28
+ Requires-Dist: lingua-language-detector>=2.0.2; python_version < "3.13"
28
29
  Requires-Dist: aiohttp==3.9.5; extra == "locked"
29
30
  Requires-Dist: aiosignal==1.3.1; extra == "locked"
30
31
  Requires-Dist: annotated-types==0.6.0; extra == "locked"
@@ -71,6 +72,7 @@ Requires-Dist: langchain-community==0.2.0; extra == "locked"
71
72
  Requires-Dist: langchain-core==0.2.0; extra == "locked"
72
73
  Requires-Dist: langchain-text-splitters==0.2.0; extra == "locked"
73
74
  Requires-Dist: langsmith==0.1.45; extra == "locked"
75
+ Requires-Dist: lingua-language-detector==2.0.2; python_version < "3.13" and extra == "locked"
74
76
  Requires-Dist: markdown-it-py==3.0.0; extra == "locked"
75
77
  Requires-Dist: marshmallow==3.20.1; extra == "locked"
76
78
  Requires-Dist: mdurl==0.1.2; extra == "locked"
@@ -420,9 +422,10 @@ docker run -v <your-config-dir>:/config -p 9527:9527 -e XIAOGPT_HOSTNAME=<your i
420
422
 
421
423
  注意端口必须映射为与容器内一致,XIAOGPT_HOSTNAME 需要设置为宿主机的 IP 地址,否则小爱无法正常播放语音。
422
424
 
423
- ## 推荐的 fork
425
+ ## 推荐的类似项目
424
426
 
425
427
  - [XiaoBot](https://github.com/longbai/xiaobot) -> Go语言版本的Fork, 带支持不同平台的UI
428
+ - [MiGPT](https://github.com/idootop/mi-gpt) -> Node.js 版,支持流式响应和长短期记忆
426
429
 
427
430
  ## 感谢
428
431
 
@@ -306,9 +306,10 @@ docker run -v <your-config-dir>:/config -p 9527:9527 -e XIAOGPT_HOSTNAME=<your i
306
306
 
307
307
  注意端口必须映射为与容器内一致,XIAOGPT_HOSTNAME 需要设置为宿主机的 IP 地址,否则小爱无法正常播放语音。
308
308
 
309
- ## 推荐的 fork
309
+ ## 推荐的类似项目
310
310
 
311
311
  - [XiaoBot](https://github.com/longbai/xiaobot) -> Go语言版本的Fork, 带支持不同平台的UI
312
+ - [MiGPT](https://github.com/idootop/mi-gpt) -> Node.js 版,支持流式响应和长短期记忆
312
313
 
313
314
  ## 感谢
314
315
 
@@ -28,9 +28,10 @@ dependencies = [
28
28
  "groq>=0.5.0",
29
29
  "pyyaml>=6.0.1",
30
30
  "langchain-community>=0.0.38",
31
+ "lingua-language-detector>=2.0.2; python_version < \"3.13\"",
31
32
  ]
32
33
  dynamic = []
33
- version = "2.82"
34
+ version = "2.84"
34
35
 
35
36
  [project.license]
36
37
  text = "MIT"
@@ -89,6 +90,7 @@ locked = [
89
90
  "langchain-core==0.2.0",
90
91
  "langchain-text-splitters==0.2.0",
91
92
  "langsmith==0.1.45",
93
+ "lingua-language-detector==2.0.2 ; python_version < \"3.13\"",
92
94
  "markdown-it-py==3.0.0",
93
95
  "marshmallow==3.20.1",
94
96
  "mdurl==0.1.2",
@@ -118,7 +118,7 @@ class AudioFileTTS(TTS):
118
118
  continue
119
119
  logger.debug("Playing URL %s (%s seconds)", url, duration)
120
120
  await asyncio.gather(
121
- self.mina_service.play_by_url(self.device_id, url),
121
+ self.mina_service.play_by_url(self.device_id, url, _type=1),
122
122
  self.wait_for_duration(duration),
123
123
  )
124
124
  await task
@@ -5,11 +5,14 @@ import os
5
5
  import re
6
6
  import socket
7
7
  from http.cookies import SimpleCookie
8
- from typing import AsyncIterator
8
+ from typing import TYPE_CHECKING, AsyncIterator
9
9
  from urllib.parse import urlparse
10
10
 
11
11
  from requests.utils import cookiejar_from_dict
12
12
 
13
+ if TYPE_CHECKING:
14
+ from lingua import LanguageDetector
15
+
13
16
 
14
17
  ### HELP FUNCTION ###
15
18
  def parse_cookie_string(cookie_string):
@@ -69,3 +72,21 @@ def get_hostname() -> str:
69
72
  with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
70
73
  s.connect(("8.8.8.8", 80))
71
74
  return s.getsockname()[0]
75
+
76
+
77
+ def _get_detector() -> LanguageDetector | None:
78
+ try:
79
+ from lingua import LanguageDetectorBuilder
80
+ except ImportError:
81
+ return None
82
+ return LanguageDetectorBuilder.from_all_spoken_languages().build()
83
+
84
+
85
+ _detector = _get_detector()
86
+
87
+
88
+ def detect_language(text: str) -> str:
89
+ if _detector is None:
90
+ return "zh" # default to Chinese if langdetect module is not available
91
+ lang = _detector.detect_language_of(text)
92
+ return lang.iso_code_639_1.name.lower() if lang is not None else "zh"
@@ -24,9 +24,7 @@ from xiaogpt.config import (
24
24
  Config,
25
25
  )
26
26
  from xiaogpt.tts import TTS, MiTTS, TetosTTS
27
- from xiaogpt.utils import (
28
- parse_cookie_string,
29
- )
27
+ from xiaogpt.utils import detect_language, parse_cookie_string
30
28
 
31
29
  EOF = object()
32
30
 
@@ -325,7 +323,7 @@ class MiGPT:
325
323
  # WTF xiaomi api
326
324
  is_playing = (
327
325
  json.loads(playing_info.get("data", {}).get("info", "{}")).get("status", -1)
328
- >= 1
326
+ == 1
329
327
  )
330
328
  return is_playing
331
329
 
@@ -333,7 +331,7 @@ class MiGPT:
333
331
  is_playing = await self.get_if_xiaoai_is_playing()
334
332
  if is_playing:
335
333
  # stop it
336
- await self.mina_service.player_stop(self.device_id)
334
+ await self.mina_service.player_pause(self.device_id)
337
335
 
338
336
  async def wakeup_xiaoai(self):
339
337
  return await miio_command(
@@ -390,11 +388,6 @@ class MiGPT:
390
388
  query = f"{query},{self.config.prompt}"
391
389
  # some model can not detect the language code, so we need to add it
392
390
 
393
- if self.config.tts != "mi": # mi only say Chinese
394
- query += (
395
- ",并用本段话的language code作为开头,用|分隔,如:en-US|你好……"
396
- )
397
-
398
391
  if self.config.mute_xiaoai:
399
392
  await self.stop_if_xiaoai_is_playing()
400
393
  else:
@@ -420,18 +413,11 @@ class MiGPT:
420
413
  await self.wakeup_xiaoai()
421
414
 
422
415
  async def speak(self, text_stream: AsyncIterator[str]) -> None:
423
- text = await text_stream.__anext__()
424
- # See if the first part contains language code(e.g. en-US|Hello world)
425
- lang, _, first_chunk = text.rpartition("|")
426
- if len(lang) > 7:
427
- # It is not a legal language code, discard it
428
- lang, first_chunk = "", text
429
-
430
- lang = (
431
- matches[0]
432
- if (matches := re.findall(r"([a-z]{2}-[A-Z]{2})", lang))
433
- else "zh-CN"
434
- )
416
+ first_chunk = await text_stream.__anext__()
417
+ # Detect the language from the first chunk
418
+ # Add suffix '-' because tetos expects it to exist when selecting voices
419
+ # however, the nation code is never used.
420
+ lang = detect_language(first_chunk) + "-"
435
421
 
436
422
  async def gen(): # reconstruct the generator
437
423
  yield first_chunk
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes