ziya 0.1.0__py3-none-any.whl
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 ziya might be problematic. Click here for more details.
- app/__init__.py +0 -0
- app/agents/__init__.py +0 -0
- app/agents/agent.py +114 -0
- app/agents/prompts.py +47 -0
- app/main.py +33 -0
- app/server.py +22 -0
- app/utils/__init__.py +0 -0
- app/utils/directory_util.py +57 -0
- app/utils/gitignore_parser.py +217 -0
- app/utils/logging_utils.py +10 -0
- app/utils/print_tree_util.py +43 -0
- pyproject.toml +33 -0
- static/app.js +104 -0
- static/favicon.ico +0 -0
- static/sendPayload.js +62 -0
- static/ziya.css +88 -0
- templates/index.html +19 -0
- ziya-0.1.0.dist-info/LICENSE +21 -0
- ziya-0.1.0.dist-info/METADATA +86 -0
- ziya-0.1.0.dist-info/RECORD +22 -0
- ziya-0.1.0.dist-info/WHEEL +4 -0
- ziya-0.1.0.dist-info/entry_points.txt +3 -0
app/__init__.py
ADDED
|
File without changes
|
app/agents/__init__.py
ADDED
|
File without changes
|
app/agents/agent.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Generator, List, Tuple, Set, Union
|
|
3
|
+
|
|
4
|
+
import tiktoken
|
|
5
|
+
from langchain.agents import AgentExecutor
|
|
6
|
+
from langchain.agents.format_scratchpad import format_xml
|
|
7
|
+
from langchain_aws import ChatBedrock
|
|
8
|
+
from langchain_community.document_loaders import TextLoader
|
|
9
|
+
from langchain_core.messages import AIMessage, HumanMessage
|
|
10
|
+
from langchain_core.pydantic_v1 import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
from app.agents.prompts import conversational_prompt, parse_output
|
|
13
|
+
from app.utils.directory_util import get_ignored_patterns, get_complete_file_list
|
|
14
|
+
from app.utils.logging_utils import logger
|
|
15
|
+
from app.utils.print_tree_util import print_file_tree
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _format_chat_history(chat_history: List[Tuple[str, str]]) -> List[Union[HumanMessage, AIMessage]]:
|
|
19
|
+
buffer = []
|
|
20
|
+
for human, ai in chat_history:
|
|
21
|
+
buffer.append(HumanMessage(content=human))
|
|
22
|
+
buffer.append(AIMessage(content=ai))
|
|
23
|
+
return buffer
|
|
24
|
+
|
|
25
|
+
aws_profile = os.environ.get("ZIYA_AWS_PROFILE")
|
|
26
|
+
if aws_profile:
|
|
27
|
+
logger.info(f"Using AWS Profile: {aws_profile}")
|
|
28
|
+
else:
|
|
29
|
+
logger.info("No AWS profile specified via --aws-profile flag, using default credentials")
|
|
30
|
+
model_id = {
|
|
31
|
+
"sonnet": "anthropic.claude-3-sonnet-20240229-v1:0",
|
|
32
|
+
"haiku": "anthropic.claude-3-haiku-20240307-v1:0",
|
|
33
|
+
"opus": "anthropic.claude-3-opus-20240229-v1:0",
|
|
34
|
+
}[os.environ.get("ZIYA_AWS_MODEL", "haiku")]
|
|
35
|
+
logger.info(f"Using Claude Model: {model_id}")
|
|
36
|
+
|
|
37
|
+
model = ChatBedrock(
|
|
38
|
+
model_id=model_id,
|
|
39
|
+
model_kwargs={"max_tokens": 4096},
|
|
40
|
+
credentials_profile_name=aws_profile if aws_profile else None,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_combined_document_contents() -> str:
|
|
45
|
+
user_codebase_dir: str = os.environ["ZIYA_USER_CODEBASE_DIR"]
|
|
46
|
+
print(f"Reading user's current codebase: {user_codebase_dir}")
|
|
47
|
+
|
|
48
|
+
combined_contents: str = ""
|
|
49
|
+
ignored_patterns: List[str] = get_ignored_patterns(user_codebase_dir)
|
|
50
|
+
all_files: List[str] = get_complete_file_list(user_codebase_dir, ignored_patterns)
|
|
51
|
+
|
|
52
|
+
print_file_tree(all_files)
|
|
53
|
+
|
|
54
|
+
seen_dirs: Set[str] = set()
|
|
55
|
+
for file_path in all_files:
|
|
56
|
+
try:
|
|
57
|
+
docs = TextLoader(file_path).load()
|
|
58
|
+
for doc in docs:
|
|
59
|
+
combined_contents += f"File: {file_path}\n{doc.page_content}\n\n"
|
|
60
|
+
dir_path = os.path.dirname(file_path)
|
|
61
|
+
if dir_path not in seen_dirs:
|
|
62
|
+
# print_file_tree(dir_path, ignored_patterns)
|
|
63
|
+
seen_dirs.add(dir_path)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
print(f"Skipping file {file_path} due to error: {e}")
|
|
66
|
+
|
|
67
|
+
print("--------------------------------------------------------")
|
|
68
|
+
print(f"Ignoring following paths based on gitIgnore and other defaults: {ignored_patterns}")
|
|
69
|
+
print("--------------------------------------------------------")
|
|
70
|
+
print(f"Codebase word count: {len(combined_contents.split()):,}")
|
|
71
|
+
token_count = len(tiktoken.get_encoding("cl100k_base").encode(combined_contents))
|
|
72
|
+
print(f"Codebase token count: {token_count:,}")
|
|
73
|
+
print(f"Max Claude Token limit: 200,000")
|
|
74
|
+
print("--------------------------------------------------------")
|
|
75
|
+
return combined_contents
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_child_paths(directory: str) -> Generator[str, None, None]:
|
|
79
|
+
for entry in os.listdir(directory):
|
|
80
|
+
child_path = os.path.join(directory, entry)
|
|
81
|
+
yield child_path
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
prompt = conversational_prompt.partial(
|
|
85
|
+
codebase=get_combined_document_contents,
|
|
86
|
+
)
|
|
87
|
+
llm_with_stop = model.bind(stop=["</tool_input>"])
|
|
88
|
+
|
|
89
|
+
agent = (
|
|
90
|
+
{
|
|
91
|
+
"question": lambda x: x["question"],
|
|
92
|
+
"agent_scratchpad": lambda x: format_xml(x["intermediate_steps"]),
|
|
93
|
+
"chat_history": lambda x: _format_chat_history(x["chat_history"]),
|
|
94
|
+
}
|
|
95
|
+
| prompt
|
|
96
|
+
| llm_with_stop
|
|
97
|
+
| parse_output
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class AgentInput(BaseModel):
|
|
102
|
+
question: str
|
|
103
|
+
chat_history: List[Tuple[str, str]] = Field(..., extra={"widget": {"type": "chat"}})
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
agent_executor = AgentExecutor(
|
|
107
|
+
agent=agent, tools=[], verbose=True, handle_parsing_errors=True
|
|
108
|
+
).with_types(input_type=AgentInput)
|
|
109
|
+
|
|
110
|
+
agent_executor = agent_executor | (lambda x: x["output"])
|
|
111
|
+
|
|
112
|
+
if __name__ == "__main__":
|
|
113
|
+
question = "How are you ?"
|
|
114
|
+
print(agent_executor.invoke({"question": question, "chat_history": []}))
|
app/agents/prompts.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from langchain_core.agents import AgentFinish
|
|
2
|
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
3
|
+
# import pydevd_pycharm
|
|
4
|
+
|
|
5
|
+
template = """You are an excellent coder. Help the user with their coding tasks. You are given the entire codebase
|
|
6
|
+
of the user in your context. It is in the format like below where first line has the File path and then the content follows.
|
|
7
|
+
|
|
8
|
+
File: <filepath>
|
|
9
|
+
<Content of the file>.
|
|
10
|
+
|
|
11
|
+
Now below is the current codebase of the user:
|
|
12
|
+
|
|
13
|
+
{codebase}
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
conversational_prompt = ChatPromptTemplate.from_messages(
|
|
17
|
+
[
|
|
18
|
+
("system", template),
|
|
19
|
+
MessagesPlaceholder(variable_name="chat_history"),
|
|
20
|
+
("user", "{question}"),
|
|
21
|
+
("ai", "{agent_scratchpad}"),
|
|
22
|
+
]
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def parse_output(message):
|
|
27
|
+
text = message.content
|
|
28
|
+
# pydevd_pycharm.settrace('localhost', port=61565, stdoutToServer=True, stderrToServer=True)
|
|
29
|
+
# print('----TEXT START----')
|
|
30
|
+
# print(text)
|
|
31
|
+
# print('----TEXT END----')
|
|
32
|
+
# if "</tool>" in text:
|
|
33
|
+
# tool, tool_input = text.split("</tool>")
|
|
34
|
+
# _tool = tool.split("<tool>")[1]
|
|
35
|
+
# _tool_input = tool_input.split("<tool_input>")[1]
|
|
36
|
+
#
|
|
37
|
+
# if _tool == "write_file":
|
|
38
|
+
# _tool_input = json.loads(_tool_input)
|
|
39
|
+
# # newline_index = _tool_input.find('\n')
|
|
40
|
+
# # file_path = _tool_input[:newline_index]
|
|
41
|
+
# # text = _tool_input[newline_index + 1:]
|
|
42
|
+
# if "</tool_input>" in _tool_input:
|
|
43
|
+
# _tool_input = _tool_input.split("</tool_input>")[0]
|
|
44
|
+
#
|
|
45
|
+
# return AgentAction(tool=_tool, tool_input=_tool_input, log=text)
|
|
46
|
+
# else:
|
|
47
|
+
return AgentFinish(return_values={"output": text}, log=text)
|
app/main.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from langchain_cli.cli import serve
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
def main():
|
|
6
|
+
os.environ["ZIYA_USER_CODEBASE_DIR"] = os.getcwd()
|
|
7
|
+
|
|
8
|
+
parser = argparse.ArgumentParser(description="Run with custom options")
|
|
9
|
+
parser.add_argument("--exclude", default=[], type=lambda x: x.split(','),
|
|
10
|
+
help="List of files or directories to exclude (e.g., --exclude 'tst,build,*.py')")
|
|
11
|
+
parser.add_argument("--profile", type=str, default=None,
|
|
12
|
+
help="AWS profile to use (e.g., --profile ziya)")
|
|
13
|
+
parser.add_argument("--model", type=str, choices=["sonnet", "haiku", "opus"], default="haiku",
|
|
14
|
+
help="AWS Bedrock Model to use (e.g., --model sonnet)")
|
|
15
|
+
parser.add_argument("--port", type=int, default=6969,
|
|
16
|
+
help="Port number to run Ziya frontend on (e.g., --port 8080)")
|
|
17
|
+
args = parser.parse_args()
|
|
18
|
+
|
|
19
|
+
additional_excluded_dirs = ','.join([item for item in args.exclude])
|
|
20
|
+
os.environ["ZIYA_ADDITIONAL_EXCLUDE_DIRS"] = additional_excluded_dirs
|
|
21
|
+
|
|
22
|
+
if args.profile:
|
|
23
|
+
os.environ["ZIYA_AWS_PROFILE"] = args.profile
|
|
24
|
+
if args.model:
|
|
25
|
+
os.environ["ZIYA_AWS_MODEL"] = args.model
|
|
26
|
+
|
|
27
|
+
langchain_serve_directory = os.path.dirname(os.path.abspath(__file__))
|
|
28
|
+
os.chdir(langchain_serve_directory)
|
|
29
|
+
serve(port=args.port)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
main()
|
app/server.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from fastapi import FastAPI, Request
|
|
2
|
+
from fastapi.staticfiles import StaticFiles
|
|
3
|
+
from fastapi.templating import Jinja2Templates
|
|
4
|
+
from langserve import add_routes
|
|
5
|
+
from app.agents.agent import agent_executor
|
|
6
|
+
|
|
7
|
+
import uvicorn
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
app = FastAPI()
|
|
11
|
+
app.mount("/static", StaticFiles(directory="../static"), name="static")
|
|
12
|
+
templates = Jinja2Templates(directory="../templates")
|
|
13
|
+
|
|
14
|
+
# Add a route for the frontend
|
|
15
|
+
add_routes(app, agent_executor, disabled_endpoints=["playground"], path="/ziya")
|
|
16
|
+
|
|
17
|
+
@app.get("/")
|
|
18
|
+
async def root(request: Request):
|
|
19
|
+
return templates.TemplateResponse("index.html", {"request": request})
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
app/utils/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import glob
|
|
2
|
+
import os
|
|
3
|
+
from typing import List, Set, Tuple
|
|
4
|
+
|
|
5
|
+
from app.utils.gitignore_parser import parse_gitignore_patterns
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_ignored_patterns(directory: str) -> List[Tuple[str, str]]:
|
|
9
|
+
ignored_patterns: List[Tuple[str, str]] = [
|
|
10
|
+
("poetry.lock", os.environ["ZIYA_USER_CODEBASE_DIR"]),
|
|
11
|
+
("package-lock.json", os.environ["ZIYA_USER_CODEBASE_DIR"]),
|
|
12
|
+
(".DS_Store", os.environ["ZIYA_USER_CODEBASE_DIR"]),
|
|
13
|
+
(".git", os.environ["ZIYA_USER_CODEBASE_DIR"]),
|
|
14
|
+
*[(pattern, os.environ["ZIYA_USER_CODEBASE_DIR"])
|
|
15
|
+
for pattern in os.environ["ZIYA_ADDITIONAL_EXCLUDE_DIRS"].split(',')
|
|
16
|
+
if pattern]
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
def read_gitignore(path: str) -> List[Tuple[str, str]]:
|
|
20
|
+
gitignore_patterns: List[Tuple[str, str]] = []
|
|
21
|
+
with open(path, "r") as f:
|
|
22
|
+
for line in f:
|
|
23
|
+
line = line.strip()
|
|
24
|
+
if line and not line.startswith("#"):
|
|
25
|
+
gitignore_patterns.append((line, os.path.dirname(path)))
|
|
26
|
+
return gitignore_patterns
|
|
27
|
+
|
|
28
|
+
def get_patterns_recursive(path: str) -> List[Tuple[str, str]]:
|
|
29
|
+
patterns: List[Tuple[str, str]] = []
|
|
30
|
+
gitignore_path = os.path.join(path, ".gitignore")
|
|
31
|
+
|
|
32
|
+
if os.path.exists(gitignore_path):
|
|
33
|
+
patterns.extend(read_gitignore(gitignore_path))
|
|
34
|
+
|
|
35
|
+
for subdir in glob.glob(os.path.join(path, "*/")):
|
|
36
|
+
patterns.extend(get_patterns_recursive(subdir))
|
|
37
|
+
|
|
38
|
+
return patterns
|
|
39
|
+
|
|
40
|
+
ignored_patterns.extend(get_patterns_recursive(directory))
|
|
41
|
+
return ignored_patterns
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_complete_file_list(user_codebase_dir: str, ignored_patterns: List[str]) -> List[str]:
|
|
45
|
+
should_ignore = parse_gitignore_patterns(ignored_patterns, base_dir=user_codebase_dir)
|
|
46
|
+
file_set: Set[str] = set()
|
|
47
|
+
|
|
48
|
+
for root, dirs, files in os.walk(user_codebase_dir):
|
|
49
|
+
# Filter out ignored directories
|
|
50
|
+
dirs[:] = [d for d in dirs if not should_ignore(os.path.join(root, d))]
|
|
51
|
+
|
|
52
|
+
for file in files:
|
|
53
|
+
file_path = os.path.join(root, file)
|
|
54
|
+
if not should_ignore(file_path):
|
|
55
|
+
file_set.add(file_path)
|
|
56
|
+
|
|
57
|
+
return list(file_set)
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from os.path import abspath, dirname
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Reversible, Union, List, Tuple
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def handle_negation(file_path, rules: Reversible["IgnoreRule"]):
|
|
11
|
+
for rule in reversed(rules):
|
|
12
|
+
if rule.match(file_path):
|
|
13
|
+
return not rule.negation
|
|
14
|
+
return False
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def parse_gitignore_patterns(patterns: List[Tuple[str, str]], base_dir=None):
|
|
18
|
+
if base_dir is None:
|
|
19
|
+
base_dir = os.getcwd()
|
|
20
|
+
rules = []
|
|
21
|
+
for counter, (pattern, directory) in enumerate(patterns, start=1):
|
|
22
|
+
rule = rule_from_pattern(pattern, base_path=_normalize_path(directory),
|
|
23
|
+
source=('in-memory', counter))
|
|
24
|
+
if rule:
|
|
25
|
+
rules.append(rule)
|
|
26
|
+
if not any(r.negation for r in rules):
|
|
27
|
+
return lambda file_path: any(r.match(file_path) for r in rules)
|
|
28
|
+
else:
|
|
29
|
+
# We have negation rules. We can't use a simple "any" to evaluate them.
|
|
30
|
+
# Later rules override earlier rules.
|
|
31
|
+
return lambda file_path: handle_negation(file_path, rules)
|
|
32
|
+
|
|
33
|
+
def rule_from_pattern(pattern, base_path=None, source=None):
|
|
34
|
+
"""
|
|
35
|
+
Take a .gitignore match pattern, such as "*.py[cod]" or "**/*.bak",
|
|
36
|
+
and return an IgnoreRule suitable for matching against files and
|
|
37
|
+
directories. Patterns which do not match files, such as comments
|
|
38
|
+
and blank lines, will return None.
|
|
39
|
+
Because git allows for nested .gitignore files, a base_path value
|
|
40
|
+
is required for correct behavior. The base path should be absolute.
|
|
41
|
+
"""
|
|
42
|
+
# Store the exact pattern for our repr and string functions
|
|
43
|
+
orig_pattern = pattern
|
|
44
|
+
# Early returns follow
|
|
45
|
+
# Discard comments and separators
|
|
46
|
+
if pattern.strip() == '' or pattern[0] == '#':
|
|
47
|
+
return
|
|
48
|
+
# Strip leading bang before examining double asterisks
|
|
49
|
+
if pattern[0] == '!':
|
|
50
|
+
negation = True
|
|
51
|
+
pattern = pattern[1:]
|
|
52
|
+
else:
|
|
53
|
+
negation = False
|
|
54
|
+
# Multi-asterisks not surrounded by slashes (or at the start/end) should
|
|
55
|
+
# be treated like single-asterisks.
|
|
56
|
+
pattern = re.sub(r'([^/])\*{2,}', r'\1*', pattern)
|
|
57
|
+
pattern = re.sub(r'\*{2,}([^/])', r'*\1', pattern)
|
|
58
|
+
|
|
59
|
+
# Special-casing '/', which doesn't match any files or directories
|
|
60
|
+
if pattern.rstrip() == '/':
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
directory_only = pattern[-1] == '/'
|
|
64
|
+
# A slash is a sign that we're tied to the base_path of our rule
|
|
65
|
+
# set.
|
|
66
|
+
anchored = '/' in pattern[:-1]
|
|
67
|
+
if pattern[0] == '/':
|
|
68
|
+
pattern = pattern[1:]
|
|
69
|
+
if pattern[0] == '*' and len(pattern) >= 2 and pattern[1] == '*':
|
|
70
|
+
pattern = pattern[2:]
|
|
71
|
+
anchored = False
|
|
72
|
+
if pattern[0] == '/':
|
|
73
|
+
pattern = pattern[1:]
|
|
74
|
+
if pattern[-1] == '/':
|
|
75
|
+
pattern = pattern[:-1]
|
|
76
|
+
# patterns with leading hashes or exclamation marks are escaped with a
|
|
77
|
+
# backslash in front, unescape it
|
|
78
|
+
if pattern[0] == '\\' and pattern[1] in ('#', '!'):
|
|
79
|
+
pattern = pattern[1:]
|
|
80
|
+
# trailing spaces are ignored unless they are escaped with a backslash
|
|
81
|
+
i = len(pattern)-1
|
|
82
|
+
striptrailingspaces = True
|
|
83
|
+
while i > 1 and pattern[i] == ' ':
|
|
84
|
+
if pattern[i-1] == '\\':
|
|
85
|
+
pattern = pattern[:i-1] + pattern[i:]
|
|
86
|
+
i = i - 1
|
|
87
|
+
striptrailingspaces = False
|
|
88
|
+
else:
|
|
89
|
+
if striptrailingspaces:
|
|
90
|
+
pattern = pattern[:i]
|
|
91
|
+
i = i - 1
|
|
92
|
+
regex = fnmatch_pathname_to_regex(
|
|
93
|
+
pattern, directory_only, negation, anchored=bool(anchored)
|
|
94
|
+
)
|
|
95
|
+
return IgnoreRule(
|
|
96
|
+
pattern=orig_pattern,
|
|
97
|
+
regex=regex,
|
|
98
|
+
negation=negation,
|
|
99
|
+
directory_only=directory_only,
|
|
100
|
+
anchored=anchored,
|
|
101
|
+
base_path=_normalize_path(base_path) if base_path else None,
|
|
102
|
+
source=source
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
IGNORE_RULE_FIELDS = [
|
|
107
|
+
'pattern', 'regex', # Basic values
|
|
108
|
+
'negation', 'directory_only', 'anchored', # Behavior flags
|
|
109
|
+
'base_path', # Meaningful for gitignore-style behavior
|
|
110
|
+
'source' # (file, line) tuple for reporting
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class IgnoreRule(collections.namedtuple('IgnoreRule_', IGNORE_RULE_FIELDS)):
|
|
115
|
+
def __str__(self):
|
|
116
|
+
return self.pattern
|
|
117
|
+
|
|
118
|
+
def __repr__(self):
|
|
119
|
+
return ''.join(['IgnoreRule(\'', self.pattern, '\')'])
|
|
120
|
+
|
|
121
|
+
def match(self, abs_path: Union[str, Path]):
|
|
122
|
+
matched = False
|
|
123
|
+
if self.base_path:
|
|
124
|
+
if str(abs_path).startswith(str(self.base_path)):
|
|
125
|
+
rel_path = str(_normalize_path(abs_path).relative_to(self.base_path))
|
|
126
|
+
else:
|
|
127
|
+
rel_path = str(_normalize_path(abs_path))
|
|
128
|
+
else:
|
|
129
|
+
rel_path = str(_normalize_path(abs_path))
|
|
130
|
+
# Path() strips the trailing slash, so we need to preserve it
|
|
131
|
+
# in case of directory-only negation
|
|
132
|
+
if self.negation and type(abs_path) == str and abs_path[-1] == '/':
|
|
133
|
+
rel_path += '/'
|
|
134
|
+
if rel_path.startswith('./'):
|
|
135
|
+
rel_path = rel_path[2:]
|
|
136
|
+
if re.search(self.regex, rel_path):
|
|
137
|
+
matched = True
|
|
138
|
+
return matched
|
|
139
|
+
|
|
140
|
+
# Frustratingly, python's fnmatch doesn't provide the FNM_PATHNAME
|
|
141
|
+
# option that .gitignore's behavior depends on.
|
|
142
|
+
def fnmatch_pathname_to_regex(
|
|
143
|
+
pattern, directory_only: bool, negation: bool, anchored: bool = False
|
|
144
|
+
):
|
|
145
|
+
"""
|
|
146
|
+
Implements fnmatch style-behavior, as though with FNM_PATHNAME flagged;
|
|
147
|
+
the path separator will not match shell-style '*' and '.' wildcards.
|
|
148
|
+
"""
|
|
149
|
+
i, n = 0, len(pattern)
|
|
150
|
+
|
|
151
|
+
seps = [re.escape(os.sep)]
|
|
152
|
+
if os.altsep is not None:
|
|
153
|
+
seps.append(re.escape(os.altsep))
|
|
154
|
+
seps_group = '[' + '|'.join(seps) + ']'
|
|
155
|
+
nonsep = r'[^{}]'.format('|'.join(seps))
|
|
156
|
+
|
|
157
|
+
res = []
|
|
158
|
+
while i < n:
|
|
159
|
+
c = pattern[i]
|
|
160
|
+
i += 1
|
|
161
|
+
if c == '*':
|
|
162
|
+
try:
|
|
163
|
+
if pattern[i] == '*':
|
|
164
|
+
i += 1
|
|
165
|
+
res.append('.*')
|
|
166
|
+
else:
|
|
167
|
+
res.append(''.join([nonsep, '*']))
|
|
168
|
+
except IndexError:
|
|
169
|
+
res.append(''.join([nonsep, '*']))
|
|
170
|
+
elif c == '?':
|
|
171
|
+
res.append(nonsep)
|
|
172
|
+
elif c == '/':
|
|
173
|
+
res.append(seps_group)
|
|
174
|
+
elif c == '[':
|
|
175
|
+
j = i
|
|
176
|
+
if j < n and pattern[j] == '!':
|
|
177
|
+
j += 1
|
|
178
|
+
if j < n and pattern[j] == ']':
|
|
179
|
+
j += 1
|
|
180
|
+
while j < n and pattern[j] != ']':
|
|
181
|
+
j += 1
|
|
182
|
+
if j >= n:
|
|
183
|
+
res.append('\\[')
|
|
184
|
+
else:
|
|
185
|
+
stuff = pattern[i:j].replace('\\', '\\\\').replace('/', '')
|
|
186
|
+
i = j + 1
|
|
187
|
+
if stuff[0] == '!':
|
|
188
|
+
stuff = ''.join(['^', stuff[1:]])
|
|
189
|
+
elif stuff[0] == '^':
|
|
190
|
+
stuff = ''.join('\\' + stuff)
|
|
191
|
+
res.append('[{}]'.format(stuff))
|
|
192
|
+
else:
|
|
193
|
+
res.append(re.escape(c))
|
|
194
|
+
if anchored:
|
|
195
|
+
res.insert(0, '^')
|
|
196
|
+
else:
|
|
197
|
+
# Handle leading slash patterns
|
|
198
|
+
if pattern.startswith('/'):
|
|
199
|
+
res.insert(0, '^')
|
|
200
|
+
else:
|
|
201
|
+
res.insert(0, f"(^|{seps_group})")
|
|
202
|
+
if not directory_only:
|
|
203
|
+
res.append('$')
|
|
204
|
+
elif directory_only and negation:
|
|
205
|
+
res.append('/$')
|
|
206
|
+
else:
|
|
207
|
+
res.append('($|\\/)')
|
|
208
|
+
return ''.join(res)
|
|
209
|
+
|
|
210
|
+
def _normalize_path(path: Union[str, Path]) -> Path:
|
|
211
|
+
"""Normalize a path without resolving symlinks.
|
|
212
|
+
|
|
213
|
+
This is equivalent to `Path.resolve()` except that it does not resolve symlinks.
|
|
214
|
+
Note that this simplifies paths by removing double slashes, `..`, `.` etc. like
|
|
215
|
+
`Path.resolve()` does.
|
|
216
|
+
"""
|
|
217
|
+
return Path(abspath(path))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
# Create and configure the logger
|
|
4
|
+
formatter = logging.Formatter("\033[35mZIYA\033[0m: %(message)s")
|
|
5
|
+
handler = logging.StreamHandler()
|
|
6
|
+
handler.setFormatter(formatter)
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
logger.setLevel(logging.INFO)
|
|
10
|
+
logger.addHandler(handler)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
def print_file_tree(file_paths):
|
|
4
|
+
# Create a dictionary to store files and directories
|
|
5
|
+
file_tree = {}
|
|
6
|
+
|
|
7
|
+
# Populate the file tree dictionary
|
|
8
|
+
for path in file_paths:
|
|
9
|
+
dir_path, file_name = os.path.split(path)
|
|
10
|
+
if dir_path not in file_tree:
|
|
11
|
+
file_tree[dir_path] = []
|
|
12
|
+
file_tree[dir_path].append(file_name)
|
|
13
|
+
|
|
14
|
+
# Sort directories and files
|
|
15
|
+
sorted_dirs = sorted(file_tree.keys())
|
|
16
|
+
for dir_path in sorted_dirs:
|
|
17
|
+
file_tree[dir_path].sort()
|
|
18
|
+
|
|
19
|
+
# Print the file tree recursively
|
|
20
|
+
def print_dir(dir_path, indent):
|
|
21
|
+
nonlocal printed_dirs
|
|
22
|
+
if dir_path in printed_dirs:
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
printed_dirs.add(dir_path)
|
|
26
|
+
print(f"{indent}{os.path.basename(dir_path)}")
|
|
27
|
+
if file_tree[dir_path]:
|
|
28
|
+
for i, file_name in enumerate(file_tree[dir_path]):
|
|
29
|
+
if i == len(file_tree[dir_path]) - 1:
|
|
30
|
+
print(f"{indent} └── {file_name}")
|
|
31
|
+
else:
|
|
32
|
+
print(f"{indent} ├── {file_name}")
|
|
33
|
+
else:
|
|
34
|
+
print(f"{indent} (empty)")
|
|
35
|
+
|
|
36
|
+
# Recursively print subdirectories
|
|
37
|
+
subdirs = [subdir for subdir in sorted_dirs if subdir.startswith(dir_path + os.sep)]
|
|
38
|
+
for subdir in subdirs:
|
|
39
|
+
print_dir(subdir, indent + " ")
|
|
40
|
+
|
|
41
|
+
printed_dirs = set()
|
|
42
|
+
for dir_path in sorted_dirs:
|
|
43
|
+
print_dir(dir_path, "")
|
pyproject.toml
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "ziya"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = ""
|
|
5
|
+
authors = ["Vishnu Krishnaprasad <vishnukool@gmail.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
include = ["static/**/*", "templates/**/*", "pyproject.toml"]
|
|
8
|
+
packages = [
|
|
9
|
+
{ include = "app" },
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[tool.poetry.dependencies]
|
|
13
|
+
python = ">=3.9,<4.0"
|
|
14
|
+
uvicorn = "^0.23.2"
|
|
15
|
+
pydantic = "<2"
|
|
16
|
+
jinja2 = "^3.1.3"
|
|
17
|
+
tiktoken = "^0.6.0"
|
|
18
|
+
boto3 = "^1.34.88"
|
|
19
|
+
langchain-aws = "^0.1.0"
|
|
20
|
+
langchain = "^0.1"
|
|
21
|
+
langchainhub = ">=0.1.15"
|
|
22
|
+
langchain-anthropic = "^0.1.4"
|
|
23
|
+
langchain-cli = ">=0.0.15"
|
|
24
|
+
|
|
25
|
+
[tool.poetry.group.dev.dependencies]
|
|
26
|
+
pydevd-pycharm = "^241.15989.57"
|
|
27
|
+
|
|
28
|
+
[build-system]
|
|
29
|
+
requires = ["poetry-core"]
|
|
30
|
+
build-backend = "poetry.core.masonry.api"
|
|
31
|
+
|
|
32
|
+
[tool.poetry.scripts]
|
|
33
|
+
ziya = 'app.main:main'
|
static/app.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const {useState, useRef, useEffect} = React;
|
|
2
|
+
|
|
3
|
+
const App = () => {
|
|
4
|
+
const [messages, setMessages] = useState([]);
|
|
5
|
+
const [question, setQuestion] = useState('');
|
|
6
|
+
const [streamedContent, setStreamedContent] = useState('');
|
|
7
|
+
const [isStreaming, setIsStreaming] = useState(false);
|
|
8
|
+
const inputTextareaRef = useRef(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (inputTextareaRef.current) {
|
|
12
|
+
inputTextareaRef.current.focus();
|
|
13
|
+
}
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
const handleSendPayload = async () => {
|
|
17
|
+
setQuestion('');
|
|
18
|
+
setIsStreaming(true);
|
|
19
|
+
setMessages((messages) => [...messages, {content: question, role: 'human'}]);
|
|
20
|
+
setStreamedContent('');
|
|
21
|
+
await window.sendPayload(messages, question, setStreamedContent, setIsStreaming);
|
|
22
|
+
setStreamedContent((cont) => {
|
|
23
|
+
setMessages((messages) => [...messages, {content: cont, role: 'assistant'}]);
|
|
24
|
+
return ""
|
|
25
|
+
});
|
|
26
|
+
inputTextareaRef.current.focus();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const handleChange = (event) => {
|
|
30
|
+
setQuestion(event.target.value);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div><h2 style={{textAlign: "center"}}>Ziya: Code Assist</h2>
|
|
35
|
+
<div className="container">
|
|
36
|
+
<InputContainer
|
|
37
|
+
inputTextareaRef={inputTextareaRef}
|
|
38
|
+
question={question}
|
|
39
|
+
handleChange={handleChange}
|
|
40
|
+
sendPayload={handleSendPayload}
|
|
41
|
+
isStreaming={isStreaming}
|
|
42
|
+
/>
|
|
43
|
+
{streamedContent || messages.length > 0 ? <div className="chat-container">
|
|
44
|
+
{streamedContent && <StreamedContent streamedContent={streamedContent}/>}
|
|
45
|
+
{messages.length > 0 && <ChatContainer messages={messages}/>}
|
|
46
|
+
</div> : null}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const ChatContainer = ({messages}) => (
|
|
53
|
+
<div>
|
|
54
|
+
{messages.slice().reverse().map((msg, index) => (
|
|
55
|
+
<div key={index} className={`message ${msg.role}`}>
|
|
56
|
+
{msg.role === 'human' ? <div className="message-sender">You:</div> :
|
|
57
|
+
<div className="message-sender">AI:</div>}
|
|
58
|
+
<MarkdownRenderer markdown={msg.content}/>
|
|
59
|
+
</div>
|
|
60
|
+
))}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const isQuestionEmpty = (input) => input.trim().length === 0;
|
|
65
|
+
|
|
66
|
+
const StreamedContent = ({streamedContent}) => (
|
|
67
|
+
<div className="message assistant">
|
|
68
|
+
<div className="message-sender">AI:</div>
|
|
69
|
+
<MarkdownRenderer markdown={streamedContent}/>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
const InputContainer = ({question, handleChange, sendPayload, isStreaming, inputTextareaRef}) => (
|
|
73
|
+
|
|
74
|
+
<div className="input-container">
|
|
75
|
+
<textarea
|
|
76
|
+
ref={inputTextareaRef}
|
|
77
|
+
value={question}
|
|
78
|
+
onChange={handleChange}
|
|
79
|
+
placeholder="Enter your question.."
|
|
80
|
+
rows={3}
|
|
81
|
+
className="input-textarea"
|
|
82
|
+
onKeyDown={(event) => {
|
|
83
|
+
if (event.key === 'Enter' && !event.shiftKey && !isQuestionEmpty(question)) {
|
|
84
|
+
event.preventDefault(); // Prevent the default behavior of adding a new line
|
|
85
|
+
sendPayload();
|
|
86
|
+
}
|
|
87
|
+
}}
|
|
88
|
+
/>
|
|
89
|
+
<button onClick={sendPayload} disabled={isStreaming || isQuestionEmpty(question)} className="send-button">
|
|
90
|
+
{isStreaming ? `Sending..` : `Send`}
|
|
91
|
+
</button>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const MarkdownRenderer = ({markdown}) => {
|
|
96
|
+
const renderMarkdown = () => {
|
|
97
|
+
const html = marked.parse(markdown);
|
|
98
|
+
return {__html: html};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return <div dangerouslySetInnerHTML={renderMarkdown()}/>;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
ReactDOM.render(<App/>, document.getElementById('root'));
|
static/favicon.ico
ADDED
|
Binary file
|
static/sendPayload.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
async function getApiResponse(messages, question) {
|
|
2
|
+
const messageTuples = [];
|
|
3
|
+
let tempArray = [];
|
|
4
|
+
for (let i = 0; i < messages.length; i++) {
|
|
5
|
+
tempArray.push(messages[i].content);
|
|
6
|
+
if (tempArray.length === 2) {
|
|
7
|
+
messageTuples.push(tempArray);
|
|
8
|
+
tempArray = [];
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const response = await fetch('/ziya/stream_log', {
|
|
12
|
+
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
13
|
+
body: JSON.stringify({
|
|
14
|
+
input: {
|
|
15
|
+
chat_history: messageTuples,
|
|
16
|
+
question: question,
|
|
17
|
+
},
|
|
18
|
+
config: {},
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
return response;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const processLine = (line, setStreamedContent) => {
|
|
25
|
+
const data = JSON.parse(line.slice(6));
|
|
26
|
+
const streamedOutputOp = data.ops.find(
|
|
27
|
+
(op) => op.op === 'add' && op.path === '/logs/ChatBedrock/streamed_output_str/-'
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (streamedOutputOp) {
|
|
31
|
+
setStreamedContent((prevContent) => prevContent + streamedOutputOp.value);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
window.sendPayload = async (messages, question, setStreamedContent, setIsStreaming) => {
|
|
36
|
+
try {
|
|
37
|
+
const response = await getApiResponse(messages, question);
|
|
38
|
+
const reader = response.body.getReader();
|
|
39
|
+
|
|
40
|
+
const processData = async ({done, value}) => {
|
|
41
|
+
if (done) {
|
|
42
|
+
setIsStreaming(false);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
let buffer = '';
|
|
46
|
+
buffer += new TextDecoder('utf-8').decode(value);
|
|
47
|
+
const lines = buffer.split('\n');
|
|
48
|
+
buffer = lines.pop() || '';
|
|
49
|
+
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
if (line.startsWith('data: ')) {
|
|
52
|
+
processLine(line, setStreamedContent);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
await reader.read().then(processData);
|
|
56
|
+
};
|
|
57
|
+
await reader.read().then(processData);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(error);
|
|
60
|
+
setIsStreaming(false);
|
|
61
|
+
}
|
|
62
|
+
};
|
static/ziya.css
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/* General Styles */
|
|
2
|
+
body {
|
|
3
|
+
font-family: Arial, sans-serif;
|
|
4
|
+
margin: 0;
|
|
5
|
+
padding: 0;
|
|
6
|
+
background-color: #f5f5f5;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.container {
|
|
10
|
+
max-width: 800px;
|
|
11
|
+
margin: 0 auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
background-color: #fff;
|
|
14
|
+
border-radius: 8px;
|
|
15
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Chat Container */
|
|
19
|
+
.chat-container {
|
|
20
|
+
height: fit-content;
|
|
21
|
+
overflow-y: scroll;
|
|
22
|
+
padding: 10px;
|
|
23
|
+
border: 1px solid #ccc;
|
|
24
|
+
border-radius: 4px;
|
|
25
|
+
margin: 20px 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.message {
|
|
29
|
+
padding: 10px;
|
|
30
|
+
border-radius: 8px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.message.human {
|
|
34
|
+
background-color: #efefef;
|
|
35
|
+
align-self: flex-start;
|
|
36
|
+
margin-right: auto;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.message.ai {
|
|
40
|
+
background-color: #f0f0f0;
|
|
41
|
+
align-self: flex-end;
|
|
42
|
+
margin-left: auto;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.message-sender {
|
|
46
|
+
font-weight: bold;
|
|
47
|
+
margin-bottom: 5px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Input Container */
|
|
51
|
+
.input-container {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.input-textarea {
|
|
57
|
+
flex-grow: 1;
|
|
58
|
+
padding: 10px;
|
|
59
|
+
border: 1px solid #ccc;
|
|
60
|
+
border-radius: 4px;
|
|
61
|
+
resize: none;
|
|
62
|
+
font-size: 16px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.send-button {
|
|
66
|
+
margin-left: 10px;
|
|
67
|
+
padding: 10px 20px;
|
|
68
|
+
background-color: #007bff;
|
|
69
|
+
color: #fff;
|
|
70
|
+
border: none;
|
|
71
|
+
border-radius: 4px;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
font-size: 16px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.send-button:disabled {
|
|
77
|
+
background-color: #ccc;
|
|
78
|
+
cursor: not-allowed;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Streamed Content */
|
|
82
|
+
.streamed-content {
|
|
83
|
+
margin-top: 20px;
|
|
84
|
+
padding: 10px;
|
|
85
|
+
border: 1px solid #ccc;
|
|
86
|
+
border-radius: 4px;
|
|
87
|
+
background-color: #f0f0f0;
|
|
88
|
+
}
|
templates/index.html
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Ziya - Code Assistant</title>
|
|
7
|
+
<link rel="stylesheet" href="/static/ziya.css">
|
|
8
|
+
<link rel="icon" href="/static/favicon.ico" type="image/x-icon">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"/>
|
|
12
|
+
<script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
|
|
13
|
+
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
|
|
14
|
+
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
|
|
15
|
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
16
|
+
<script type="text/babel" src="/static/sendPayload.js"></script>
|
|
17
|
+
<script type="text/babel" src="/static/app.js"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 LangChain, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ziya
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary:
|
|
5
|
+
Author: Vishnu Krishnaprasad
|
|
6
|
+
Author-email: vishnukool@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
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Requires-Dist: boto3 (>=1.34.88,<2.0.0)
|
|
14
|
+
Requires-Dist: jinja2 (>=3.1.3,<4.0.0)
|
|
15
|
+
Requires-Dist: langchain (>=0.1,<0.2)
|
|
16
|
+
Requires-Dist: langchain-anthropic (>=0.1.4,<0.2.0)
|
|
17
|
+
Requires-Dist: langchain-aws (>=0.1.0,<0.2.0)
|
|
18
|
+
Requires-Dist: langchain-cli (>=0.0.15)
|
|
19
|
+
Requires-Dist: langchainhub (>=0.1.15)
|
|
20
|
+
Requires-Dist: pydantic (<2)
|
|
21
|
+
Requires-Dist: tiktoken (>=0.6.0,<0.7.0)
|
|
22
|
+
Requires-Dist: uvicorn (>=0.23.2,<0.24.0)
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Ziya
|
|
26
|
+
|
|
27
|
+
Ziya is a code assist tool for AWS Bedrock models. It can read your entire codebase and answer questions.
|
|
28
|
+
|
|
29
|
+
The current version only performs read operations. However, future versions will be able to:
|
|
30
|
+
|
|
31
|
+
1. Write and edit code.
|
|
32
|
+
2. Search the web for resources.
|
|
33
|
+
3. Run commands locally.
|
|
34
|
+
4. Iteratively continue to do 1,2,3 for a given objective.
|
|
35
|
+
|
|
36
|
+
## Pre-requisites
|
|
37
|
+
### Setup AWS credentials:
|
|
38
|
+
The easiest way is to set the env variables with access to AWS Bedrock claude models.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export AWS_ACCESS_KEY_ID=<YOUR-KEY>
|
|
42
|
+
export AWS_SECRET_ACCESS_KEY=<YOUR-SECRET>
|
|
43
|
+
```
|
|
44
|
+
### Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install ziya
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Run Ziya
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ziya
|
|
54
|
+
```
|
|
55
|
+
Then navigate to http://localhost:6969 in your browser and start chatting with your codebase.
|
|
56
|
+
|
|
57
|
+
When you ask a question Ziya sends your entire codebase as context to the LLM, along with your question and any chat history.
|
|
58
|
+
```
|
|
59
|
+
> Entering new AgentExecutor chain...
|
|
60
|
+
Reading user's current codebase: /Users/vkrishnaprasad/personal_projects/ziya
|
|
61
|
+
ziya
|
|
62
|
+
├── .gitignore
|
|
63
|
+
├── DEVELOPMENT.md
|
|
64
|
+
├── LICENSE
|
|
65
|
+
├── README.md
|
|
66
|
+
└── pyproject.toml
|
|
67
|
+
app
|
|
68
|
+
├── __init__.py
|
|
69
|
+
├── main.py
|
|
70
|
+
└── server.py
|
|
71
|
+
...
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Options
|
|
75
|
+
|
|
76
|
+
`--exclude`: Comma-separated list of files or directories to exclude from the codebase.
|
|
77
|
+
|
|
78
|
+
`--profile`: AWS profile to use for the Bedrock LLM.
|
|
79
|
+
|
|
80
|
+
`--model`: The AWS Bedrock Model to use, one of `haiku`(default), `sonnet` or `opus`.
|
|
81
|
+
|
|
82
|
+
`--port`: The port number for frontend app. Default is `6969`.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
ziya --exclude='tst,build,*.py' --profile=ziya --model=sonnet --port=8080
|
|
86
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
app/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
app/agents/agent.py,sha256=k0e0GMKFfU6-3e-GyAX95R9iV3sWwvLknL1gxd3TO88,4181
|
|
4
|
+
app/agents/prompts.py,sha256=O54rH2KupyY7ZSjPEvm3j9DSGjdL3jJOz8F9PTcePQQ,1674
|
|
5
|
+
app/main.py,sha256=blgAdLjoMa2HRqlr17lwbZ3hQYz2jUZJwu18KLI9FiQ,1359
|
|
6
|
+
app/server.py,sha256=YTEHYUsFQhgkGRHZ_y7K3Ju3SmUIbVxLSdgrgi1BuEU,676
|
|
7
|
+
app/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
app/utils/directory_util.py,sha256=XOImpzqVa2NrIAPl054VN2WC4kk1QUIE4COEL062ULw,2132
|
|
9
|
+
app/utils/gitignore_parser.py,sha256=ksAAvXr8_GFh94cvOdkLmES5k3xxNxW2_tQuQtialIA,7496
|
|
10
|
+
app/utils/logging_utils.py,sha256=8JEcc1t7L-a0G4HLmM8zFydNNSOd5l2-gkTxviLQUns,280
|
|
11
|
+
app/utils/print_tree_util.py,sha256=O4Rb-GS8UODxfH7Z6bZGsr-opG6QLmvdaU1im5kh4IA,1419
|
|
12
|
+
pyproject.toml,sha256=p35kypx9MscMQR1a_MWhgKOr764YZJOlNa9FW7s0Wrw,716
|
|
13
|
+
static/app.js,sha256=qz2F0e5LxuVFI3MXWvcON9l1cN0J_ODdQOwbgT3ZqWA,3622
|
|
14
|
+
static/favicon.ico,sha256=HgB8xAZdDHFK2lODUsp2H_Dds_i14pnpydx7NEJrNrU,15086
|
|
15
|
+
static/sendPayload.js,sha256=VnypSWF7t8bv83026LGU3GMyr9tMrp05hmWATcbCG4k,1956
|
|
16
|
+
static/ziya.css,sha256=OaieSXw_7LOk0WNNi-1mPsAaS3rOxhHycKFgFDoiZB0,1395
|
|
17
|
+
templates/index.html,sha256=8auy9lGLdcDzBkzpjYB1ygrAVbXpo0rqQ8p1FgMEeck,800
|
|
18
|
+
ziya-0.1.0.dist-info/LICENSE,sha256=DppmdYJVSc1jd0aio6ptnMUn5tIHrdAhQ12SclEBfBg,1072
|
|
19
|
+
ziya-0.1.0.dist-info/METADATA,sha256=V8cWv_zwPjFzBheptnTXc7wimA2x3Pdz8iu4ApLJNgk,2472
|
|
20
|
+
ziya-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
21
|
+
ziya-0.1.0.dist-info/entry_points.txt,sha256=1HspxMqCYRli3SqM6CqmT6gsW_G14G4ab3sHlrYUCAA,38
|
|
22
|
+
ziya-0.1.0.dist-info/RECORD,,
|