Deepak Sahu commited on
Commit
97127b4
·
1 Parent(s): b70ec81
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.xlsx filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ *.pyc
Dockerfile ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python image
2
+ FROM langchain/langchain
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy your app files
8
+ COPY requirements.txt requirements.txt
9
+
10
+ # Install dependencies (adjust as needed)
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ COPY . .
14
+
15
+ # Install agents
16
+ # RUN pip install -e pandas_expression_generator
17
+
18
+ # # Make the script executable
19
+ # RUN chmod +x start.sh
20
+
21
+ # Start both processes
22
+ # CMD ["./start.sh"]
23
+
24
+
_data/retail_customer/Retail_Customer_Cluster_Data.xlsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:643249aed77417875d9de227e9278f19a6fa015a27cccdcc1bfa6f30f96300ca
3
+ size 14884
_data/retail_customer/meta.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ | Column Name | Description | Value Type | Valid Data Regex / Allowed Values |
2
+ |---------------------------|------------------------------------------------------|-------------|----------------------------------------------------|
3
+ | CustomerID | Unique customer identifier | Categorical | `CUST\d{3}` |
4
+ | Age | Age of the customer in years | Numerical | `\d{1,3}` |
5
+ | Gender | Gender of the customer | Categorical | Male, Female, Other |
6
+ | Income (Monthly) | Monthly income of the customer | Numerical | `\d+(\.\d+)?` |
7
+ | Location | Customer's city location | Categorical | Berlin, Hamburg, Cologne, Frankfurt |
8
+ | Purchase Frequency | Number of purchases in a period | Numerical | `\d+` |
9
+ | Avg. Transaction Value | Average value per transaction | Numerical | `\d+(\.\d+)?` |
10
+ | Loyalty Program Member | Whether the customer is in loyalty program | Categorical | Yes, No |
11
+ | Tenure (Months) | How long they've been a customer (in months) | Numerical | `\d+` |
12
+ | Last Purchase Date | Date of the last purchase | Date | `\d{4}-\d{2}-\d{2}` yyyy-mm-dd |
13
+ | Total Spend (6M) | Total spending in last 6 months | Numerical | `\d+(\.\d+)?` |
14
+ | Visit Recency (Days) | Days since last visit | Numerical | `\d+` |
15
+ | Preferred Category | Product category most often purchased | Categorical | Grocery, Home, Beauty, Electronics |
16
+ | Engagement Score | Score representing user interaction | Numerical | `\d+(\.\d+)?` |
17
+ | Value Score | Score indicating customer value | Numerical | `\d+(\.\d+)?` |
18
+ | Retention Risk Score | Score estimating likelihood of customer churn | Numerical | `\d+(\.\d+)?` |
19
+ | Overall Customer Index | Composite score for customer performance | Numerical | `\d+(\.\d+)?` |
_data/retail_customer/readme.md ADDED
@@ -0,0 +1 @@
 
 
1
+ this is a synthetic data generated out of chat gpt.
config.yaml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ general:
2
+ use_uvloop: true
3
+ logging:
4
+ console:
5
+ _type: console
6
+ level: WARN
7
+
8
+ front_end:
9
+ _type: fastapi
10
+
11
+ front_end:
12
+ _type: console
13
+
14
+ llms:
15
+ nim_llm:
16
+ _type: nim
17
+ model_name : meta/llama-3.1-405b-instruct
18
+ temperature: 0.0
19
+
20
+ workflow:
21
+ _type: pandas_expression_generator
22
+ llm: nim_llm
23
+ csv_file: "/app/_data/retail_customer/Retail_Customer_Cluster_Data.xlsx"
24
+ csv_metafile: "/app/_data/retail_customer/meta.md"
25
+ description: "Use this tool to get data related to Customer Retails."
26
+
frontend.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+
4
+ API_URL = "http://localhost:8000/chat"
5
+
6
+ def chat_with_agentiq(message, history):
7
+ # Convert Gradio history to ChatML-style format
8
+ messages = []
9
+ for user_msg, agent_msg in history:
10
+ messages.append({"role": "User", "content": user_msg})
11
+ messages.append({"role": "Assistant", "content": agent_msg})
12
+ messages.append({"role": "User", "content": message})
13
+
14
+ payload = {
15
+ "messages": messages,
16
+ "model": "", # Fill in your model name if required
17
+ "temperature": 0.7,
18
+ "max_tokens": 512,
19
+ "top_p": 1.0,
20
+ "additionalProp1": {}
21
+ }
22
+
23
+ try:
24
+ response = requests.post(API_URL, json=payload)
25
+ data = response.json()
26
+ reply = data["choices"][0]["message"]["content"]
27
+ except Exception as e:
28
+ reply = f"[Error: {str(e)}]"
29
+
30
+ return reply
31
+
32
+ demo= gr.ChatInterface(fn=chat_with_agentiq, title="AgentIQ Chat")
33
+
34
+ if __name__=="__main__":
35
+ demo.launch(server_name="0.0.0.0", server_port=7860)
pandas_expression_generator/pyproject.toml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ build-backend = "setuptools.build_meta"
3
+ requires = ["setuptools >= 64"]
4
+
5
+ [project]
6
+ name = "pandas_expression_generator"
7
+ version = "0.1.0"
8
+ dependencies = [
9
+ "aiqtoolkit[langchain]",
10
+ ]
11
+ requires-python = ">=3.11,<3.13"
12
+ description = "Custom AIQ Toolkit Workflow"
13
+ classifiers = ["Programming Language :: Python"]
14
+
15
+
16
+
17
+ [project.entry-points.'aiq.components']
18
+ pandas_expression_generator = "pandas_expression_generator.register"
pandas_expression_generator/src/pandas_expression_generator.egg-info/PKG-INFO ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: pandas_expression_generator
3
+ Version: 0.1.0
4
+ Summary: Custom AIQ Toolkit Workflow
5
+ Classifier: Programming Language :: Python
6
+ Requires-Python: <3.13,>=3.11
7
+ Requires-Dist: aiqtoolkit[langchain]
pandas_expression_generator/src/pandas_expression_generator.egg-info/SOURCES.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ pyproject.toml
2
+ src/pandas_expression_generator/__init__.py
3
+ src/pandas_expression_generator/pandas_expression_generator_function.py
4
+ src/pandas_expression_generator/register.py
5
+ src/pandas_expression_generator.egg-info/PKG-INFO
6
+ src/pandas_expression_generator.egg-info/SOURCES.txt
7
+ src/pandas_expression_generator.egg-info/dependency_links.txt
8
+ src/pandas_expression_generator.egg-info/entry_points.txt
9
+ src/pandas_expression_generator.egg-info/requires.txt
10
+ src/pandas_expression_generator.egg-info/top_level.txt
pandas_expression_generator/src/pandas_expression_generator.egg-info/dependency_links.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
pandas_expression_generator/src/pandas_expression_generator.egg-info/entry_points.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [aiq.components]
2
+ pandas_expression_generator = pandas_expression_generator.register
pandas_expression_generator/src/pandas_expression_generator.egg-info/requires.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ aiqtoolkit[langchain]
pandas_expression_generator/src/pandas_expression_generator.egg-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ pandas_expression_generator
pandas_expression_generator/src/pandas_expression_generator/__init__.py ADDED
File without changes
pandas_expression_generator/src/pandas_expression_generator/configs/config.yml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ general:
2
+ use_uvloop: true
3
+ logging:
4
+ console:
5
+ _type: console
6
+ level: WARN
7
+
8
+ front_end:
9
+ _type: fastapi
10
+
11
+ front_end:
12
+ _type: console
13
+
14
+ llms:
15
+ nim_llm:
16
+ _type: nim
17
+ model_name : meta/llama-3.1-405b-instruct
18
+ temperature: 0.0
19
+
20
+ workflow:
21
+ _type: pandas_expression_generator
22
+ llm: nim_llm
23
+ csv_file: "/workspaces/do_aiq2/_data/retail_customer/Retail_Customer_Cluster_Data.xlsx"
24
+ csv_metafile: "/workspaces/do_aiq2/_data/retail_customer/meta.md"
25
+ description: "Use this agent to handles retail customers data"
pandas_expression_generator/src/pandas_expression_generator/pandas_expression_generator_function.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ from pydantic import Field
4
+
5
+ from aiq.builder.builder import Builder
6
+ from aiq.builder.function_info import FunctionInfo
7
+ from aiq.cli.register_workflow import register_function
8
+ from aiq.data_models.function import FunctionBaseConfig
9
+ from aiq.data_models.component_ref import LLMRef
10
+ from aiq.builder.framework_enum import LLMFrameworkEnum
11
+ from langchain_core.messages import AIMessage
12
+ import pandas as pd
13
+ from pydantic import BaseModel
14
+ import numpy as np
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class PandasExpressionGeneratorFunctionConfig(FunctionBaseConfig, name="pandas_expression_generator"):
20
+ """
21
+ AIQ Toolkit function template. Please update the description.
22
+ """
23
+ # Add your custom configuration parameters here
24
+ # parameter: str = Field(default="default_value", description="Notional description for this parameter")
25
+ llm: LLMRef
26
+ csv_file: str
27
+ csv_metafile: str
28
+ description: str = Field(default="A dataset query engine", description="Describe for which data the engine is used for")
29
+ max_retries: int = Field(default=2)
30
+
31
+ class FunctionInput(BaseModel):
32
+ original_user_query: str = Field(description="The original user query as-is")
33
+ thought: str = Field(description="Describe what's essential to solve the query")
34
+ current_step: str = Field(description="Part of the intermediate step when resovling the big user query.")
35
+ next_step: str = Field(description="What next are we plannning to do once we perform the current step.")
36
+
37
+ @register_function(config_type=PandasExpressionGeneratorFunctionConfig)
38
+ async def pandas_expression_generator_function(
39
+ config: PandasExpressionGeneratorFunctionConfig, builder: Builder
40
+ ):
41
+ df: pd.DataFrame = pd.read_excel(config.csv_file)
42
+ with open(config.csv_metafile, "r", encoding="utf-8") as f:
43
+ df_meta: str = f.read()
44
+
45
+
46
+ def extract_bracket_content(text):
47
+ start = text.find('[')
48
+ end = text.rfind(']') + 1 # include the last ']'
49
+ if start == -1 or end == -1 or start >= end:
50
+ return "" # return empty if brackets not found properly
51
+ return text[start:end]
52
+
53
+ import ast
54
+ def expression_executor(input_exp: str, df=None) -> tuple:
55
+ # Convert the input string to a list
56
+ commands = ast.literal_eval(input_exp)
57
+
58
+ # local_vars = dict([(str.strip, command.split('=', 1)) for command in commands])
59
+ local_vars:dict = dict([list(map(str.strip, command.split('=', 1))) for command in commands])
60
+
61
+ # Dictionary to simulate local scope
62
+ local_vars.update({'df': df, 'pd': pd, 'np': np})
63
+ # local_vars = {}
64
+ for command in commands:
65
+ exec(command, globals(), local_vars)
66
+
67
+ # for command in commands:
68
+ # # Split at the first `=`
69
+ # var, expr = map(str.strip, command.split('=', 1))
70
+ # # Evaluate the expression in the local_vars context and assign to var
71
+ # local_vars[var] = eval(expr, {}, local_vars)
72
+ return local_vars.get("output", None)
73
+ try:
74
+ output
75
+ # output = scope.get("output")
76
+ except Exception as e:
77
+ logger.error("[expression_executor] ", e)
78
+ output = None
79
+ return output # return all evaluated variables
80
+
81
+
82
+
83
+ # Implement your function logic here
84
+ async def _response_fn(input_query: FunctionInput) -> str:
85
+
86
+ # Create LLM
87
+ llm_ = await builder.get_llm(config.llm, wrapper_type=LLMFrameworkEnum.LANGCHAIN)
88
+
89
+ # Prompt
90
+ prompt_ = f'''You are a python expression generator.
91
+
92
+ Given the dataframe `df` and pandas import as `pd` which has the following metadata
93
+
94
+ CSV Meta
95
+ ---
96
+ {df_meta}
97
+
98
+ Generate python expression to solve the query:
99
+ current_step: {input_query.current_step}
100
+
101
+ You can reformulate(extend or reduce) the current step based on the following information
102
+ original_user_query: {input_query.original_user_query}
103
+ past_step: {input_query.thought}
104
+ next_step: {input_query.next_step}
105
+
106
+ You must generate list of python expressions output format must as follows:
107
+
108
+ [
109
+ "key_var = df[...]" // intermediate step
110
+ "key_var2 = key_var[df[...]...]" // intermediate step
111
+
112
+ // reset the index of df if requrired
113
+ // convert the grouped dataframe to dictionaries
114
+ //
115
+ "output" = sting. Have the string as list (records) of dictionaries (columns). Ensure to reset index if required
116
+ ]
117
+
118
+
119
+ Certain template questions and expected approach from you
120
+ 1. When user wants to what is present in the data
121
+ > you should respond back with names of columns
122
+
123
+ Dont write reasoning; just list of strings which has python expressions
124
+ The list should not have markdown fencing.
125
+ '''
126
+
127
+ # just var declaration
128
+ df
129
+
130
+ try:
131
+ ai_message: AIMessage = await llm_.ainvoke(prompt_)
132
+ logger.info("[Following Should just be structured list of string]")
133
+ logger.info(ai_message)
134
+ structured_text_str = extract_bracket_content(ai_message.content)
135
+ output_message = str(expression_executor(structured_text_str, df))[:250]
136
+ #
137
+ # Loop break
138
+ except Exception as e:
139
+ logger.error(str(e))
140
+ logger.info("Retrying...")
141
+ output_message = "Unable to serve the request."
142
+ # output_message = f"Hello from pandas_expression_generator workflow! You said: {input_message}"
143
+
144
+ return output_message
145
+
146
+ try:
147
+ yield FunctionInfo.from_fn(
148
+ _response_fn,
149
+ description=config.description
150
+ )
151
+ except GeneratorExit:
152
+ print("Function exited early!")
153
+ finally:
154
+ print("Cleaning up pandas_expression_generator workflow.")
pandas_expression_generator/src/pandas_expression_generator/register.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # pylint: disable=unused-import
2
+ # flake8: noqa
3
+
4
+ # Import any tools which need to be automatically registered here
5
+ from pandas_expression_generator import pandas_expression_generator_function
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio
2
+ agentiq
3
+ langgraph
4
+ aiqtoolkit[langchain]
start.sh ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Run both commands in parallel
4
+ aiq serve --config_file=config.yaml &
5
+ python frontend.py
6
+
7
+ # Wait for any to exit (optional)
8
+ wait -n
9
+
10
+ # Exit with status of the first failed process
11
+ exit $?