Your task is to review pull requests. Instructions:
- Provide the response in following JSON format: {"reviews": [{"line": <line_number>, "body": "<review comment>"}]}
- Do not give positive comments or compliments.
- Provide comments and suggestions ONLY if there is something to improve, otherwise "reviews" should be an empty array.
- Write the comment in GitHub Markdown format.
- Use the given description only for the overall context and only comment the code.
- IMPORTANT: NEVER suggest adding comments to the code.

Review the following code diff in the file "g4f/Provider/Airforce.py" and take the pull request title and description into account when writing the response.
  
Pull request title: [pull] main from xtekky:main
Pull request description:
---
See Commits and Changes for more details.

-----
Created by [<img src="https://prod.download/pull-18h-svg" valign="bottom"/> **pull[bot]**](https://github.com/wei/pull)

_Can you help keep this open source service alive? **[💖 Please sponsor : )](https://prod.download/pull-pr-sponsor)**_
---

Each line is prefixed by its number. Code to review:
```
1: from __future__ import annotations
2:+
3: import random
4: import json
5: import re
-from aiohttp import ClientSession
6:+
7: from ..typing import AsyncResult, Messages
8: from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
9: from ..image import ImageResponse
-
-def split_long_message(message: str, max_length: int = 4000) -> list[str]:
-    return [message[i:i+max_length] for i in range(0, len(message), max_length)]
10:+from ..requests import StreamSession, raise_for_status
11:+from .airforce.AirforceChat import AirforceChat
12:+from .airforce.AirforceImage import AirforceImage
13: 
14: class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
15:     url = "https://api.airforce"
-    image_api_endpoint = "https://api.airforce/imagine2"
-    text_api_endpoint = "https://api.airforce/chat/completions"
16:+    api_endpoint_completions = AirforceChat.api_endpoint
17:+    api_endpoint_imagine = AirforceImage.api_endpoint
18:     working = True
-    
-    default_model = 'llama-3-70b-chat'
-
-    supports_stream = True
19:+    default_model = "gpt-4o-mini"
20:     supports_system_message = True
21:     supports_message_history = True
-    
22:     text_models = [
-        'claude-3-haiku-20240307', 
-        'claude-3-sonnet-20240229', 
-        'claude-3-5-sonnet-20240620', 
-        'claude-3-opus-20240229', 
-        'chatgpt-4o-latest', 
-        'gpt-4', 
-        'gpt-4-turbo', 
-        'gpt-4o-mini-2024-07-18', 
-        'gpt-4o-mini', 
-        'gpt-3.5-turbo', 
-        'gpt-3.5-turbo-0125', 
-        'gpt-3.5-turbo-1106', 
23:+        'gpt-4-turbo',
24:         default_model,
-        'llama-3-70b-chat-turbo', 
-        'llama-3-8b-chat', 
-        'llama-3-8b-chat-turbo', 
-        'llama-3-70b-chat-lite', 
-        'llama-3-8b-chat-lite', 
-        'llama-2-13b-chat', 
-        'llama-3.1-405b-turbo', 
-        'llama-3.1-70b-turbo', 
-        'llama-3.1-8b-turbo', 
-        'LlamaGuard-2-8b', 
-        'Llama-Guard-7b', 
-        'Llama-3.2-90B-Vision-Instruct-Turbo',
-        'Mixtral-8x7B-Instruct-v0.1', 
-        'Mixtral-8x22B-Instruct-v0.1', 
-        'Mistral-7B-Instruct-v0.1', 
-        'Mistral-7B-Instruct-v0.2', 
-        'Mistral-7B-Instruct-v0.3', 
-        'Qwen1.5-7B-Chat', 
-        'Qwen1.5-14B-Chat', 
-        'Qwen1.5-72B-Chat', 
-        'Qwen1.5-110B-Chat', 
-        'Qwen2-72B-Instruct', 
-        'gemma-2b-it', 
-        'gemma-2-9b-it', 
-        'gemma-2-27b-it', 
-        'gemini-1.5-flash', 
-        'gemini-1.5-pro', 
-        'deepseek-llm-67b-chat', 
-        'Nous-Hermes-2-Mixtral-8x7B-DPO', 
-        'Nous-Hermes-2-Yi-34B', 
-        'WizardLM-2-8x22B', 
-        'SOLAR-10.7B-Instruct-v1.0', 
-        'MythoMax-L2-13b', 
-        'cosmosrp', 
25:+        'llama-3.1-70b-turbo',
26:+        'llama-3.1-8b-turbo',
27:     ]
-    
28:     image_models = [
29:         'flux',
30:         'flux-realism',
35:         'flux-4o',
36:         'any-dark',
37:     ]
-    
38:     models = [
39:         *text_models,
40:         *image_models,
41:     ]
-    
42:     model_aliases = {
-        "claude-3-haiku": "claude-3-haiku-20240307",
-        "claude-3-sonnet": "claude-3-sonnet-20240229",
43:         "gpt-4o": "chatgpt-4o-latest",
-        "llama-3-70b": "llama-3-70b-chat",
-        "llama-3-8b": "llama-3-8b-chat",
-        "mixtral-8x7b": "Mixtral-8x7B-Instruct-v0.1",
-        "qwen-1.5-7b": "Qwen1.5-7B-Chat",
-        "gemma-2b": "gemma-2b-it",
-        "gemini-flash": "gemini-1.5-flash",
-        "mythomax-l2-13b": "MythoMax-L2-13b",
-        "solar-10.7b": "SOLAR-10.7B-Instruct-v1.0",
44:+        "llama-3.1-70b": "llama-3.1-70b-turbo",
45:+        "llama-3.1-8b": "llama-3.1-8b-turbo",
46:+        "gpt-4": "gpt-4-turbo",
47:     }
48: 
49:     @classmethod
-    def get_model(cls, model: str) -> str:
-        if model in cls.models:
-            return model
-        elif model in cls.model_aliases:
-            return cls.model_aliases.get(model, cls.default_model)
-        else:
-            return cls.default_model
-
-    @classmethod
-    async def create_async_generator(
50:+    def create_async_generator(
51:         cls,
52:         model: str,
53:         messages: Messages,
60:         model = cls.get_model(model)
61: 
62:         if model in cls.image_models:
-            async for result in cls._generate_image(model, messages, proxy, seed, size):
-                yield result
-        elif model in cls.text_models:
-            async for result in cls._generate_text(model, messages, proxy, stream):
-                yield result
-    
63:+            return cls._generate_image(model, messages, proxy, seed, size)
64:+        else:
65:+            return cls._generate_text(model, messages, proxy, stream, **kwargs)
66:+
67:     @classmethod
68:     async def _generate_image(
69:         cls,
81:             "origin": "https://llmplayground.net",
82:             "user-agent": "Mozilla/5.0"
83:         }
-
84:         if seed is None:
85:             seed = random.randint(0, 100000)
-
86:         prompt = messages[-1]['content']
87: 
-        async with ClientSession(headers=headers) as session:
88:+        async with StreamSession(headers=headers, proxy=proxy) as session:
89:             params = {
90:                 "model": model,
91:                 "prompt": prompt,
92:                 "size": size,
93:                 "seed": seed
94:             }
-            async with session.get(f"{cls.image_api_endpoint}", params=params, proxy=proxy) as response:
-                response.raise_for_status()
95:+            async with session.get(f"{cls.api_endpoint_imagine}", params=params) as response:
96:+                await raise_for_status(response)
97:                 content_type = response.headers.get('Content-Type', '').lower()
98: 
99:                 if 'application/json' in content_type:
-                    async for chunk in response.content.iter_chunked(1024):
-                        if chunk:
-                            yield chunk.decode('utf-8')
100:+                    raise RuntimeError(await response.json().get("error", {}).get("message"))
101:                 elif 'image' in content_type:
102:                     image_data = b""
-                    async for chunk in response.content.iter_chunked(1024):
103:+                    async for chunk in response.iter_content():
104:                         if chunk:
105:                             image_data += chunk
-                    image_url = f"{cls.image_api_endpoint}?model={model}&prompt={prompt}&size={size}&seed={seed}"
-                    alt_text = f"Generated image for prompt: {prompt}"
-                    yield ImageResponse(images=image_url, alt=alt_text)
106:+                    image_url = f"{cls.api_endpoint_imagine}?model={model}&prompt={prompt}&size={size}&seed={seed}"
107:+                    yield ImageResponse(images=image_url, alt=prompt)
108: 
109:     @classmethod
110:     async def _generate_text(
113:         messages: Messages,
114:         proxy: str = None,
115:         stream: bool = False,
116:+        max_tokens: int = 4096,
117:+        temperature: float = 1,
118:+        top_p: float = 1,
119:         **kwargs
120:     ) -> AsyncResult:
121:         headers = {
125:             "content-type": "application/json",
126:             "user-agent": "Mozilla/5.0"
127:         }
-
-        async with ClientSession(headers=headers) as session:
-            formatted_prompt = cls._format_messages(messages)
-            prompt_parts = split_long_message(formatted_prompt)
-            full_response = ""
-
-            for part in prompt_parts:
-                data = {
-                    "messages": [{"role": "user", "content": part}],
-                    "model": model,
-                    "max_tokens": 4096,
-                    "temperature": 1,
-                    "top_p": 1,
-                    "stream": stream
-                }
-                async with session.post(cls.text_api_endpoint, json=data, proxy=proxy) as response:
-                    response.raise_for_status()
-                    part_response = ""
-                    if stream:
-                        async for line in response.content:
-                            if line:
-                                line = line.decode('utf-8').strip()
-                                if line.startswith("data: ") and line != "data: [DONE]":
-                                    json_data = json.loads(line[6:])
-                                    content = json_data['choices'][0]['delta'].get('content', '')
-                                    part_response += content
-                    else:
-                        json_data = await response.json()
-                        content = json_data['choices'][0]['message']['content']
-                        part_response = content
-
-                    part_response = re.sub(
-                        r"One message exceeds the \d+chars per message limit\..+https:\/\/discord\.com\/invite\/\S+",
-                        '',
-                        part_response
-                    )
-                    
-                    part_response = re.sub(
-                        r"Rate limit \(\d+\/minute\) exceeded\. Join our discord for more: .+https:\/\/discord\.com\/invite\/\S+",
-                        '',
-                        part_response
-                    )
-
-                    full_response += part_response
-            yield full_response
128:+        async with StreamSession(headers=headers, proxy=proxy) as session:
129:+            data = {
130:+                "messages": messages,
131:+                "model": model,
132:+                "max_tokens": max_tokens,
133:+                "temperature": temperature,
134:+                "top_p": top_p,
135:+                "stream": stream
136:+            }
137:+            async with session.post(cls.api_endpoint_completions, json=data) as response:
138:+                await raise_for_status(response)
139:+                content_type = response.headers.get('Content-Type', '').lower()
140:+                if 'application/json' in content_type:
141:+                    json_data = await response.json()
142:+                    if json_data.get("model") == "error":
143:+                        raise RuntimeError(json_data['choices'][0]['message'].get('content', ''))
144:+                if stream:
145:+                    async for line in response.iter_lines():
146:+                        if line:
147:+                            line = line.decode('utf-8').strip()
148:+                            if line.startswith("data: ") and line != "data: [DONE]":
149:+                                json_data = json.loads(line[6:])
150:+                                content = json_data['choices'][0]['delta'].get('content', '')
151:+                                if content:
152:+                                    yield cls._filter_content(content)
153:+                else:
154:+                    json_data = await response.json()
155:+                    content = json_data['choices'][0]['message']['content']
156:+                    yield cls._filter_content(content)
157: 
158:     @classmethod
-    def _format_messages(cls, messages: Messages) -> str:
-        return " ".join([msg['content'] for msg in messages])
159:+    def _filter_content(cls, part_response: str) -> str:
160:+        part_response = re.sub(
161:+            r"One message exceeds the \d+chars per message limit\..+https:\/\/discord\.com\/invite\/\S+",
162:+            '',
163:+            part_response
164:+        )
165:+        
166:+        part_response = re.sub(
167:+            r"Rate limit \(\d+\/minute\) exceeded\. Join our discord for more: .+https:\/\/discord\.com\/invite\/\S+",
168:+            '',
169:+            part_response
170:+        )
171:+        return part_response
```