Coverage for src/dmxfy/client/client.py: 83%

36 statements  

« prev     ^ index     » next       coverage.py v7.10.1, created at 2025-08-12 11:37 +0800

1import http.client 

2import json 

3import socket 

4from typing import Any 

5 

6from dmxfy.config.config import Config 

7from dmxfy.exceptions.exceptions import TranslationError 

8from dmxfy.languages.languages import LANGUAGES 

9 

10 

11class TranslationClient: 

12 """Client for handling translations with the DashScope API""" 

13 

14 def __init__(self) -> None: 

15 self.config = Config() 

16 

17 def translate(self, text: str, source_lang: str, target_lang: str) -> str: 

18 """ 

19 Translate text using the DashScope API 

20 

21 Args: 

22 text: The text to translate 

23 source_lang: The source language name (in Chinese) 

24 target_lang: The target language name (in Chinese) 

25 

26 Returns: 

27 The translated text 

28 

29 Raises: 

30 TranslationError: If there's an error during translation 

31 """ 

32 if not text.strip(): 

33 return "请输入要翻译的文本" 

34 

35 try: 

36 # Create a new connection for each request to avoid connection issues 

37 conn: http.client.HTTPSConnection = http.client.HTTPSConnection( 

38 "dashscope.aliyuncs.com" 

39 ) 

40 

41 # Prepare the request data 

42 json_data = { 

43 "model": "qwen-mt-turbo", 

44 "messages": [ 

45 { 

46 "role": "user", 

47 "content": text, 

48 }, 

49 ], 

50 "translation_options": { 

51 "source_lang": LANGUAGES.get(source_lang, "auto"), 

52 "target_lang": LANGUAGES.get(target_lang, "English"), 

53 }, 

54 } 

55 

56 # Make the request 

57 conn.request( 

58 "POST", 

59 "/compatible-mode/v1/chat/completions", 

60 json.dumps(json_data), 

61 self.config.headers, 

62 ) 

63 

64 # Get and parse the response 

65 response = conn.getresponse() 

66 resp_str = response.read().decode("utf-8") 

67 

68 # Check if response is valid 

69 if not resp_str: 

70 raise TranslationError("Received empty response from server") 

71 

72 resp_json: dict[str, Any] = json.loads(resp_str) 

73 

74 # Close the connection 

75 conn.close() 

76 

77 # Check if we have a valid response structure 

78 if "choices" not in resp_json or not resp_json["choices"]: 

79 raise TranslationError(f"Invalid response format: {resp_json}") 

80 

81 return str(resp_json["choices"][0]["message"]["content"]) 

82 

83 except (socket.gaierror, TimeoutError, ConnectionRefusedError) as e: 

84 raise TranslationError(f"Network connection error: {str(e)}") from e 

85 except http.client.RemoteDisconnected as e: 

86 raise TranslationError( 

87 "Remote server disconnected unexpectedly. Please try again." 

88 ) from e 

89 except http.client.ResponseNotReady as e: 

90 raise TranslationError( 

91 "Server not ready to respond. Please try again." 

92 ) from e 

93 except json.JSONDecodeError as e: 

94 raise TranslationError(f"Failed to parse server response: {str(e)}") from e 

95 except Exception as e: 

96 raise TranslationError(f"Translation failed: {str(e)}") from e