completion.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. # -*- coding:utf-8 -*-
  2. import json
  3. import logging
  4. from datetime import datetime
  5. from typing import Generator, Union
  6. import services
  7. from controllers.console import api
  8. from controllers.console.app.error import (AppUnavailableError, CompletionRequestError, ConversationCompletedError,
  9. ProviderModelCurrentlyNotSupportError, ProviderNotInitializeError,
  10. ProviderQuotaExceededError)
  11. from controllers.console.explore.error import NotChatAppError, NotCompletionAppError
  12. from controllers.console.explore.wraps import InstalledAppResource
  13. from core.application_queue_manager import ApplicationQueueManager
  14. from core.entities.application_entities import InvokeFrom
  15. from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
  16. from core.model_runtime.errors.invoke import InvokeError
  17. from extensions.ext_database import db
  18. from flask import Response, stream_with_context
  19. from flask_login import current_user
  20. from flask_restful import reqparse
  21. from libs.helper import uuid_value
  22. from services.completion_service import CompletionService
  23. from werkzeug.exceptions import InternalServerError, NotFound
  24. # define completion api for user
  25. class CompletionApi(InstalledAppResource):
  26. def post(self, installed_app):
  27. app_model = installed_app.app
  28. if app_model.mode != 'completion':
  29. raise NotCompletionAppError()
  30. parser = reqparse.RequestParser()
  31. parser.add_argument('inputs', type=dict, required=True, location='json')
  32. parser.add_argument('query', type=str, location='json', default='')
  33. parser.add_argument('files', type=list, required=False, location='json')
  34. parser.add_argument('response_mode', type=str, choices=['blocking', 'streaming'], location='json')
  35. parser.add_argument('retriever_from', type=str, required=False, default='explore_app', location='json')
  36. args = parser.parse_args()
  37. streaming = args['response_mode'] == 'streaming'
  38. args['auto_generate_name'] = False
  39. installed_app.last_used_at = datetime.utcnow()
  40. db.session.commit()
  41. try:
  42. response = CompletionService.completion(
  43. app_model=app_model,
  44. user=current_user,
  45. args=args,
  46. invoke_from=InvokeFrom.EXPLORE,
  47. streaming=streaming
  48. )
  49. return compact_response(response)
  50. except services.errors.conversation.ConversationNotExistsError:
  51. raise NotFound("Conversation Not Exists.")
  52. except services.errors.conversation.ConversationCompletedError:
  53. raise ConversationCompletedError()
  54. except services.errors.app_model_config.AppModelConfigBrokenError:
  55. logging.exception("App model config broken.")
  56. raise AppUnavailableError()
  57. except ProviderTokenNotInitError as ex:
  58. raise ProviderNotInitializeError(ex.description)
  59. except QuotaExceededError:
  60. raise ProviderQuotaExceededError()
  61. except ModelCurrentlyNotSupportError:
  62. raise ProviderModelCurrentlyNotSupportError()
  63. except InvokeError as e:
  64. raise CompletionRequestError(e.description)
  65. except ValueError as e:
  66. raise e
  67. except Exception as e:
  68. logging.exception("internal server error.")
  69. raise InternalServerError()
  70. class CompletionStopApi(InstalledAppResource):
  71. def post(self, installed_app, task_id):
  72. app_model = installed_app.app
  73. if app_model.mode != 'completion':
  74. raise NotCompletionAppError()
  75. ApplicationQueueManager.set_stop_flag(task_id, InvokeFrom.EXPLORE, current_user.id)
  76. return {'result': 'success'}, 200
  77. class ChatApi(InstalledAppResource):
  78. def post(self, installed_app):
  79. app_model = installed_app.app
  80. if app_model.mode != 'chat':
  81. raise NotChatAppError()
  82. parser = reqparse.RequestParser()
  83. parser.add_argument('inputs', type=dict, required=True, location='json')
  84. parser.add_argument('query', type=str, required=True, location='json')
  85. parser.add_argument('files', type=list, required=False, location='json')
  86. parser.add_argument('response_mode', type=str, choices=['blocking', 'streaming'], location='json')
  87. parser.add_argument('conversation_id', type=uuid_value, location='json')
  88. parser.add_argument('retriever_from', type=str, required=False, default='explore_app', location='json')
  89. args = parser.parse_args()
  90. streaming = args['response_mode'] == 'streaming'
  91. args['auto_generate_name'] = False
  92. installed_app.last_used_at = datetime.utcnow()
  93. db.session.commit()
  94. try:
  95. response = CompletionService.completion(
  96. app_model=app_model,
  97. user=current_user,
  98. args=args,
  99. invoke_from=InvokeFrom.EXPLORE,
  100. streaming=streaming
  101. )
  102. return compact_response(response)
  103. except services.errors.conversation.ConversationNotExistsError:
  104. raise NotFound("Conversation Not Exists.")
  105. except services.errors.conversation.ConversationCompletedError:
  106. raise ConversationCompletedError()
  107. except services.errors.app_model_config.AppModelConfigBrokenError:
  108. logging.exception("App model config broken.")
  109. raise AppUnavailableError()
  110. except ProviderTokenNotInitError as ex:
  111. raise ProviderNotInitializeError(ex.description)
  112. except QuotaExceededError:
  113. raise ProviderQuotaExceededError()
  114. except ModelCurrentlyNotSupportError:
  115. raise ProviderModelCurrentlyNotSupportError()
  116. except InvokeError as e:
  117. raise CompletionRequestError(e.description)
  118. except ValueError as e:
  119. raise e
  120. except Exception as e:
  121. logging.exception("internal server error.")
  122. raise InternalServerError()
  123. class ChatStopApi(InstalledAppResource):
  124. def post(self, installed_app, task_id):
  125. app_model = installed_app.app
  126. if app_model.mode != 'chat':
  127. raise NotChatAppError()
  128. ApplicationQueueManager.set_stop_flag(task_id, InvokeFrom.EXPLORE, current_user.id)
  129. return {'result': 'success'}, 200
  130. def compact_response(response: Union[dict, Generator]) -> Response:
  131. if isinstance(response, dict):
  132. return Response(response=json.dumps(response), status=200, mimetype='application/json')
  133. else:
  134. def generate() -> Generator:
  135. for chunk in response:
  136. yield chunk
  137. return Response(stream_with_context(generate()), status=200,
  138. mimetype='text/event-stream')
  139. api.add_resource(CompletionApi, '/installed-apps/<uuid:installed_app_id>/completion-messages', endpoint='installed_app_completion')
  140. api.add_resource(CompletionStopApi, '/installed-apps/<uuid:installed_app_id>/completion-messages/<string:task_id>/stop', endpoint='installed_app_stop_completion')
  141. api.add_resource(ChatApi, '/installed-apps/<uuid:installed_app_id>/chat-messages', endpoint='installed_app_chat_completion')
  142. api.add_resource(ChatStopApi, '/installed-apps/<uuid:installed_app_id>/chat-messages/<string:task_id>/stop', endpoint='installed_app_stop_chat_completion')