Skip to content

Commit

Permalink
feat: integrate backend
Browse files Browse the repository at this point in the history
  • Loading branch information
vophihungvn committed Aug 7, 2024
1 parent fbe1b11 commit c181aa8
Show file tree
Hide file tree
Showing 14 changed files with 4,685 additions and 223 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ examples/**/*.json
!examples/**/package.json
!examples/**/package-lock.json


# Exception
!examples/semiconductor/semiconductor-ui/api/poetry.lock

.openssa/
test*.ipynb
tmp/
9 changes: 5 additions & 4 deletions examples/semiconductor/semiconductor-ui/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM --platform=linux/amd64 python:3.10-slim AS base
FROM --platform=linux/amd64 python:3.12-slim AS base

# Install Poetry
RUN apt update -y && apt upgrade -y && apt install git -y
RUN apt update -y && apt install poppler-utils -y
RUN python -m pip install --upgrade pip && \
pip install --no-cache-dir poetry==1.3.2
Expand All @@ -11,15 +12,15 @@ RUN poetry config virtualenvs.in-project true && \

WORKDIR /api

COPY pyproject.toml /api/
COPY pyproject.toml poetry.lock /api/

# =======================================
# Build image
FROM base AS build

ENV POETRY_REQUESTS_TIMEOUT=300
ENV PIP_DEFAULT_TIMEOUT=300
RUN poetry install


# =======================================
# App image
FROM base AS app
Expand Down
35 changes: 35 additions & 0 deletions examples/semiconductor/semiconductor-ui/api/data_and_knowledge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from dotenv import load_dotenv
import yaml

if TYPE_CHECKING:
from openssa.core.programming.hierarchical.plan import HTPDict


load_dotenv()


EXPERT_KNOWLEDGE_FILE_PATH: Path = Path(__file__).parent / 'expert-knowledge.txt'
with open(file=EXPERT_KNOWLEDGE_FILE_PATH,
buffering=-1,
encoding='utf-8',
errors='strict',
newline=None,
closefd=True,
opener=None) as f:
EXPERT_KNOWLEDGE: str = f.read()


EXPERT_PROGRAM_SPACE_FILE_PATH: Path = Path(__file__).parent / 'expert-program-space.yml'
with open(file=EXPERT_PROGRAM_SPACE_FILE_PATH,
buffering=-1,
encoding='utf-8',
errors='strict',
newline=None,
closefd=True,
opener=None) as f:
EXPERT_PROGRAM_SPACE: dict[str, HTPDict] = yaml.safe_load(stream=f)
62 changes: 62 additions & 0 deletions examples/semiconductor/semiconductor-ui/api/expert-knowledge.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
Etching Silicon Dioxide (SiO2): typical recipe(s)
=================================================

If using Inductively Coupled Plasma (ICP) Reactive Ion Etching (RIE)
--------------------------------------------------------------------


GASES & FLOW RATES:

Common gas is CHF3, often mixed with small amount of Ar and/or O2:
- CHF3 provides fluorine for etching while also polymerising to provide sidewall protection, improving anisotropy
- Ar helps maintain stable plasma
- O2 enhances volatility of etch products

Typical starting point:
- 20-50 sccm of CHF3
- 5-10 sccm of Ar
- 2-5 sccm of O2


ICP POWER:

Higher ICP power (e.g., 500-1000W) increases plasma density and etch rate
BUT may also lead to more physical damage and less anisotropic profiles


RF POWER:

Lower RF power (e.g., 10-50W) provides more anisotropic profiles


PRESSURE:

Lower pressure (e.g., 5-20 mTorr) helps improve anisotropy


ETCH TIME:

You need to adjust etch time depending on desired depth and etch rate.

Remember that etch rate can vary across wafer and over time, so it's best to overestimate time and measure depth periodically.


END-POINT DETECTION:

Many RIE systems have optical emission spectroscopy (OES) or interferometry for end-point detection.
These can stop etching process when desired depth is reached.


OPTIMIZATION CONSIDERATIONS:

- Etch rate
- Selectivity to mask and underlying layers
- Etch profile (anisotropy)
- Uniformity
- Physical or chemical damage


SAFETY PROCEDURES:

