Qwen_Qwen_2_5.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. from __future__ import annotations
  2. import aiohttp
  3. import json
  4. import uuid
  5. import re
  6. from ...typing import AsyncResult, Messages
  7. from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
  8. from ..helper import format_prompt
  9. from ... import debug
  10. class Qwen_Qwen_2_5(AsyncGeneratorProvider, ProviderModelMixin):
  11. label = "Qwen Qwen-2.5"
  12. url = "https://qwen-qwen2-5.hf.space"
  13. api_endpoint = "https://qwen-qwen2-5.hf.space/queue/join"
  14. working = True
  15. supports_stream = True
  16. supports_system_message = True
  17. supports_message_history = False
  18. default_model = "qwen-qwen2-5"
  19. model_aliases = {"qwen-2.5": default_model}
  20. models = list(model_aliases.keys())
  21. @classmethod
  22. async def create_async_generator(
  23. cls,
  24. model: str,
  25. messages: Messages,
  26. proxy: str = None,
  27. **kwargs
  28. ) -> AsyncResult:
  29. def generate_session_hash():
  30. """Generate a unique session hash."""
  31. return str(uuid.uuid4()).replace('-', '')[:10]
  32. # Generate a unique session hash
  33. session_hash = generate_session_hash()
  34. headers_join = {
  35. 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0',
  36. 'Accept': '*/*',
  37. 'Accept-Language': 'en-US,en;q=0.5',
  38. 'Accept-Encoding': 'gzip, deflate, br, zstd',
  39. 'Referer': f'{cls.url}/?__theme=system',
  40. 'content-type': 'application/json',
  41. 'Origin': cls.url,
  42. 'Connection': 'keep-alive',
  43. 'Sec-Fetch-Dest': 'empty',
  44. 'Sec-Fetch-Mode': 'cors',
  45. 'Sec-Fetch-Site': 'same-origin',
  46. 'Pragma': 'no-cache',
  47. 'Cache-Control': 'no-cache',
  48. }
  49. # Prepare the prompt
  50. system_prompt = "\n".join([message["content"] for message in messages if message["role"] == "system"])
  51. if not system_prompt:
  52. system_prompt = "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."
  53. messages = [message for message in messages if message["role"] != "system"]
  54. prompt = format_prompt(messages)
  55. payload_join = {
  56. "data": [prompt, [], system_prompt, "72B"],
  57. "event_data": None,
  58. "fn_index": 3,
  59. "trigger_id": 25,
  60. "session_hash": session_hash
  61. }
  62. async with aiohttp.ClientSession() as session:
  63. # Send join request
  64. async with session.post(cls.api_endpoint, headers=headers_join, json=payload_join) as response:
  65. event_id = (await response.json())['event_id']
  66. # Prepare data stream request
  67. url_data = f'{cls.url}/queue/data'
  68. headers_data = {
  69. 'Accept': 'text/event-stream',
  70. 'Accept-Language': 'en-US,en;q=0.5',
  71. 'Referer': f'{cls.url}/?__theme=system',
  72. 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0',
  73. }
  74. params_data = {
  75. 'session_hash': session_hash
  76. }
  77. # Send data stream request
  78. async with session.get(url_data, headers=headers_data, params=params_data) as response:
  79. full_response = ""
  80. async for line in response.content:
  81. decoded_line = line.decode('utf-8')
  82. if decoded_line.startswith('data: '):
  83. try:
  84. json_data = json.loads(decoded_line[6:])
  85. # Look for generation stages
  86. if json_data.get('msg') == 'process_generating':
  87. if 'output' in json_data and 'data' in json_data['output']:
  88. output_data = json_data['output']['data']
  89. if len(output_data) > 1 and len(output_data[1]) > 0:
  90. for item in output_data[1]:
  91. if isinstance(item, list) and len(item) > 1:
  92. # Extract the fragment, handling both string and dict types
  93. fragment = item[1]
  94. if isinstance(fragment, dict) and 'text' in fragment:
  95. # For the first chunk, extract only the text part
  96. fragment = fragment['text']
  97. else:
  98. fragment = str(fragment)
  99. # Ignore [0, 1] type fragments and duplicates
  100. if not re.match(r'^\[.*\]$', fragment) and not full_response.endswith(fragment):
  101. full_response += fragment
  102. yield fragment
  103. # Check for completion
  104. if json_data.get('msg') == 'process_completed':
  105. # Final check to ensure we get the complete response
  106. if 'output' in json_data and 'data' in json_data['output']:
  107. output_data = json_data['output']['data']
  108. if len(output_data) > 1 and len(output_data[1]) > 0:
  109. # Get the final response text
  110. response_item = output_data[1][0][1]
  111. if isinstance(response_item, dict) and 'text' in response_item:
  112. final_full_response = response_item['text']
  113. else:
  114. final_full_response = str(response_item)
  115. # Clean up the final response
  116. if isinstance(final_full_response, str) and final_full_response.startswith(full_response):
  117. final_text = final_full_response[len(full_response):]
  118. else:
  119. final_text = final_full_response
  120. # Yield the remaining part of the final response
  121. if final_text and final_text != full_response:
  122. yield final_text
  123. break
  124. except json.JSONDecodeError:
  125. debug.log("Could not parse JSON:", decoded_line)