| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- """
- Examples API - 提供 examples 项目列表和 prompt 读取接口
- """
- import os
- from typing import List, Optional
- from pathlib import Path
- from fastapi import APIRouter, HTTPException
- from pydantic import BaseModel
- router = APIRouter(prefix="/api/examples", tags=["examples"])
- class ExampleProject(BaseModel):
- """Example 项目信息"""
- name: str
- path: str
- has_prompt: bool
- class ExampleListResponse(BaseModel):
- """Example 列表响应"""
- projects: List[ExampleProject]
- class PromptResponse(BaseModel):
- """Prompt 响应"""
- system_prompt: str
- user_prompt: str
- model: Optional[str] = None
- temperature: Optional[float] = None
- # 配置 examples 目录路径
- EXAMPLES_DIR = Path("examples")
- @router.get("", response_model=ExampleListResponse)
- async def list_examples():
- """
- 列出所有 example 项目
- 扫描 examples 目录,返回所有子目录及其 prompt 文件状态
- """
- if not EXAMPLES_DIR.exists():
- return ExampleListResponse(projects=[])
- projects = []
- for item in EXAMPLES_DIR.iterdir():
- if item.is_dir():
- # 检查是否有 prompt 文件
- prompt_file = item / "production.prompt"
- has_prompt = prompt_file.exists()
- projects.append(ExampleProject(
- name=item.name,
- path=str(item),
- has_prompt=has_prompt
- ))
- # 按名称排序
- projects.sort(key=lambda x: x.name)
- return ExampleListResponse(projects=projects)
- @router.get("/{project_name}/prompt", response_model=PromptResponse)
- async def get_example_prompt(project_name: str):
- """
- 获取指定 example 项目的 prompt
- 读取 production.prompt 文件,解析 frontmatter 和内容
- """
- project_path = EXAMPLES_DIR / project_name
- if not project_path.exists() or not project_path.is_dir():
- raise HTTPException(status_code=404, detail=f"Project not found: {project_name}")
- prompt_file = project_path / "production.prompt"
- if not prompt_file.exists():
- raise HTTPException(status_code=404, detail=f"Prompt file not found for project: {project_name}")
- try:
- content = prompt_file.read_text(encoding="utf-8")
- # 解析 frontmatter 和内容
- system_prompt = ""
- user_prompt = ""
- model = None
- temperature = None
- # 检查是否有 frontmatter
- if content.startswith("---"):
- parts = content.split("---", 2)
- if len(parts) >= 3:
- frontmatter = parts[1].strip()
- body = parts[2].strip()
- # 解析 frontmatter
- for line in frontmatter.split("\n"):
- if ":" in line:
- key, value = line.split(":", 1)
- key = key.strip()
- value = value.strip()
- if key == "model":
- model = value
- elif key == "temperature":
- try:
- temperature = float(value)
- except ValueError:
- pass
- else:
- body = content
- else:
- body = content
- # 解析 $system$ 和 $user$ 部分
- if "$system$" in body:
- parts = body.split("$system$", 1)
- if len(parts) > 1:
- rest = parts[1]
- if "$user$" in rest:
- system_part, user_part = rest.split("$user$", 1)
- system_prompt = system_part.strip()
- user_prompt = user_part.strip()
- else:
- system_prompt = rest.strip()
- elif "$user$" in body:
- parts = body.split("$user$", 1)
- if len(parts) > 1:
- user_prompt = parts[1].strip()
- else:
- # 没有标记,全部作为 user_prompt
- user_prompt = body.strip()
- return PromptResponse(
- system_prompt=system_prompt,
- user_prompt=user_prompt,
- model=model,
- temperature=temperature
- )
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Failed to read prompt file: {str(e)}")
|