From e3e05a548e728319270b5b96bb9c6dec68947cc0 Mon Sep 17 00:00:00 2001 From: genekogan Date: Wed, 8 Jan 2025 13:27:15 -0800 Subject: [PATCH 1/9] use lora mode --- eve/models.py | 1 + eve/postprocessing.py | 32 ++++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/eve/models.py b/eve/models.py index c783921..6039f74 100644 --- a/eve/models.py +++ b/eve/models.py @@ -20,6 +20,7 @@ class Model(Document): checkpoint: str base_model: str lora_trigger_text: Optional[str] = None + lora_model: Optional[str] = None # users: SkipJsonSchema[Optional[Collection]] = Field(None, exclude=True) diff --git a/eve/postprocessing.py b/eve/postprocessing.py index 634a709..f1f0bf0 100644 --- a/eve/postprocessing.py +++ b/eve/postprocessing.py @@ -68,7 +68,8 @@ async def generate_lora_thumbnails(): try: tool = Tool.load(key="flux_dev_lora") - prompts = await generate_prompts() + lora_mode = model.get("lora_mode") + prompts = await generate_prompts(lora_mode) thumbnails = [] for prompt in prompts: @@ -145,22 +146,37 @@ async def generate_thumbnail(): traceback.print_exc() -async def generate_prompts(): - sampled_prompts = random.sample(ALL_PROMPTS, 16) - prompt_examples = [{"prompts": sampled_prompts[i:i+4]} for i in range(0, 16, 4)] - +async def generate_prompts(lora_mode: str = None): + if lora_mode == "face": + sampled_prompts = random.sample(FACE_PROMPTS, 16) + elif lora_mode == "object": + sampled_prompts = random.sample(OBJECT_PROMPTS, 16) + elif lora_mode == "style": + sampled_prompts = random.sample(STYLE_PROMPTS, 16) + else: + sampled_prompts = random.sample(ALL_PROMPTS, 16) + class Prompts(BaseModel): """Exactly FOUR prompts for image generation models about """ prompts: List[str] = Field(..., description="A list of 4 image prompts about ") model_config = ConfigDict( json_schema_extra={ - "examples": prompt_examples + "examples": [ + {"prompts": sampled_prompts[i:i+4]} for i in range(0, 16, 4) + ] } ) prompt = """Come up with exactly FOUR (4, no more, no less) detailed and visually rich prompts about . These will go to image generation models to be generated. Prompts must contain the word at least once, including the angle brackets.""" + if lora_mode == "face": + prompt += " The concept refers to a specific person." + elif lora_mode == "object": + prompt += " The concept refers to a specific object or thing." + elif lora_mode == "style": + prompt += " The concept refers to a specific style or aesthetic." + try: client = instructor.from_openai(openai.AsyncOpenAI()) result = await client.chat.completions.create( @@ -256,7 +272,3 @@ class Prompts(BaseModel): ] ALL_PROMPTS = FACE_PROMPTS + OBJECT_PROMPTS + STYLE_PROMPTS - - -# if __name__ == "__main__": -# asyncio.run(generate_lora_thumbnails()) \ No newline at end of file From 318c5b210d42f13aedf4f830ca6c0203b6be9753 Mon Sep 17 00:00:00 2001 From: genekogan Date: Wed, 8 Jan 2025 13:32:28 -0800 Subject: [PATCH 2/9] use sampled prompts as fallback --- eve/postprocessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eve/postprocessing.py b/eve/postprocessing.py index f1f0bf0..43cc58e 100644 --- a/eve/postprocessing.py +++ b/eve/postprocessing.py @@ -194,7 +194,7 @@ class Prompts(BaseModel): except Exception as e: print("failed to sample new prompts, falling back to old prompts") - prompts = random.sample(ALL_PROMPTS, 4) + prompts = random.sample(sampled_prompts, 4) return prompts From f5eb3f6659723c0c0e31c507e21164482c2138f5 Mon Sep 17 00:00:00 2001 From: genekogan Date: Wed, 8 Jan 2025 14:34:26 -0800 Subject: [PATCH 3/9] fix regex to escape concept --- eve/tools/replicate_tool.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eve/tools/replicate_tool.py b/eve/tools/replicate_tool.py index c9d01bf..2f3d398 100644 --- a/eve/tools/replicate_tool.py +++ b/eve/tools/replicate_tool.py @@ -114,7 +114,8 @@ def _format_args_for_replicate(self, args: dict): lora_trigger_text = lora_doc.get("lora_trigger_text") new_args[field] = lora_url if "prompt" in new_args: - pattern = re.compile(re.escape(lora_name), re.IGNORECASE) + name_pattern = f"(\\b{re.escape(lora_name)}\\b|<{re.escape(lora_name)}>|\\)" + pattern = re.compile(name_pattern, re.IGNORECASE) new_args["prompt"] = pattern.sub(lora_trigger_text, new_args['prompt']) if is_number: new_args[field] = float(args[field]) From a22eeb0274ee5575935d40d5f7d58f3ee8ae910f Mon Sep 17 00:00:00 2001 From: genekogan Date: Wed, 8 Jan 2025 14:34:40 -0800 Subject: [PATCH 4/9] number bug --- eve/tools/flux_dev_lora/api.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eve/tools/flux_dev_lora/api.yaml b/eve/tools/flux_dev_lora/api.yaml index 487c1ac..9c426c8 100644 --- a/eve/tools/flux_dev_lora/api.yaml +++ b/eve/tools/flux_dev_lora/api.yaml @@ -29,7 +29,7 @@ parameters: label: Input image description: Input image. Aspect ratio will match this. prompt_strength: - type: number + type: float label: Prompt strength description: Prompt strength when using img2img. 1.0 corresponds to full destruction of information in image default: 0.8 @@ -86,7 +86,7 @@ parameters: minimum: 1 maximum: 50 guidance: - type: number + type: float label: Guidance scale description: How strictly to follow the prompt hide_from_ui: true From c6c9548b1e967e55ca880d4512c0da838c33d0b8 Mon Sep 17 00:00:00 2001 From: genekogan Date: Wed, 8 Jan 2025 14:34:54 -0800 Subject: [PATCH 5/9] concurrency limit on postprocessing --- eve/api/api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/eve/api/api.py b/eve/api/api.py index 226d715..6b509a9 100644 --- a/eve/api/api.py +++ b/eve/api/api.py @@ -224,6 +224,7 @@ def fastapi_app(): @app.function( image=image, + concurrency_limit=1, schedule=modal.Period(minutes=15), timeout=3600 ) From f6b619c548e8f4f9a2aa9a1c073f4b51d9a8df1a Mon Sep 17 00:00:00 2001 From: genekogan Date: Wed, 8 Jan 2025 15:39:51 -0800 Subject: [PATCH 6/9] nsfw detect --- eve/api/api.py | 17 +++++++++++++-- eve/postprocessing.py | 50 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/eve/api/api.py b/eve/api/api.py index 6b509a9..ecb0abb 100644 --- a/eve/api/api.py +++ b/eve/api/api.py @@ -18,6 +18,8 @@ from eve.postprocessing import ( generate_lora_thumbnails, cancel_stuck_tasks, + download_nsfw_models, + run_nsfw_detection ) from eve.api.handlers import ( handle_create, @@ -202,11 +204,18 @@ async def trigger_delete( .env({"DB": db, "MODAL_SERVE": os.getenv("MODAL_SERVE")}) .apt_install("git", "libmagic1", "ffmpeg", "wget") .pip_install_from_pyproject(str(root_dir / "pyproject.toml")) + .pip_install( + "numpy<2.0", + "torch==2.0.1", + "torchvision", + "transformers", + "Pillow" + ) .run_commands(["playwright install"]) + .run_function(download_nsfw_models) .copy_local_dir(str(workflows_dir), "/workflows") ) - @app.function( image=image, keep_warm=1, @@ -234,8 +243,12 @@ async def postprocessing(): except Exception as e: print(f"Error cancelling stuck tasks: {e}") + try: + await run_nsfw_detection() + except Exception as e: + print(f"Error running nsfw detection: {e}") + try: await generate_lora_thumbnails() except Exception as e: print(f"Error generating lora thumbnails: {e}") - diff --git a/eve/postprocessing.py b/eve/postprocessing.py index 43cc58e..72f0a47 100644 --- a/eve/postprocessing.py +++ b/eve/postprocessing.py @@ -46,12 +46,60 @@ def cancel_stuck_tasks(): tool.cancel(task, force=True) except Exception as e: - print("Error canceling task", e) + print(f"Error canceling task {str(task.id)} {task.tool}", e) task.update(status="failed", error="Tool not found") sentry_sdk.capture_exception(e) traceback.print_exc() +def download_nsfw_models(): + from transformers import AutoModelForImageClassification, ViTImageProcessor + AutoModelForImageClassification.from_pretrained("Falconsai/nsfw_image_detection") + ViTImageProcessor.from_pretrained("Falconsai/nsfw_image_detection") + + +async def run_nsfw_detection(): + import torch + from PIL import Image + from transformers import AutoModelForImageClassification, ViTImageProcessor + + model = AutoModelForImageClassification.from_pretrained( + "Falconsai/nsfw_image_detection", + cache_dir="model-cache", + ) + processor = ViTImageProcessor.from_pretrained("Falconsai/nsfw_image_detection") + + image_paths = [ + "https://edenartlab-stage-data.s3.us-east-1.amazonaws.com/62946527441201f82e0e3d667fda480e176e9940a2e04f4e54c5230665dfc6f6.jpg", + "https://edenartlab-prod-data.s3.us-east-1.amazonaws.com/bb88e857586a358ce3f02f92911588207fbddeabff62a3d6a479517a646f053c.jpg" + ] + + images = [ + Image.open(eden_utils.download_file(url, f"{i}.jpg")).convert('RGB') + for i, url in enumerate(image_paths) + ] + + with torch.no_grad(): + inputs = processor(images=images, return_tensors="pt") + outputs = model(**inputs) + logits = outputs.logits + + print(logits) + predicted_labels = logits.argmax(-1).tolist() + print(predicted_labels) + output = [model.config.id2label[predicted_label] for predicted_label in predicted_labels] + print(output) + + # Sort image paths based on safe logit values + first_logits = logits[:, 0].tolist() + sorted_pairs = sorted(zip(image_paths, first_logits), key=lambda x: x[1], reverse=True) + sorted_image_paths = [pair[0] for pair in sorted_pairs] + + print("\nImage paths sorted by first logit value (highest to lowest):") + for i, path in enumerate(sorted_image_paths): + print(f"{i+1}. {path} (logit: {sorted_pairs[i][1]:.4f})") + + async def generate_lora_thumbnails(): tasks = get_collection(Task.collection_name) models = get_collection(Model.collection_name) From 842a597433a21bf5694dae52093f287adb740230 Mon Sep 17 00:00:00 2001 From: genekogan Date: Wed, 8 Jan 2025 15:55:05 -0800 Subject: [PATCH 7/9] thread test --- tests/test_thread.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/test_thread.py diff --git a/tests/test_thread.py b/tests/test_thread.py new file mode 100644 index 0000000..cc8a030 --- /dev/null +++ b/tests/test_thread.py @@ -0,0 +1,11 @@ +import json +from eve.thread import Thread +from eve.llm import title_thread + +def test_title_thread(): + """Pytest entry point""" + + thread = Thread.from_mongo("67660123b01077573b056e33") + results = title_thread(thread=thread) + + print(json.dumps(results, indent=2)) From 6f7478e38f67078fef402b9af1355fbc48cb2a94 Mon Sep 17 00:00:00 2001 From: genekogan Date: Thu, 9 Jan 2025 01:11:48 -0800 Subject: [PATCH 8/9] make agents more robust --- eve/agent.py | 81 ++++++++++++++++++++++++------- eve/agents/prod/abraham/api.yaml | 15 +----- eve/agents/prod/banny/api.yaml | 39 ++------------- eve/agents/prod/eve/api.yaml | 1 + eve/agents/prod/verdelis/api.yaml | 39 ++------------- eve/cli/chat_cli.py | 2 +- eve/cli/tool_cli.py | 2 +- eve/tool.py | 4 +- eve/tools/flux_trainer/api.yaml | 2 +- eve/tools/reel/handler.py | 8 +-- 10 files changed, 81 insertions(+), 112 deletions(-) diff --git a/eve/agent.py b/eve/agent.py index 575fa7a..9f4f97e 100644 --- a/eve/agent.py +++ b/eve/agent.py @@ -17,17 +17,40 @@ CHECK_INTERVAL = 30 # how often to check cached agents for updates + default_presets_flux = { - "flux_dev_lora": {}, - "runway": {}, - "reel": {}, -} -default_presets_sdxl = { - "txt2img": {}, - "runway": {}, - "reel": {}, + "flux_schnell": { + "tip": "This must be your primary tool for making images. The other flux tools are only used for inpainting, remixing, and variations." + }, + "flux_inpainting": {}, + "flux_redux": {}, + "vid2vid_sdxl": { + "tip": "Only use this tool if asked to restyle an existing video with a style image" + }, + "video_FX": { + "tip": "Only use this tool if asked to make subtle or targeted variations on an existing video" + }, + "texture_flow": { + "tip": "Just use this tool if asked to make VJing material." + }, + "outpaint": {}, + "remix_flux_schnell": {}, + "stable_audio": {}, + "musicgen": {}, + "runway": { + "tip": "This should be your primary tool for making videos or animations. Only use the other video tools if specifically asked to or asked to make VJing material." + }, + "reel": { + "tip": "This is a tool for making short films with vocals, music, and several video cuts. This can be used to make commercials, films, music videos, and other kinds of shortform content. But it takes a while to make, around 5 minutes." + }, + "news": {}, + "websearch": {}, + "audio_video_combine": { + "tip": "This and video_concat can merge a video track with an audio track, so it's good for compositing/mixing or manually creating reels." + }, + "video_concat": {} } - + @Collection("users3") class Agent(User): @@ -42,6 +65,7 @@ class Agent(User): # status: Optional[Literal["inactive", "stage", "prod"]] = "stage" public: Optional[bool] = False allowlist: Optional[List[str]] = None + featured: Optional[bool] = False name: str description: str @@ -56,6 +80,8 @@ class Agent(User): def __init__(self, **data): if isinstance(data.get('owner'), str): data['owner'] = ObjectId(data['owner']) + if isinstance(data.get('owner'), str): + data['model'] = ObjectId(data['model']) # Load environment variables into secrets dictionary db = os.getenv("DB") env_dir = Path(__file__).parent / "agents" @@ -74,6 +100,8 @@ def convert_from_yaml(cls, schema: dict, file_path: str = None) -> dict: owner = schema.get('owner') schema["owner"] = ObjectId(owner) if isinstance(owner, str) else owner + model = schema.get('model') + schema["model"] = ObjectId(model) if isinstance(model, str) else model schema["username"] = schema.get("username") or file_path.split("/")[-2] schema = cls._setup_tools(schema) @@ -148,16 +176,17 @@ def _setup_tools(cls, schema: dict) -> dict: schema["tools"] = {k: v or {} for k, v in tools.items()} else: schema["tools"] = default_presets_flux - if "model" in schema: + if schema.get("model"): model = Model.from_mongo(schema["model"]) if model.base_model == "flux-dev": schema["tools"] = default_presets_flux + schema["tools"].pop("flux_schnell", None) schema["tools"]["flux_dev_lora"] = { - "name": f"Generate {model.name}", - "description": f"Generate an image of {model.name}", + "description": f"This is your primary and default tool for making images. The other flux tools are only used for inpainting, remixing, and variations. In particular, this will generate an image of {model.name}", + "tip": f"If you want to depict {model.name} in the image, make sure to include {model.name} in the prompt.", "parameters": { "prompt": { - "description": f"The text prompt. Always mention {model.name}." + "tip": 'Try to enhance or embellish prompts. For example, if the user requests "Verdelis as a mermaid smoking a cigar", you would make it much longer and more intricate and detailed, like "Verdelis as a dried-out crusty old mermaid, wrinkled and weathered skin, tangled and brittle seaweed-like hair, smoking a smoldering cigarette underwater with tiny bubbles rising, jagged and cracked tail with faded iridescent scales, adorned with a tarnished coral crown, holding a rusted trident, faint sunlight beams coming through." If the user provides a lot of detail, just stay faithful to their wishes.' }, "lora": { "default": str(model.id), @@ -170,9 +199,12 @@ def _setup_tools(cls, schema: dict) -> dict: } } schema["tools"]["reel"] = { - "name": f"Generate {model.name}", - "tip": f"Make sure to always include {model.name} in all of the prompts.", + "tip": f"If you want to depict {model.name} in the image, make sure to include {model.name} in the prompt.", "parameters": { + "use_lora": { + "default": True, + "hide_from_agent": True, + }, "lora": { "default": str(model.id), "hide_from_agent": True, @@ -184,7 +216,8 @@ def _setup_tools(cls, schema: dict) -> dict: } } elif model.base_model == "sdxl": - schema["tools"] = default_presets_sdxl + # schema["tools"] = default_presets_sdxl + pass return schema @@ -212,14 +245,26 @@ def get_tool(self, tool_name, cache=False): def _check_for_updates(cls, cache_key: str, agent_id: ObjectId): """Check if agent needs to be updated based on updatedAt field""" current_time = time.time() + print("\n\nthe current time is", current_time) last_check = cls.last_check.get(cache_key, 0) + print("the last check was", last_check) + + print("check for updates", current_time - last_check) if current_time - last_check >= CHECK_INTERVAL: + print("updating") cls.last_check[cache_key] = current_time collection = get_collection(cls.collection_name) db_agent = collection.find_one({"_id": agent_id}) - if db_agent and db_agent.get("updatedAt") != _agent_cache[cache_key].updatedAt: - _agent_cache[cache_key].reload() + print("---- db agent") + print(db_agent) + if db_agent: + print(db_agent.get("updatedAt")) + print("---- agent cache") + if _agent_cache.get(cache_key): + print(_agent_cache[cache_key].updatedAt) + if db_agent and db_agent.get("updatedAt") != _agent_cache[cache_key].updatedAt: + _agent_cache[cache_key].reload() def get_agents_from_mongo(agents: List[str] = None, include_inactive: bool = False) -> Dict[str, Agent]: diff --git a/eve/agents/prod/abraham/api.yaml b/eve/agents/prod/abraham/api.yaml index 0aa13de..0f11c92 100644 --- a/eve/agents/prod/abraham/api.yaml +++ b/eve/agents/prod/abraham/api.yaml @@ -1,5 +1,7 @@ name: Abraham owner: 6526f38042a1043421aa28e6 +userImage: 87bece8d180c8a1effe2d5d1d80b530f591d59f19085c63e747e5e2061843498.jpg +featured: true featureFlags: - freeTools @@ -26,19 +28,6 @@ instructions: | Do not be verbose. Speak concisely. Transmit as much information as possible in the least amount of words. Less is more. Do not include any introductory phrases or parentheticals. Just write your spoken messag tools: - animate_3D: - tip: You should only use this tool to make video as a fallback if runway fails or is unavailable, or if the user specifically requests it. - texture_flow: - flux_inpainting: - stable_audio: - musicgen: - runway: - tip: This should be your primary tool for making videos. - flux_schnell: - flux_dev_lora: - reel: - tweet: - get_tweets: clients: discord: diff --git a/eve/agents/prod/banny/api.yaml b/eve/agents/prod/banny/api.yaml index 1cbbc0f..10c5b38 100644 --- a/eve/agents/prod/banny/api.yaml +++ b/eve/agents/prod/banny/api.yaml @@ -1,6 +1,8 @@ name: Banny owner: 6526f38042a1043421aa28e6 -userImage: https://edenartlab-stage-data.s3.us-east-1.amazonaws.com/405024ab0572704cad07a0d7c22158ef443d2d988490e4f1a538e235d321a9c9.png +model: 6766760643808b38016c64ce +userImage: 405024ab0572704cad07a0d7c22158ef443d2d988490e4f1a538e235d321a9c9.png +featured: true featureFlags: - freeTools @@ -30,41 +32,6 @@ instructions: | start_with_all_tools: true tools: - animate_3D: - texture_flow: - face_styler: - upscaler: - txt2img: - flux_inpainting: - remix_flux_schnell: - stable_audio: - musicgen: - runway: - flux_dev_lora: - name: Generate Banny (High quality) - description: Generate an image of Banny where quality is favored over speed. - parameters: - prompt: - description: The text prompt. Always mention Banny. - lora: - default: 6766760643808b38016c64ce - hide_from_agent: true - hide_from_ui: true - lora_strength: - default: 0.9 - hide_from_agent: true - hide_from_ui: true - reel: - tip: Make sure to always include Banny in all of the prompts. - parameters: - lora: - default: 6766760643808b38016c64ce - hide_from_agent: true - hide_from_ui: true - lora_strength: - default: 1.0 - hide_from_agent: true - hide_from_ui: true clients: discord: diff --git a/eve/agents/prod/eve/api.yaml b/eve/agents/prod/eve/api.yaml index 8425573..b6c7651 100644 --- a/eve/agents/prod/eve/api.yaml +++ b/eve/agents/prod/eve/api.yaml @@ -1,6 +1,7 @@ name: Eve owner: 6526f38042a1043421aa28e6 userImage: https://edenartlab-stage-data.s3.amazonaws.com/d158dc1e5c62479489c1c3d119dd211bd56ba86a127359f7476990ec9e081cba.jpg +featured: true featureFlags: - freeTools diff --git a/eve/agents/prod/verdelis/api.yaml b/eve/agents/prod/verdelis/api.yaml index b140183..c2c1b3e 100644 --- a/eve/agents/prod/verdelis/api.yaml +++ b/eve/agents/prod/verdelis/api.yaml @@ -1,6 +1,8 @@ name: Verdelis owner: 6526f38042a1043421aa28e6 -userImage: https://edenartlab-stage-data.s3.amazonaws.com/41c397a76de66ba54d8fd72e7138423d132d2aa5e741c5a9c6cc4a0090a946ef.jpg +userImage: 41c397a76de66ba54d8fd72e7138423d132d2aa5e741c5a9c6cc4a0090a946ef.jpg +model: 677f7ee84fa5d1cc96c17856 +featured: true description: | You are Verdelis, a guardian of the "Human Imaginarium." @@ -96,41 +98,6 @@ instructions: | You are roleplaying as Verdelis. Stay in character, do not reveal that you are an AI, do not apologize too much, and do not be verbose. Engage in playful banter with the people and make art together. tools: - animate_3D: - texture_flow: - face_styler: - upscaler: - txt2img: - flux_inpainting: - remix_flux_schnell: - stable_audio: - musicgen: - runway: - flux_dev_lora: - name: Generate Verdelis (High quality) - description: Generate an image of Verdelis where quality is favored over speed. - parameters: - prompt: - description: The text prompt. Always mention Verdelis. - lora: - default: 67662bd943808b38016c6478 - hide_from_agent: true - hide_from_ui: true - lora_strength: - default: 1.0 - hide_from_agent: true - hide_from_ui: true - reel: - tip: Make sure to always include Verdelis in the prompts. - parameters: - lora: - default: 67662bd943808b38016c6478 - hide_from_agent: true - hide_from_ui: true - lora_strength: - default: 1.0 - hide_from_agent: true - hide_from_ui: true clients: discord: diff --git a/eve/cli/chat_cli.py b/eve/cli/chat_cli.py index 42b8502..bc5bdb8 100644 --- a/eve/cli/chat_cli.py +++ b/eve/cli/chat_cli.py @@ -82,7 +82,7 @@ async def async_chat(agent_name, new_thread=True, debug=False): progress.update(task) if update.type == UpdateType.ASSISTANT_MESSAGE: console.print( - "[bold green]Eve [dim]→[/dim] [green]" + f"[bold green]{agent.name} [dim]→[/dim] [green]" + update.message.content ) print() diff --git a/eve/cli/tool_cli.py b/eve/cli/tool_cli.py index 4cb4c53..83ff733 100644 --- a/eve/cli/tool_cli.py +++ b/eve/cli/tool_cli.py @@ -298,7 +298,7 @@ async def async_run_tests(tools, api, parallel): "Include flux_trainer test? This will take a long time.", default=False ) if not confirm: - all_tools.pop("flux_trainer") + all_tools.pop("flux_trainer", None) results = asyncio.run(async_run_tests(all_tools, api, parallel)) diff --git a/eve/tool.py b/eve/tool.py index c004463..476be3c 100644 --- a/eve/tool.py +++ b/eve/tool.py @@ -149,14 +149,14 @@ def convert_from_yaml(cls, schema: dict, file_path: str = None) -> dict: """ key = schema.get("key") or schema.get("parent_tool") or file_path.split("/")[-2] - parent_tool = schema.get("parent_tool") if parent_tool: parent_schema = cls._get_schema(parent_tool, from_yaml=True) parent_schema["parameter_presets"] = schema.pop("parameters", {}) parent_parameters = parent_schema.pop("parameters", {}) for k, v in parent_schema["parameter_presets"].items(): - parent_parameters[k].update(v) + if k in parent_parameters: + parent_parameters[k].update(v) schema.pop("workspace", None) # we want the parent workspace parent_schema.update(schema) parent_schema["parameters"] = parent_parameters diff --git a/eve/tools/flux_trainer/api.yaml b/eve/tools/flux_trainer/api.yaml index e21d41f..3f7583c 100644 --- a/eve/tools/flux_trainer/api.yaml +++ b/eve/tools/flux_trainer/api.yaml @@ -3,7 +3,7 @@ description: Finetune a model on top of Flux-dev tip: |- This will create a LoRA model from a base Flux-dev which captures and integrates the style, human face, or object represented in the training data. thumbnail: app/LoRA-trainer-flux-dev_opt.jpg -cost_estimate: 0.5 * max_train_steps +cost_estimate: 0.15 * max_train_steps base_model: flux-dev output_type: lora gpu: A100 diff --git a/eve/tools/reel/handler.py b/eve/tools/reel/handler.py index 9be6e63..e36a383 100644 --- a/eve/tools/reel/handler.py +++ b/eve/tools/reel/handler.py @@ -246,7 +246,7 @@ class Reel(BaseModel): voiceover: str = Field(..., description="The text of the voiceover, if one is not provided by the user.") music_prompt: str = Field(..., description='A prompt describing music for the entire reel. Usually describing format, genre, sub-genre, instruments, moods, BPM, and styles, separated by |. Include specific details by combining musical and emotional terms for moods, using descriptive adjectives for instruments, and selecting BPM settings appropriate to the genre. Follow the provided examples to ensure clarity and comprehensiveness, ensuring each prompt clearly defines the desired audio output. Examples: "Orchestra | Epic cinematic trailer | Instrumentation Strings, Brass, Percussion, and Choir | Dramatic, Inspiring, Heroic | Hollywood Blockbuster | 90 BPM", "Electronic, Synthwave, Retro-Futuristic | Instruments: Analog Synths, Drum Machine, Bass | Moods: Nostalgic, Cool, Rhythmic | 1980s Sci-Fi | 115 BPM"') - visual_prompt: str = Field(..., description="A prompt for a text-to-image model to precisely describe the visual content of the reel. The visual prompt should be structured as a descriptive sentence, precisely describing the visible content of the reel, the aesthetic style, visual elements, and action.") + visual_prompt: str = Field(..., description='A prompt for a text-to-image model to precisely describe the visual content of the reel. The visual prompt should be structured as a descriptive sentence, precisely describing the visible content of the reel, the aesthetic style, visual elements, and action. Try to enhance or embellish prompts. For example, if the user requests "A mermaid smoking a cigar", you would make it much longer and more intricate and detailed, like "A dried-out crusty old mermaid, wrinkled and weathered skin, tangled and brittle seaweed-like hair, smoking a smoldering cigarette underwater with tiny bubbles rising, jagged and cracked tail with faded iridescent scales, adorned with a tarnished coral crown, holding a rusted trident, faint sunlight beams coming through." If the user provides a lot of detail, just stay faithful to their wishes.') visual_style: str = Field(..., description="A short fragment description of the art direction, aesthetic, and style. Focus here not on content, but on genre, mood, medium, abstraction, textural elements, and other aesthetic terms. Aim for 10-15 words") # camera_motion: str = Field(..., description="A short description, 2-5 words only, describing the camera motion") @@ -325,12 +325,12 @@ async def handler(args: dict): use_lora = args.get("use_lora", False) if use_lora: lora = args.get("lora") - loras = get_collection("models") + loras = get_collection("models3") lora_doc = loras.find_one({"_id": ObjectId(lora)}) lora_name = lora_doc.get("name") - caption_prefix = lora_doc["args"]["caption_prefix"] + lora_trigger_text = lora_doc.get("lora_trigger_text") lora_strength = args.get("lora_strength") - instructions = f'In the visual prompts, *all* mentions of {lora_name} should be replaced with "{caption_prefix}". So for example, instead of "A photo of {lora_name} on the beach", always write "A photo of {caption_prefix} on the beach".' + instructions = f'In the visual prompts, *all* mentions of {lora_name} should be replaced with "{lora_trigger_text}". So for example, instead of "A photo of {lora_name} on the beach", always write "A photo of {lora_trigger_text} on the beach".' reel = write_reel( prompt=args.get("prompt"), From ac527494455874e654231aff5f4eb137f977f23b Mon Sep 17 00:00:00 2001 From: genekogan Date: Thu, 9 Jan 2025 01:19:36 -0800 Subject: [PATCH 9/9] go --- eve/llm.py | 22 +++++++++++++++++++++- eve/task.py | 3 ++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/eve/llm.py b/eve/llm.py index 7172c32..b5d112f 100644 --- a/eve/llm.py +++ b/eve/llm.py @@ -17,6 +17,7 @@ from . import sentry_sdk from .tool import Tool +from .task import Creation from .user import User from .agent import Agent from .thread import UserMessage, AssistantMessage, ToolCall, Thread @@ -574,8 +575,26 @@ async def async_prompt_thread( result = await tool.async_wait(task) thread.update_tool_call(assistant_message.id, t, result) - # yield update + # task completed if result["status"] == "completed": + + # make a Creation + name = task.args.get("prompt") or task.args.get("text_input") + filename = result.get("output", [{}])[0].get("filename") + media_attributes = result.get("output", [{}])[0].get("mediaAttributes") + if filename and media_attributes: + new_creation = Creation( + user=task.user, + requester=task.requester, + task=task.id, + tool=task.tool, + filename=filename, + mediaAttributes=media_attributes, + name=name + ) + new_creation.save() + + # yield update yield ThreadUpdate( type=UpdateType.TOOL_COMPLETE, tool_name=tool_call.tool, @@ -583,6 +602,7 @@ async def async_prompt_thread( result=result, ) else: + # yield error yield ThreadUpdate( type=UpdateType.ERROR, tool_name=tool_call.tool, diff --git a/eve/task.py b/eve/task.py index b5b5a68..b1e1f4c 100644 --- a/eve/task.py +++ b/eve/task.py @@ -140,7 +140,8 @@ async def _task_handler(func, *args, **kwargs): result = eden_utils.upload_result(result, save_thumbnails=True, save_blurhash=True) for output in result["output"]: - name = preprocess_result.get("name") or task_args.get("prompt") or args.get("text_input") + # name = preprocess_result.get("name") or task_args.get("prompt") or args.get("text_input") + name = task_args.get("prompt") or args.get("text_input") if not name: name = args.get("interpolation_prompts") or args.get("interpolation_texts") if name: