Airforce.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. from __future__ import annotations
  2. import random
  3. import json
  4. import re
  5. import requests
  6. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  7. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  8. from ..typing import AsyncResult, Messages
  9. from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
  10. from ..image import ImageResponse
  11. from ..requests import StreamSession, raise_for_status
  12. class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
  13. url = "https://llmplayground.net"
  14. api_endpoint_completions = "https://api.airforce/chat/completions"
  15. api_endpoint_imagine = "https://api.airforce/imagine2"
  16. working = True
  17. supports_system_message = True
  18. supports_message_history = True
  19. @classmethod
  20. def fetch_completions_models(cls):
  21. response = requests.get('https://api.airforce/models', verify=False)
  22. response.raise_for_status()
  23. data = response.json()
  24. return [model['id'] for model in data['data']]
  25. @classmethod
  26. def fetch_imagine_models(cls):
  27. response = requests.get('https://api.airforce/imagine/models', verify=False)
  28. response.raise_for_status()
  29. return response.json()
  30. default_model = "gpt-4o-mini"
  31. default_image_model = "flux"
  32. additional_models_imagine = ["stable-diffusion-xl-base", "stable-diffusion-xl-lightning", "Flux-1.1-Pro"]
  33. @classmethod
  34. def get_models(cls):
  35. if not cls.models:
  36. cls.image_models = [*cls.fetch_imagine_models(), *cls.additional_models_imagine]
  37. cls.models = [
  38. *cls.fetch_completions_models(),
  39. *cls.image_models
  40. ]
  41. return cls.models
  42. model_aliases = {
  43. ### completions ###
  44. # openchat
  45. "openchat-3.5": "openchat-3.5-0106",
  46. # deepseek-ai
  47. "deepseek-coder": "deepseek-coder-6.7b-instruct",
  48. # NousResearch
  49. "hermes-2-dpo": "Nous-Hermes-2-Mixtral-8x7B-DPO",
  50. "hermes-2-pro": "hermes-2-pro-mistral-7b",
  51. # teknium
  52. "openhermes-2.5": "openhermes-2.5-mistral-7b",
  53. # liquid
  54. "lfm-40b": "lfm-40b-moe",
  55. # DiscoResearch
  56. "german-7b": "discolm-german-7b-v1",
  57. # meta-llama
  58. "llama-2-7b": "llama-2-7b-chat-int8",
  59. "llama-2-7b": "llama-2-7b-chat-fp16",
  60. "llama-3.1-70b": "llama-3.1-70b-chat",
  61. "llama-3.1-8b": "llama-3.1-8b-chat",
  62. "llama-3.1-70b": "llama-3.1-70b-turbo",
  63. "llama-3.1-8b": "llama-3.1-8b-turbo",
  64. # inferless
  65. "neural-7b": "neural-chat-7b-v3-1",
  66. # HuggingFaceH4
  67. "zephyr-7b": "zephyr-7b-beta",
  68. ### imagine ###
  69. "sdxl": "stable-diffusion-xl-base",
  70. "sdxl": "stable-diffusion-xl-lightning",
  71. "flux-pro": "Flux-1.1-Pro",
  72. }
  73. @classmethod
  74. def create_async_generator(
  75. cls,
  76. model: str,
  77. messages: Messages,
  78. proxy: str = None,
  79. seed: int = None,
  80. size: str = "1:1", # "1:1", "16:9", "9:16", "21:9", "9:21", "1:2", "2:1"
  81. stream: bool = False,
  82. **kwargs
  83. ) -> AsyncResult:
  84. model = cls.get_model(model)
  85. if model in cls.image_models:
  86. return cls._generate_image(model, messages, proxy, seed, size)
  87. else:
  88. return cls._generate_text(model, messages, proxy, stream, **kwargs)
  89. @classmethod
  90. async def _generate_image(
  91. cls,
  92. model: str,
  93. messages: Messages,
  94. proxy: str = None,
  95. seed: int = None,
  96. size: str = "1:1",
  97. **kwargs
  98. ) -> AsyncResult:
  99. headers = {
  100. "accept": "*/*",
  101. "accept-language": "en-US,en;q=0.9",
  102. "cache-control": "no-cache",
  103. "origin": "https://llmplayground.net",
  104. "user-agent": "Mozilla/5.0"
  105. }
  106. if seed is None:
  107. seed = random.randint(0, 100000)
  108. prompt = messages[-1]['content']
  109. async with StreamSession(headers=headers, proxy=proxy) as session:
  110. params = {
  111. "model": model,
  112. "prompt": prompt,
  113. "size": size,
  114. "seed": seed
  115. }
  116. async with session.get(f"{cls.api_endpoint_imagine}", params=params) as response:
  117. await raise_for_status(response)
  118. content_type = response.headers.get('Content-Type', '').lower()
  119. if 'application/json' in content_type:
  120. raise RuntimeError(await response.json().get("error", {}).get("message"))
  121. elif 'image' in content_type:
  122. image_data = b""
  123. async for chunk in response.iter_content():
  124. if chunk:
  125. image_data += chunk
  126. image_url = f"{cls.api_endpoint_imagine}?model={model}&prompt={prompt}&size={size}&seed={seed}"
  127. yield ImageResponse(images=image_url, alt=prompt)
  128. @classmethod
  129. async def _generate_text(
  130. cls,
  131. model: str,
  132. messages: Messages,
  133. proxy: str = None,
  134. stream: bool = False,
  135. max_tokens: int = 4096,
  136. temperature: float = 1,
  137. top_p: float = 1,
  138. **kwargs
  139. ) -> AsyncResult:
  140. headers = {
  141. "accept": "*/*",
  142. "accept-language": "en-US,en;q=0.9",
  143. "authorization": "Bearer missing api key",
  144. "content-type": "application/json",
  145. "user-agent": "Mozilla/5.0"
  146. }
  147. async with StreamSession(headers=headers, proxy=proxy) as session:
  148. data = {
  149. "messages": messages,
  150. "model": model,
  151. "max_tokens": max_tokens,
  152. "temperature": temperature,
  153. "top_p": top_p,
  154. "stream": stream
  155. }
  156. async with session.post(cls.api_endpoint_completions, json=data) as response:
  157. await raise_for_status(response)
  158. content_type = response.headers.get('Content-Type', '').lower()
  159. if 'application/json' in content_type:
  160. json_data = await response.json()
  161. if json_data.get("model") == "error":
  162. raise RuntimeError(json_data['choices'][0]['message'].get('content', ''))
  163. if stream:
  164. async for line in response.iter_lines():
  165. if line:
  166. line = line.decode('utf-8').strip()
  167. if line.startswith("data: ") and line != "data: [DONE]":
  168. json_data = json.loads(line[6:])
  169. content = json_data['choices'][0]['delta'].get('content', '')
  170. if content:
  171. yield cls._filter_content(content)
  172. else:
  173. json_data = await response.json()
  174. content = json_data['choices'][0]['message']['content']
  175. yield cls._filter_content(content)
  176. @classmethod
  177. def _filter_content(cls, part_response: str) -> str:
  178. part_response = re.sub(
  179. r"One message exceeds the \d+chars per message limit\..+https:\/\/discord\.com\/invite\/\S+",
  180. '',
  181. part_response
  182. )
  183. part_response = re.sub(
  184. r"Rate limit \(\d+\/minute\) exceeded\. Join our discord for more: .+https:\/\/discord\.com\/invite\/\S+",
  185. '',
  186. part_response
  187. )
  188. return part_response