agenta 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of agenta might be problematic. Click here for more details.

agenta-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.1
2
+ Name: agenta
3
+ Version: 0.1.0
4
+ Summary:
5
+ Author: Mahmoud Mabrouk
6
+ Author-email: mahmoudmabrouk.mail@gmail.com
7
+ Requires-Python: >=3.9,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Requires-Dist: click (>=8.1.3,<9.0.0)
13
+ Requires-Dist: docker (>=6.1.1,<7.0.0)
14
+ Requires-Dist: fastapi (>=0.95.1,<0.96.0)
15
+ Requires-Dist: ipdb (>=0.13.13,<0.14.0)
16
+ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
17
+ Requires-Dist: questionary (>=1.10.0,<2.0.0)
18
+ Requires-Dist: toml (>=0.10.2,<0.11.0)
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Agenta CLI tool.
22
+
23
+ The Agenta CLI tool enables users to add new versions of their code to the Agenta platform, allowing them to be evaluated, compared to other versions, and deployed.
24
+ Installation
25
+
26
+ To install dependencies, run the following command:
27
+
28
+ ```poetry install```
29
+
30
+ ## Requirements
31
+ You need to have docker installed to be able to use the cli locally.
32
+
33
+ ## How does it work
34
+
35
+ The CLI allows you to push in one command your projects for evaluation in the dashboard.
36
+
37
+ You only need to modify your code very slightly by adding a decorator to your chat/ and ingest functions.
38
+
39
+ Under the hood the cli packages your code into a docker container and send it to a registry.
40
+
41
+ Later the dashboard spins off these containers and runs the benchmarks and evaluations over them.
42
+ ## Quickstart
43
+
44
+ To enter the virtual environment, run the following command:
45
+
46
+ ```poetry shell```
47
+
48
+ To init a new project and start from a simple template. Run the following command in an empty folder:
49
+
50
+ ```agenta init```
51
+
52
+ Build your code and add it to the platform to be tested in the UI. This command builds a Docker image for the version and upload the container to the registry:
53
+
54
+ ```agenta add-variant```
55
+
56
+ Start your code as a containarized service locally:
57
+
58
+ ```agenta start```
59
+
60
+
61
+ ## How to write code to be user in agenta
62
+
63
+ To write code that can be used in Agenta, you need to structure your project as follows:
64
+
65
+ ### Project Structure
66
+ The project folder should contain:
67
+ 1. A Python file named `app.py`
68
+ 2. A `requirements.txt` file with all the necessary dependencies for running your code
69
+
70
+ ### app.py
71
+
72
+ The `app.py` file should have the following functions:
73
+ 0. import `agenta`
74
+ 1. A function named chat that is exposed using the `@agenta.post` decorator
75
+ 2. An optional function named ingest that is exposed using the `@agenta.post` decorator
76
+
77
+ ### Example Project Structure
78
+
79
+ Here's an example of how your project folder might look:
80
+
81
+ my_agenda_project/
82
+
83
+ ├── app.py
84
+ └── requirements.txt
85
+
86
+ ### Example app.py
87
+ ```python
88
+ from agenta import post, get
89
+
90
+ class ChatInput(BaseModel):
91
+ messages: List[str]
92
+
93
+ class ChatOutput(BaseModel):
94
+ response: str
95
+
96
+ @post
97
+ def chat(input_data: ChatInput) -> ChatOutput:
98
+ # Your chat function implementation here
99
+ response = "Hello, World!"
100
+ return ChatOutput(response=response)
101
+
102
+ class IngestInput(BaseModel):
103
+ data: List[str]
104
+
105
+ class IngestOutput(BaseModel):
106
+ status: str
107
+
108
+ @post
109
+ def ingest(input_data: IngestInput) -> IngestOutput:
110
+ # Your ingest function implementation here (if needed)
111
+ status = "Data ingestion successful."
112
+ return IngestOutput(status=status)
113
+
114
+ ```
115
+ ## How to deal with secrets:
116
+ - For now we are using a .env file to store secrets.
117
+ - Create an .env file to store your secrets.
118
+ - The .env file is built into the image and uploaded to the local registry. THIS IS NOT GOOD. WE WILL FIX IT ASAP.
agenta-0.1.0/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Agenta CLI tool.
2
+
3
+ The Agenta CLI tool enables users to add new versions of their code to the Agenta platform, allowing them to be evaluated, compared to other versions, and deployed.
4
+ Installation
5
+
6
+ To install dependencies, run the following command:
7
+
8
+ ```poetry install```
9
+
10
+ ## Requirements
11
+ You need to have docker installed to be able to use the cli locally.
12
+
13
+ ## How does it work
14
+
15
+ The CLI allows you to push in one command your projects for evaluation in the dashboard.
16
+
17
+ You only need to modify your code very slightly by adding a decorator to your chat/ and ingest functions.
18
+
19
+ Under the hood the cli packages your code into a docker container and send it to a registry.
20
+
21
+ Later the dashboard spins off these containers and runs the benchmarks and evaluations over them.
22
+ ## Quickstart
23
+
24
+ To enter the virtual environment, run the following command:
25
+
26
+ ```poetry shell```
27
+
28
+ To init a new project and start from a simple template. Run the following command in an empty folder:
29
+
30
+ ```agenta init```
31
+
32
+ Build your code and add it to the platform to be tested in the UI. This command builds a Docker image for the version and upload the container to the registry:
33
+
34
+ ```agenta add-variant```
35
+
36
+ Start your code as a containarized service locally:
37
+
38
+ ```agenta start```
39
+
40
+
41
+ ## How to write code to be user in agenta
42
+
43
+ To write code that can be used in Agenta, you need to structure your project as follows:
44
+
45
+ ### Project Structure
46
+ The project folder should contain:
47
+ 1. A Python file named `app.py`
48
+ 2. A `requirements.txt` file with all the necessary dependencies for running your code
49
+
50
+ ### app.py
51
+
52
+ The `app.py` file should have the following functions:
53
+ 0. import `agenta`
54
+ 1. A function named chat that is exposed using the `@agenta.post` decorator
55
+ 2. An optional function named ingest that is exposed using the `@agenta.post` decorator
56
+
57
+ ### Example Project Structure
58
+
59
+ Here's an example of how your project folder might look:
60
+
61
+ my_agenda_project/
62
+
63
+ ├── app.py
64
+ └── requirements.txt
65
+
66
+ ### Example app.py
67
+ ```python
68
+ from agenta import post, get
69
+
70
+ class ChatInput(BaseModel):
71
+ messages: List[str]
72
+
73
+ class ChatOutput(BaseModel):
74
+ response: str
75
+
76
+ @post
77
+ def chat(input_data: ChatInput) -> ChatOutput:
78
+ # Your chat function implementation here
79
+ response = "Hello, World!"
80
+ return ChatOutput(response=response)
81
+
82
+ class IngestInput(BaseModel):
83
+ data: List[str]
84
+
85
+ class IngestOutput(BaseModel):
86
+ status: str
87
+
88
+ @post
89
+ def ingest(input_data: IngestInput) -> IngestOutput:
90
+ # Your ingest function implementation here (if needed)
91
+ status = "Data ingestion successful."
92
+ return IngestOutput(status=status)
93
+
94
+ ```
95
+ ## How to deal with secrets:
96
+ - For now we are using a .env file to store secrets.
97
+ - Create an .env file to store your secrets.
98
+ - The .env file is built into the image and uploaded to the local registry. THIS IS NOT GOOD. WE WILL FIX IT ASAP.
@@ -0,0 +1 @@
1
+ from .agenta import post, get, TextParam, FloatParam
@@ -0,0 +1,109 @@
1
+ import argparse
2
+ import functools
3
+ import inspect
4
+ import os
5
+ import sys
6
+ from typing import Any, Callable, Optional
7
+
8
+ from dotenv import load_dotenv
9
+ from fastapi import FastAPI
10
+ from fastapi.middleware.cors import CORSMiddleware
11
+
12
+ app = FastAPI()
13
+
14
+ origins = [
15
+ "http://localhost:3000",
16
+ ]
17
+
18
+ app.add_middleware(
19
+ CORSMiddleware,
20
+ allow_origins=origins,
21
+ allow_credentials=True,
22
+ allow_methods=["*"],
23
+ allow_headers=["*"],
24
+ )
25
+
26
+
27
+ class TextParam(str):
28
+
29
+ @classmethod
30
+ def __modify_schema__(cls, field_schema):
31
+ field_schema.update({"x-parameter": "text"})
32
+
33
+
34
+ class FloatParam(float):
35
+
36
+ @classmethod
37
+ def __modify_schema__(cls, field_schema):
38
+ field_schema.update({"x-parameter": "float"})
39
+
40
+
41
+ def post(func: Callable[..., Any]):
42
+ load_dotenv() # TODO: remove later when we have a better way to inject env variables
43
+ sig = inspect.signature(func)
44
+ func_params = sig.parameters
45
+
46
+ # find the optional parameters for the app
47
+ app_params = {name: param for name, param in func_params.items()
48
+ if param.annotation in {TextParam, FloatParam}}
49
+ # find the default values for the optional parameters
50
+ for name, param in app_params.items():
51
+ default_value = param.default if param.default is not param.empty else None
52
+ app_params[name] = default_value
53
+
54
+ @functools.wraps(func)
55
+ def wrapper(*args, **kwargs):
56
+ kwargs = {**app_params, **kwargs}
57
+ return func(*args, **kwargs)
58
+
59
+ new_params = []
60
+ for name, param in sig.parameters.items():
61
+ if name in app_params:
62
+ new_params.append(
63
+ inspect.Parameter(
64
+ name,
65
+ inspect.Parameter.KEYWORD_ONLY,
66
+ default=app_params[name],
67
+ annotation=Optional[param.annotation]
68
+
69
+ )
70
+ )
71
+ else:
72
+ new_params.append(param)
73
+
74
+ wrapper.__signature__ = sig.replace(parameters=new_params)
75
+
76
+ route = "/generate"
77
+ app.post(route)(wrapper)
78
+
79
+ # check if the module is being run as the main script
80
+ if os.path.splitext(os.path.basename(sys.argv[0]))[0] == os.path.splitext(os.path.basename(inspect.getfile(func)))[0]:
81
+ parser = argparse.ArgumentParser()
82
+ # add arguments to the command-line parser
83
+ for name, param in sig.parameters.items():
84
+ if name in app_params:
85
+ # For optional parameters, we add them as options
86
+ parser.add_argument(f"--{name}", type=type(param.default),
87
+ default=param.default)
88
+ else:
89
+ # For required parameters, we add them as arguments
90
+ parser.add_argument(name, type=param.annotation)
91
+
92
+ args = parser.parse_args()
93
+ print(func(**vars(args)))
94
+
95
+ return wrapper
96
+
97
+
98
+ def get(func):
99
+ """get decorator
100
+
101
+ Arguments:
102
+ func -- _description_
103
+
104
+ Returns:
105
+ _description_
106
+ """
107
+ route = f"/{func.__name__}"
108
+ app.get(route)(func)
109
+ return func
@@ -0,0 +1,168 @@
1
+ import os
2
+ import shutil
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ import click
7
+ import questionary
8
+ import toml
9
+ from agenta.client import client
10
+ from agenta.docker.docker_utils import build_and_upload_docker_image
11
+ from docker.models.images import Image as DockerImage
12
+
13
+
14
+ def add_variant(variant_name: str, app_folder: str) -> str:
15
+ """Add a new variant.
16
+ Returns the name of the variant. (useful for serve)"""
17
+ app_path = Path(app_folder)
18
+ config_file = app_path / 'config.toml'
19
+ if not config_file.exists():
20
+ click.echo("Please run agenta init first")
21
+ return None
22
+ else:
23
+ config = toml.load(config_file)
24
+ app_name = config['app-name']
25
+ if 'variants' not in config:
26
+ config['variants'] = []
27
+ app_file = app_path / 'app.py'
28
+ if not app_file.exists():
29
+ click.echo(click.style(f"No app.py exists! Please make sure you are in the right directory", fg='red'))
30
+ return None
31
+ env_file = app_path / '.env'
32
+ if not env_file.exists():
33
+ continue_without_env = questionary.confirm(
34
+ 'No .env file found! Are you sure you handled the API keys needed in your application?\n Do you want to continue without it?').ask()
35
+ if not continue_without_env:
36
+ click.echo("Operation cancelled.")
37
+ sys.exit(0)
38
+
39
+ if not variant_name:
40
+ variant_name = questionary.text('Please enter the variant name').ask()
41
+
42
+ if variant_name in config['variants']:
43
+ overwrite = questionary.confirm(
44
+ 'This variant already exists. Do you want to overwrite it?').ask()
45
+ if not overwrite:
46
+ click.echo("Operation cancelled.")
47
+ sys.exit(0)
48
+ else:
49
+ config['variants'].append(variant_name)
50
+ try:
51
+ docker_image: DockerImage = build_and_upload_docker_image(
52
+ folder=app_path, app_name=app_name, variant_name=variant_name)
53
+ except Exception as ex:
54
+ click.echo(click.style(f"Error while building image: {ex}", fg='red'))
55
+ return None
56
+ try:
57
+ client.add_variant_to_server(app_name, variant_name, docker_image)
58
+ except Exception as ex:
59
+ click.echo(click.style(f"Error while adding variant: {ex}", fg='red'))
60
+ return None
61
+ click.echo(click.style(f"Variant {variant_name} for App {app_name} added successfully", fg='green'))
62
+ # Last step us to save the config file
63
+ toml.dump(config, config_file.open('w'))
64
+ return variant_name
65
+
66
+
67
+ def start_variant(variant_name: str, app_folder: str):
68
+ app_folder = Path(app_folder)
69
+ config_file = app_folder / 'config.toml'
70
+ if not config_file.exists():
71
+ click.echo("Please run agenta init first")
72
+ return
73
+ else:
74
+ config = toml.load(config_file)
75
+ app_name = config['app-name']
76
+ if 'variants' not in config:
77
+ click.echo("No variants found. Please add a variant first.")
78
+ return
79
+
80
+ if not variant_name:
81
+ variant_name = questionary.select(
82
+ 'Please choose a variant',
83
+ choices=config['variants']
84
+ ).ask()
85
+
86
+ endpoint = client.start_variant(app_name, variant_name)
87
+ click.echo(
88
+ f"Started variant {variant_name} for App {app_name}. Endpoint: {endpoint}")
89
+
90
+
91
+ @click.group()
92
+ def cli():
93
+ pass
94
+
95
+
96
+ @click.command(name='serve')
97
+ @click.argument('app_folder', default='.')
98
+ def serve_cli(app_folder: str):
99
+ """Add a variant and start its container."""
100
+ variant_name = add_variant(variant_name='', app_folder=app_folder)
101
+ if variant_name: # otherwise we failed
102
+ start_variant(variant_name=variant_name, app_folder=app_folder)
103
+
104
+
105
+ @click.command(name='add-variant')
106
+ @click.argument('app_folder', default='.')
107
+ @click.option('--variant_name', default='')
108
+ def add_variant_cli(variant_name: str, app_folder: str):
109
+ return add_variant(variant_name, app_folder)
110
+
111
+
112
+ @click.command()
113
+ @click.option('--app_name', default='')
114
+ def init(app_name: str):
115
+ """Initialize a new Agenta app with the template files."""
116
+ if not app_name:
117
+ app_name = questionary.text('Please enter the app name').ask()
118
+
119
+ config = {"app-name": app_name}
120
+ with open('config.toml', 'w') as config_file:
121
+ toml.dump(config, config_file)
122
+
123
+ # Ask for init option
124
+ init_option = questionary.select(
125
+ "How do you want to initialize your app?",
126
+ choices=['Blank App', 'From Template']
127
+ ).ask()
128
+
129
+ # If the user selected the second option, show a list of available templates
130
+ if init_option == 'From Template':
131
+ current_dir = Path.cwd()
132
+ template_dir = Path(__file__).parent / "templates"
133
+ templates = [folder.name for folder in template_dir.iterdir()
134
+ if folder.is_dir()]
135
+ template_desc = [toml.load(
136
+ (template_dir / name / 'template.toml'))['short_desc'] for name in templates]
137
+
138
+ # Show the templates to the user
139
+ template = questionary.select(
140
+ "Which template do you want to use?",
141
+ choices=[questionary.Choice(title=f"{template} - {template_desc}", value=template)
142
+ for template, template_desc in zip(templates, template_desc)]
143
+ ).ask()
144
+
145
+ # Copy the template files to the current directory
146
+ chosen_template_dir = template_dir / template
147
+ for file in chosen_template_dir.glob("*"):
148
+ if file.name != 'template.toml':
149
+ shutil.copy(file, current_dir / file.name)
150
+ click.echo("App initialized successfully")
151
+
152
+
153
+ @click.command(name='start')
154
+ @click.option('--variant_name', default=None)
155
+ @click.argument('app_folder', default=".")
156
+ def start_variant_cli(variant_name: str, app_folder: str):
157
+ """Start a variant."""
158
+ start_variant(variant_name, app_folder)
159
+
160
+
161
+ # Add the commands to the CLI group
162
+ cli.add_command(add_variant_cli)
163
+ cli.add_command(init)
164
+ cli.add_command(start_variant_cli)
165
+ cli.add_command(serve_cli)
166
+
167
+ if __name__ == '__main__':
168
+ cli()
@@ -0,0 +1,3 @@
1
+ Client code to communicate with the backend.
2
+
3
+ Currently the models are manually copied from the backend code. This needs to change.
File without changes
@@ -0,0 +1,18 @@
1
+ from pydantic import BaseModel
2
+ from typing import List, Optional, Dict, Any
3
+
4
+
5
+ class AppVariant(BaseModel):
6
+ app_name: str
7
+ variant_name: str
8
+ parameters: Optional[Dict[str, Any]]
9
+ previous_variant_name: Optional[str]
10
+
11
+
12
+ class Image(BaseModel):
13
+ docker_id: str
14
+ tags: str
15
+
16
+
17
+ class URI(BaseModel):
18
+ uri: str
@@ -0,0 +1,39 @@
1
+ from agenta.client.api_models import AppVariant, Image
2
+ from docker.models.images import Image as DockerImage
3
+ import requests
4
+
5
+
6
+ def add_variant_to_server(app_name: str, variant_name: str, docker_image: DockerImage):
7
+ """Adds a variant to the server.
8
+
9
+ Arguments:
10
+ app_name -- Name of the app
11
+ variant_name -- Name of the variant
12
+ image_name -- Name of the image
13
+ """
14
+ image: Image = Image(docker_id=docker_image.id,
15
+ tags=f"{docker_image.tags[0]}")
16
+ app_variant: AppVariant = AppVariant(
17
+ app_name=app_name, variant_name=variant_name)
18
+ # TODO: save uri as a config
19
+ response = requests.post("http://localhost/api/app_variant/add/from_image/",
20
+ json={"app_variant": app_variant.dict(), "image": image.dict()})
21
+ if response.status_code != 200:
22
+ raise Exception(
23
+ f"Request to add variant failed with status code {response.status_code}. Response: {response.text}")
24
+
25
+
26
+ def start_variant(app_name: str, variant_name: str) -> str:
27
+ """Starts a container with the variant an expose its endpoint
28
+
29
+ Arguments:
30
+ app_name --
31
+ variant_name -- _description_
32
+
33
+ Returns:
34
+ The endpoint of the container
35
+ """
36
+ response = requests.post("http://localhost/api/app_variant/start/",
37
+ json={"app_name": app_name, "variant_name": variant_name})
38
+ assert response.status_code == 200
39
+ return response.json()['uri']
@@ -0,0 +1,21 @@
1
+ from pydantic import BaseSettings
2
+
3
+ import os
4
+ import toml
5
+ from pathlib import Path
6
+ # Load the settings from the .toml file
7
+ toml_config = toml.load(f"{Path(__file__).parent}/config.toml")
8
+
9
+ # Set the environment variables from the TOML configurations
10
+ os.environ["DOCKER_REGISTRY_URL"] = toml_config["docker_registry_url"]
11
+ os.environ["DATABASE_URL"] = toml_config["database_url"]
12
+ os.environ["REGISTRY"] = toml_config["registry"]
13
+
14
+
15
+ class Settings(BaseSettings):
16
+ docker_registry_url: str
17
+ database_url: str
18
+ registry: str
19
+
20
+
21
+ settings = Settings()
@@ -0,0 +1,3 @@
1
+ docker_registry_url="127.0.0.1:5001"
2
+ database_url="localhost:5432"
3
+ registry="agenta-server"
@@ -0,0 +1,13 @@
1
+ FROM python:3.8-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY . .
6
+
7
+ RUN pip install --no-cache-dir -r requirements.txt
8
+ RUN pip install fastapi uvicorn python-dotenv
9
+ EXPOSE 80
10
+
11
+ CMD ["python", "main.py"]
12
+ # uvicorn agenta_backend.main:app --reload --host 0.0.0.0 --port 8881
13
+ # TODO: add root_path as env variable and give it to the docker to solve the docs issue
@@ -0,0 +1 @@
1
+ The code here is just used when creating the template to dockerize the app. It is not part of the cli.
@@ -0,0 +1,8 @@
1
+ from uvicorn import run
2
+
3
+ import agenta
4
+ import app # This will register the routes with the FastAPI application
5
+ from dotenv import load_dotenv # I∑mport the load_dotenv function
6
+
7
+ if __name__ == "__main__":
8
+ run("agenta:app", host="0.0.0.0", port=80)
@@ -0,0 +1,75 @@
1
+ import os
2
+ import shutil
3
+ from pathlib import Path
4
+ from tempfile import TemporaryDirectory
5
+
6
+ import docker
7
+ from agenta.config import settings
8
+ from docker.models.images import Image
9
+
10
+
11
+ def create_dockerfile(out_folder: Path):
12
+ """Creates a dockerfile based on the template in the out_folder.
13
+
14
+ Arguments:
15
+ out_folder -- Folder in which to create the Dockerfile.
16
+ """
17
+ assert Path(out_folder).exists(), f"Folder {out_folder} does not exist."
18
+ dockerfile_template = Path(__file__).parent / \
19
+ "docker-assets" / "Dockerfile.template"
20
+ dockerfile_path = out_folder / "Dockerfile"
21
+ shutil.copy(dockerfile_template, dockerfile_path)
22
+ return dockerfile_path
23
+
24
+
25
+ def build_and_upload_docker_image(folder: Path, variant_name: str, app_name: str) -> Image:
26
+ """Builds an image from the folder and returns the path
27
+
28
+ Arguments:
29
+ folder -- The folder containg the app code
30
+
31
+ Returns:
32
+ The image object
33
+ TODO: Check that the variant name does not exist
34
+ TODO: Deal with different app names (probably we need to look then at multiple tags)
35
+ TODO: Error handling
36
+ """
37
+ # Initialize Docker client
38
+ client = docker.from_env()
39
+
40
+ with TemporaryDirectory() as temp_dir:
41
+ # Create a Dockerfile for the app
42
+ # TODO: Later do this in the temp dir
43
+ dockerfile_path = create_dockerfile(folder)
44
+ shutil.copy(Path(__file__).parent.parent / "agenta.py", folder)
45
+ shutil.copy(Path(__file__).parent /
46
+ "docker-assets" / "main.py", folder)
47
+
48
+ # Copy the app files to a temporary directory
49
+ shutil.copytree(folder, temp_dir, dirs_exist_ok=True)
50
+
51
+ # Build the Docker image
52
+ registry = settings.registry
53
+ tag = f"{registry}/{app_name.lower()}_{variant_name.lower()}:latest"
54
+ print("Building Docker image...")
55
+ try:
56
+ image, build_log = client.images.build(
57
+ path=temp_dir,
58
+ tag=tag,
59
+ rm=True # Remove intermediate containers after a successful build
60
+ )
61
+ except docker.errors.BuildError as e:
62
+ print("Error building Docker image:\n", e)
63
+ raise e
64
+
65
+ # Print the build log
66
+ for line in build_log:
67
+ print(line)
68
+ # Upload the Docker image to the Agenta registry
69
+ print("Uploading Docker image...")
70
+ client.images.push(repository=f"{registry}", tag="latest")
71
+ print("Docker image uploaded successfully.")
72
+
73
+ # Clean up the temporary Dockerfile
74
+ dockerfile_path.unlink()
75
+ return image
@@ -0,0 +1,9 @@
1
+ # Using this template
2
+
3
+ Please make sure to create a `.env` file with your OpenAI API key before running the app.
4
+ OPENAI_API_KEY=sk-xxxxxxx
5
+
6
+ ## Running
7
+ You can first test your app locally by using by running `python app.py`, after experimenting, send it to evaluation by running `agenta up folder`.
8
+ You will find then the app in the dashboard, where you can evaluate it and compare it to previous versions.
9
+
@@ -0,0 +1,20 @@
1
+ from agenta import post, TextParam, FloatParam
2
+ from dotenv import load_dotenv
3
+ from langchain.chains import LLMChain
4
+ from langchain.llms import OpenAI
5
+ from langchain.prompts import PromptTemplate
6
+
7
+ default_prompt = "What is a good name for a company that makes {product}?"
8
+
9
+
10
+ @post
11
+ def generate(product: str, temperature: FloatParam = 0.9, prompt_template: TextParam = default_prompt) -> str:
12
+ llm = OpenAI(temperature=temperature)
13
+ prompt = PromptTemplate(
14
+ input_variables=["product"],
15
+ template=prompt_template,
16
+ )
17
+ chain = LLMChain(llm=llm, prompt=prompt)
18
+ output = chain.run(product=product)
19
+
20
+ return output
@@ -0,0 +1,3 @@
1
+ langchain
2
+ openai
3
+ python-dotenv
@@ -0,0 +1 @@
1
+ short_desc="Simple app that uses one prompt using langchain"
@@ -0,0 +1,26 @@
1
+ [tool.poetry]
2
+ name = "agenta"
3
+ version = "0.1.0"
4
+ description = ""
5
+ authors = ["Mahmoud Mabrouk <mahmoudmabrouk.mail@gmail.com>"]
6
+ readme = "README.md"
7
+
8
+ [tool.poetry.dependencies]
9
+ python = "^3.9"
10
+ docker = "^6.1.1"
11
+ click = "^8.1.3"
12
+ fastapi = "^0.95.1"
13
+ toml = "^0.10.2"
14
+ questionary = "^1.10.0"
15
+ ipdb = "^0.13.13"
16
+ python-dotenv = "^1.0.0"
17
+
18
+ [tool.poetry.dev-dependencies]
19
+ pytest = "^6.2"
20
+
21
+ [build-system]
22
+ requires = ["poetry-core"]
23
+ build-backend = "poetry.core.masonry.api"
24
+
25
+ [tool.poetry.scripts]
26
+ agenta = "agenta.cli:cli"