a
Some checks failed
Flask 提示词大师 - CI/CD 流水线 / 代码质量检查 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 单元测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 集成测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 构建Docker镜像 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到测试环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到生产环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署监控系统 (push) Has been cancelled
Some checks failed
Flask 提示词大师 - CI/CD 流水线 / 代码质量检查 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 单元测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 集成测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 构建Docker镜像 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到测试环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到生产环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署监控系统 (push) Has been cancelled
This commit is contained in:
108
docs/api_expert_generate_3_open.md
Normal file
108
docs/api_expert_generate_3_open.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# 智能提示词优化3号专家 - 对外接口文档
|
||||
|
||||
供 Android 等外部应用调用的 REST API。
|
||||
|
||||
## 接口地址
|
||||
|
||||
```
|
||||
POST http://101.43.95.130:5002/api/open/expert-generate-3
|
||||
```
|
||||
|
||||
## 请求
|
||||
|
||||
- **Method**: POST
|
||||
- **Content-Type**: application/json
|
||||
|
||||
### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| input_text | string | 是 | 用户需求描述 |
|
||||
| temperature | number | 否 | 生成随机性,0-2,默认 0.7 |
|
||||
| max_tokens | int | 否 | 最大生成 token 数,100-4000,默认 1000 |
|
||||
| timeout | int | 否 | 超时时间(秒),10-300,默认 60 |
|
||||
| uid | int | 否 | 用户ID,用于历史记录归属,不传则使用默认用户 |
|
||||
|
||||
### 示例
|
||||
|
||||
```json
|
||||
{
|
||||
"input_text": "android内存溢出分析",
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 1000,
|
||||
"timeout": 60,
|
||||
"uid": 1
|
||||
}
|
||||
```
|
||||
|
||||
## 响应
|
||||
|
||||
### 成功 (code=200)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"intent_analysis": {
|
||||
"core_intent": "技术",
|
||||
"domain": "xxx",
|
||||
"key_requirements": ["..."],
|
||||
"expected_output": "...",
|
||||
"constraints": ["..."]
|
||||
},
|
||||
"generated_prompt": "生成的完整提示词文本"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 失败
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "错误描述",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
常见 code:400 参数错误,429 重复提交,500 服务器错误。
|
||||
|
||||
## Android 调用示例 (Kotlin + Retrofit)
|
||||
|
||||
```kotlin
|
||||
// 请求体
|
||||
data class ExpertGenerate3Request(
|
||||
val input_text: String,
|
||||
val temperature: Float? = 0.7f,
|
||||
val max_tokens: Int? = 1000,
|
||||
val timeout: Int? = 60,
|
||||
val uid: Int? = null
|
||||
)
|
||||
|
||||
// 响应体
|
||||
data class ExpertGenerate3Response(
|
||||
val code: Int,
|
||||
val message: String,
|
||||
val data: Data?
|
||||
)
|
||||
data class Data(
|
||||
val intent_analysis: IntentAnalysis,
|
||||
val generated_prompt: String
|
||||
)
|
||||
|
||||
// 使用
|
||||
val api = Retrofit.Builder()
|
||||
.baseUrl("http://101.43.95.130:5002/")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(YourApi::class.java)
|
||||
|
||||
api.expertGenerate3(ExpertGenerate3Request(input_text = "android内存溢出分析"))
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 项目已启用 CORS,支持跨域调用
|
||||
- 对外接口不做 8 秒内重复提交校验,由客户端自行控制
|
||||
- 建议在客户端增加防重复点击、超时重试等逻辑
|
||||
29
exampleAiApp01/README.md
Normal file
29
exampleAiApp01/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# 提示词智能优化 Android App
|
||||
|
||||
调用提示词大师 3 号专家接口,实现智能提示词生成。
|
||||
|
||||
## 环境
|
||||
|
||||
- Android Studio(推荐使用 AGP 8.7+、Gradle 8.9)
|
||||
- minSdk 24,targetSdk 34
|
||||
- Java 17
|
||||
|
||||
## 接口
|
||||
|
||||
- 地址:`POST http://101.43.95.130:5002/api/open/expert-generate-3`
|
||||
- 参数:`input_text`(必填)、`temperature`、`max_tokens`、`timeout`、`uid`
|
||||
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
cd exampleAiApp01
|
||||
./gradlew assembleDebug
|
||||
```
|
||||
|
||||
或在 Android Studio 中打开 `exampleAiApp01` 目录,直接运行到真机或模拟器。
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 需配置网络权限,并允许明文 HTTP(101.43.95.130 为 HTTP)
|
||||
- 确保设备可访问 `101.43.95.130:5002`
|
||||
- 如缺少启动图标,可在 Android Studio 中通过 `File > New > Image Asset` 生成
|
||||
46
exampleAiApp01/app/build.gradle.kts
Normal file
46
exampleAiApp01/app/build.gradle.kts
Normal file
@@ -0,0 +1,46 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.promptoptimizer"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.example.promptoptimizer"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.core:core-ktx:1.12.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.11.0")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
|
||||
// Retrofit
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
|
||||
}
|
||||
|
||||
3
exampleAiApp01/app/proguard-rules.pro
vendored
Normal file
3
exampleAiApp01/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
-keepattributes Signature
|
||||
-keepattributes *Annotation*
|
||||
-keep class com.example.promptoptimizer.api.** { *; }
|
||||
23
exampleAiApp01/app/src/main/AndroidManifest.xml
Normal file
23
exampleAiApp01/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.PromptOptimizer"
|
||||
android:usesCleartextTraffic="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.PromptOptimizer">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.example.promptoptimizer;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.example.promptoptimizer.api.ExpertGenerate3Api;
|
||||
import com.example.promptoptimizer.model.ExpertGenerate3Request;
|
||||
import com.example.promptoptimizer.model.ExpertGenerate3Response;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
/**
|
||||
* 提示词智能优化 - 主界面
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private EditText etInput;
|
||||
private MaterialButton btnGenerate;
|
||||
private ProgressBar progressBar;
|
||||
private TextView tvLoading;
|
||||
private MaterialCardView cardResult;
|
||||
private TextView tvIntent;
|
||||
private TextView tvPrompt;
|
||||
private MaterialButton btnCopy;
|
||||
|
||||
private boolean isSubmitting = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
etInput = findViewById(R.id.etInput);
|
||||
btnGenerate = findViewById(R.id.btnGenerate);
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
tvLoading = findViewById(R.id.tvLoading);
|
||||
cardResult = findViewById(R.id.cardResult);
|
||||
tvIntent = findViewById(R.id.tvIntent);
|
||||
tvPrompt = findViewById(R.id.tvPrompt);
|
||||
btnCopy = findViewById(R.id.btnCopy);
|
||||
|
||||
btnGenerate.setOnClickListener(v -> doGenerate());
|
||||
btnCopy.setOnClickListener(v -> copyPrompt());
|
||||
}
|
||||
|
||||
private void doGenerate() {
|
||||
if (isSubmitting) return;
|
||||
|
||||
String input = etInput.getText() != null ? etInput.getText().toString().trim() : "";
|
||||
if (input.isEmpty()) {
|
||||
Toast.makeText(this, R.string.error_empty, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
isSubmitting = true;
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
tvLoading.setVisibility(View.VISIBLE);
|
||||
btnGenerate.setEnabled(false);
|
||||
cardResult.setVisibility(View.GONE);
|
||||
|
||||
ExpertGenerate3Request request = new ExpertGenerate3Request(input);
|
||||
ExpertGenerate3Api api = RetrofitClient.getApi();
|
||||
|
||||
api.generate(request).enqueue(new Callback<ExpertGenerate3Response>() {
|
||||
@Override
|
||||
public void onResponse(Call<ExpertGenerate3Response> call,
|
||||
Response<ExpertGenerate3Response> response) {
|
||||
isSubmitting = false;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
tvLoading.setVisibility(View.GONE);
|
||||
btnGenerate.setEnabled(true);
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
ExpertGenerate3Response body = response.body();
|
||||
if (body.getCode() == 200 && body.getData() != null) {
|
||||
showResult(body);
|
||||
} else {
|
||||
Toast.makeText(MainActivity.this,
|
||||
body.getMessage() != null ? body.getMessage() : getString(R.string.error_network),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(MainActivity.this, R.string.error_network, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ExpertGenerate3Response> call, Throwable t) {
|
||||
isSubmitting = false;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
tvLoading.setVisibility(View.GONE);
|
||||
btnGenerate.setEnabled(true);
|
||||
Toast.makeText(MainActivity.this, R.string.error_network + ": " + t.getMessage(),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showResult(ExpertGenerate3Response response) {
|
||||
ExpertGenerate3Response.ResponseData data = response.getData();
|
||||
if (data == null) return;
|
||||
|
||||
StringBuilder intentSb = new StringBuilder();
|
||||
ExpertGenerate3Response.IntentAnalysis ia = data.getIntentAnalysis();
|
||||
if (ia != null) {
|
||||
intentSb.append("核心意图:").append(ia.getCoreIntent()).append("\n");
|
||||
intentSb.append("专业领域:").append(ia.getDomain()).append("\n");
|
||||
intentSb.append("预期输出:").append(ia.getExpectedOutput()).append("\n");
|
||||
if (ia.getKeyRequirements() != null && ia.getKeyRequirements().length > 0) {
|
||||
intentSb.append("关键需求:\n").append(Arrays.toString(ia.getKeyRequirements())).append("\n");
|
||||
}
|
||||
if (ia.getConstraints() != null && ia.getConstraints().length > 0) {
|
||||
intentSb.append("约束条件:\n").append(Arrays.toString(ia.getConstraints()));
|
||||
}
|
||||
}
|
||||
tvIntent.setText(intentSb.toString());
|
||||
tvPrompt.setText(data.getGeneratedPrompt() != null ? data.getGeneratedPrompt() : "");
|
||||
cardResult.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void copyPrompt() {
|
||||
String text = tvPrompt.getText() != null ? tvPrompt.getText().toString() : "";
|
||||
if (text.isEmpty()) return;
|
||||
|
||||
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) {
|
||||
cm.setPrimaryClip(ClipData.newPlainText("prompt", text));
|
||||
Toast.makeText(this, R.string.toast_copied, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.example.promptoptimizer;
|
||||
|
||||
import com.example.promptoptimizer.api.ExpertGenerate3Api;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RetrofitClient {
|
||||
|
||||
private static final String BASE_URL = "http://101.43.95.130:5002/";
|
||||
|
||||
private static Retrofit retrofit;
|
||||
private static ExpertGenerate3Api api;
|
||||
|
||||
public static ExpertGenerate3Api getApi() {
|
||||
if (api == null) {
|
||||
api = getRetrofit().create(ExpertGenerate3Api.class);
|
||||
}
|
||||
return api;
|
||||
}
|
||||
|
||||
private static Retrofit getRetrofit() {
|
||||
if (retrofit == null) {
|
||||
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.connectTimeout(90, TimeUnit.SECONDS)
|
||||
.readTimeout(90, TimeUnit.SECONDS)
|
||||
.writeTimeout(90, TimeUnit.SECONDS)
|
||||
.addInterceptor(interceptor)
|
||||
.build();
|
||||
|
||||
retrofit = new Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build();
|
||||
}
|
||||
return retrofit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.example.promptoptimizer.api;
|
||||
|
||||
import com.example.promptoptimizer.model.ExpertGenerate3Response;
|
||||
import com.example.promptoptimizer.model.ExpertGenerate3Request;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
/**
|
||||
* 智能提示词优化3号专家 API
|
||||
*/
|
||||
public interface ExpertGenerate3Api {
|
||||
|
||||
@POST("api/open/expert-generate-3")
|
||||
Call<ExpertGenerate3Response> generate(@Body ExpertGenerate3Request request);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.example.promptoptimizer.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* 请求体
|
||||
*/
|
||||
public class ExpertGenerate3Request {
|
||||
|
||||
@SerializedName("input_text")
|
||||
private String inputText;
|
||||
|
||||
@SerializedName("temperature")
|
||||
private Float temperature;
|
||||
|
||||
@SerializedName("max_tokens")
|
||||
private Integer maxTokens;
|
||||
|
||||
@SerializedName("timeout")
|
||||
private Integer timeout;
|
||||
|
||||
@SerializedName("uid")
|
||||
private Integer uid;
|
||||
|
||||
public ExpertGenerate3Request(String inputText) {
|
||||
this.inputText = inputText;
|
||||
this.temperature = 0.7f;
|
||||
this.maxTokens = 1000;
|
||||
this.timeout = 60;
|
||||
}
|
||||
|
||||
public String getInputText() {
|
||||
return inputText;
|
||||
}
|
||||
|
||||
public void setInputText(String inputText) {
|
||||
this.inputText = inputText;
|
||||
}
|
||||
|
||||
public Float getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(Float temperature) {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
public Integer getMaxTokens() {
|
||||
return maxTokens;
|
||||
}
|
||||
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
public Integer getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(Integer timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public Integer getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public void setUid(Integer uid) {
|
||||
this.uid = uid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.example.promptoptimizer.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* 响应体
|
||||
*/
|
||||
public class ExpertGenerate3Response {
|
||||
|
||||
private int code;
|
||||
private String message;
|
||||
|
||||
@SerializedName("data")
|
||||
private ResponseData data;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ResponseData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(ResponseData data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static class ResponseData {
|
||||
@SerializedName("intent_analysis")
|
||||
private IntentAnalysis intentAnalysis;
|
||||
|
||||
@SerializedName("generated_prompt")
|
||||
private String generatedPrompt;
|
||||
|
||||
public IntentAnalysis getIntentAnalysis() {
|
||||
return intentAnalysis;
|
||||
}
|
||||
|
||||
public void setIntentAnalysis(IntentAnalysis intentAnalysis) {
|
||||
this.intentAnalysis = intentAnalysis;
|
||||
}
|
||||
|
||||
public String getGeneratedPrompt() {
|
||||
return generatedPrompt;
|
||||
}
|
||||
|
||||
public void setGeneratedPrompt(String generatedPrompt) {
|
||||
this.generatedPrompt = generatedPrompt;
|
||||
}
|
||||
}
|
||||
|
||||
public static class IntentAnalysis {
|
||||
@SerializedName("core_intent")
|
||||
private String coreIntent;
|
||||
|
||||
@SerializedName("domain")
|
||||
private String domain;
|
||||
|
||||
@SerializedName("key_requirements")
|
||||
private String[] keyRequirements;
|
||||
|
||||
@SerializedName("expected_output")
|
||||
private String expectedOutput;
|
||||
|
||||
@SerializedName("constraints")
|
||||
private String[] constraints;
|
||||
|
||||
public String getCoreIntent() {
|
||||
return coreIntent;
|
||||
}
|
||||
|
||||
public void setCoreIntent(String coreIntent) {
|
||||
this.coreIntent = coreIntent;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String[] getKeyRequirements() {
|
||||
return keyRequirements;
|
||||
}
|
||||
|
||||
public void setKeyRequirements(String[] keyRequirements) {
|
||||
this.keyRequirements = keyRequirements;
|
||||
}
|
||||
|
||||
public String getExpectedOutput() {
|
||||
return expectedOutput;
|
||||
}
|
||||
|
||||
public void setExpectedOutput(String expectedOutput) {
|
||||
this.expectedOutput = expectedOutput;
|
||||
}
|
||||
|
||||
public String[] getConstraints() {
|
||||
return constraints;
|
||||
}
|
||||
|
||||
public void setConstraints(String[] constraints) {
|
||||
this.constraints = constraints;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
exampleAiApp01/app/src/main/res/drawable/edit_bg.xml
Normal file
6
exampleAiApp01/app/src/main/res/drawable/edit_bg.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#FFFFFF"/>
|
||||
<corners android:radius="4dp"/>
|
||||
<stroke android:width="1dp" android:color="#E2E8F0"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#1E3A8A"
|
||||
android:pathData="M54,40 L68,54 L54,68 L40,54 Z" />
|
||||
</vector>
|
||||
153
exampleAiApp01/app/src/main/res/layout/activity_main.xml
Normal file
153
exampleAiApp01/app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="#F8FAFC">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="提示词智能优化"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#1E3A8A"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="请描述您的需求"
|
||||
android:textSize="14sp"
|
||||
android:textColor="#333333"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:gravity="top|start"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/edit_bg"
|
||||
android:inputType="textMultiLine"
|
||||
android:minLines="3"
|
||||
android:hint="@string/hint_input" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnGenerate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/btn_generate" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone"
|
||||
android:layout_marginVertical="24dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvLoading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/loading"
|
||||
android:visibility="gone"
|
||||
android:layout_marginBottom="24dp" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/cardResult"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_result"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_intent"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvIntent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:background="#F1F5F9"
|
||||
android:textSize="13sp"
|
||||
android:lineSpacingExtra="4dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_prompt"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPrompt"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:background="#F1F5F9"
|
||||
android:textSize="13sp"
|
||||
android:lineSpacingExtra="4dp"
|
||||
android:fontFamily="monospace" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnCopy"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/btn_copy" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
5
exampleAiApp01/app/src/main/res/values/colors.xml
Normal file
5
exampleAiApp01/app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#F8FAFC</color>
|
||||
<color name="primary">#1E3A8A</color>
|
||||
</resources>
|
||||
14
exampleAiApp01/app/src/main/res/values/strings.xml
Normal file
14
exampleAiApp01/app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">提示词智能优化</string>
|
||||
<string name="hint_input">请描述您的需求,系统将进行专业分析并生成高质量提示词</string>
|
||||
<string name="btn_generate">生成专家提示词</string>
|
||||
<string name="label_result">生成结果</string>
|
||||
<string name="label_intent">需求分析</string>
|
||||
<string name="label_prompt">生成的专家提示词</string>
|
||||
<string name="btn_copy">复制提示词</string>
|
||||
<string name="toast_copied">已复制到剪贴板</string>
|
||||
<string name="loading">正在分析需求并生成专业提示词…</string>
|
||||
<string name="error_network">网络请求失败,请检查网络后重试</string>
|
||||
<string name="error_empty">请输入您的需求</string>
|
||||
</resources>
|
||||
8
exampleAiApp01/app/src/main/res/values/themes.xml
Normal file
8
exampleAiApp01/app/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.PromptOptimizer" parent="Theme.Material3.Light.NoActionBar">
|
||||
<item name="colorPrimary">#1E3A8A</item>
|
||||
<item name="colorPrimaryVariant">#3B82F6</item>
|
||||
<item name="colorOnPrimary">#FFFFFF</item>
|
||||
</style>
|
||||
</resources>
|
||||
3
exampleAiApp01/build.gradle.kts
Normal file
3
exampleAiApp01/build.gradle.kts
Normal file
@@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
id("com.android.application") version "8.7.3" apply false
|
||||
}
|
||||
4
exampleAiApp01/gradle.properties
Normal file
4
exampleAiApp01/gradle.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
android.useAndroidX=true
|
||||
kotlin.code.style=official
|
||||
android.nonTransitiveRClass=true
|
||||
7
exampleAiApp01/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
exampleAiApp01/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
17
exampleAiApp01/settings.gradle.kts
Normal file
17
exampleAiApp01/settings.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "PromptOptimizer"
|
||||
include(":app")
|
||||
@@ -2927,3 +2927,4 @@ werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'expert
|
||||
[in /home/renjianbo/aitsc/src/flask_prompt_master/__init__.py:120]
|
||||
2026-02-28 22:15:25,968 INFO: 应用启动 [in /home/renjianbo/aitsc/config/base.py:82]
|
||||
2026-02-28 22:22:12,598 INFO: 应用启动 [in /home/renjianbo/aitsc/config/base.py:82]
|
||||
2026-03-01 22:57:49,275 INFO: 应用启动 [in /home/renjianbo/aitsc/config/base.py:82]
|
||||
|
||||
@@ -1 +1 @@
|
||||
22948
|
||||
21107
|
||||
|
||||
@@ -15248,3 +15248,6 @@
|
||||
206.168.34.39 - - [01/Mar/2026:01:05:25 +0800] "PRI * HTTP/2.0" 404 207 "-" "-" 828
|
||||
206.168.34.39 - - [01/Mar/2026:01:05:26 +0800] "GET /favicon.ico HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 806
|
||||
206.168.34.39 - - [01/Mar/2026:01:05:45 +0800] "GET /security.txt HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 659
|
||||
123.139.40.200 - - [01/Mar/2026:22:58:01 +0800] "GET / HTTP/1.1" 200 216259 "http://101.43.95.130:5002/expert-generate-3" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" 712510
|
||||
123.139.40.200 - - [01/Mar/2026:22:58:01 +0800] "GET /static/js/interactions.js HTTP/1.1" 404 207 "http://101.43.95.130:5002/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" 5764
|
||||
123.139.40.200 - - [01/Mar/2026:22:58:02 +0800] "GET /api/check-login HTTP/1.1" 200 35 "http://101.43.95.130:5002/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" 5242
|
||||
|
||||
@@ -10587,3 +10587,36 @@ werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'expert
|
||||
[2026-03-01 02:01:44 +0800] [31755] [ERROR] Worker (pid:696) was sent SIGTERM!
|
||||
[2026-03-01 02:01:44 +0800] [31755] [ERROR] Worker (pid:831) was sent SIGTERM!
|
||||
[2026-03-01 02:01:44 +0800] [31755] [INFO] Shutting down: Master
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] Starting gunicorn 21.2.0
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] Gunicorn服务器启动中...
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] Listening at: http://0.0.0.0:5002 (21107)
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] Using worker: sync
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动
|
||||
[2026-03-01 22:57:51 +0800] [21286] [INFO] Booting worker with pid: 21286
|
||||
[2026-03-01 22:57:51 +0800] [21286] [INFO] 工作进程 21286 已启动
|
||||
[2026-03-01 22:57:51 +0800] [21286] [INFO] 工作进程 21286 初始化完成
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动
|
||||
[2026-03-01 22:57:51 +0800] [21293] [INFO] Booting worker with pid: 21293
|
||||
[2026-03-01 22:57:51 +0800] [21293] [INFO] 工作进程 21293 已启动
|
||||
[2026-03-01 22:57:51 +0800] [21293] [INFO] 工作进程 21293 初始化完成
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动
|
||||
[2026-03-01 22:57:51 +0800] [21294] [INFO] Booting worker with pid: 21294
|
||||
[2026-03-01 22:57:51 +0800] [21294] [INFO] 工作进程 21294 已启动
|
||||
[2026-03-01 22:57:51 +0800] [21294] [INFO] 工作进程 21294 初始化完成
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动
|
||||
[2026-03-01 22:57:51 +0800] [21295] [INFO] Booting worker with pid: 21295
|
||||
[2026-03-01 22:57:51 +0800] [21295] [INFO] 工作进程 21295 已启动
|
||||
[2026-03-01 22:57:51 +0800] [21295] [INFO] 工作进程 21295 初始化完成
|
||||
[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动
|
||||
[2026-03-01 22:57:51 +0800] [21296] [INFO] Booting worker with pid: 21296
|
||||
[2026-03-01 22:57:51 +0800] [21296] [INFO] 工作进程 21296 已启动
|
||||
[2026-03-01 22:57:51 +0800] [21296] [INFO] 工作进程 21296 初始化完成
|
||||
[2026-03-01 23:03:09 +0800] [21107] [CRITICAL] WORKER TIMEOUT (pid:21296)
|
||||
[2026-03-01 23:03:09 +0800] [21296] [INFO] 工作进程 21296 异常退出
|
||||
[2026-03-01 23:03:09 +0800] [21296] [INFO] Worker exiting (pid: 21296)
|
||||
[2026-03-01 23:03:09 +0800] [21107] [ERROR] Worker (pid:21296) exited with code 1
|
||||
[2026-03-01 23:03:09 +0800] [21107] [ERROR] Worker (pid:21296) exited with code 1.
|
||||
[2026-03-01 23:03:09 +0800] [21107] [INFO] 工作进程 [booting] 即将启动
|
||||
[2026-03-01 23:03:09 +0800] [2175] [INFO] Booting worker with pid: 2175
|
||||
[2026-03-01 23:03:09 +0800] [2175] [INFO] 工作进程 2175 已启动
|
||||
[2026-03-01 23:03:09 +0800] [2175] [INFO] 工作进程 2175 初始化完成
|
||||
|
||||
Binary file not shown.
@@ -140,6 +140,84 @@ def _resolve_user_id():
|
||||
return 1
|
||||
|
||||
|
||||
def _do_generate(raw_input, temperature, max_tokens, timeout, user_id, skip_dedup=False):
|
||||
"""核心生成逻辑,供 Web API 和对外接口共用"""
|
||||
if not skip_dedup:
|
||||
req_key = (user_id, hashlib.md5(raw_input.encode()).hexdigest())
|
||||
now_ts = time.time()
|
||||
if req_key in _dedup_cache and (now_ts - _dedup_cache[req_key]) < 8:
|
||||
return {'code': 429, 'message': '请勿重复提交,请稍后再试', 'data': None}
|
||||
_dedup_cache[req_key] = now_ts
|
||||
if len(_dedup_cache) > 500:
|
||||
_dedup_cache.clear()
|
||||
|
||||
resp1 = _llm_client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": INTENT_PROMPT_3},
|
||||
{"role": "user", "content": raw_input}
|
||||
],
|
||||
temperature=0.1,
|
||||
timeout=timeout
|
||||
)
|
||||
intent_raw = (resp1.choices[0].message.content or "").strip()
|
||||
intent_raw = intent_raw.replace('```json', '').replace('```', '').strip()
|
||||
try:
|
||||
intent_data = json.loads(intent_raw)
|
||||
for field in ['core_intent', 'domain', 'key_requirements', 'expected_output', 'constraints', 'keywords']:
|
||||
if field not in intent_data:
|
||||
raise ValueError("缺少字段: " + field)
|
||||
if intent_data['core_intent'] not in ('技术', '创意', '分析', '咨询'):
|
||||
intent_data['core_intent'] = '技术'
|
||||
for arr_field in ['key_requirements', 'constraints', 'keywords']:
|
||||
v = intent_data.get(arr_field)
|
||||
if not isinstance(v, list) or len(v) == 0:
|
||||
intent_data[arr_field] = ['未指定']
|
||||
except json.JSONDecodeError:
|
||||
raise ValueError("意图分析格式有误")
|
||||
except ValueError:
|
||||
raise
|
||||
|
||||
tpl = EXPERT_TEMPLATES_3.get(intent_data['core_intent'], FALLBACK_TEMPLATE_3)
|
||||
analysis_str = json.dumps(intent_data, ensure_ascii=False, indent=2)
|
||||
resp2 = _llm_client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": tpl.format(analysis=analysis_str)},
|
||||
{"role": "user", "content": raw_input}
|
||||
],
|
||||
temperature=temperature,
|
||||
max_tokens=max_tokens,
|
||||
timeout=timeout
|
||||
)
|
||||
result_prompt = (resp2.choices[0].message.content or "").strip()
|
||||
if not result_prompt:
|
||||
raise ValueError("生成结果为空")
|
||||
|
||||
try:
|
||||
db.session.add(Prompt(input_text=raw_input, generated_text=result_prompt, user_id=user_id))
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
logger.warning("3号专家 保存 Prompt 失败: %s", e)
|
||||
try:
|
||||
PromptHistory.add_history(
|
||||
user_id=user_id,
|
||||
original_input=raw_input,
|
||||
generated_prompt=result_prompt,
|
||||
template_name=TEMPLATE_NAME_3
|
||||
)
|
||||
UserStatistics.update_statistics(user_id)
|
||||
except Exception as e:
|
||||
logger.warning("3号专家 保存历史失败: %s", e)
|
||||
|
||||
return {
|
||||
'code': 200,
|
||||
'message': 'success',
|
||||
'data': {'intent_analysis': intent_data, 'generated_prompt': result_prompt}
|
||||
}
|
||||
|
||||
|
||||
@expert_generate_3_bp.route('/expert-generate-3', methods=['GET'])
|
||||
def expert_generate_3_page():
|
||||
"""智能提示词优化3号专家 - 页面"""
|
||||
@@ -148,7 +226,20 @@ def expert_generate_3_page():
|
||||
|
||||
@expert_generate_3_bp.route('/api/expert-generate-3/generate', methods=['POST'])
|
||||
def expert_generate_3_api():
|
||||
"""智能提示词优化3号专家 - 两阶段生成 API,含历史记录"""
|
||||
"""智能提示词优化3号专家 - 两阶段生成 API(Web 用),含历史记录"""
|
||||
return _handle_generate_api(skip_dedup=False, user_id=None)
|
||||
|
||||
|
||||
@expert_generate_3_bp.route('/api/open/expert-generate-3', methods=['POST'])
|
||||
def expert_generate_3_open_api():
|
||||
"""
|
||||
智能提示词优化3号专家 - 对外接口,供 Android 等外部应用调用。
|
||||
POST JSON: input_text(必填), temperature, max_tokens, timeout, uid(可选)
|
||||
"""
|
||||
return _handle_generate_api(skip_dedup=True, user_id=None)
|
||||
|
||||
|
||||
def _handle_generate_api(skip_dedup=False, user_id=None):
|
||||
try:
|
||||
if not request.is_json:
|
||||
return jsonify({'code': 400, 'message': '请求必须是JSON格式', 'data': None})
|
||||
@@ -167,79 +258,16 @@ def expert_generate_3_api():
|
||||
timeout = int(timeout) if timeout is not None else 60
|
||||
timeout = max(10, min(300, timeout))
|
||||
|
||||
uid = _resolve_user_id()
|
||||
req_key = (uid, hashlib.md5(raw_input.encode()).hexdigest())
|
||||
now_ts = time.time()
|
||||
if req_key in _dedup_cache and (now_ts - _dedup_cache[req_key]) < 8:
|
||||
return jsonify({'code': 429, 'message': '请勿重复提交,请稍后再试', 'data': None})
|
||||
_dedup_cache[req_key] = now_ts
|
||||
if len(_dedup_cache) > 500:
|
||||
_dedup_cache.clear()
|
||||
uid = user_id if user_id is not None else payload.get('uid')
|
||||
if uid is not None:
|
||||
uid = int(uid)
|
||||
else:
|
||||
uid = _resolve_user_id()
|
||||
|
||||
resp1 = _llm_client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": INTENT_PROMPT_3},
|
||||
{"role": "user", "content": raw_input}
|
||||
],
|
||||
temperature=0.1,
|
||||
timeout=timeout
|
||||
)
|
||||
intent_raw = (resp1.choices[0].message.content or "").strip()
|
||||
intent_raw = intent_raw.replace('```json', '').replace('```', '').strip()
|
||||
try:
|
||||
intent_data = json.loads(intent_raw)
|
||||
for field in ['core_intent', 'domain', 'key_requirements', 'expected_output', 'constraints', 'keywords']:
|
||||
if field not in intent_data:
|
||||
raise ValueError("缺少字段: " + field)
|
||||
if intent_data['core_intent'] not in ('技术', '创意', '分析', '咨询'):
|
||||
intent_data['core_intent'] = '技术'
|
||||
for arr_field in ['key_requirements', 'constraints', 'keywords']:
|
||||
v = intent_data.get(arr_field)
|
||||
if not isinstance(v, list) or len(v) == 0:
|
||||
intent_data[arr_field] = ['未指定']
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error("3号专家 JSON解析失败: %s", e)
|
||||
return jsonify({'code': 500, 'message': '意图分析格式有误,请重试', 'data': None})
|
||||
except ValueError as e:
|
||||
logger.error("3号专家 数据验证失败: %s", e)
|
||||
return jsonify({'code': 500, 'message': str(e), 'data': None})
|
||||
tpl = EXPERT_TEMPLATES_3.get(intent_data['core_intent'], FALLBACK_TEMPLATE_3)
|
||||
analysis_str = json.dumps(intent_data, ensure_ascii=False, indent=2)
|
||||
resp2 = _llm_client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": tpl.format(analysis=analysis_str)},
|
||||
{"role": "user", "content": raw_input}
|
||||
],
|
||||
temperature=temperature,
|
||||
max_tokens=max_tokens,
|
||||
timeout=timeout
|
||||
)
|
||||
result_prompt = (resp2.choices[0].message.content or "").strip()
|
||||
if not result_prompt:
|
||||
return jsonify({'code': 500, 'message': '生成失败,请重试', 'data': None})
|
||||
try:
|
||||
db.session.add(Prompt(input_text=raw_input, generated_text=result_prompt, user_id=uid))
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
logger.warning("3号专家 保存 Prompt 失败: %s", e)
|
||||
try:
|
||||
PromptHistory.add_history(
|
||||
user_id=uid,
|
||||
original_input=raw_input,
|
||||
generated_prompt=result_prompt,
|
||||
template_name=TEMPLATE_NAME_3
|
||||
)
|
||||
UserStatistics.update_statistics(uid)
|
||||
except Exception as e:
|
||||
logger.warning("3号专家 保存历史失败: %s", e)
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'message': 'success',
|
||||
'data': {'intent_analysis': intent_data, 'generated_prompt': result_prompt}
|
||||
})
|
||||
result = _do_generate(raw_input, temperature, max_tokens, timeout, uid, skip_dedup=skip_dedup)
|
||||
return jsonify(result)
|
||||
except ValueError as e:
|
||||
return jsonify({'code': 400, 'message': str(e), 'data': None})
|
||||
except Exception as e:
|
||||
logger.exception("智能提示词优化3号专家失败")
|
||||
return jsonify({'code': 500, 'message': str(e) or '生成失败,请重试', 'data': None})
|
||||
|
||||
Reference in New Issue
Block a user