+ );
+}
+
+export default ExecutorOutput;
diff --git a/requirements.txt b/requirements.txt
index 692df68..f9f8362 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
jina[perf]==3.14.2.dev18
openai
ptest
-jcloud
\ No newline at end of file
+jcloud
+uvicorn
\ No newline at end of file
diff --git a/server.py b/server.py
index f58c933..69fa3c2 100644
--- a/server.py
+++ b/server.py
@@ -1,7 +1,12 @@
from fastapi import FastAPI
+from fastapi.exceptions import RequestValidationError
from pydantic import BaseModel, HttpUrl
from typing import Optional, Dict
+from starlette.middleware.cors import CORSMiddleware
+from starlette.requests import Request
+from starlette.responses import JSONResponse
+
from main import main
app = FastAPI()
@@ -9,13 +14,13 @@ app = FastAPI()
# Define the request model
class CreateRequest(BaseModel):
executor_name: str
- input_executor_description: str
+ executor_description: str
input_modality: str
input_doc_field: str
output_modality: str
output_doc_field: str
- input_test_in: HttpUrl
- input_test_out: str
+ test_in: str
+ test_out: str
# Define the response model
class CreateResponse(BaseModel):
@@ -25,17 +30,38 @@ class CreateResponse(BaseModel):
@app.post("/create", response_model=CreateResponse)
async def create_endpoint(request: CreateRequest):
- try:
- result = main(
- executor_name=request.executor_name,
- input_executor_description=request.input_executor_description,
- input_modality=request.input_modality,
- input_doc_field=request.input_doc_field,
- output_modality=request.output_modality,
- output_doc_field=request.output_doc_field,
- input_test_in=request.input_test_in,
- input_test_out=request.input_test_out,
- )
- return CreateResponse(result=result, success=True, message=None)
- except Exception as e:
- return CreateResponse(result=None, success=False, message=str(e))
\ No newline at end of file
+
+ result = await main(
+ executor_name=request.executor_name,
+ executor_description=request.executor_description,
+ input_modality=request.input_modality,
+ input_doc_field=request.input_doc_field,
+ output_modality=request.output_modality,
+ output_doc_field=request.output_doc_field,
+ test_in=request.test_in,
+ test_out=request.test_out,
+ do_validation=False
+ )
+ return CreateResponse(result=result, success=True, message=None)
+
+
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=["*"],
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+# Add a custom exception handler for RequestValidationError
+@app.exception_handler(RequestValidationError)
+async def validation_exception_handler(request: Request, exc: RequestValidationError):
+ return JSONResponse(
+ status_code=422,
+ content={"detail": exc.errors()},
+ )
+
+
+if __name__ == "__main__":
+ import uvicorn
+ uvicorn.run("server:app", host="0.0.0.0", port=8000, log_level="info")
diff --git a/src/jina_cloud.py b/src/jina_cloud.py
index 4eafc8e..a70cfb7 100644
--- a/src/jina_cloud.py
+++ b/src/jina_cloud.py
@@ -1,3 +1,4 @@
+import asyncio
import os
from multiprocessing.connection import Client
@@ -18,7 +19,15 @@ def get_user_name():
return response['data']['name']
-def deploy_flow(executor_name):
+async def deploy_on_jcloud(flow_yaml):
+ cloud_flow = CloudFlow(path=flow_yaml)
+ await cloud_flow.__aenter__()
+ return cloud_flow.endpoints['gateway']
+
+
+
+
+async def deploy_flow(executor_name, do_validation):
flow = f'''
jtype: Flow
with:
@@ -44,12 +53,14 @@ executors:
with open(full_flow_path, 'w') as f:
f.write(flow)
- # try local first
- flow = Flow.load_config(full_flow_path)
- with flow:
- pass
+ if do_validation:
+ print('try local execution')
+ flow = Flow.load_config(full_flow_path)
+ with flow:
+ pass
+ print('deploy flow on jcloud')
+ return await deploy_on_jcloud(flow_yaml=full_flow_path)
- return CloudFlow(path=full_flow_path).__enter__().endpoints['gateway']
def replace_client_line(file_content: str, replacement: str) -> str:
lines = file_content.split('\n')
@@ -59,7 +70,7 @@ def replace_client_line(file_content: str, replacement: str) -> str:
break
return '\n'.join(lines)
-def run_client_file(file_path, host):
+def run_client_file(file_path, host, do_validation):
with open(file_path, 'r') as file:
content = file.read()
@@ -69,4 +80,5 @@ def run_client_file(file_path, host):
with open(file_path, 'w') as file:
file.write(replaced_content)
- import executor.client # runs the client script for validation
+ if do_validation:
+ import executor.client # runs the client script for validation
diff --git a/src/prompt_examples.py b/src/prompt_examples.py
index b596ab8..0177d13 100644
--- a/src/prompt_examples.py
+++ b/src/prompt_examples.py
@@ -39,7 +39,7 @@ message DocumentProto {
string text = 4;
}
- // a uri of the document could be: a local file path, a remote url starts with http or https or data URI scheme
+ // a uri of the document is a remote url starts with http or https or data URI scheme
string uri = 5;
// list of the sub-documents of this document (recursive structure)
@@ -65,11 +65,12 @@ d1 = Document(text='hello')
d2 = Document(blob=b'\\x89PNG\\r\\n\\x1a\\n\\x00\\x00\\x00\\rIHDR\\x00\\x00\\x03L\\x00\\x00\\x01\\x18\\x08\\x06\\x00\\x00\\x00o...')
d3 = Document(tensor=numpy.array([1, 2, 3]), chunks=[Document(uri=/local/path/to/file)]
d4 = Document(
- uri='https://docs.docarray.org',
+ uri='https://docs.docarray.org/img/logo.png',
tags={'foo': 'bar'},
)
d5 = Document()
d5.tensor = np.ones((2,4))
+d5.uri = 'https://audio.com/audio.mp3'
d6 = Document()
d6.blob = b'RIFF\\x00\\x00\\x00\\x00WAVEfmt \\x10\\x00...'
docs = DocumentArray([
diff --git a/src/prompt_tasks.py b/src/prompt_tasks.py
index 0147854..4ca4633 100644
--- a/src/prompt_tasks.py
+++ b/src/prompt_tasks.py
@@ -7,7 +7,9 @@ def general_guidelines():
"General guidelines: "
"The code you write is production ready. "
"Every file starts with comments describing what the code is doing before the first import. "
- "Then all imports are listed. It is important to import all modules that could be needed in the executor code."
+ "Then all imports are listed. "
+ "It is important to import all modules that could be needed in the executor code. "
+ "Always import BytesIO from io. "
"Comments can only be written between tags. "
"Start from top-level and then fully implement all methods. "
"\n"
@@ -18,13 +20,14 @@ def _task(task, tag_name, file_name):
return task + f"The code will go into {file_name}. Wrap the code in the string $$$start_{tag_name}$$$...$$$end_{tag_name}$$$ \n\n"
-def executor_file_task(executor_name, input_executor_description, input_modality, input_doc_field,
+def executor_file_task(executor_name, executor_description, input_modality, input_doc_field,
output_modality, output_doc_field):
return _task(
f"Write the executor called '{executor_name}'. "
- f"It matches the following description: '{input_executor_description}'. "
+ f"It matches the following description: '{executor_description}'. "
f"It gets a DocumentArray as input where each document has the input modality '{input_modality}' that is stored in document.{input_doc_field}. "
- f"It returns a DocumentArray as output where each document has the output modality '{output_modality}' that is stored in document.{output_doc_field}. ",
+ f"It returns a DocumentArray as output where each document has the output modality '{output_modality}' that is stored in document.{output_doc_field}. "
+ f"Have in mind that d.uri is never a path to a local file. It is always a url.",
'executor',
EXECUTOR_FILE_NAME
)
@@ -37,13 +40,13 @@ def requirements_file_task():
REQUIREMENTS_FILE_NAME)
-def test_executor_file_task(executor_name, input_test_in, input_test_out):
+def test_executor_file_task(executor_name, test_in, test_out):
return _task(
"Write a small unit test for the executor. "
"Start the test with an extensive comment about the test case. "
+ (
- "Test that the executor converts the input '" + input_test_in + "' to the output '" + input_test_out + "'. "
- ) if input_test_in and input_test_out else ""
+ "Test that the executor converts the input '" + test_in + "' to the output '" + test_out + "'. "
+ ) if test_in and test_out else ""
"Use the following import to import the executor: "
f"from executor import {executor_name} ",
'test_executor',