- Always follow safety procedures when working with plasma etching systems and handling gases
- Confirm with facility and equipment manager that your planned recipe is compatible and won't cause any damage or contamination
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
plan:
task: |-
For etching PECVD SiO2 using Inductively Coupled Plasma (ICP) Reactive Ion Etching (RIE),
recommend 2 good parameter sets and their relative advantages/disadvantages
sub-htps:
- task: |-
Get typical gases used for such process and their flow rate ranges
in SiO2 etching using Inductively Coupled Plasma (ICP) Reactive Ion Etching (RIE)
- task: |-
Get typical ICP Power, RF Power and Pressure value ranges and associated trade-offs
in SiO2 etching using Inductively Coupled Plasma (ICP) Reactive Ion Etching (RIE)
- task: |-
Recommend 2 parameter sets (each including Flow Rate for each Gas, plus ICP Power, RF Power and Pressure)
with analysis of their relative pros and cons.
63 changes: 51 additions & 12 deletions examples/semiconductor/semiconductor-ui/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,36 @@
from fastapi.middleware.cors import CORSMiddleware
from collections import defaultdict
import openai
from openssa import Agent, ProgramSpace, HTP, HTPlanner, OpenAILM


# pylint: disable=wrong-import-order
from data_and_knowledge import EXPERT_PROGRAM_SPACE, EXPERT_KNOWLEDGE
from semikong_lm import SemiKongLM


def get_or_create_agent(
use_semikong_lm: bool = True, max_depth=2, max_subtasks_per_decomp=4
) -> Agent:
lm = (SemiKongLM if use_semikong_lm else OpenAILM).from_defaults()

program_space = ProgramSpace(lm=lm)
if EXPERT_PROGRAM_SPACE:
for program_name, htp_dict in EXPERT_PROGRAM_SPACE.items():
htp = HTP.from_dict(htp_dict)
program_space.add_or_update_program(
name=program_name, description=htp.task.ask, program=htp
)

return Agent(
program_space=program_space,
programmer=HTPlanner(
lm=lm, max_depth=max_depth, max_subtasks_per_decomp=max_subtasks_per_decomp
),
knowledge={EXPERT_KNOWLEDGE} if EXPERT_KNOWLEDGE else None,
resources={},
)


app = FastAPI()

Expand All @@ -14,18 +44,23 @@
allow_headers=["*"],
)

client = openai.OpenAI(api_key=os.environ['OPENAI_API_KEY'])
client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])


def call_gpt(prompt):
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are an expert in parsing text into a specific format. Please help me with this task."},
{"role": "user", "content": prompt}
]
{
"role": "system",
"content": "You are an expert in parsing text into a specific format. Please help me with this task.",
},
{"role": "user", "content": prompt},
],
)
return response.choices[0].message.content


def parse_recipe_text(text):
parsed_data = {"recipe_1": "", "recipe_2": "", "agent_advice": ""}
lines = text.split("\n")
Expand All @@ -44,14 +79,17 @@ def parse_recipe_text(text):
parsed_data = {key: value.strip() for key, value in parsed_data.items()}
return parsed_data


def solve_semiconductor_question(question):
solutions = defaultdict(str)

solutions[question] = get_or_create_agent(use_semikong_lm=True).solve(problem=question)
solutions[question] = get_or_create_agent(use_semikong_lm=True).solve(
problem=question
)

solution = solutions[question]
solution = solution.replace('$', r'\$')
solution = solution.replace("$", r"\$")

prompt = f"""{solution} \n\n Please help me parse the above text into this format:\n
recipe_1: Show the recipe 1 here\n
recipe_2: Show the recipe 2 here\n
Expand All @@ -62,25 +100,26 @@ def solve_semiconductor_question(question):
parsed_solution = parse_recipe_text(solution)
return parsed_solution


@app.get("/")
async def root():
return {"message": "Hello World"}


@app.get("/data")
async def get_data():
return {"data": "data"}


@app.post("/data")
async def post_data(request: Request):
data = await request.json()
question = data.get('question')
async def post_data(data: dict):
question = data.get("question")
if not question:
return {"error": "No question provided"}, 400

try:
parsed_answer = solve_semiconductor_question(question)
return parsed_answer
except Exception as e:
logger.error(f"Error solving the question: {e}")
print(f"Error solving the question: {e}")
return {"error": str(e)}, 500

Loading

0 comments on commit c181aa8

Please sign in to comment.