__init__.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import ast
  2. import logging
  3. import time
  4. import json
  5. import random
  6. import string
  7. import uvicorn
  8. import nest_asyncio
  9. from fastapi import FastAPI, Response, Request
  10. from fastapi.responses import StreamingResponse
  11. from typing import List, Union, Any, Dict, AnyStr
  12. #from ._tokenizer import tokenize
  13. import g4f
  14. from .. import debug
  15. debug.logging = True
  16. class Api:
  17. def __init__(self, engine: g4f, debug: bool = True, sentry: bool = False,
  18. list_ignored_providers: List[str] = None) -> None:
  19. self.engine = engine
  20. self.debug = debug
  21. self.sentry = sentry
  22. self.list_ignored_providers = list_ignored_providers
  23. self.app = FastAPI()
  24. nest_asyncio.apply()
  25. JSONObject = Dict[AnyStr, Any]
  26. JSONArray = List[Any]
  27. JSONStructure = Union[JSONArray, JSONObject]
  28. @self.app.get("/")
  29. async def read_root():
  30. return Response(content=json.dumps({"info": "g4f API"}, indent=4), media_type="application/json")
  31. @self.app.get("/v1")
  32. async def read_root_v1():
  33. return Response(content=json.dumps({"info": "Go to /v1/chat/completions or /v1/models."}, indent=4), media_type="application/json")
  34. @self.app.get("/v1/models")
  35. async def models():
  36. model_list = []
  37. for model in g4f.Model.__all__():
  38. model_info = (g4f.ModelUtils.convert[model])
  39. model_list.append({
  40. 'id': model,
  41. 'object': 'model',
  42. 'created': 0,
  43. 'owned_by': model_info.base_provider}
  44. )
  45. return Response(content=json.dumps({
  46. 'object': 'list',
  47. 'data': model_list}, indent=4), media_type="application/json")
  48. @self.app.get("/v1/models/{model_name}")
  49. async def model_info(model_name: str):
  50. try:
  51. model_info = (g4f.ModelUtils.convert[model_name])
  52. return Response(content=json.dumps({
  53. 'id': model_name,
  54. 'object': 'model',
  55. 'created': 0,
  56. 'owned_by': model_info.base_provider
  57. }, indent=4), media_type="application/json")
  58. except:
  59. return Response(content=json.dumps({"error": "The model does not exist."}, indent=4), media_type="application/json")
  60. @self.app.post("/v1/chat/completions")
  61. async def chat_completions(request: Request, item: JSONStructure = None):
  62. item_data = {
  63. 'model': 'gpt-3.5-turbo',
  64. 'stream': False,
  65. }
  66. # item contains byte keys, and dict.get suppresses error
  67. item_data.update({
  68. key.decode('utf-8') if isinstance(key, bytes) else key: str(value)
  69. for key, value in (item or {}).items()
  70. })
  71. # messages is str, need dict
  72. if isinstance(item_data.get('messages'), str):
  73. item_data['messages'] = ast.literal_eval(item_data.get('messages'))
  74. model = item_data.get('model')
  75. stream = True if item_data.get("stream") == "True" else False
  76. messages = item_data.get('messages')
  77. provider = item_data.get('provider', '').replace('g4f.Provider.', '')
  78. provider = provider if provider and provider != "Auto" else None
  79. try:
  80. response = g4f.ChatCompletion.create(
  81. model=model,
  82. stream=stream,
  83. messages=messages,
  84. provider = provider,
  85. ignored=self.list_ignored_providers
  86. )
  87. except Exception as e:
  88. logging.exception(e)
  89. content = json.dumps({
  90. "error": {"message": f"An error occurred while generating the response:\n{e}"},
  91. "model": model,
  92. "provider": g4f.get_last_provider(True)
  93. })
  94. return Response(content=content, status_code=500, media_type="application/json")
  95. completion_id = ''.join(random.choices(string.ascii_letters + string.digits, k=28))
  96. completion_timestamp = int(time.time())
  97. if not stream:
  98. #prompt_tokens, _ = tokenize(''.join([message['content'] for message in messages]))
  99. #completion_tokens, _ = tokenize(response)
  100. json_data = {
  101. 'id': f'chatcmpl-{completion_id}',
  102. 'object': 'chat.completion',
  103. 'created': completion_timestamp,
  104. 'model': model,
  105. 'provider': g4f.get_last_provider(True),
  106. 'choices': [
  107. {
  108. 'index': 0,
  109. 'message': {
  110. 'role': 'assistant',
  111. 'content': response,
  112. },
  113. 'finish_reason': 'stop',
  114. }
  115. ],
  116. 'usage': {
  117. 'prompt_tokens': 0, #prompt_tokens,
  118. 'completion_tokens': 0, #completion_tokens,
  119. 'total_tokens': 0, #prompt_tokens + completion_tokens,
  120. },
  121. }
  122. return Response(content=json.dumps(json_data, indent=4), media_type="application/json")
  123. def streaming():
  124. try:
  125. for chunk in response:
  126. completion_data = {
  127. 'id': f'chatcmpl-{completion_id}',
  128. 'object': 'chat.completion.chunk',
  129. 'created': completion_timestamp,
  130. 'model': model,
  131. 'provider': g4f.get_last_provider(True),
  132. 'choices': [
  133. {
  134. 'index': 0,
  135. 'delta': {
  136. 'role': 'assistant',
  137. 'content': chunk,
  138. },
  139. 'finish_reason': None,
  140. }
  141. ],
  142. }
  143. yield f'data: {json.dumps(completion_data)}\n\n'
  144. time.sleep(0.03)
  145. end_completion_data = {
  146. 'id': f'chatcmpl-{completion_id}',
  147. 'object': 'chat.completion.chunk',
  148. 'created': completion_timestamp,
  149. 'model': model,
  150. 'provider': g4f.get_last_provider(True),
  151. 'choices': [
  152. {
  153. 'index': 0,
  154. 'delta': {},
  155. 'finish_reason': 'stop',
  156. }
  157. ],
  158. }
  159. yield f'data: {json.dumps(end_completion_data)}\n\n'
  160. except GeneratorExit:
  161. pass
  162. except Exception as e:
  163. logging.exception(e)
  164. content = json.dumps({
  165. "error": {"message": f"An error occurred while generating the response:\n{e}"},
  166. "model": model,
  167. "provider": g4f.get_last_provider(True),
  168. })
  169. yield f'data: {content}'
  170. return StreamingResponse(streaming(), media_type="text/event-stream")
  171. @self.app.post("/v1/completions")
  172. async def completions():
  173. return Response(content=json.dumps({'info': 'Not working yet.'}, indent=4), media_type="application/json")
  174. def run(self, ip):
  175. split_ip = ip.split(":")
  176. uvicorn.run(app=self.app, host=split_ip[0], port=int(split_ip[1]), use_colors=False)