前言
当初Chat GPT性能越来越强了,简直你想问理论问题它都能给你答复。
正好,小组结课的 Android我的项目 有一个解梦的性能。正好调用chatGpt的Api来实现。
上面就来简略实现在Andorid我的项目中打造一个繁难的聊天机器人。
先贴个成果, 还没进行丑化:
1.创立一个Andorid我的项目
这里就不在具体地介绍如何创立一个Andorid我的项目了。谷歌上很多文章,比方官网示例:
https://developer.android.com/training/basics/firstapp/creati...
2.在 build.gradle 中增加依赖
这是用到的依赖
implementation 'com.google.android.material:material:1.7.0'implementation 'com.android.volley:volley:1.2.0'implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.3'compileOnly 'org.projectlombok:lombok:1.18.4'annotationProcessor 'org.projectlombok:lombok:1.18.4'implementation 'org.apache.commons:commons-lang3:3.6'
3.在 AndroidManifest.xml 中增加联网权限
<uses-permission android:name="android.permission.INTERNET"/>
4. 注册OpenAI api
来到 OpenAI api 注册账号,并生成 SECRET KEY
记得保留好,之后会用到。
5.编写xml界面文件
在res/layout下新建activity_chat.xml文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/grey"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/idTILQuery" android:layout_alignParentTop="true" android:padding="5dp" android:layout_marginTop="5dp" android:layout_marginStart="5dp" android:layout_marginEnd="5dp" android:layout_marginBottom="5dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- text view for displaying question--> <TextView android:id="@+id/idTVQuestion" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="30dp" android:padding="4dp" android:text="Question" android:textColor="@color/purple_700" android:textSize="17sp"/> <!-- text view for displaying response--> <TextView android:id="@+id/idTVResponse" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="5dp" android:padding="4dp" android:text="Response" android:textColor="@color/purple_700" android:textSize="15sp"/> </LinearLayout> </ScrollView> <!-- text field for asking question--> <com.google.android.material.textfield.TextInputLayout android:id="@+id/idTILQuery" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_margin="5dp" app:endIconMode="custom" app:endIconDrawable="@drawable/send" android:hint="Enter your query" android:padding="5dp" android:textColorHint="@color/black" app:hintTextColor="@color/black"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/idEdtQuery" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/grey" android:ems="10" android:imeOptions="actionSend" android:importantForAutofill="no" android:inputType="textEmailAddress" android:textColor="@color/black" android:textColorHint="@color/black" android:textSize="14sp" /> </com.google.android.material.textfield.TextInputLayout></RelativeLayout>
一个简略的页面如下
5.编写Activity文件
绑定控件
首先,咱们先创立了三个控件显示内容:问题、响应、用户输出。
用 setContentView 绑定xml文件,并应用 findViewById 给三个控件初始化
public class ChatActivity extends AppCompatActivity { TextView responseTV; TextView questionTV; TextInputLayout queryEdt; @Override protected void onCreate(Bundle savedInstanceState) { DynamicColors.applyToActivityIfAvailable(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_chat); // initializing responseTV = findViewById(R.id.idTVResponse); questionTV = findViewById(R.id.idTVQuestion); queryEdt = findViewById(R.id.idTILQuery); }}
监听发送按钮
其次,咱们须要监听发送按钮
,当用户点击后发送后,申请chatGpt。并显示 Please wait..
,让用户期待申请后果
@Override protected void onCreate(Bundle savedInstanceState) { DynamicColors.applyToActivityIfAvailable(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_chat); // initializing variables on below line. responseTV = findViewById(R.id.idTVResponse); questionTV = findViewById(R.id.idTVQuestion); queryEdt = findViewById(R.id.idTILQuery); queryEdt.setEndIconOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { responseTV.setText("Please wait.."); if (queryEdt.getEditText().getText().toString().length() > 0) { getResponse(queryEdt.getEditText().getText().toString()); } else { Toast.makeText(ChatActivity.this, "Please enter your query..", Toast.LENGTH_SHORT).show(); } } }); }
对 HttpURLConnection 设置代理
之后。咱们应该对api进行申请了。然而OpenAI的APi在外网上,如果手机没有设置代理,咱们就不能通过手机的网络间接对api进行申请。咱们须要对 HttpURLConnection 设置代理:
当然,如果手机的网络有代理的话,就不须要了。
新建ProxiedHurlStack类, 填上代理服务器的地址和端口。
public class ProxiedHurlStack extends HurlStack { @Override protected HttpURLConnection createConnection(URL url) throws IOException { // Start the connection by specifying a proxy server Proxy proxy = new Proxy(Type.HTTP, InetSocketAddress.createUnresolved("192.168.2.197", 7890));//the proxy server(Can be your laptop ip or company proxy) HttpURLConnection returnThis = (HttpURLConnection) url .openConnection(proxy); return returnThis; }}
如果你电脑能应用代理, 那咱们还能够通过手机和电脑处在同一局域网下,使手机通过电脑的代理拜访。这里以Clash为例。点击Clash, 凋谢端口给局域网连贯。
之后,咱们就能够把代理地址设置为电脑的IPv4地址了。
InetSocketAddress.createUnresolved("192.168.2.197", 7890));
新建响应实体
依据OpenAI API Reference, 响应如下:
{ "id": "chatcmpl-123", "object": "chat.completion", "created": 1677652288, "choices": [{ "index": 0, "message": { "role": "assistant", "content": "\n\nHello there, how may I assist you today?", }, "finish_reason": "stop" }], "usage": { "prompt_tokens": 9, "completion_tokens": 12, "total_tokens": 21 }}
所以,咱们只须要获取到 content
字段, 就能咱们和收到ChatGPT聊天的后果了。
对ChatGpt返回的响应,建设实体跟其对应
@Data@AllArgsConstructor@NoArgsConstructor@JsonIgnoreProperties(ignoreUnknown = true)public class ChatGptResponse { private String id; private String object; private Long created; private List<Choice> choices;}@Data@AllArgsConstructor@NoArgsConstructor@JsonIgnoreProperties(ignoreUnknown = true)public class Choice implements Serializable { private String index; private String finish_reason; private Message message;}@Data@AllArgsConstructor@NoArgsConstructor@JsonIgnoreProperties(ignoreUnknown = true)public class Message implements Serializable { private String role; private String content;}
发动申请
之后,查看OpenAI API Reference, 依据文档对api进行申请。这里申请的模型是ChatGpt3.5。
记得在上面的代码中填写你的SecretKey
private void getResponse(String query) { try { questionTV.setText(query); RequestQueue requestQueue = Volley.newRequestQueue(this, new ProxiedHurlStack()); String URL = "https://api.openai.com/v1/chat/completions"; JSONObject jsonBody = new JSONObject(); jsonBody.put("model", "gpt-3.5-turbo"); JSONArray array = new JSONArray(); JSONObject jsonObject = new JSONObject(); jsonObject.put("role", "user"); jsonObject.put("content", query); array.put(jsonObject); jsonBody.put("messages", array); final String requestBody = jsonBody.toString(); StringRequest stringRequest = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.i("VOLLEY", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.i("VOLLEY", String.valueOf(error)); } }) { @Override public String getBodyContentType() { return "application/json; charset=utf-8"; } @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> params = new HashMap<String, String>(); params.put("Content-Type", "application/json"); params.put("Authorization", "Bearer yourSecretKey"); return params; } @Override public byte[] getBody() throws AuthFailureError { try { return requestBody == null ? null : requestBody.getBytes("utf-8"); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8"); return null; } } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { String responseString = new String(response.data, StandardCharsets.UTF_8); // 创立ObjectMapper对象。 ObjectMapper mapper = new ObjectMapper(); // Json格局字符串转Java对象。 try { ChatGptResponse javaEntity = mapper.readValue(responseString, ChatGptResponse.class); String responseMsg = javaEntity.getChoices().get(0).getMessage().getContent(); runOnUiThread(new Runnable() { @Override public void run() { responseTV.setText(responseMsg); } }); } catch (JsonProcessingException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } return Response.success(responseString, HttpHeaderParser.parseCacheHeaders(response)); } }; stringRequest.setRetryPolicy(new RetryPolicy() { @Override public int getCurrentTimeout() { return 50000; } @Override public int getCurrentRetryCount() { return 50000; } @Override public void retry(VolleyError error) throws VolleyError { Log.i("VOLLEY", String.valueOf(error)); } }); requestQueue.add(stringRequest); } catch (JSONException e) { e.printStackTrace(); } }
咱们在申请头上填上咱们的 SecretKey
作为认证信息。
期待 ChatGpt 响应后,把响应的 byte[]
转换为Java对象。
之后将信息显示在屏幕上。
目前我只取了响应的 content 信息, 所以对话不是间断的,对接不了上文。
之后能够再参考 文档 将聊天做成间断的。
每个账户有 18美元 的收费额度,测试的时候 发了25个申请, 也才花了0.01美元。本人用着玩的话足够应用了。