diff --git a/.gitignore b/.gitignore index c6bba59..edc04f8 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,12 @@ pids *.seed *.pid.lock +# Ignore Python cache directories +__pycache__/ + +# Ignore compiled Python files +*.pyc + # Directory for instrumented libs generated by jscoverage/JSCover lib-cov @@ -44,6 +50,8 @@ jspm_packages/ # Snowpack dependency directory (https://snowpack.dev/) web_modules/ +backend/env/ +.venv # TypeScript cache *.tsbuildinfo diff --git a/backend/crud.py b/backend/crud.py new file mode 100644 index 0000000..766241f --- /dev/null +++ b/backend/crud.py @@ -0,0 +1,7 @@ +import mongoConnect as mc + +if __name__ == "__main__": + uri = "mongodb+srv://wangyukun721:ii4GZUByt7WrDxLL@cluster0.ld92j.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0" + + with mc.connect_to_mongoDB(uri) as client: + mc.upload(r'C:\Users\81548\OneDrive\文档\GitHub\Team-JSSH-HTV9\backend\test.txt', client) \ No newline at end of file diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000..f40cfa8 --- /dev/null +++ b/backend/main.py @@ -0,0 +1,150 @@ +import os +from fastapi import FastAPI +# import autogen +import logging +from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager +from mongoConnect import router + + +app = FastAPI() +app.include_router(router) + + +# logging.basicConfig(level=logging.INFO) +# logger = logging.getLogger(__name__) +os.environ["OPENAI_API_KEY"] = "" + +default_name_list = ["Critical Analyst", "The Problem-Solving Specialist", "The Creative Writer"] +default_system_prompt = [ + "You are a critical analyst with expertise in breaking down complex ideas. When given a topic, your role is to dissect arguments, present pros and cons, and offer a balanced perspective. Stay logical, precise, and thorough in your evaluations.", + "You are an expert in problem-solving. Your goal is to help users find effective solutions to challenges they present. Focus on identifying key issues, providing clear steps, and considering practical constraints to offer actionable advice.", + "You are a creative writer specializing in storytelling. Your task is to generate imaginative narratives or metaphors based on any topic or question presented. Use vivid descriptions, evoke emotions, and bring ideas to life with creativity." + ] + +config_list = [{ + "model": "gpt-4", + "api_key": os.environ["OPENAI_API_KEY"] +}] + +llm_config_openai = { + "config_list": config_list, + "temperature": 0 +} + +input = { + "agents": [ + { + "name": "Coder", + "system_prompt": "You are a coder." + }, + { + "name": "Product_manager", + "system_prompt": "Creative in software product ideas." + }, + { + "name": "security", + "system_prompt": "You act as a proxy for the user, forwarding their requests to the system and managing responses." + } + ] + } + +def create_assistant_agent(name=default_name_list[1], system_message=default_system_prompt[1]): + assistant = AssistantAgent( + name=name, + llm_config=llm_config_openai, + system_message=system_message + ) + return assistant + + +# Function to create a UserProxyAgent +def create_user_proxy_agent(name=default_name_list[2], system_message=default_system_prompt[2]): + system_message += """Reply TERMINATE if the task has been solved at full satisfaction. +Otherwise, reply CONTINUE, or the reason why the task is not solved yet.""" + user_proxy = UserProxyAgent( + name=name, + human_input_mode="NEVER", + is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"), + code_execution_config={"work_dir": "web", "use_docker": False}, + llm_config=llm_config_openai, + system_message=system_message + ) + return user_proxy + + +# Define a POST endpoint to receive the agent definitions +@app.post("/agents/") +async def receive_agents(agents_request: dict): + + agents = agents_request["agents"] + + task = agents_request["prompt"] + + created_agents = [] + + user_proxy = "" + + for agent in agents: + if agent["name"].lower() == "security": + # Create an assistant agent + user_proxy = create_user_proxy_agent(name=agent["name"], + system_message=agent["system_prompt"]) + # print(agent["name"]) + # print(agent["system_prompt"]) + # created_agents.append(user_proxy) + elif agent["name"].lower() != "security": + # Create a user proxy agent + created_agent = create_assistant_agent(name=agent["name"], + system_message=agent["system_prompt"]) + # print(agent["name"]) + # print(agent["system_prompt"]) + created_agents.append(created_agent) + else: + return {"error": "Unknown agent type"} + + # logger.info("Created agents: %s", created_agents) + + # return {"message": "Agents created successfully", "agents": "created_agents", "user_proxy": "user_proxy"} + # return {"message": "Agents created successfully", "agents": agents} + groupchat = GroupChat( + agents=created_agents, + messages=[], + max_round=20, + speaker_selection_method='round_robin' + ) + + manager = GroupChatManager(groupchat=groupchat, llm_config=llm_config_openai) + + result = user_proxy.initiate_chat( + manager, + message=task + ) + result_text = groupchat.messages + # chat_history_list = str(result_text) + chat_history_list = result_text + # chat_history_list = [{'content': '\nTell me about the meaning of life\n', 'role': 'user', 'name': 'security'}, {'content': "I'm here to assist with coding-related questions. If you have any coding tasks or questions, feel free to ask!", 'role': 'user', 'name': 'Coder'}, {'content': 'How about a software product that helps users track and manage their digital footprint and online security? It could provide insights into what personal information is available online, offer suggestions for improving privacy settings, and alert users to potential security risks. Users could also receive tips on how to enhance their online security practices. What do you think?', 'role': 'user', 'name': 'Product_manager'}, {'content': "That sounds like a valuable and relevant software product idea! It addresses a growing concern for many users about their online privacy and security. Implementing features like tracking personal information online, providing privacy setting suggestions, and offering security risk alerts can be very beneficial. Additionally, providing tips to enhance online security practices can help users better protect themselves. It's important to consider user-friendly interfaces and clear communication of the benefits to attract and retain users. If you need help with the technical aspects or development of this product, feel free to ask!", 'role': 'user', 'name': 'Coder'}, {'content': "Great to hear that you find the software product idea valuable! If you have any specific technical questions or need assistance with the development of this product, feel free to ask. I'm here to help with any coding-related tasks or challenges you may encounter along the way.", 'role': 'user', 'name': 'Product_manager'}, {'content': 'TERMINATE', 'role': 'user', 'name': 'Coder'}] + + names = [] + for item in chat_history_list: + names.append(item['name']) + + json_data = {} + round = 1 + name_have_seen = [] + json_data[f"round-{round}"] = {} + # begin with "round" + round to combine to a string + for i in range(len(chat_history_list)): + if not chat_history_list[i]['name'] in name_have_seen: + name_have_seen.append(chat_history_list[i]['name']) + json_data[f"round-{round}"][chat_history_list[i]['name']] = chat_history_list[i]['content'] + else: + name_have_seen = [] + round += 1 + json_data[f"round-{round}"] = {} + + return {"conversation_summary": json_data} + + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="127.0.0.1", port=8000) \ No newline at end of file diff --git a/backend/mongoConnect.py b/backend/mongoConnect.py new file mode 100644 index 0000000..4bc7101 --- /dev/null +++ b/backend/mongoConnect.py @@ -0,0 +1,132 @@ +import pprint +import ast +from fastapi import APIRouter + +from pymongo import MongoClient +import pymongo +from bson.objectid import ObjectId +from pydantic import BaseModel + +class MeetingRecord(BaseModel): + name: str + role: str + content: str + +router = APIRouter() + + +def connect_to_mongoDB(uri): + try: + client = MongoClient(uri, server_api=pymongo.server_api.ServerApi( + version="1", strict=True, deprecation_errors=True)) + # end example code here + client.admin.command("ping") + print("Connected successfully") + return client + + except Exception as e: + raise Exception( + "The following error occurred: ", e) +def read_and_parse_file(file_path): + """ + Safely reads a string from a text file and converts it into a list of dictionaries. + + :param file_path: The path to the text file containing the string representation of a list of dictionaries. + :return: A list of dictionaries if parsing is successful, otherwise None. + """ + try: + # Step 1: Read the file content + with open(file_path, 'r', encoding='utf-8') as file: + file_content = file.read() + + # Step 2: Safely parse the content using ast.literal_eval + data = ast.literal_eval(file_content) + + # Ensure that the parsed data is indeed a list of dictionaries + if isinstance(data, list) and all(isinstance(item, dict) for item in data): + return data + else: + raise ValueError("Parsed content is not a list of dictionaries.") + + except (SyntaxError, ValueError, IOError) as e: + print(f"An error occurred while reading or parsing the file: {e}") + return None + +def upload_txt (fp, client): + db = client.history + history_collection = db.singleton + content = read_and_parse_file(fp) + for dictionary in content: + db.singleton.insert_one(dictionary) + print("upload success") + +def upload_json(jsonFile, client): + db = client.history + history_collection = db.singleton + for dictionary in jsonFile: + db.singleton.insert_one(dictionary) + print("upload success") + +def format_meeting_records(documents): + """ + Converts a list of MongoDB documents into a human-readable string format, + separating each meeting by the 'TERMINATE' marker and formatting each speaker's content. + + :param documents: List of dictionaries containing 'content', 'role', and 'name'. + :return: A string that organizes the content into separate meetings, formatted for readability. + """ + meetings = [] + current_meeting = [] + + for document in documents: + content = document['content'].strip() + role = document['role'] + name = document['name'] + + # If the document's content is 'TERMINATE', finalize the current meeting and start a new one + if content == 'TERMINATE': + meetings.append('\n'.join(current_meeting)) # Finalize the current meeting + current_meeting = [] # Reset for the next meeting + else: + # Format each speaker's contribution + formatted_entry = f"{name} ({role}):\n{content}\n" + current_meeting.append(formatted_entry) + + # If there's leftover content after the last 'TERMINATE', finalize it + if current_meeting: + meetings.append('\n'.join(current_meeting)) + + # Combine all meetings with a separator between them + formatted_output = "\n\n=== New Meeting ===\n\n".join(meetings) + + return formatted_output + +@router.get("/read_history/") +async def download_from_db(client = None): # Dependency injection + """ + Downloads the entire meeting history from MongoDB and returns it as a formatted string. + """ + + if client is None: + # Connect to MongoDB if client is not provided through dependency injection + client = connect_to_mongoDB(uri="mongodb+srv://wangyukun721:@cluster0.ld92j.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0") + db = client.history + history_collection = db.singleton + result = history_collection.find({}, {"content": 1, "role": 1, "name": 1, "_id": 0}) # Project relevant fields + meetings = format_meeting_records(result) + # Close the connection if not using dependency injection + if client is not None: + client.close() + + return meetings + + +if __name__ == "__main__": + uri = "mongodb+srv://wangyukun721:@cluster0.ld92j.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0" + + # with connect_to_mongoDB(uri) as client: + # meetings = download_from_db(client) + # print(meetings) + # client.close() + + \ No newline at end of file diff --git a/backend/test.txt b/backend/test.txt new file mode 100644 index 0000000..747f412 --- /dev/null +++ b/backend/test.txt @@ -0,0 +1 @@ +[{'content': '\nwrite a code to comput the factorial of a numbers\n', 'role': 'assistant', 'name': 'user_proxy'}, {'content': 'Sure, here is a Python code to compute the factorial of a number:\n\n```python\ndef factorial(n):\n if n == 0:\n return 1\n else:\n return n * factorial(n-1)\n\nnumber = 5\nresult = factorial(number)\nprint(f"The factorial of {number} is {result}")\n```\n\nThis code defines a recursive function `factorial` that calculates the factorial of a given number `n`. It then calculates the factorial of 5 and prints the result.', 'name': 'Sam', 'role': 'user'}, {'content': 'The code provided by Sam looks correct. It defines a recursive function to calculate the factorial of a number and then calculates the factorial of 5. The code should work as expected.\n\nDo you need any further assistance with this code?', 'name': 'John', 'role': 'user'}, {'content': 'exitcode: 0 (execution succeeded)\nCode output: \nThe factorial of 5 is 120\n', 'role': 'assistant', 'name': 'user_proxy'}, {'content': "Great! I'm glad the code worked as expected. If you have any more questions or need further assistance in the future, feel free to ask.", 'name': 'Sam', 'role': 'user'}, {'content': "I'm glad to hear that the code worked correctly. If you have any more questions or need assistance in the future, feel free to reach out. Have a great day!", 'name': 'John', 'role': 'user'}, {'content': 'TERMINATE', 'role': 'assistant', 'name': 'user_proxy'}] \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..8561181 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,163 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Ignore Python cache directories +__pycache__/ + +# Ignore compiled Python files +*.pyc + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ +backend/env/ +.venv + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* +