Algorithm
网格图中鱼的最大数目
- 思路
类似《图像渲染》问题,任选一点作为起点,广度/深度优先搜索出鱼数量大于0的方格,打捞后将鱼的数量记为0,防止重复计算。最终比较得出捞得鱼数最多的区块。
- 解法
class Solution { private int[] dx = {1, 0, 0, -1}; private int[] dy = {0, 1, -1, 0}; public int findMaxFish(int[][] grid) { // ignore null check int columnCnt = grid[0].length; int rowCnt = grid.length; int max = 0; for (int i = 0; i < columnCnt; i++) { for (int j = 0; j < rowCnt; j++) { if (grid[j][i] != 0) { int cnt = findFishCountByZone(grid, i, j); max = max < cnt ? cnt : max; } } } return max; } /** * find all adjacent points's fish count and set zero */ private int findFishCountByZone(int[][] grid, int startColumn, int startRow) { int cnt = grid[startRow][startColumn]; if (cnt == 0) { return cnt; } grid[startRow][startColumn] = 0; for (int i = 0; i < 4; i++) { int row = startRow + dx[i]; int column = startColumn + dy[i]; if (row >= 0 && row < grid.length && column >= 0 && column < grid[0].length) { cnt += findFishCountByZone(grid, column, row); } } return cnt; } }
Review
Sidecar vs. Init Container in Kubernetes
https://www.baeldung.com/linux/kubernetes-sidecar-vs-init-container
平时工作中更多时间都在关注 Pod 里主容器中的业务逻辑,没有关注过 initContainer 和 sidecar Container 的作用,故找了几篇文章给自己答疑解惑。
总结二者的作用及区别
Sidecar Containers | Init Containers | |
作用 | 为主容器提供一些业务外的附加功能 | 为主容器的启动初始化环境 |
和主容器的关系 | 和主容器是串联关系,如下图 | 在主容器之前启动并退出 |
生命周期 | 和主容器一起启动,运行,终止 | 在主容器之前启动并退出 |
使用场景 | 日志,监控,安全 | 初始化环境,拉取数据供主容器启动使用 |
sidecar 容器使用示例
来自 Kubernetes sidecar container overview,介绍了一个处理日志的 sidecar 容器设计,定义 nginx 的日志目录为 volume,从而读取主容器的日志内容进行处理。
metadata: name: simple-webapp labels: app: webapp spec: containers: - name: main-application image: nginx volumeMounts: - name: shared-logs mountPath: /var/log/nginx - name: sidecar-container image: busybox command: ["sh","-c","while true; do cat /var/log/nginx/access.log; sleep 30; done"] volumeMounts: - name: shared-logs mountPath: /var/log/nginx volumes: - name: shared-logs emptyDir: {} --- # Service Configuration # -------------------- apiVersion: v1 kind: Service metadata: name: simple-webapp labels: run: simple-webapp spec: ports: - port: 80 protocol: TCP selector: app: webapp type: NodePort
Technique/Tips
使用 Streamlit 搭建一个简单的小网页
突然想到用 OpenAI 的 API 做些轻量的小应用玩玩,对比了一下发现使用 Streamlit 非常简单。
Streamlit demo
pip install streamlit streamlit hello
搭建步骤
前置准备
- Zeabur 账号:非常方便的一键式服务部署平台
- 一个 Git 仓库,需要将部署服务的 Dockerfile 放在根目录,如 kaftsang/varierity-of-docs
- 编写页面
这一步可以直接让 ChatGPT 代写,写一个初版然后不断让 ChatGPT 优化。
# -*- coding: utf-8 -*- import openai import os import logging import functools import requests import streamlit as st from streamlit_lottie import st_lottie logger = logging.getLogger("streamlit-openai") logger.setLevel(logging.INFO) openai.api_key = os.getenv("OPENAI_API_KEY") max_tokens = os.getenv("OPENAI_MAX_TOKENS") max_tokens = int(max_tokens) if max_tokens else 1024 def handle_exception(default=None): def wrapper(fn): @functools.wraps(fn) def wrapped(*args, **kwargs): try: return fn(*args, **kwargs) except Exception as e: logger.exception(e) return default or str(e) return wrapped return wrapper def load_lottie_url(url): r = requests.get(url) if r.status_code != 200: return None return r.json() # chatbot @handle_exception() def chat_fn(prompt: str) -> str: if not prompt: return "" engine = os.getenv("CHAT_ENGINE") or "text-davinci-003" res = openai.Completion.create( engine=engine, prompt=prompt, max_tokens=max_tokens ) return res["choices"][0]["text"] # image generation @handle_exception() def img_gen_fn(prompt: str) -> str: if not prompt: return "" res = openai.Image.create( prompt=prompt, n=1, size="1024x1024" ) return res["data"][0]["url"] # text summary @handle_exception() def summary_fn(prompt: str) -> str: if not prompt: return "" engine = os.getenv("CHAT_ENGINE") or "text-davinci-002" res = openai.Completion.create( engine=engine, prompt=f"Summarize this:\n\n{prompt}", max_tokens=max_tokens ) return res["choices"][0]["text"] # title and description st.set_page_config( page_title="ChatBot", page_icon="🤖", layout="wide" ) st.title("Little Bot") lottie_chat = load_lottie_url('https://assets5.lottiefiles.com/packages/lf20_fcfjwiyb.json') st_lottie(lottie_chat, speed=1, height=150, key="initial") st.info(""" + 🤖 **在左侧选择要使用的工具** 1. 对话 2. 图像生成 3. 文字总结 + @see https://github.com/kaftsang/varierity-of-docs """) st.sidebar.header('导航') page = st.sidebar.radio("选择一个页面", ["聊天", "图像生成", "总结文字"]) user_input = st.text_input("随便说些什么吧") logger.info("request prompt: %s" % user_input) if page == "聊天": if st.button("发送"): response = chat_fn(user_input) logger.info("response: %s" % user_input) st.success('成功!', icon="✅") st.write(response) if page == "图像生成": if st.button("生成"): response = img_gen_fn(user_input) logger.info("response: %s" % user_input) st.success('成功!', icon="✅") st.image(response) if page == "总结文字": if st.button("发送"): response = summary_fn(user_input) logger.info("response: %s" % user_input) st.success('成功!', icon="✅") st.write(response) st.sidebar.markdown('---') st.sidebar.markdown('Made with OpenAI API by [Kevin Tsang](https://zengkangfu.com/)')
- 准备部署容器环境
FROM python:3 WORKDIR /app CMD pip install streamlit \ && pip install openai \ && pip install streamlit_lottie \ && streamlit run https://raw.githubusercontent.com/kaftsang/varierity-of-docs/main/streamlit/streamlit.py ENV PORT=8501 HOST=0.0.0.0 EXPOSE 8501
8501 是 Streamlit 的默认启动端口,将这个文件放在 Git 仓库的根目录。
- 应用部署
在 Zeabur 导入 Git 仓库,配置环境变量 OPENAI_API_KEY 为 OpenAI 的 API Token,到这里就全部完成了。